summaryrefslogtreecommitdiffstats
path: root/src/libs/dxvk-native-1.9.2a/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dxvk-native-1.9.2a/src')
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10.def29
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_1.def29
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.cpp81
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.h58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.cpp113
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.h71
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_core.cpp67
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.cpp60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.h55
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.cpp1601
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.h480
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_include.h9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.cpp53
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.h52
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_interfaces.h9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_main.cpp335
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.cpp60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.h103
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.cpp98
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.h68
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.cpp60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.h55
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.cpp326
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.h163
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.cpp73
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.h55
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_shader.h78
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.cpp432
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.h82
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.cpp345
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.h207
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.cpp100
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.h88
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.cpp102
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.h58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.cpp68
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.h58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.cpp83
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.h61
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10core.def5
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/meson.build46
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/version10.rc32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/version10_1.rc32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d10/version10_core.rc32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def5
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp92
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h42
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp309
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h93
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp287
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h162
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp59
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h38
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp85
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h49
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp4507
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h1011
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp383
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h131
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp198
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h78
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp623
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h166
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h187
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp51
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h83
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp166
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h68
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp3447
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h857
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h130
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp14
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h7
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp208
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h46
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp290
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h73
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp84
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h176
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp166
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h67
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp247
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h109
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp352
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h114
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp195
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h66
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp228
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h147
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp147
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp140
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h158
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp199
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h79
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp37
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp681
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h164
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp1269
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h628
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp141
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h46
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp1303
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h612
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h81
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp280
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h98
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp440
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h89
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp592
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h94
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp447
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h94
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build88
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag56
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert12
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9.def22
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.cpp834
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.h112
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.cpp116
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.h96
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_caps.h32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.cpp136
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.h225
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.cpp522
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.h512
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_config.h13
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_layout.h31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_set.h47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.cpp67
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.h35
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.cpp7219
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.h1250
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device_child.h61
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.cpp2486
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.h254
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.cpp568
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.h223
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.cpp146
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.h55
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.cpp36
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.h31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_include.h95
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.cpp183
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.h62
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.cpp374
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.h148
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_main.cpp86
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.cpp66
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.h35
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.cpp9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.h77
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.cpp230
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.h7
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.cpp92
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.h160
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.cpp338
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.h91
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_resource.h84
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.cpp44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.h75
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp192
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.h196
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_permutations.h20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_validator.h68
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_spec_constants.h24
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.h300
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.cpp531
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.h380
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_subresource.h149
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.cpp204
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.h66
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.cpp1320
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.h192
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.cpp359
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.h38
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.cpp248
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.h241
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.cpp380
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.h295
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.cpp234
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.h82
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.cpp112
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.h38
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/meson.build54
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_a2w10v10u10.comp44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_common.h44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_l6v5u5.comp43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_nv12.comp63
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_x8l8v8u8.comp43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp53
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yv12.comp58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/d3d9/version.rc31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.cpp103
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.h87
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.cpp114
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.h69
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.cpp24
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.h39
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.cpp32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.h68
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.cpp7905
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.h1265
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.cpp360
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.h504
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.cpp1117
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.h103
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_enums.h635
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.cpp30
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.h48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_include.h18
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_modinfo.h59
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.cpp116
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.h96
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.cpp445
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.h26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.cpp71
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.h70
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.cpp58
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.h78
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_tag.h47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.h119
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxbc/meson.build23
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi.def7
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.cpp482
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.h129
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.cpp123
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.h5
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.cpp401
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.h157
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.cpp976
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.h173
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_include.h48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_interfaces.h378
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_main.cpp59
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.cpp111
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.h97
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_object.h43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.cpp46
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.h40
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.cpp589
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.h142
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp747
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.h224
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain_dispatcher.h280
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/meson.build25
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxgi/version.rc32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.cpp57
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.h41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.cpp28
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.h54
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.h88
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.cpp3862
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.h683
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.cpp19
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.h32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.cpp280
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.h276
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.cpp101
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.h164
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.cpp24
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.h31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_helpers.h0
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_include.h18
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_isgn.h41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_modinfo.h17
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.cpp86
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.h85
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.cpp48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.h59
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.h60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.cpp93
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.h11
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.cpp34
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.h47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxso/meson.build23
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.cpp802
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.h291
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.cpp288
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.h572
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_bind_mask.h158
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.cpp237
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.h688
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.cpp221
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.h814
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.cpp162
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.h166
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_constant_state.h208
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.cpp5370
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.h1358
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context_state.h173
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.cpp170
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.h433
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.h82
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.cpp88
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.h100
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.cpp291
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.h512
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.cpp40
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.h54
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_info.h53
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extension_provider.h67
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.cpp132
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.h321
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.cpp586
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.h57
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.cpp141
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.h252
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.cpp104
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.h154
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.cpp456
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.h449
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.cpp561
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.h261
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics_state.h728
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_hash.h41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.cpp244
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.h542
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_include.h25
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.cpp218
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.h129
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.cpp15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.h48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_limits.h24
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.cpp5
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.h8
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.cpp448
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.h328
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.cpp599
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.h245
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.cpp210
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.h111
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.cpp695
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.h209
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.cpp181
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.h93
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.cpp287
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.h133
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.cpp714
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.h185
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_objects.h100
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.cpp327
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.h83
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.cpp168
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.h69
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.cpp15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.h37
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.cpp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.h43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.cpp197
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.h281
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.cpp90
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.h121
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_platform_exts.h26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.cpp187
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.h198
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_recycler.h63
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.cpp282
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.h230
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.cpp9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.h93
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.cpp84
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.h79
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.cpp386
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.h355
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.cpp43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.h76
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.cpp30
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.h41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.cpp36
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.h91
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.cpp70
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.h56
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.cpp1059
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.h203
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache_types.h233
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.cpp34
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.h109
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.cpp373
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.h116
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.cpp197
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.h191
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.cpp346
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.h338
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.cpp112
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.h101
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.cpp1872
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.h31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.cpp605
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.h417
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.cpp365
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.h182
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_frag.frag23
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_vert.vert13
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_frag.frag38
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_vert.vert16
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/meson.build143
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_headless_exts.cpp32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_sdl2_exts.cpp60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_win32_exts.cpp36
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_1d.frag19
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_2d.frag19
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_3d.frag20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_f.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_u.comp26
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_buffer_image.comp30
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_1d.frag16
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_2d.frag16
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_ms.frag17
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_1d.frag14
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_2d.frag14
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_ms.frag15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_1d.frag20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_2d.frag20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_ms.frag20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_geom.geom19
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_layer_vert.vert15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_vert.vert14
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d24s8.comp41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d32s8.comp44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag.frag27
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_blit.frag28
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms.frag33
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms_amd.frag52
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_vert.vert12
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_d.frag54
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag83
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f.frag20
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_i.frag15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_u.frag15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8.comp41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8_as_d32s8.comp41
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d32s8.comp46
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/meson.build48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/meson.build9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.cpp154
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.h223
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.cpp110
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.h36
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_include.h12
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_instruction.h155
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.cpp3741
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.h1280
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.cpp28
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.h8
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_include.h17
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_object.h119
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_pointer.h146
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.cpp171
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.h115
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/config/config.cpp723
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/config/config.h152
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/log/log.cpp146
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/log/log.h71
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.cpp11
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.h49
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/meson.build49
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/thread_native.cpp21
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_linux.cpp44
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_win32.cpp38
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_linux.cpp13
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_win32.cpp34
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_linux.cpp19
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_win32.cpp43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc.h36
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc_ptr.h124
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.c170
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.h53
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.cpp48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.h63
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.cpp37
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.h32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sync/sync_signal.h160
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sync/sync_spinlock.h69
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/sync/sync_ticketlock.h40
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/thread.h351
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_bit.h349
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_enum.h7
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_env.cpp71
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_env.h73
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_error.h31
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_flags.h110
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.cpp175
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.h89
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_gdi.cpp33
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_gdi.h32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_lazy.h40
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_likely.h9
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_luid.h15
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_math.h34
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_matrix.cpp232
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_matrix.h85
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_monitor.cpp51
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_monitor.h47
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_ratio.h88
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_small_vector.h133
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_string.h43
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_time.h50
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/util/util_vector.h161
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/meson.build18
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.cpp82
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.h374
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.cpp333
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.h21
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.cpp493
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.h248
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter_headless.cpp177
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_util.h247
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_helpers_headless.h11
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_mode_headless.cpp62
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_monitor_headless.cpp60
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_presenter_headless.cpp14
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_window_headless.cpp83
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/meson.build32
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_helpers_sdl2.h16
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_mode_sdl2.cpp93
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_monitor_sdl2.cpp63
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_presenter_sdl2.cpp21
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_window_sdl2.cpp135
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_mode_win32.cpp62
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_monitor_win32.cpp79
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_presenter_win32.cpp23
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_window_win32.cpp266
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/wsi_mode.h70
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/wsi_monitor.h48
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/wsi_presenter.h21
-rw-r--r--src/libs/dxvk-native-1.9.2a/src/wsi/wsi_window.h115
549 files changed, 129240 insertions, 0 deletions
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10.def b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10.def
new file mode 100644
index 00000000..6da63131
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10.def
@@ -0,0 +1,29 @@
+LIBRARY D3D10.DLL
+EXPORTS
+ D3D10CreateDevice
+ D3D10CreateDeviceAndSwapChain
+ D3D10GetVertexShaderProfile
+ D3D10GetGeometryShaderProfile
+ D3D10GetPixelShaderProfile
+ D3D10CreateBlob
+ D3D10GetInputSignatureBlob
+ D3D10GetOutputSignatureBlob
+ D3D10ReflectShader
+ D3D10CompileShader
+ D3D10CreateEffectFromMemory
+ D3D10CreateEffectPoolFromMemory
+ D3D10CompileEffectFromMemory
+ D3D10DisassembleEffect
+ D3D10DisassembleShader
+ D3D10PreprocessShader
+ D3D10CreateStateBlock
+ D3D10StateBlockMaskDifference
+ D3D10StateBlockMaskDisableAll
+ D3D10StateBlockMaskDisableCapture
+ D3D10StateBlockMaskEnableAll
+ D3D10StateBlockMaskEnableCapture
+ D3D10StateBlockMaskGetSetting
+ D3D10StateBlockMaskIntersect
+ D3D10StateBlockMaskUnion
+ D3D10GetVersion
+ D3D10RegisterLayers
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_1.def b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_1.def
new file mode 100644
index 00000000..d32e4e1a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_1.def
@@ -0,0 +1,29 @@
+LIBRARY D3D10_1.DLL
+EXPORTS
+ D3D10CreateDevice1
+ D3D10CreateDeviceAndSwapChain1
+ D3D10GetVertexShaderProfile
+ D3D10GetGeometryShaderProfile
+ D3D10GetPixelShaderProfile
+ D3D10CreateBlob
+ D3D10GetInputSignatureBlob
+ D3D10GetOutputSignatureBlob
+ D3D10ReflectShader
+ D3D10CompileShader
+ D3D10CreateEffectFromMemory
+ D3D10CreateEffectPoolFromMemory
+ D3D10CompileEffectFromMemory
+ D3D10DisassembleEffect
+ D3D10DisassembleShader
+ D3D10PreprocessShader
+ D3D10CreateStateBlock
+ D3D10StateBlockMaskDifference
+ D3D10StateBlockMaskDisableAll
+ D3D10StateBlockMaskDisableCapture
+ D3D10StateBlockMaskEnableAll
+ D3D10StateBlockMaskEnableCapture
+ D3D10StateBlockMaskGetSetting
+ D3D10StateBlockMaskIntersect
+ D3D10StateBlockMaskUnion
+ D3D10GetVersion
+ D3D10RegisterLayers \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.cpp
new file mode 100644
index 00000000..3dc637d1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.cpp
@@ -0,0 +1,81 @@
+#include "d3d10_blend.h"
+
+#include "../d3d11/d3d11_blend.h"
+#include "../d3d11/d3d11_device.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10BlendState::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10BlendState::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10BlendState::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10BlendState::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10BlendState::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10BlendState::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10BlendState::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10BlendState::GetDesc(
+ D3D10_BLEND_DESC* pDesc) {
+ D3D11_BLEND_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->AlphaToCoverageEnable = d3d11Desc.AlphaToCoverageEnable;
+ pDesc->SrcBlend = D3D10_BLEND (d3d11Desc.RenderTarget[0].SrcBlend);
+ pDesc->DestBlend = D3D10_BLEND (d3d11Desc.RenderTarget[0].DestBlend);
+ pDesc->BlendOp = D3D10_BLEND_OP(d3d11Desc.RenderTarget[0].BlendOp);
+ pDesc->SrcBlendAlpha = D3D10_BLEND (d3d11Desc.RenderTarget[0].SrcBlendAlpha);
+ pDesc->DestBlendAlpha = D3D10_BLEND (d3d11Desc.RenderTarget[0].DestBlendAlpha);
+ pDesc->BlendOpAlpha = D3D10_BLEND_OP(d3d11Desc.RenderTarget[0].BlendOpAlpha);
+
+ for (uint32_t i = 0; i < 8; i++) {
+ uint32_t srcId = d3d11Desc.IndependentBlendEnable ? i : 0;
+ pDesc->BlendEnable[i] = d3d11Desc.RenderTarget[srcId].BlendEnable;
+ pDesc->RenderTargetWriteMask[i] = d3d11Desc.RenderTarget[srcId].RenderTargetWriteMask;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10BlendState::GetDesc1(
+ D3D10_BLEND_DESC1* pDesc) {
+ static_assert(sizeof(D3D10_BLEND_DESC1) == sizeof(D3D11_BLEND_DESC));
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_BLEND_DESC*>(pDesc));
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.h
new file mode 100644
index 00000000..d5d201d7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_blend.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11BlendState;
+ class D3D11Device;
+
+ class D3D10BlendState : public ID3D10BlendState1 {
+
+ public:
+
+ D3D10BlendState(D3D11BlendState* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_BLEND_DESC* pDesc);
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D10_BLEND_DESC1* pDesc);
+
+ D3D11BlendState* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11BlendState* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.cpp
new file mode 100644
index 00000000..2bd089b0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.cpp
@@ -0,0 +1,113 @@
+#include "d3d10_buffer.h"
+
+#include "../d3d11/d3d11_buffer.h"
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_context.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10Buffer::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Buffer::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Buffer::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Buffer::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Buffer::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Buffer::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Buffer::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Buffer::GetType(
+ D3D10_RESOURCE_DIMENSION* rType) {
+ *rType = D3D10_RESOURCE_DIMENSION_BUFFER;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Buffer::SetEvictionPriority(
+ UINT EvictionPriority) {
+ m_d3d11->SetEvictionPriority(EvictionPriority);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Buffer::GetEvictionPriority() {
+ return m_d3d11->GetEvictionPriority();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Buffer::Map(
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ void** ppData) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ HRESULT hr = ctx->Map(m_d3d11, 0,
+ D3D11_MAP(MapType), MapFlags, &sr);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (ppData != nullptr) {
+ *ppData = sr.pData;
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Buffer::Unmap() {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->Unmap(m_d3d11, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Buffer::GetDesc(
+ D3D10_BUFFER_DESC* pDesc) {
+ D3D11_BUFFER_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->ByteWidth = d3d11Desc.ByteWidth;
+ pDesc->Usage = D3D10_USAGE(d3d11Desc.Usage);
+ pDesc->BindFlags = d3d11Desc.BindFlags;
+ pDesc->CPUAccessFlags = d3d11Desc.CPUAccessFlags;
+ pDesc->MiscFlags = ConvertD3D11ResourceFlags(d3d11Desc.MiscFlags);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.h
new file mode 100644
index 00000000..f26a7154
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_buffer.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Buffer;
+ class D3D11Device;
+ class D3D10Device;
+
+ class D3D10Buffer : public ID3D10Buffer {
+
+ public:
+
+ D3D10Buffer(D3D11Buffer* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetType(
+ D3D10_RESOURCE_DIMENSION* rType);
+
+ void STDMETHODCALLTYPE SetEvictionPriority(
+ UINT EvictionPriority);
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority();
+
+ HRESULT STDMETHODCALLTYPE Map(
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ void** ppData);
+
+ void STDMETHODCALLTYPE Unmap();
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_BUFFER_DESC* pDesc);
+
+ D3D11Buffer* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11Buffer* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_core.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_core.cpp
new file mode 100644
index 00000000..d4d229ed
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_core.cpp
@@ -0,0 +1,67 @@
+#include <d3d11.h>
+#include <d3d10_1.h>
+
+#include "../dxgi/dxgi_interfaces.h"
+
+extern "C" {
+ using namespace dxvk;
+
+ HRESULT __stdcall D3D11CoreCreateDevice(
+ IDXGIFactory* pFactory,
+ IDXGIAdapter* pAdapter,
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ ID3D11Device** ppDevice);
+
+
+ DLLEXPORT HRESULT __stdcall D3D10CoreCreateDevice(
+ IDXGIFactory* pFactory,
+ IDXGIAdapter* pAdapter,
+ UINT Flags,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ ID3D10Device** ppDevice) {
+ InitReturnPtr(ppDevice);
+
+ Com<ID3D11Device> d3d11Device;
+
+ HRESULT hr = pAdapter->CheckInterfaceSupport(
+ __uuidof(ID3D10Device), nullptr);
+
+ if (FAILED(hr))
+ return hr;
+
+ hr = D3D11CoreCreateDevice(pFactory, pAdapter,
+ Flags, &FeatureLevel, 1, &d3d11Device);
+
+ if (FAILED(hr))
+ return hr;
+
+ Com<ID3D10Multithread> multithread;
+ d3d11Device->QueryInterface(__uuidof(ID3D10Multithread), reinterpret_cast<void**>(&multithread));
+ multithread->SetMultithreadProtected(!(Flags & D3D10_CREATE_DEVICE_SINGLETHREADED));
+
+ Com<IDXGIDXVKDevice> dxvkDevice;
+ d3d11Device->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast<void**>(&dxvkDevice));
+ dxvkDevice->SetAPIVersion(10);
+
+ if (FAILED(d3d11Device->QueryInterface(
+ __uuidof(ID3D10Device), reinterpret_cast<void**>(ppDevice))))
+ return E_FAIL;
+
+ return S_OK;
+ }
+
+
+ UINT64 STDMETHODCALLTYPE D3D10CoreGetVersion() {
+ // Match the Windows 10 return value, but we
+ // don't know the exact function signature
+ return 0xa000100041770ull;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CoreRegisterLayers() {
+ return E_NOTIMPL;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.cpp
new file mode 100644
index 00000000..a56749cb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.cpp
@@ -0,0 +1,60 @@
+#include "d3d10_depth_stencil.h"
+
+#include "../d3d11/d3d11_depth_stencil.h"
+#include "../d3d11/d3d11_device.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilState::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10DepthStencilState::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10DepthStencilState::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10DepthStencilState::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilState::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilState::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilState::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10DepthStencilState::GetDesc(
+ D3D10_DEPTH_STENCIL_DESC* pDesc) {
+ static_assert(sizeof(D3D10_DEPTH_STENCIL_DESC) == sizeof(D3D11_DEPTH_STENCIL_DESC));
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_DEPTH_STENCIL_DESC*>(pDesc));
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.h
new file mode 100644
index 00000000..953a8b0c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_depth_stencil.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11DepthStencilState;
+ class D3D11Device;
+
+ class D3D10DepthStencilState : public ID3D10DepthStencilState {
+
+ public:
+
+ D3D10DepthStencilState(D3D11DepthStencilState* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_DEPTH_STENCIL_DESC* pDesc);
+
+ D3D11DepthStencilState* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11DepthStencilState* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.cpp
new file mode 100644
index 00000000..4b639fc6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.cpp
@@ -0,0 +1,1601 @@
+#include "d3d10_device.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_context_imm.h"
+
+namespace dxvk {
+
+ D3D10Device::D3D10Device(
+ D3D11Device* pDevice,
+ D3D11ImmediateContext* pContext)
+ : m_device(pDevice), m_context(pContext) {
+ }
+
+
+ D3D10Device::~D3D10Device() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_device->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Device::AddRef() {
+ return m_device->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Device::Release() {
+ return m_device->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_device->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_device->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_device->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::GetDeviceRemovedReason() {
+ return m_device->GetDeviceRemovedReason();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::SetExceptionMode(
+ UINT RaiseFlags) {
+ return m_device->SetExceptionMode(RaiseFlags);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Device::GetExceptionMode() {
+ return m_device->GetExceptionMode();
+ }
+
+
+ D3D10_FEATURE_LEVEL1 STDMETHODCALLTYPE D3D10Device::GetFeatureLevel() {
+ return D3D10_FEATURE_LEVEL1(m_device->GetFeatureLevel());
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::ClearState() {
+ m_context->ClearState();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::Flush() {
+ m_context->Flush();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateBuffer(
+ const D3D10_BUFFER_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Buffer** ppBuffer) {
+ InitReturnPtr(ppBuffer);
+
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_BUFFER_DESC d3d11Desc;
+ d3d11Desc.ByteWidth = pDesc->ByteWidth;
+ d3d11Desc.Usage = D3D11_USAGE(pDesc->Usage);
+ d3d11Desc.BindFlags = pDesc->BindFlags;
+ d3d11Desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ d3d11Desc.MiscFlags = ConvertD3D10ResourceFlags(pDesc->MiscFlags);
+ d3d11Desc.StructureByteStride = 0;
+
+ ID3D11Buffer* d3d11Buffer = nullptr;
+ HRESULT hr = m_device->CreateBuffer(&d3d11Desc,
+ reinterpret_cast<const D3D11_SUBRESOURCE_DATA*>(pInitialData),
+ ppBuffer != nullptr ? &d3d11Buffer : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppBuffer = static_cast<D3D11Buffer*>(d3d11Buffer)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateTexture1D(
+ const D3D10_TEXTURE1D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture1D** ppTexture1D) {
+ InitReturnPtr(ppTexture1D);
+
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE1D_DESC d3d11Desc;
+ d3d11Desc.Width = pDesc->Width;
+ d3d11Desc.MipLevels = pDesc->MipLevels;
+ d3d11Desc.ArraySize = pDesc->ArraySize;
+ d3d11Desc.Format = pDesc->Format;
+ d3d11Desc.Usage = D3D11_USAGE(pDesc->Usage);
+ d3d11Desc.BindFlags = pDesc->BindFlags;
+ d3d11Desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ d3d11Desc.MiscFlags = ConvertD3D10ResourceFlags(pDesc->MiscFlags);
+
+ ID3D11Texture1D* d3d11Texture1D = nullptr;
+ HRESULT hr = m_device->CreateTexture1D(&d3d11Desc,
+ reinterpret_cast<const D3D11_SUBRESOURCE_DATA*>(pInitialData),
+ ppTexture1D != nullptr ? &d3d11Texture1D : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppTexture1D = static_cast<D3D11Texture1D*>(d3d11Texture1D)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateTexture2D(
+ const D3D10_TEXTURE2D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture2D** ppTexture2D) {
+ InitReturnPtr(ppTexture2D);
+
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE2D_DESC d3d11Desc;
+ d3d11Desc.Width = pDesc->Width;
+ d3d11Desc.Height = pDesc->Height;
+ d3d11Desc.MipLevels = pDesc->MipLevels;
+ d3d11Desc.ArraySize = pDesc->ArraySize;
+ d3d11Desc.Format = pDesc->Format;
+ d3d11Desc.SampleDesc = pDesc->SampleDesc;
+ d3d11Desc.Usage = D3D11_USAGE(pDesc->Usage);
+ d3d11Desc.BindFlags = pDesc->BindFlags;
+ d3d11Desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ d3d11Desc.MiscFlags = ConvertD3D10ResourceFlags(pDesc->MiscFlags);
+
+ ID3D11Texture2D* d3d11Texture2D = nullptr;
+ HRESULT hr = m_device->CreateTexture2D(&d3d11Desc,
+ reinterpret_cast<const D3D11_SUBRESOURCE_DATA*>(pInitialData),
+ ppTexture2D != nullptr ? &d3d11Texture2D : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppTexture2D = static_cast<D3D11Texture2D*>(d3d11Texture2D)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateTexture3D(
+ const D3D10_TEXTURE3D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture3D** ppTexture3D) {
+ InitReturnPtr(ppTexture3D);
+
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE3D_DESC d3d11Desc;
+ d3d11Desc.Width = pDesc->Width;
+ d3d11Desc.Height = pDesc->Height;
+ d3d11Desc.Depth = pDesc->Depth;
+ d3d11Desc.MipLevels = pDesc->MipLevels;
+ d3d11Desc.Format = pDesc->Format;
+ d3d11Desc.Usage = D3D11_USAGE(pDesc->Usage);
+ d3d11Desc.BindFlags = pDesc->BindFlags;
+ d3d11Desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ d3d11Desc.MiscFlags = ConvertD3D10ResourceFlags(pDesc->MiscFlags);
+
+ ID3D11Texture3D* d3d11Texture3D = nullptr;
+ HRESULT hr = m_device->CreateTexture3D(&d3d11Desc,
+ reinterpret_cast<const D3D11_SUBRESOURCE_DATA*>(pInitialData),
+ ppTexture3D != nullptr ? &d3d11Texture3D : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppTexture3D = static_cast<D3D11Texture3D*>(d3d11Texture3D)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateShaderResourceView(
+ ID3D10Resource* pResource,
+ const D3D10_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D10ShaderResourceView** ppSRView) {
+ InitReturnPtr(ppSRView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ Com<ID3D11Resource> d3d11Resource;
+ GetD3D11Resource(pResource, &d3d11Resource);
+
+ ID3D11ShaderResourceView* d3d11Srv = nullptr;
+ HRESULT hr = m_device->CreateShaderResourceView(d3d11Resource.ptr(),
+ reinterpret_cast<const D3D11_SHADER_RESOURCE_VIEW_DESC*>(pDesc),
+ ppSRView ? &d3d11Srv : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppSRView = static_cast<D3D11ShaderResourceView*>(d3d11Srv)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateShaderResourceView1(
+ ID3D10Resource* pResource,
+ const D3D10_SHADER_RESOURCE_VIEW_DESC1* pDesc,
+ ID3D10ShaderResourceView1** ppSRView) {
+ InitReturnPtr(ppSRView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ Com<ID3D11Resource> d3d11Resource;
+ GetD3D11Resource(pResource, &d3d11Resource);
+
+ ID3D11ShaderResourceView* d3d11View = nullptr;
+ HRESULT hr = m_device->CreateShaderResourceView(d3d11Resource.ptr(),
+ reinterpret_cast<const D3D11_SHADER_RESOURCE_VIEW_DESC*>(pDesc),
+ ppSRView ? &d3d11View : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppSRView = static_cast<D3D11ShaderResourceView*>(d3d11View)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateRenderTargetView(
+ ID3D10Resource* pResource,
+ const D3D10_RENDER_TARGET_VIEW_DESC* pDesc,
+ ID3D10RenderTargetView** ppRTView) {
+ InitReturnPtr(ppRTView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ Com<ID3D11Resource> d3d11Resource;
+ GetD3D11Resource(pResource, &d3d11Resource);
+
+ ID3D11RenderTargetView* d3d11View = nullptr;
+ HRESULT hr = m_device->CreateRenderTargetView(d3d11Resource.ptr(),
+ reinterpret_cast<const D3D11_RENDER_TARGET_VIEW_DESC*>(pDesc),
+ ppRTView ? &d3d11View : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppRTView = static_cast<D3D11RenderTargetView*>(d3d11View)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateDepthStencilView(
+ ID3D10Resource* pResource,
+ const D3D10_DEPTH_STENCIL_VIEW_DESC* pDesc,
+ ID3D10DepthStencilView** ppDepthStencilView) {
+ InitReturnPtr(ppDepthStencilView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ Com<ID3D11Resource> d3d11Resource;
+ GetD3D11Resource(pResource, &d3d11Resource);
+
+ // D3D10 doesn't have the Flags member, so we have
+ // to convert the structure. pDesc can be nullptr.
+ D3D11_DEPTH_STENCIL_VIEW_DESC d3d11Desc;
+
+ if (pDesc != nullptr) {
+ d3d11Desc.ViewDimension = D3D11_DSV_DIMENSION(pDesc->ViewDimension);
+ d3d11Desc.Format = pDesc->Format;
+ d3d11Desc.Flags = 0;
+
+ switch (pDesc->ViewDimension) {
+ case D3D10_DSV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE1D:
+ d3d11Desc.Texture1D.MipSlice = pDesc->Texture1D.MipSlice;
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE1DARRAY:
+ d3d11Desc.Texture1DArray.MipSlice = pDesc->Texture1DArray.MipSlice;
+ d3d11Desc.Texture1DArray.FirstArraySlice = pDesc->Texture1DArray.FirstArraySlice;
+ d3d11Desc.Texture1DArray.ArraySize = pDesc->Texture1DArray.ArraySize;
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE2D:
+ d3d11Desc.Texture2D.MipSlice = pDesc->Texture2D.MipSlice;
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE2DARRAY:
+ d3d11Desc.Texture2DArray.MipSlice = pDesc->Texture2DArray.MipSlice;
+ d3d11Desc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
+ d3d11Desc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize;
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE2DMS:
+ break;
+
+ case D3D10_DSV_DIMENSION_TEXTURE2DMSARRAY:
+ d3d11Desc.Texture2DMSArray.FirstArraySlice = pDesc->Texture2DMSArray.FirstArraySlice;
+ d3d11Desc.Texture2DMSArray.ArraySize = pDesc->Texture2DMSArray.ArraySize;
+ break;
+ }
+ }
+
+ ID3D11DepthStencilView* d3d11View = nullptr;
+ HRESULT hr = m_device->CreateDepthStencilView(
+ d3d11Resource.ptr(), pDesc ? &d3d11Desc : nullptr,
+ ppDepthStencilView ? &d3d11View : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppDepthStencilView = static_cast<D3D11DepthStencilView*>(d3d11View)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateInputLayout(
+ const D3D10_INPUT_ELEMENT_DESC* pInputElementDescs,
+ UINT NumElements,
+ const void* pShaderBytecodeWithInputSignature,
+ SIZE_T BytecodeLength,
+ ID3D10InputLayout** ppInputLayout) {
+ InitReturnPtr(ppInputLayout);
+
+ static_assert(sizeof(D3D10_INPUT_ELEMENT_DESC) ==
+ sizeof(D3D11_INPUT_ELEMENT_DESC));
+
+ ID3D11InputLayout* d3d11InputLayout = nullptr;
+ HRESULT hr = m_device->CreateInputLayout(
+ reinterpret_cast<const D3D11_INPUT_ELEMENT_DESC*>(pInputElementDescs),
+ NumElements, pShaderBytecodeWithInputSignature, BytecodeLength,
+ ppInputLayout ? &d3d11InputLayout : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppInputLayout = static_cast<D3D11InputLayout*>(d3d11InputLayout)->GetD3D10Iface();
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateVertexShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10VertexShader** ppVertexShader) {
+ InitReturnPtr(ppVertexShader);
+
+ ID3D11VertexShader* d3d11Shader = nullptr;
+
+ HRESULT hr = m_device->CreateVertexShader(
+ pShaderBytecode, BytecodeLength, nullptr,
+ ppVertexShader ? &d3d11Shader : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppVertexShader = static_cast<D3D11VertexShader*>(d3d11Shader)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateGeometryShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10GeometryShader** ppGeometryShader) {
+ InitReturnPtr(ppGeometryShader);
+
+ ID3D11GeometryShader* d3d11Shader = nullptr;
+
+ HRESULT hr = m_device->CreateGeometryShader(
+ pShaderBytecode, BytecodeLength, nullptr,
+ ppGeometryShader ? &d3d11Shader : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppGeometryShader = static_cast<D3D11GeometryShader*>(d3d11Shader)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateGeometryShaderWithStreamOutput(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ const D3D10_SO_DECLARATION_ENTRY* pSODeclaration,
+ UINT NumEntries,
+ UINT OutputStreamStride,
+ ID3D10GeometryShader** ppGeometryShader) {
+ InitReturnPtr(ppGeometryShader);
+
+ std::vector<D3D11_SO_DECLARATION_ENTRY> d3d11Entries(NumEntries);
+
+ for (uint32_t i = 0; i < NumEntries; i++) {
+ d3d11Entries[i].Stream = 0;
+ d3d11Entries[i].SemanticName = pSODeclaration[i].SemanticName;
+ d3d11Entries[i].SemanticIndex = pSODeclaration[i].SemanticIndex;
+ d3d11Entries[i].StartComponent = pSODeclaration[i].StartComponent;
+ d3d11Entries[i].ComponentCount = pSODeclaration[i].ComponentCount;
+ d3d11Entries[i].OutputSlot = pSODeclaration[i].OutputSlot;
+ }
+
+ ID3D11GeometryShader* d3d11Shader = nullptr;
+
+ HRESULT hr = m_device->CreateGeometryShaderWithStreamOutput(
+ pShaderBytecode, BytecodeLength,
+ d3d11Entries.data(),
+ d3d11Entries.size(),
+ &OutputStreamStride, 1,
+ D3D11_SO_NO_RASTERIZED_STREAM, nullptr,
+ ppGeometryShader ? &d3d11Shader : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppGeometryShader = static_cast<D3D11GeometryShader*>(d3d11Shader)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreatePixelShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10PixelShader** ppPixelShader) {
+ InitReturnPtr(ppPixelShader);
+
+ ID3D11PixelShader* d3d11Shader = nullptr;
+
+ HRESULT hr = m_device->CreatePixelShader(
+ pShaderBytecode, BytecodeLength, nullptr,
+ ppPixelShader ? &d3d11Shader : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppPixelShader = static_cast<D3D11PixelShader*>(d3d11Shader)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateBlendState(
+ const D3D10_BLEND_DESC* pBlendStateDesc,
+ ID3D10BlendState** ppBlendState) {
+ InitReturnPtr(ppBlendState);
+
+ D3D11_BLEND_DESC d3d11Desc;
+
+ if (pBlendStateDesc != nullptr) {
+ d3d11Desc.AlphaToCoverageEnable = pBlendStateDesc->AlphaToCoverageEnable;
+ d3d11Desc.IndependentBlendEnable = TRUE;
+
+ for (uint32_t i = 0; i < 8; i++) {
+ d3d11Desc.RenderTarget[i].BlendEnable = pBlendStateDesc->BlendEnable[i];
+ d3d11Desc.RenderTarget[i].SrcBlend = D3D11_BLEND (pBlendStateDesc->SrcBlend);
+ d3d11Desc.RenderTarget[i].DestBlend = D3D11_BLEND (pBlendStateDesc->DestBlend);
+ d3d11Desc.RenderTarget[i].BlendOp = D3D11_BLEND_OP(pBlendStateDesc->BlendOp);
+ d3d11Desc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND (pBlendStateDesc->SrcBlendAlpha);
+ d3d11Desc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND (pBlendStateDesc->DestBlendAlpha);
+ d3d11Desc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP(pBlendStateDesc->BlendOpAlpha);
+ d3d11Desc.RenderTarget[i].RenderTargetWriteMask = pBlendStateDesc->RenderTargetWriteMask[i];
+ }
+ }
+
+ ID3D11BlendState* d3d11BlendState = nullptr;
+ HRESULT hr = m_device->CreateBlendState(&d3d11Desc,
+ ppBlendState ? &d3d11BlendState : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppBlendState = static_cast<D3D11BlendState*>(d3d11BlendState)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateBlendState1(
+ const D3D10_BLEND_DESC1* pBlendStateDesc,
+ ID3D10BlendState1** ppBlendState) {
+ InitReturnPtr(ppBlendState);
+
+ ID3D11BlendState* d3d11BlendState = nullptr;
+ HRESULT hr = m_device->CreateBlendState(
+ reinterpret_cast<const D3D11_BLEND_DESC*>(pBlendStateDesc),
+ ppBlendState ? &d3d11BlendState : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppBlendState = static_cast<D3D11BlendState*>(d3d11BlendState)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateDepthStencilState(
+ const D3D10_DEPTH_STENCIL_DESC* pDepthStencilDesc,
+ ID3D10DepthStencilState** ppDepthStencilState) {
+ InitReturnPtr(ppDepthStencilState);
+
+ ID3D11DepthStencilState* d3d11DepthStencilState = nullptr;
+ HRESULT hr = m_device->CreateDepthStencilState(
+ reinterpret_cast<const D3D11_DEPTH_STENCIL_DESC*>(pDepthStencilDesc),
+ ppDepthStencilState ? &d3d11DepthStencilState : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppDepthStencilState = static_cast<D3D11DepthStencilState*>(d3d11DepthStencilState)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateRasterizerState(
+ const D3D10_RASTERIZER_DESC* pRasterizerDesc,
+ ID3D10RasterizerState** ppRasterizerState) {
+ InitReturnPtr(ppRasterizerState);
+
+ ID3D11RasterizerState* d3d11RasterizerState = nullptr;
+ HRESULT hr = m_device->CreateRasterizerState(
+ reinterpret_cast<const D3D11_RASTERIZER_DESC*>(pRasterizerDesc),
+ ppRasterizerState ? &d3d11RasterizerState : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppRasterizerState = static_cast<D3D11RasterizerState*>(d3d11RasterizerState)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateSamplerState(
+ const D3D10_SAMPLER_DESC* pSamplerDesc,
+ ID3D10SamplerState** ppSamplerState) {
+ InitReturnPtr(ppSamplerState);
+
+ if (pSamplerDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_SAMPLER_DESC d3d11Desc;
+ d3d11Desc.Filter = D3D11_FILTER(pSamplerDesc->Filter);
+ d3d11Desc.AddressU = D3D11_TEXTURE_ADDRESS_MODE(pSamplerDesc->AddressU);
+ d3d11Desc.AddressV = D3D11_TEXTURE_ADDRESS_MODE(pSamplerDesc->AddressV);
+ d3d11Desc.AddressW = D3D11_TEXTURE_ADDRESS_MODE(pSamplerDesc->AddressW);
+ d3d11Desc.MipLODBias = pSamplerDesc->MipLODBias;
+ d3d11Desc.MaxAnisotropy = pSamplerDesc->MaxAnisotropy;
+ d3d11Desc.ComparisonFunc = D3D11_COMPARISON_FUNC(pSamplerDesc->ComparisonFunc);
+ d3d11Desc.MinLOD = pSamplerDesc->MinLOD;
+ d3d11Desc.MaxLOD = pSamplerDesc->MaxLOD;
+
+ for (uint32_t i = 0; i < 4; i++)
+ d3d11Desc.BorderColor[i] = pSamplerDesc->BorderColor[i];
+
+ ID3D11SamplerState* d3d11SamplerState = nullptr;
+ HRESULT hr = m_device->CreateSamplerState(&d3d11Desc,
+ ppSamplerState ? &d3d11SamplerState : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppSamplerState = static_cast<D3D11SamplerState*>(d3d11SamplerState)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateQuery(
+ const D3D10_QUERY_DESC* pQueryDesc,
+ ID3D10Query** ppQuery) {
+ InitReturnPtr(ppQuery);
+
+ if (pQueryDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_QUERY_DESC d3d11Desc;
+ d3d11Desc.Query = D3D11_QUERY(pQueryDesc->Query);
+ d3d11Desc.MiscFlags = pQueryDesc->MiscFlags;
+
+ ID3D11Query* d3d11Query = nullptr;
+ HRESULT hr = m_device->CreateQuery(&d3d11Desc,
+ ppQuery ? &d3d11Query : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppQuery = static_cast<D3D11Query*>(d3d11Query)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreatePredicate(
+ const D3D10_QUERY_DESC* pPredicateDesc,
+ ID3D10Predicate** ppPredicate) {
+ InitReturnPtr(ppPredicate);
+
+ D3D11_QUERY_DESC d3d11Desc;
+ d3d11Desc.Query = D3D11_QUERY(pPredicateDesc->Query);
+ d3d11Desc.MiscFlags = pPredicateDesc->MiscFlags;
+
+ ID3D11Predicate* d3d11Predicate = nullptr;
+ HRESULT hr = m_device->CreatePredicate(&d3d11Desc,
+ ppPredicate ? &d3d11Predicate : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppPredicate = D3D11Query::FromPredicate(d3d11Predicate)->GetD3D10Iface();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CreateCounter(
+ const D3D10_COUNTER_DESC* pCounterDesc,
+ ID3D10Counter** ppCounter) {
+ Logger::err("D3D10Device::CreateCounter: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CheckFormatSupport(
+ DXGI_FORMAT Format,
+ UINT* pFormatSupport) {
+ return m_device->CheckFormatSupport(Format, pFormatSupport);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CheckMultisampleQualityLevels(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT* pNumQualityLevels) {
+ return m_device->CheckMultisampleQualityLevels(
+ Format, SampleCount, pNumQualityLevels);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::CheckCounterInfo(
+ D3D10_COUNTER_INFO* pCounterInfo) {
+ Logger::err("D3D10Device::CheckCounterInfo: Not implemented");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::CheckCounter(
+ const D3D10_COUNTER_DESC* pDesc,
+ D3D10_COUNTER_TYPE* pType,
+ UINT* pActiveCounters,
+ char* name,
+ UINT* pNameLength,
+ char* units,
+ UINT* pUnitsLength,
+ char* description,
+ UINT* pDescriptionLength) {
+ Logger::err("D3D10Device::CheckCounter: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Device::GetCreationFlags() {
+ return m_device->GetCreationFlags();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Device::OpenSharedResource(
+ HANDLE hResource,
+ REFIID ReturnedInterface,
+ void** ppResource) {
+ InitReturnPtr(ppResource);
+
+ Logger::err("D3D10Device::OpenSharedResource: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::ClearRenderTargetView(
+ ID3D10RenderTargetView* pRenderTargetView,
+ const FLOAT ColorRGBA[4]) {
+ D3D10RenderTargetView* d3d10View = static_cast<D3D10RenderTargetView*>(pRenderTargetView);
+ D3D11RenderTargetView* d3d11View = d3d10View ? d3d10View->GetD3D11Iface() : nullptr;
+
+ m_context->ClearRenderTargetView(d3d11View, ColorRGBA);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::ClearDepthStencilView(
+ ID3D10DepthStencilView* pDepthStencilView,
+ UINT ClearFlags,
+ FLOAT Depth,
+ UINT8 Stencil) {
+ D3D10DepthStencilView* d3d10View = static_cast<D3D10DepthStencilView*>(pDepthStencilView);
+ D3D11DepthStencilView* d3d11View = d3d10View ? d3d10View->GetD3D11Iface() : nullptr;
+
+ m_context->ClearDepthStencilView(d3d11View, ClearFlags, Depth, Stencil);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::SetPredication(
+ ID3D10Predicate* pPredicate,
+ BOOL PredicateValue) {
+ D3D10Query* d3d10Predicate = static_cast<D3D10Query*>(pPredicate);
+ D3D11Query* d3d11Predicate = d3d10Predicate ? d3d10Predicate->GetD3D11Iface() : nullptr;
+
+ m_context->SetPredication(D3D11Query::AsPredicate(d3d11Predicate), PredicateValue);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GetPredication(
+ ID3D10Predicate** ppPredicate,
+ BOOL* pPredicateValue) {
+ ID3D11Predicate* d3d11Predicate = nullptr;
+
+ m_context->GetPredication(
+ ppPredicate ? &d3d11Predicate : nullptr,
+ pPredicateValue);
+
+ if (ppPredicate)
+ *ppPredicate = d3d11Predicate ? D3D11Query::FromPredicate(d3d11Predicate)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::CopySubresourceRegion(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D10Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D10_BOX* pSrcBox) {
+ if (!pDstResource || !pSrcResource)
+ return;
+
+ Com<ID3D11Resource> d3d11DstResource;
+ Com<ID3D11Resource> d3d11SrcResource;
+
+ GetD3D11Resource(pDstResource, &d3d11DstResource);
+ GetD3D11Resource(pSrcResource, &d3d11SrcResource);
+
+ m_context->CopySubresourceRegion(
+ d3d11DstResource.ptr(), DstSubresource, DstX, DstY, DstZ,
+ d3d11SrcResource.ptr(), SrcSubresource,
+ reinterpret_cast<const D3D11_BOX*>(pSrcBox));
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::CopyResource(
+ ID3D10Resource* pDstResource,
+ ID3D10Resource* pSrcResource) {
+ if (!pDstResource || !pSrcResource)
+ return;
+
+ Com<ID3D11Resource> d3d11DstResource;
+ Com<ID3D11Resource> d3d11SrcResource;
+
+ GetD3D11Resource(pDstResource, &d3d11DstResource);
+ GetD3D11Resource(pSrcResource, &d3d11SrcResource);
+
+ m_context->CopyResource(
+ d3d11DstResource.ptr(),
+ d3d11SrcResource.ptr());
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::UpdateSubresource(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D10_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch) {
+ if (!pDstResource)
+ return;
+
+ Com<ID3D11Resource> d3d11DstResource;
+ GetD3D11Resource(pDstResource, &d3d11DstResource);
+
+ m_context->UpdateSubresource(
+ d3d11DstResource.ptr(), DstSubresource,
+ reinterpret_cast<const D3D11_BOX*>(pDstBox),
+ pSrcData, SrcRowPitch, SrcDepthPitch);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GenerateMips(
+ ID3D10ShaderResourceView* pShaderResourceView) {
+ D3D10ShaderResourceView* d3d10View = static_cast<D3D10ShaderResourceView*>(pShaderResourceView);
+ D3D11ShaderResourceView* d3d11View = d3d10View ? d3d10View->GetD3D11Iface() : nullptr;
+
+ m_context->GenerateMips(d3d11View);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::ResolveSubresource(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ ID3D10Resource* pSrcResource,
+ UINT SrcSubresource,
+ DXGI_FORMAT Format) {
+ if (!pDstResource || !pSrcResource)
+ return;
+
+ Com<ID3D11Resource> d3d11DstResource;
+ Com<ID3D11Resource> d3d11SrcResource;
+
+ GetD3D11Resource(pDstResource, &d3d11DstResource);
+ GetD3D11Resource(pSrcResource, &d3d11SrcResource);
+
+ m_context->ResolveSubresource(
+ d3d11DstResource.ptr(), DstSubresource,
+ d3d11SrcResource.ptr(), SrcSubresource,
+ Format);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::Draw(
+ UINT VertexCount,
+ UINT StartVertexLocation) {
+ m_context->Draw(VertexCount,
+ StartVertexLocation);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::DrawIndexed(
+ UINT IndexCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation) {
+ m_context->DrawIndexed(IndexCount,
+ StartIndexLocation,
+ BaseVertexLocation);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::DrawInstanced(
+ UINT VertexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartVertexLocation,
+ UINT StartInstanceLocation) {
+ m_context->DrawInstanced(
+ VertexCountPerInstance,
+ InstanceCount,
+ StartVertexLocation,
+ StartInstanceLocation);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::DrawIndexedInstanced(
+ UINT IndexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation,
+ UINT StartInstanceLocation) {
+ m_context->DrawIndexedInstanced(
+ IndexCountPerInstance,
+ InstanceCount,
+ StartIndexLocation,
+ BaseVertexLocation,
+ StartInstanceLocation);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::DrawAuto() {
+ m_context->DrawAuto();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IASetInputLayout(
+ ID3D10InputLayout* pInputLayout) {
+ D3D10InputLayout* d3d10InputLayout = static_cast<D3D10InputLayout*>(pInputLayout);
+ D3D11InputLayout* d3d11InputLayout = d3d10InputLayout ? d3d10InputLayout->GetD3D11Iface() : nullptr;
+
+ m_context->IASetInputLayout(d3d11InputLayout);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IASetPrimitiveTopology(
+ D3D10_PRIMITIVE_TOPOLOGY Topology) {
+ m_context->IASetPrimitiveTopology(
+ D3D11_PRIMITIVE_TOPOLOGY(Topology));
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IASetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppVertexBuffers,
+ const UINT* pStrides,
+ const UINT* pOffsets) {
+ ID3D11Buffer* d3d11Buffers[D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+
+ if (NumBuffers > D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ d3d11Buffers[i] = ppVertexBuffers[i]
+ ? static_cast<D3D10Buffer*>(ppVertexBuffers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->IASetVertexBuffers(
+ StartSlot, NumBuffers, d3d11Buffers,
+ pStrides, pOffsets);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IASetIndexBuffer(
+ ID3D10Buffer* pIndexBuffer,
+ DXGI_FORMAT Format,
+ UINT Offset) {
+ D3D10Buffer* d3d10Buffer = static_cast<D3D10Buffer*>(pIndexBuffer);
+ D3D11Buffer* d3d11Buffer = d3d10Buffer ? d3d10Buffer->GetD3D11Iface() : nullptr;
+
+ m_context->IASetIndexBuffer(d3d11Buffer, Format, Offset);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IAGetInputLayout(
+ ID3D10InputLayout** ppInputLayout) {
+ ID3D11InputLayout* d3d11InputLayout = nullptr;
+ m_context->IAGetInputLayout(&d3d11InputLayout);
+
+ *ppInputLayout = d3d11InputLayout
+ ? static_cast<D3D11InputLayout*>(d3d11InputLayout)->GetD3D10Iface()
+ : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IAGetPrimitiveTopology(
+ D3D10_PRIMITIVE_TOPOLOGY* pTopology) {
+ D3D11_PRIMITIVE_TOPOLOGY d3d11Topology;
+ m_context->IAGetPrimitiveTopology(&d3d11Topology);
+
+ *pTopology = d3d11Topology <= 32 /* begin patch list */
+ ? D3D10_PRIMITIVE_TOPOLOGY(d3d11Topology)
+ : D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IAGetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppVertexBuffers,
+ UINT* pStrides,
+ UINT* pOffsets) {
+ ID3D11Buffer* d3d11Buffers[D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+
+ m_context->IAGetVertexBuffers(
+ StartSlot, NumBuffers,
+ ppVertexBuffers ? d3d11Buffers : nullptr,
+ pStrides, pOffsets);
+
+ if (ppVertexBuffers) {
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppVertexBuffers[i] = d3d11Buffers[i]
+ ? static_cast<D3D11Buffer*>(d3d11Buffers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::IAGetIndexBuffer(
+ ID3D10Buffer** pIndexBuffer,
+ DXGI_FORMAT* Format,
+ UINT* Offset) {
+ ID3D11Buffer* d3d11Buffer = nullptr;
+
+ m_context->IAGetIndexBuffer(
+ pIndexBuffer ? &d3d11Buffer : nullptr,
+ Format, Offset);
+
+ if (pIndexBuffer)
+ *pIndexBuffer = d3d11Buffer ? static_cast<D3D11Buffer*>(d3d11Buffer)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSSetShader(
+ ID3D10VertexShader* pVertexShader) {
+ D3D10VertexShader* d3d10Shader = static_cast<D3D10VertexShader*>(pVertexShader);
+ D3D11VertexShader* d3d11Shader = d3d10Shader ? d3d10Shader->GetD3D11Iface() : nullptr;
+
+ m_context->VSSetShader(d3d11Shader, nullptr, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+
+ if (NumBuffers > D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ d3d11Buffers[i] = ppConstantBuffers && ppConstantBuffers[i]
+ ? static_cast<D3D10Buffer*>(ppConstantBuffers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->VSSetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+
+ if (NumViews > D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ d3d11Views[i] = ppShaderResourceViews && ppShaderResourceViews[i]
+ ? static_cast<D3D10ShaderResourceView*>(ppShaderResourceViews[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->VSSetShaderResources(StartSlot, NumViews, d3d11Views);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+
+ if (NumSamplers > D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ d3d11Samplers[i] = ppSamplers && ppSamplers[i]
+ ? static_cast<D3D10SamplerState*>(ppSamplers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->VSSetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSGetShader(
+ ID3D10VertexShader** ppVertexShader) {
+ ID3D11VertexShader* d3d11Shader = nullptr;
+ m_context->VSGetShader(&d3d11Shader, nullptr, nullptr);
+
+ *ppVertexShader = d3d11Shader ? static_cast<D3D11VertexShader*>(d3d11Shader)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+ m_context->VSGetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppConstantBuffers[i] = d3d11Buffers[i]
+ ? static_cast<D3D11Buffer*>(d3d11Buffers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+ m_context->VSGetShaderResources(StartSlot, NumViews, d3d11Views);
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppShaderResourceViews[i] = d3d11Views[i]
+ ? static_cast<D3D11ShaderResourceView*>(d3d11Views[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::VSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+ m_context->VSGetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ ppSamplers[i] = d3d11Samplers[i]
+ ? static_cast<D3D11SamplerState*>(d3d11Samplers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSSetShader(
+ ID3D10GeometryShader* pShader) {
+ D3D10GeometryShader* d3d10Shader = static_cast<D3D10GeometryShader*>(pShader);
+ D3D11GeometryShader* d3d11Shader = d3d10Shader ? d3d10Shader->GetD3D11Iface() : nullptr;
+
+ m_context->GSSetShader(d3d11Shader, nullptr, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+
+ if (NumBuffers > D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ d3d11Buffers[i] = ppConstantBuffers && ppConstantBuffers[i]
+ ? static_cast<D3D10Buffer*>(ppConstantBuffers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->GSSetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+
+ if (NumViews > D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ d3d11Views[i] = ppShaderResourceViews && ppShaderResourceViews[i]
+ ? static_cast<D3D10ShaderResourceView*>(ppShaderResourceViews[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->GSSetShaderResources(StartSlot, NumViews, d3d11Views);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+
+ if (NumSamplers > D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ d3d11Samplers[i] = ppSamplers && ppSamplers[i]
+ ? static_cast<D3D10SamplerState*>(ppSamplers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->GSSetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSGetShader(
+ ID3D10GeometryShader** ppGeometryShader) {
+ ID3D11GeometryShader* d3d11Shader = nullptr;
+ m_context->GSGetShader(&d3d11Shader, nullptr, nullptr);
+
+ *ppGeometryShader = d3d11Shader ? static_cast<D3D11GeometryShader*>(d3d11Shader)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+ m_context->GSGetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppConstantBuffers[i] = d3d11Buffers[i]
+ ? static_cast<D3D11Buffer*>(d3d11Buffers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+ m_context->GSGetShaderResources(StartSlot, NumViews, d3d11Views);
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppShaderResourceViews[i] = d3d11Views[i]
+ ? static_cast<D3D11ShaderResourceView*>(d3d11Views[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+ m_context->GSGetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ ppSamplers[i] = d3d11Samplers[i]
+ ? static_cast<D3D11SamplerState*>(d3d11Samplers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSSetShader(
+ ID3D10PixelShader* pPixelShader) {
+ D3D10PixelShader* d3d10Shader = static_cast<D3D10PixelShader*>(pPixelShader);
+ D3D11PixelShader* d3d11Shader = d3d10Shader ? d3d10Shader->GetD3D11Iface() : nullptr;
+
+ m_context->PSSetShader(d3d11Shader, nullptr, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+
+ if (NumBuffers > D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ d3d11Buffers[i] = ppConstantBuffers && ppConstantBuffers[i]
+ ? static_cast<D3D10Buffer*>(ppConstantBuffers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->PSSetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+
+ if (NumViews > D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ d3d11Views[i] = ppShaderResourceViews && ppShaderResourceViews[i]
+ ? static_cast<D3D10ShaderResourceView*>(ppShaderResourceViews[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->PSSetShaderResources(StartSlot, NumViews, d3d11Views);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+
+ if (NumSamplers > D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ d3d11Samplers[i] = ppSamplers && ppSamplers[i]
+ ? static_cast<D3D10SamplerState*>(ppSamplers[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->PSSetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSGetShader(
+ ID3D10PixelShader** ppPixelShader) {
+ ID3D11PixelShader* d3d11Shader = nullptr;
+ m_context->PSGetShader(&d3d11Shader, nullptr, nullptr);
+
+ *ppPixelShader = d3d11Shader ? static_cast<D3D11PixelShader*>(d3d11Shader)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers) {
+ ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
+ m_context->PSGetConstantBuffers(StartSlot, NumBuffers, d3d11Buffers);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppConstantBuffers[i] = d3d11Buffers[i]
+ ? static_cast<D3D11Buffer*>(d3d11Buffers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews) {
+ ID3D11ShaderResourceView* d3d11Views[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
+ m_context->PSGetShaderResources(StartSlot, NumViews, d3d11Views);
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppShaderResourceViews[i] = d3d11Views[i]
+ ? static_cast<D3D11ShaderResourceView*>(d3d11Views[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::PSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers) {
+ ID3D11SamplerState* d3d11Samplers[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT];
+ m_context->PSGetSamplers(StartSlot, NumSamplers, d3d11Samplers);
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ ppSamplers[i] = d3d11Samplers[i]
+ ? static_cast<D3D11SamplerState*>(d3d11Samplers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMSetRenderTargets(
+ UINT NumViews,
+ ID3D10RenderTargetView* const* ppRenderTargetViews,
+ ID3D10DepthStencilView* pDepthStencilView) {
+ ID3D11RenderTargetView* d3d11Rtv[D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT];
+
+ if (NumViews > D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ d3d11Rtv[i] = ppRenderTargetViews && ppRenderTargetViews[i]
+ ? static_cast<D3D10RenderTargetView*>(ppRenderTargetViews[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ D3D10DepthStencilView* d3d10Dsv = static_cast<D3D10DepthStencilView*>(pDepthStencilView);
+ D3D11DepthStencilView* d3d11Dsv = d3d10Dsv ? d3d10Dsv->GetD3D11Iface() : nullptr;
+
+ m_context->OMSetRenderTargets(NumViews, d3d11Rtv, d3d11Dsv);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMSetBlendState(
+ ID3D10BlendState* pBlendState,
+ const FLOAT BlendFactor[4],
+ UINT SampleMask) {
+ D3D10BlendState* d3d10BlendState = static_cast<D3D10BlendState*>(pBlendState);
+ D3D11BlendState* d3d11BlendState = d3d10BlendState ? d3d10BlendState->GetD3D11Iface() : nullptr;
+
+ m_context->OMSetBlendState(d3d11BlendState, BlendFactor, SampleMask);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMSetDepthStencilState(
+ ID3D10DepthStencilState* pDepthStencilState,
+ UINT StencilRef) {
+ D3D10DepthStencilState* d3d10DepthStencilState = static_cast<D3D10DepthStencilState*>(pDepthStencilState);
+ D3D11DepthStencilState* d3d11DepthStencilState = d3d10DepthStencilState ? d3d10DepthStencilState->GetD3D11Iface() : nullptr;
+
+ m_context->OMSetDepthStencilState(d3d11DepthStencilState, StencilRef);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMGetRenderTargets(
+ UINT NumViews,
+ ID3D10RenderTargetView** ppRenderTargetViews,
+ ID3D10DepthStencilView** ppDepthStencilView) {
+ ID3D11RenderTargetView* d3d11Rtv[D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT];
+ ID3D11DepthStencilView* d3d11Dsv = nullptr;
+
+ m_context->OMGetRenderTargets(NumViews,
+ ppRenderTargetViews ? d3d11Rtv : nullptr,
+ ppDepthStencilView ? &d3d11Dsv : nullptr);
+
+ if (ppRenderTargetViews != nullptr) {
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppRenderTargetViews[i] = d3d11Rtv[i]
+ ? static_cast<D3D11RenderTargetView*>(d3d11Rtv[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+
+ if (ppDepthStencilView)
+ *ppDepthStencilView = d3d11Dsv ? static_cast<D3D11DepthStencilView*>(d3d11Dsv)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMGetBlendState(
+ ID3D10BlendState** ppBlendState,
+ FLOAT BlendFactor[4],
+ UINT* pSampleMask) {
+ ID3D11BlendState* d3d11BlendState = nullptr;
+
+ m_context->OMGetBlendState(
+ ppBlendState ? &d3d11BlendState : nullptr,
+ BlendFactor, pSampleMask);
+
+ if (ppBlendState != nullptr)
+ *ppBlendState = d3d11BlendState ? static_cast<D3D11BlendState*>(d3d11BlendState)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::OMGetDepthStencilState(
+ ID3D10DepthStencilState** ppDepthStencilState,
+ UINT* pStencilRef) {
+ ID3D11DepthStencilState* d3d11DepthStencilState = nullptr;
+
+ m_context->OMGetDepthStencilState(
+ ppDepthStencilState ? &d3d11DepthStencilState : nullptr,
+ pStencilRef);
+
+ if (ppDepthStencilState != nullptr)
+ *ppDepthStencilState = d3d11DepthStencilState ? static_cast<D3D11DepthStencilState*>(d3d11DepthStencilState)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSSetState(
+ ID3D10RasterizerState* pRasterizerState) {
+ D3D10RasterizerState* d3d10RasterizerState = static_cast<D3D10RasterizerState*>(pRasterizerState);
+ D3D11RasterizerState* d3d11RasterizerState = d3d10RasterizerState ? d3d10RasterizerState->GetD3D11Iface() : nullptr;
+
+ m_context->RSSetState(d3d11RasterizerState);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSSetViewports(
+ UINT NumViewports,
+ const D3D10_VIEWPORT* pViewports) {
+ D3D11_VIEWPORT vp[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+
+ if (NumViewports > D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE)
+ return;
+
+ for (uint32_t i = 0; i < NumViewports; i++) {
+ vp[i].TopLeftX = float(pViewports[i].TopLeftX);
+ vp[i].TopLeftY = float(pViewports[i].TopLeftY);
+ vp[i].Width = float(pViewports[i].Width);
+ vp[i].Height = float(pViewports[i].Height);
+ vp[i].MinDepth = pViewports[i].MinDepth;
+ vp[i].MaxDepth = pViewports[i].MaxDepth;
+ }
+
+ m_context->RSSetViewports(NumViewports, vp);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSSetScissorRects(
+ UINT NumRects,
+ const D3D10_RECT* pRects) {
+ m_context->RSSetScissorRects(NumRects, pRects);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSGetState(
+ ID3D10RasterizerState** ppRasterizerState) {
+ ID3D11RasterizerState* d3d11RasterizerState = nullptr;
+ m_context->RSGetState(&d3d11RasterizerState);
+
+ *ppRasterizerState = d3d11RasterizerState ? static_cast<D3D11RasterizerState*>(d3d11RasterizerState)->GetD3D10Iface() : nullptr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSGetViewports(
+ UINT* NumViewports,
+ D3D10_VIEWPORT* pViewports) {
+ D3D11_VIEWPORT vp[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ m_context->RSGetViewports(NumViewports, pViewports != nullptr ? vp : nullptr);
+
+ if (pViewports != nullptr) {
+ for (uint32_t i = 0; i < *NumViewports; i++) {
+ pViewports[i].TopLeftX = int32_t(vp[i].TopLeftX);
+ pViewports[i].TopLeftY = int32_t(vp[i].TopLeftY);
+ pViewports[i].Width = uint32_t(vp[i].Width);
+ pViewports[i].Height = uint32_t(vp[i].Height);
+ pViewports[i].MinDepth = vp[i].MinDepth;
+ pViewports[i].MaxDepth = vp[i].MaxDepth;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::RSGetScissorRects(
+ UINT* NumRects,
+ D3D10_RECT* pRects) {
+ m_context->RSGetScissorRects(NumRects, pRects);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::SOSetTargets(
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppSOTargets,
+ const UINT* pOffsets) {
+ ID3D11Buffer* d3d11Buffers[D3D10_SO_BUFFER_SLOT_COUNT];
+
+ if (NumBuffers > D3D10_SO_BUFFER_SLOT_COUNT)
+ return;
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ d3d11Buffers[i] = ppSOTargets && ppSOTargets[i]
+ ? static_cast<D3D10Buffer*>(ppSOTargets[i])->GetD3D11Iface()
+ : nullptr;
+ }
+
+ m_context->SOSetTargets(NumBuffers, d3d11Buffers, pOffsets);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::SOGetTargets(
+ UINT NumBuffers,
+ ID3D10Buffer** ppSOTargets,
+ UINT* pOffsets) {
+ ID3D11Buffer* d3d11Buffers[D3D10_SO_BUFFER_SLOT_COUNT];
+
+ m_context->SOGetTargetsWithOffsets(NumBuffers,
+ ppSOTargets ? d3d11Buffers : nullptr,
+ pOffsets);
+
+ if (ppSOTargets != nullptr) {
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppSOTargets[i] = d3d11Buffers[i]
+ ? static_cast<D3D11Buffer*>(d3d11Buffers[i])->GetD3D10Iface()
+ : nullptr;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::SetTextFilterSize(
+ UINT Width,
+ UINT Height) {
+ // D3D10 doesn't seem to actually store or do anything with these values,
+ // as when calling GetTextFilterSize, it just makes the values 0.
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Device::GetTextFilterSize(
+ UINT* pWidth,
+ UINT* pHeight) {
+ if (pWidth)
+ *pWidth = 0;
+
+ if (pHeight)
+ *pHeight = 0;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.h
new file mode 100644
index 00000000..c3494cfe
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_device.h
@@ -0,0 +1,480 @@
+#pragma once
+
+#include "d3d10_multithread.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11ImmediateContext;
+
+ class D3D10Device final : public ID3D10Device1 {
+
+ public:
+
+ D3D10Device(
+ D3D11Device* pDevice,
+ D3D11ImmediateContext* pContext);
+
+ ~D3D10Device();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason();
+
+ HRESULT STDMETHODCALLTYPE SetExceptionMode(
+ UINT RaiseFlags);
+
+ UINT STDMETHODCALLTYPE GetExceptionMode();
+
+ D3D10_FEATURE_LEVEL1 STDMETHODCALLTYPE GetFeatureLevel();
+
+ void STDMETHODCALLTYPE ClearState();
+
+ void STDMETHODCALLTYPE Flush();
+
+ HRESULT STDMETHODCALLTYPE CreateBuffer(
+ const D3D10_BUFFER_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Buffer** ppBuffer);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture1D(
+ const D3D10_TEXTURE1D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture1D** ppTexture1D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture2D(
+ const D3D10_TEXTURE2D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture2D** ppTexture2D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture3D(
+ const D3D10_TEXTURE3D_DESC* pDesc,
+ const D3D10_SUBRESOURCE_DATA* pInitialData,
+ ID3D10Texture3D** ppTexture3D);
+
+ HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
+ ID3D10Resource* pResource,
+ const D3D10_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D10ShaderResourceView** ppSRView);
+
+ HRESULT STDMETHODCALLTYPE CreateShaderResourceView1(
+ ID3D10Resource* pResource,
+ const D3D10_SHADER_RESOURCE_VIEW_DESC1* pDesc,
+ ID3D10ShaderResourceView1** ppSRView);
+
+ HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
+ ID3D10Resource* pResource,
+ const D3D10_RENDER_TARGET_VIEW_DESC* pDesc,
+ ID3D10RenderTargetView** ppRTView);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
+ ID3D10Resource* pResource,
+ const D3D10_DEPTH_STENCIL_VIEW_DESC* pDesc,
+ ID3D10DepthStencilView** ppDepthStencilView);
+
+ HRESULT STDMETHODCALLTYPE CreateInputLayout(
+ const D3D10_INPUT_ELEMENT_DESC* pInputElementDescs,
+ UINT NumElements,
+ const void* pShaderBytecodeWithInputSignature,
+ SIZE_T BytecodeLength,
+ ID3D10InputLayout** ppInputLayout);
+
+ HRESULT STDMETHODCALLTYPE CreateVertexShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10VertexShader** ppVertexShader);
+
+ HRESULT STDMETHODCALLTYPE CreateGeometryShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10GeometryShader** ppGeometryShader);
+
+ HRESULT STDMETHODCALLTYPE CreateGeometryShaderWithStreamOutput(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ const D3D10_SO_DECLARATION_ENTRY* pSODeclaration,
+ UINT NumEntries,
+ UINT OutputStreamStride,
+ ID3D10GeometryShader** ppGeometryShader);
+
+ HRESULT STDMETHODCALLTYPE CreatePixelShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10PixelShader** ppPixelShader);
+
+ HRESULT STDMETHODCALLTYPE CreateBlendState(
+ const D3D10_BLEND_DESC* pBlendStateDesc,
+ ID3D10BlendState** ppBlendState);
+
+ HRESULT STDMETHODCALLTYPE CreateBlendState1(
+ const D3D10_BLEND_DESC1* pBlendStateDesc,
+ ID3D10BlendState1** ppBlendState);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilState(
+ const D3D10_DEPTH_STENCIL_DESC* pDepthStencilDesc,
+ ID3D10DepthStencilState** ppDepthStencilState);
+
+ HRESULT STDMETHODCALLTYPE CreateRasterizerState(
+ const D3D10_RASTERIZER_DESC* pRasterizerDesc,
+ ID3D10RasterizerState** ppRasterizerState);
+
+ HRESULT STDMETHODCALLTYPE CreateSamplerState(
+ const D3D10_SAMPLER_DESC* pSamplerDesc,
+ ID3D10SamplerState** ppSamplerState);
+
+ HRESULT STDMETHODCALLTYPE CreateQuery(
+ const D3D10_QUERY_DESC* pQueryDesc,
+ ID3D10Query** ppQuery);
+
+ HRESULT STDMETHODCALLTYPE CreatePredicate(
+ const D3D10_QUERY_DESC* pPredicateDesc,
+ ID3D10Predicate** ppPredicate);
+
+ HRESULT STDMETHODCALLTYPE CreateCounter(
+ const D3D10_COUNTER_DESC* pCounterDesc,
+ ID3D10Counter** ppCounter);
+
+ HRESULT STDMETHODCALLTYPE CheckFormatSupport(
+ DXGI_FORMAT Format,
+ UINT* pFormatSupport);
+
+ HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT* pNumQualityLevels);
+
+ void STDMETHODCALLTYPE CheckCounterInfo(
+ D3D10_COUNTER_INFO* pCounterInfo);
+
+ HRESULT STDMETHODCALLTYPE CheckCounter(
+ const D3D10_COUNTER_DESC* pDesc,
+ D3D10_COUNTER_TYPE* pType,
+ UINT* pActiveCounters,
+ char* name,
+ UINT* pNameLength,
+ char* units,
+ UINT* pUnitsLength,
+ char* description,
+ UINT* pDescriptionLength);
+
+ UINT STDMETHODCALLTYPE GetCreationFlags();
+
+ HRESULT STDMETHODCALLTYPE OpenSharedResource(
+ HANDLE hResource,
+ REFIID ReturnedInterface,
+ void** ppResource);
+
+ void STDMETHODCALLTYPE ClearRenderTargetView(
+ ID3D10RenderTargetView* pRenderTargetView,
+ const FLOAT ColorRGBA[4]);
+
+ void STDMETHODCALLTYPE ClearDepthStencilView(
+ ID3D10DepthStencilView* pDepthStencilView,
+ UINT ClearFlags,
+ FLOAT Depth,
+ UINT8 Stencil);
+
+ void STDMETHODCALLTYPE SetPredication(
+ ID3D10Predicate* pPredicate,
+ BOOL PredicateValue);
+
+ void STDMETHODCALLTYPE GetPredication(
+ ID3D10Predicate** ppPredicate,
+ BOOL* pPredicateValue);
+
+ void STDMETHODCALLTYPE CopySubresourceRegion(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D10Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D10_BOX* pSrcBox);
+
+ void STDMETHODCALLTYPE CopyResource(
+ ID3D10Resource* pDstResource,
+ ID3D10Resource* pSrcResource);
+
+ void STDMETHODCALLTYPE UpdateSubresource(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D10_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch);
+
+ void STDMETHODCALLTYPE GenerateMips(
+ ID3D10ShaderResourceView* pShaderResourceView);
+
+ void STDMETHODCALLTYPE ResolveSubresource(
+ ID3D10Resource* pDstResource,
+ UINT DstSubresource,
+ ID3D10Resource* pSrcResource,
+ UINT SrcSubresource,
+ DXGI_FORMAT Format);
+
+ void STDMETHODCALLTYPE Draw(
+ UINT VertexCount,
+ UINT StartVertexLocation);
+
+ void STDMETHODCALLTYPE DrawIndexed(
+ UINT IndexCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation);
+
+ void STDMETHODCALLTYPE DrawInstanced(
+ UINT VertexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartVertexLocation,
+ UINT StartInstanceLocation);
+
+ void STDMETHODCALLTYPE DrawIndexedInstanced(
+ UINT IndexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation,
+ UINT StartInstanceLocation);
+
+ void STDMETHODCALLTYPE DrawAuto();
+
+ void STDMETHODCALLTYPE IASetInputLayout(
+ ID3D10InputLayout* pInputLayout);
+
+ void STDMETHODCALLTYPE IASetPrimitiveTopology(
+ D3D10_PRIMITIVE_TOPOLOGY Topology);
+
+ void STDMETHODCALLTYPE IASetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppVertexBuffers,
+ const UINT* pStrides,
+ const UINT* pOffsets);
+
+ void STDMETHODCALLTYPE IASetIndexBuffer(
+ ID3D10Buffer* pIndexBuffer,
+ DXGI_FORMAT Format,
+ UINT Offset);
+
+ void STDMETHODCALLTYPE IAGetInputLayout(
+ ID3D10InputLayout** ppInputLayout);
+
+ void STDMETHODCALLTYPE IAGetPrimitiveTopology(
+ D3D10_PRIMITIVE_TOPOLOGY* pTopology);
+
+ void STDMETHODCALLTYPE IAGetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppVertexBuffers,
+ UINT* pStrides,
+ UINT* pOffsets);
+
+ void STDMETHODCALLTYPE IAGetIndexBuffer(
+ ID3D10Buffer** pIndexBuffer,
+ DXGI_FORMAT* Format,
+ UINT* Offset);
+
+ void STDMETHODCALLTYPE VSSetShader(
+ ID3D10VertexShader* pVertexShader);
+
+ void STDMETHODCALLTYPE VSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE VSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE VSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE VSGetShader(
+ ID3D10VertexShader** ppVertexShader);
+
+ void STDMETHODCALLTYPE VSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE VSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE VSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE GSSetShader(
+ ID3D10GeometryShader* pShader);
+
+ void STDMETHODCALLTYPE GSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE GSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE GSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE GSGetShader(
+ ID3D10GeometryShader** ppGeometryShader);
+
+ void STDMETHODCALLTYPE GSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE GSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE GSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE PSSetShader(
+ ID3D10PixelShader* pPixelShader);
+
+ void STDMETHODCALLTYPE PSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE PSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE PSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE PSGetShader(
+ ID3D10PixelShader** ppPixelShader);
+
+ void STDMETHODCALLTYPE PSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D10Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE PSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D10ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE PSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D10SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE OMSetRenderTargets(
+ UINT NumViews,
+ ID3D10RenderTargetView* const* ppRenderTargetViews,
+ ID3D10DepthStencilView* pDepthStencilView);
+
+ void STDMETHODCALLTYPE OMSetBlendState(
+ ID3D10BlendState* pBlendState,
+ const FLOAT BlendFactor[4],
+ UINT SampleMask);
+
+ void STDMETHODCALLTYPE OMSetDepthStencilState(
+ ID3D10DepthStencilState* pDepthStencilState,
+ UINT StencilRef);
+
+ void STDMETHODCALLTYPE OMGetRenderTargets(
+ UINT NumViews,
+ ID3D10RenderTargetView** ppRenderTargetViews,
+ ID3D10DepthStencilView** ppDepthStencilView);
+
+ void STDMETHODCALLTYPE OMGetBlendState(
+ ID3D10BlendState** ppBlendState,
+ FLOAT BlendFactor[4],
+ UINT* pSampleMask);
+
+ void STDMETHODCALLTYPE OMGetDepthStencilState(
+ ID3D10DepthStencilState** ppDepthStencilState,
+ UINT* pStencilRef);
+
+ void STDMETHODCALLTYPE RSSetState(
+ ID3D10RasterizerState* pRasterizerState);
+
+ void STDMETHODCALLTYPE RSSetViewports(
+ UINT NumViewports,
+ const D3D10_VIEWPORT* pViewports);
+
+ void STDMETHODCALLTYPE RSSetScissorRects(
+ UINT NumRects,
+ const D3D10_RECT* pRects);
+
+ void STDMETHODCALLTYPE RSGetState(
+ ID3D10RasterizerState** ppRasterizerState);
+
+ void STDMETHODCALLTYPE RSGetViewports(
+ UINT* NumViewports,
+ D3D10_VIEWPORT* pViewports);
+
+ void STDMETHODCALLTYPE RSGetScissorRects(
+ UINT* NumRects,
+ D3D10_RECT* pRects);
+
+ void STDMETHODCALLTYPE SOSetTargets(
+ UINT NumBuffers,
+ ID3D10Buffer* const* ppSOTargets,
+ const UINT* pOffsets);
+
+ void STDMETHODCALLTYPE SOGetTargets(
+ UINT NumBuffers,
+ ID3D10Buffer** ppSOTargets,
+ UINT* pOffsets);
+
+ void STDMETHODCALLTYPE SetTextFilterSize(
+ UINT Width,
+ UINT Height);
+
+ void STDMETHODCALLTYPE GetTextFilterSize(
+ UINT* pWidth,
+ UINT* pHeight);
+
+ private:
+
+ D3D11Device* m_device;
+ D3D11ImmediateContext* m_context;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_include.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_include.h
new file mode 100644
index 00000000..17143a08
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_include.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "../dxgi/dxgi_include.h"
+
+#include "../util/sync/sync_spinlock.h"
+#include "../util/sync/sync_recursive.h"
+
+#include <d3d10_1.h>
+#include <d3d11_1.h>
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.cpp
new file mode 100644
index 00000000..c9e74de8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.cpp
@@ -0,0 +1,53 @@
+#include "d3d10_input_layout.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_input_layout.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10InputLayout::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10InputLayout::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10InputLayout::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10InputLayout::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10InputLayout::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10InputLayout::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10InputLayout::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.h
new file mode 100644
index 00000000..73169227
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_input_layout.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11InputLayout;
+
+ class D3D10InputLayout : public ID3D10InputLayout {
+
+ public:
+
+ D3D10InputLayout(D3D11InputLayout* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ D3D11InputLayout* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11InputLayout* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_interfaces.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_interfaces.h
new file mode 100644
index 00000000..aa028ab5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_interfaces.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "d3d10_include.h"
+
+#ifdef _MSC_VER
+struct __declspec(uuid("0803425a-57f5-4dd6-9465-a87570834a08")) ID3D10StateBlock;
+#else
+__CRT_UUID_DECL(ID3D10StateBlock, 0x0803425a,0x57f5,0x4dd6,0x94,0x65,0xa8,0x75,0x70,0x83,0x4a,0x08);
+#endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_main.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_main.cpp
new file mode 100644
index 00000000..7bec4d0b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_main.cpp
@@ -0,0 +1,335 @@
+#include <d3dcompiler.h>
+
+#include "d3d10_include.h"
+#include "d3d10_reflection.h"
+
+#include "../dxgi/dxgi_adapter.h"
+
+namespace dxvk {
+ Logger Logger::s_instance("d3d10.log");
+}
+
+extern "C" {
+ using namespace dxvk;
+
+ HRESULT __stdcall D3D10CoreCreateDevice(
+ IDXGIFactory* pFactory,
+ IDXGIAdapter* pAdapter,
+ UINT Flags,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ ID3D10Device** ppDevice);
+
+ static HRESULT D3D10InternalCreateDeviceAndSwapChain(
+ IDXGIAdapter* pAdapter,
+ D3D10_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ D3D10_FEATURE_LEVEL1 HardwareLevel,
+ UINT SDKVersion,
+ DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
+ IDXGISwapChain** ppSwapChain,
+ REFIID deviceIID,
+ void** ppDevice) {
+ InitReturnPtr(ppDevice);
+ InitReturnPtr(ppSwapChain);
+
+ if (ppSwapChain && !pSwapChainDesc)
+ return E_INVALIDARG;
+
+ HRESULT hr;
+
+ // Get DXGI factory and adapter. This is mostly
+ // copied from the equivalent D3D11 functions.
+ Com<IDXGIFactory> dxgiFactory = nullptr;
+ Com<IDXGIAdapter> dxgiAdapter = pAdapter;
+ Com<ID3D10Device> device = nullptr;
+
+ if (!pAdapter) {
+ if (DriverType != D3D10_DRIVER_TYPE_HARDWARE)
+ Logger::warn("D3D10CreateDevice: Unsupported driver type");
+
+ hr = CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory));
+
+ if (FAILED(hr)) {
+ Logger::err("D3D10CreateDevice: Failed to create a DXGI factory");
+ return hr;
+ }
+
+ hr = dxgiFactory->EnumAdapters(0, &dxgiAdapter);
+
+ if (FAILED(hr)) {
+ Logger::err("D3D10CreateDevice: No default adapter available");
+ return hr;
+ }
+ } else {
+ if (FAILED(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory)))) {
+ Logger::err("D3D10CreateDevice: Failed to query DXGI factory from DXGI adapter");
+ return E_INVALIDARG;
+ }
+
+ if (DriverType != D3D10_DRIVER_TYPE_HARDWARE || Software)
+ return E_INVALIDARG;
+ }
+
+ hr = D3D10CoreCreateDevice(
+ dxgiFactory.ptr(), dxgiAdapter.ptr(),
+ Flags, D3D_FEATURE_LEVEL(HardwareLevel),
+ &device);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (ppSwapChain) {
+ DXGI_SWAP_CHAIN_DESC desc = *pSwapChainDesc;
+ hr = dxgiFactory->CreateSwapChain(device.ptr(), &desc, ppSwapChain);
+
+ if (FAILED(hr)) {
+ Logger::err("D3D10CreateDevice: Failed to create swap chain");
+ return hr;
+ }
+ }
+
+ if (ppDevice) {
+ // Just assume that this succeeds
+ device->QueryInterface(deviceIID, ppDevice);
+ }
+
+ if (!ppDevice && !ppSwapChain)
+ return S_FALSE;
+
+ return S_OK;
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D10CreateDevice(
+ IDXGIAdapter* pAdapter,
+ D3D10_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ UINT SDKVersion,
+ ID3D10Device** ppDevice) {
+ return D3D10InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ D3D10_FEATURE_LEVEL_10_0, SDKVersion,
+ nullptr, nullptr,
+ __uuidof(ID3D10Device),
+ reinterpret_cast<void**>(ppDevice));
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D10CreateDevice1(
+ IDXGIAdapter* pAdapter,
+ D3D10_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ D3D10_FEATURE_LEVEL1 HardwareLevel,
+ UINT SDKVersion,
+ ID3D10Device1** ppDevice) {
+ return D3D10InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ HardwareLevel, SDKVersion,
+ nullptr, nullptr,
+ __uuidof(ID3D10Device1),
+ reinterpret_cast<void**>(ppDevice));
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D10CreateDeviceAndSwapChain(
+ IDXGIAdapter* pAdapter,
+ D3D10_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ UINT SDKVersion,
+ DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
+ IDXGISwapChain** ppSwapChain,
+ ID3D10Device** ppDevice) {
+ return D3D10InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ D3D10_FEATURE_LEVEL_10_0, SDKVersion,
+ pSwapChainDesc, ppSwapChain,
+ __uuidof(ID3D10Device),
+ reinterpret_cast<void**>(ppDevice));
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D10CreateDeviceAndSwapChain1(
+ IDXGIAdapter* pAdapter,
+ D3D10_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ D3D10_FEATURE_LEVEL1 HardwareLevel,
+ UINT SDKVersion,
+ DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
+ IDXGISwapChain** ppSwapChain,
+ ID3D10Device1** ppDevice) {
+ return D3D10InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ HardwareLevel, SDKVersion,
+ pSwapChainDesc, ppSwapChain,
+ __uuidof(ID3D10Device1),
+ reinterpret_cast<void**>(ppDevice));
+ }
+
+
+ const char* STDMETHODCALLTYPE D3D10GetVertexShaderProfile (ID3D10Device*) { return "vs_4_1"; }
+ const char* STDMETHODCALLTYPE D3D10GetGeometryShaderProfile (ID3D10Device*) { return "gs_4_1"; }
+ const char* STDMETHODCALLTYPE D3D10GetPixelShaderProfile (ID3D10Device*) { return "ps_4_1"; }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CreateBlob(SIZE_T size, LPD3D10BLOB* ppBuffer) {
+ return D3DCreateBlob(size, ppBuffer);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10GetInputSignatureBlob(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10Blob** ppSignatureBlob) {
+ return D3DGetInputSignatureBlob(
+ pShaderBytecode,
+ BytecodeLength,
+ ppSignatureBlob);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10GetOutputSignatureBlob(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10Blob** ppSignatureBlob) {
+ return D3DGetOutputSignatureBlob(
+ pShaderBytecode,
+ BytecodeLength,
+ ppSignatureBlob);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ReflectShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D10ShaderReflection** ppReflector) {
+ static const GUID IID_ID3D11ShaderReflection =
+ {0x0a233719,0x3960,0x4578,{0x9d,0x7c,0x20,0x3b,0x8b,0x1d,0x9c,0xc1}};
+
+ InitReturnPtr(ppReflector);
+
+ Com<ID3D11ShaderReflection> d3d11Reflector = nullptr;
+
+ HRESULT hr = D3DReflect(pShaderBytecode,
+ BytecodeLength, IID_ID3D11ShaderReflection,
+ reinterpret_cast<void**>(&d3d11Reflector));
+
+ if (FAILED(hr)) {
+ Logger::err("D3D10ReflectShader: Failed to create ID3D11ShaderReflection");
+ return hr;
+ }
+
+ *ppReflector = ref(new D3D10ShaderReflection(d3d11Reflector.ptr()));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CompileShader(
+ LPCSTR pSrcData,
+ SIZE_T SrcDataSize,
+ LPCSTR pFileName,
+ const D3D10_SHADER_MACRO* pDefines,
+ LPD3D10INCLUDE pInclude,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ UINT Flags,
+ ID3D10Blob** ppShader,
+ ID3D10Blob** ppErrorMsgs) {
+ return D3DCompile(pSrcData, SrcDataSize, pFileName,
+ pDefines, pInclude, pFunctionName, pProfile, Flags,
+ 0, ppShader, ppErrorMsgs);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CreateEffectFromMemory(
+ void* pData,
+ SIZE_T DataSize,
+ UINT EffectFlags,
+ ID3D10Device* pDevice,
+ ID3D10EffectPool* pEffectPool,
+ ID3D10Effect** ppEffect) {
+ Logger::warn("D3D10CreateEffectFromMemory: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CreateEffectPoolFromMemory(
+ void* pData,
+ SIZE_T DataSize,
+ UINT EffectFlags,
+ ID3D10Device* pDevice,
+ ID3D10EffectPool** ppEffectPool) {
+ Logger::warn("D3D10CreateEffectPoolFromMemory: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10CompileEffectFromMemory(
+ void* pData,
+ SIZE_T DataLength,
+ LPCSTR pSrcFileName,
+ const D3D10_SHADER_MACRO* pDefines,
+ ID3D10Include* pInclude,
+ UINT ShaderFlags,
+ UINT EffectFlags,
+ ID3D10Blob** ppCompiledEffect,
+ ID3D10Blob** ppErrors) {
+ Logger::warn("D3D10CompileEffectFromMemory: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DisassembleEffect(
+ ID3D10Effect* pEffect,
+ BOOL EnableColorCode,
+ ID3D10Blob** ppDisassembly) {
+ Logger::warn("D3D10DisassembleEffect: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DisassembleShader(
+ const void* pShader,
+ SIZE_T BytecodeLength,
+ BOOL EnableColorCode,
+ LPCSTR pComments,
+ ID3D10Blob** ppDisassembly) {
+ return D3DDisassemble(
+ pShader, BytecodeLength,
+ 0, pComments, ppDisassembly);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10PreprocessShader(
+ LPCSTR pSrcData,
+ SIZE_T SrcDataSize,
+ LPCSTR pFileName,
+ const D3D10_SHADER_MACRO* pDefines,
+ LPD3D10INCLUDE pInclude,
+ ID3D10Blob** ppShaderText,
+ ID3D10Blob** ppErrorMsgs) {
+ return D3DPreprocess(
+ pSrcData, SrcDataSize,
+ pFileName, pDefines,
+ pInclude,
+ ppShaderText,
+ ppErrorMsgs);
+ }
+
+
+ UINT64 STDMETHODCALLTYPE D3D10GetVersion() {
+ return 0xa000100041770ull;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RegisterLayers() {
+ return E_NOTIMPL;
+ }
+
+}
+
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.cpp
new file mode 100644
index 00000000..65932b53
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.cpp
@@ -0,0 +1,60 @@
+#include <utility>
+
+#include "d3d10_device.h"
+
+namespace dxvk {
+
+ D3D10Multithread::D3D10Multithread(
+ IUnknown* pParent,
+ BOOL Protected)
+ : m_parent (pParent),
+ m_protected (Protected) {
+
+ }
+
+
+ D3D10Multithread::~D3D10Multithread() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Multithread::AddRef() {
+ return m_parent->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Multithread::Release() {
+ return m_parent->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Multithread::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_parent->QueryInterface(riid, ppvObject);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Multithread::Enter() {
+ if (m_protected)
+ m_mutex.lock();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Multithread::Leave() {
+ if (m_protected)
+ m_mutex.unlock();
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D10Multithread::SetMultithreadProtected(
+ BOOL bMTProtect) {
+ return std::exchange(m_protected, bMTProtect);
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D10Multithread::GetMultithreadProtected() {
+ return m_protected;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.h
new file mode 100644
index 00000000..39a736cc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_multithread.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "d3d10_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Device lock
+ *
+ * Lightweight RAII wrapper that implements
+ * a subset of the functionality provided by
+ * \c std::unique_lock, with the goal of being
+ * cheaper to construct and destroy.
+ */
+ class D3D10DeviceLock {
+
+ public:
+
+ D3D10DeviceLock()
+ : m_mutex(nullptr) { }
+
+ D3D10DeviceLock(sync::RecursiveSpinlock& mutex)
+ : m_mutex(&mutex) {
+ mutex.lock();
+ }
+
+ D3D10DeviceLock(D3D10DeviceLock&& other)
+ : m_mutex(other.m_mutex) {
+ other.m_mutex = nullptr;
+ }
+
+ D3D10DeviceLock& operator = (D3D10DeviceLock&& other) {
+ if (m_mutex)
+ m_mutex->unlock();
+
+ m_mutex = other.m_mutex;
+ other.m_mutex = nullptr;
+ return *this;
+ }
+
+ ~D3D10DeviceLock() {
+ if (unlikely(m_mutex != nullptr))
+ m_mutex->unlock();
+ }
+
+ private:
+
+ sync::RecursiveSpinlock* m_mutex;
+
+ };
+
+
+ /**
+ * \brief D3D10 device and D3D11 context lock
+ *
+ * Can be queried from the D3D10 device or from
+ * any D3D11 context in order to make individual
+ * calls thread-safe. Provides methods to lock
+ * the device or context explicitly.
+ */
+ class D3D10Multithread : public ID3D10Multithread {
+
+ public:
+
+ D3D10Multithread(
+ IUnknown* pParent,
+ BOOL Protected);
+
+ ~D3D10Multithread();
+
+ ULONG STDMETHODCALLTYPE AddRef() final;
+
+ ULONG STDMETHODCALLTYPE Release() final;
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE Enter() final;
+
+ void STDMETHODCALLTYPE Leave() final;
+
+ BOOL STDMETHODCALLTYPE SetMultithreadProtected(
+ BOOL bMTProtect) final;
+
+ BOOL STDMETHODCALLTYPE GetMultithreadProtected() final;
+
+ D3D10DeviceLock AcquireLock() {
+ return unlikely(m_protected)
+ ? D3D10DeviceLock(m_mutex)
+ : D3D10DeviceLock();
+ }
+
+ private:
+
+ IUnknown* m_parent;
+ BOOL m_protected;
+
+ sync::RecursiveSpinlock m_mutex;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.cpp
new file mode 100644
index 00000000..8730a611
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.cpp
@@ -0,0 +1,98 @@
+#include "d3d10_query.h"
+#include "d3d10_device.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_context.h"
+#include "../d3d11/d3d11_query.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10Query::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Query::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Query::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Query::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Query::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Query::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Query::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Query::Begin() {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->Begin(m_d3d11);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Query::End() {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->End(m_d3d11);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Query::GetData(
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ return ctx->GetData(m_d3d11,
+ pData, DataSize, GetDataFlags);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Query::GetDataSize() {
+ return m_d3d11->GetDataSize();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Query::GetDesc(
+ D3D10_QUERY_DESC* pDesc) {
+ D3D11_QUERY_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->Query = D3D10_QUERY(d3d11Desc.Query);
+ pDesc->MiscFlags = d3d11Desc.MiscFlags;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.h
new file mode 100644
index 00000000..c189e979
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_query.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D10Device;
+ class D3D11Device;
+ class D3D11DeviceContext;
+ class D3D11Query;
+
+ class D3D10Query : public ID3D10Predicate {
+
+ public:
+
+ D3D10Query(D3D11Query* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE Begin();
+
+ void STDMETHODCALLTYPE End();
+
+ HRESULT STDMETHODCALLTYPE GetData(
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags);
+
+ UINT STDMETHODCALLTYPE GetDataSize();
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_QUERY_DESC* pDesc);
+
+ D3D11Query* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11Query* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.cpp
new file mode 100644
index 00000000..42de25ec
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.cpp
@@ -0,0 +1,60 @@
+#include "d3d10_rasterizer.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_rasterizer.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10RasterizerState::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10RasterizerState::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10RasterizerState::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10RasterizerState::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RasterizerState::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RasterizerState::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RasterizerState::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10RasterizerState::GetDesc(
+ D3D10_RASTERIZER_DESC* pDesc) {
+ static_assert(sizeof(D3D10_RASTERIZER_DESC) == sizeof(D3D11_RASTERIZER_DESC));
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_RASTERIZER_DESC*>(pDesc));
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.h
new file mode 100644
index 00000000..9ccad042
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_rasterizer.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11RasterizerState;
+ class D3D11Device;
+
+ class D3D10RasterizerState : public ID3D10RasterizerState {
+
+ public:
+
+ D3D10RasterizerState(D3D11RasterizerState* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_RASTERIZER_DESC* pDesc);
+
+ D3D11RasterizerState* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11RasterizerState* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.cpp
new file mode 100644
index 00000000..d49dea90
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.cpp
@@ -0,0 +1,326 @@
+#include "d3d10_reflection.h"
+
+namespace dxvk {
+
+ D3D10ShaderReflectionType::D3D10ShaderReflectionType(
+ ID3D11ShaderReflectionType* d3d11)
+ : m_d3d11(d3d11) {
+
+ }
+
+
+ D3D10ShaderReflectionType::~D3D10ShaderReflectionType() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflectionType::GetDesc(
+ D3D10_SHADER_TYPE_DESC* pDesc) {
+ D3D11_SHADER_TYPE_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetDesc(&d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ pDesc->Class = D3D10_SHADER_VARIABLE_CLASS(d3d11Desc.Class);
+ pDesc->Type = D3D10_SHADER_VARIABLE_TYPE (d3d11Desc.Type);
+ pDesc->Rows = d3d11Desc.Rows;
+ pDesc->Columns = d3d11Desc.Columns;
+ pDesc->Elements = d3d11Desc.Elements;
+ pDesc->Members = d3d11Desc.Members;
+ pDesc->Offset = d3d11Desc.Offset;
+ return S_OK;
+ }
+
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE D3D10ShaderReflectionType::GetMemberTypeByIndex(
+ UINT Index) {
+ return FindMemberType(m_d3d11->GetMemberTypeByIndex(Index));
+ }
+
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE D3D10ShaderReflectionType::GetMemberTypeByName(
+ const char* Name) {
+ return FindMemberType(m_d3d11->GetMemberTypeByName(Name));
+ }
+
+
+ const char* STDMETHODCALLTYPE D3D10ShaderReflectionType::GetMemberTypeName(
+ UINT Index) {
+ return m_d3d11->GetMemberTypeName(Index);
+ }
+
+
+ ID3D10ShaderReflectionType* D3D10ShaderReflectionType::FindMemberType(
+ ID3D11ShaderReflectionType* pMemberType) {
+ if (!pMemberType)
+ return nullptr;
+
+ auto entry = m_members.find(pMemberType);
+
+ if (entry == m_members.end()) {
+ entry = m_members.insert({ pMemberType,
+ std::make_unique<D3D10ShaderReflectionType>(pMemberType) }).first;
+ }
+
+ return entry->second.get();
+ }
+
+
+ D3D10ShaderReflectionVariable::D3D10ShaderReflectionVariable(ID3D11ShaderReflectionVariable* d3d11)
+ : m_d3d11(d3d11), m_type(m_d3d11->GetType()) {
+
+ }
+
+
+ D3D10ShaderReflectionVariable::~D3D10ShaderReflectionVariable() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflectionVariable::GetDesc(
+ D3D10_SHADER_VARIABLE_DESC* pDesc) {
+ D3D11_SHADER_VARIABLE_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetDesc(&d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ pDesc->Name = d3d11Desc.Name;
+ pDesc->StartOffset = d3d11Desc.StartOffset;
+ pDesc->Size = d3d11Desc.Size;
+ pDesc->uFlags = d3d11Desc.uFlags;
+ pDesc->DefaultValue = d3d11Desc.DefaultValue;
+ return S_OK;
+ }
+
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE D3D10ShaderReflectionVariable::GetType() {
+ return &m_type;
+ }
+
+
+ D3D10ShaderReflectionConstantBuffer::D3D10ShaderReflectionConstantBuffer(
+ ID3D11ShaderReflectionConstantBuffer* d3d11)
+ : m_d3d11(d3d11) {
+
+ }
+
+
+ D3D10ShaderReflectionConstantBuffer::~D3D10ShaderReflectionConstantBuffer() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflectionConstantBuffer::GetDesc(
+ D3D10_SHADER_BUFFER_DESC* pDesc) {
+ D3D11_SHADER_BUFFER_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetDesc(&d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ pDesc->Name = d3d11Desc.Name;
+ pDesc->Type = D3D10_CBUFFER_TYPE(d3d11Desc.Type);
+ pDesc->Variables = d3d11Desc.Variables;
+ pDesc->Size = d3d11Desc.Size;
+ pDesc->uFlags = d3d11Desc.uFlags;
+ return S_OK;
+ }
+
+
+ ID3D10ShaderReflectionVariable* STDMETHODCALLTYPE D3D10ShaderReflectionConstantBuffer::GetVariableByIndex(
+ UINT Index) {
+ return FindVariable(m_d3d11->GetVariableByIndex(Index));
+ }
+
+
+ ID3D10ShaderReflectionVariable* STDMETHODCALLTYPE D3D10ShaderReflectionConstantBuffer::GetVariableByName(
+ LPCSTR Name) {
+ return FindVariable(m_d3d11->GetVariableByName(Name));
+ }
+
+
+ ID3D10ShaderReflectionVariable* D3D10ShaderReflectionConstantBuffer::FindVariable(
+ ID3D11ShaderReflectionVariable* pVariable) {
+ if (!pVariable)
+ return nullptr;
+
+ auto entry = m_variables.find(pVariable);
+
+ if (entry == m_variables.end()) {
+ entry = m_variables.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(pVariable),
+ std::forward_as_tuple(pVariable)).first;
+ }
+
+ return &entry->second;
+ }
+
+
+ D3D10ShaderReflection::D3D10ShaderReflection(ID3D11ShaderReflection* d3d11)
+ : m_d3d11(d3d11) {
+
+ }
+
+
+ D3D10ShaderReflection::~D3D10ShaderReflection() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflection::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ static const GUID IID_ID3D10ShaderReflection
+ = {0xd40e20b6,0xf8f7,0x42ad,{0xab,0x20,0x4b,0xaf,0x8f,0x15,0xdf,0xaa}};
+
+ if (riid == __uuidof(IUnknown)
+ || riid == IID_ID3D10ShaderReflection) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflection::GetDesc(
+ D3D10_SHADER_DESC* pDesc) {
+ D3D11_SHADER_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetDesc(&d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ pDesc->Version = d3d11Desc.Version;
+ pDesc->Creator = d3d11Desc.Creator;
+ pDesc->Flags = d3d11Desc.Flags;
+ pDesc->ConstantBuffers = d3d11Desc.ConstantBuffers;
+ pDesc->BoundResources = d3d11Desc.BoundResources;
+ pDesc->InputParameters = d3d11Desc.InputParameters;
+ pDesc->OutputParameters = d3d11Desc.OutputParameters;
+ pDesc->InstructionCount = d3d11Desc.InstructionCount;
+ pDesc->TempRegisterCount = d3d11Desc.TempRegisterCount;
+ pDesc->TempArrayCount = d3d11Desc.TempArrayCount;
+ pDesc->DefCount = d3d11Desc.DefCount;
+ pDesc->DclCount = d3d11Desc.DclCount;
+ pDesc->TextureNormalInstructions = d3d11Desc.TextureNormalInstructions;
+ pDesc->TextureLoadInstructions = d3d11Desc.TextureLoadInstructions;
+ pDesc->TextureCompInstructions = d3d11Desc.TextureCompInstructions;
+ pDesc->TextureBiasInstructions = d3d11Desc.TextureBiasInstructions;
+ pDesc->TextureGradientInstructions = d3d11Desc.TextureGradientInstructions;
+ pDesc->FloatInstructionCount = d3d11Desc.FloatInstructionCount;
+ pDesc->IntInstructionCount = d3d11Desc.IntInstructionCount;
+ pDesc->UintInstructionCount = d3d11Desc.UintInstructionCount;
+ pDesc->StaticFlowControlCount = d3d11Desc.StaticFlowControlCount;
+ pDesc->DynamicFlowControlCount = d3d11Desc.DynamicFlowControlCount;
+ pDesc->MacroInstructionCount = d3d11Desc.MacroInstructionCount;
+ pDesc->ArrayInstructionCount = d3d11Desc.ArrayInstructionCount;
+ pDesc->CutInstructionCount = d3d11Desc.CutInstructionCount;
+ pDesc->EmitInstructionCount = d3d11Desc.EmitInstructionCount;
+ pDesc->GSOutputTopology = D3D10_PRIMITIVE_TOPOLOGY(d3d11Desc.GSOutputTopology);
+ pDesc->GSMaxOutputVertexCount = d3d11Desc.GSMaxOutputVertexCount;
+ return S_OK;
+ }
+
+
+ ID3D10ShaderReflectionConstantBuffer* STDMETHODCALLTYPE
+ D3D10ShaderReflection::GetConstantBufferByIndex(
+ UINT Index) {
+ return FindConstantBuffer(m_d3d11->GetConstantBufferByIndex(Index));
+ }
+
+
+ ID3D10ShaderReflectionConstantBuffer* STDMETHODCALLTYPE
+ D3D10ShaderReflection::GetConstantBufferByName(
+ LPCSTR Name) {
+ return FindConstantBuffer(m_d3d11->GetConstantBufferByName(Name));
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflection::GetInputParameterDesc(
+ UINT ParameterIndex,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDesc) {
+ D3D11_SIGNATURE_PARAMETER_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetInputParameterDesc(ParameterIndex, &d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ ConvertSignatureParameterDesc(&d3d11Desc, pDesc);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflection::GetOutputParameterDesc(
+ UINT ParameterIndex,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDesc) {
+ D3D11_SIGNATURE_PARAMETER_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetOutputParameterDesc(ParameterIndex, &d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ ConvertSignatureParameterDesc(&d3d11Desc, pDesc);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderReflection::GetResourceBindingDesc(
+ UINT ResourceIndex,
+ D3D10_SHADER_INPUT_BIND_DESC* pDesc) {
+ D3D11_SHADER_INPUT_BIND_DESC d3d11Desc;
+ HRESULT hr = m_d3d11->GetResourceBindingDesc(
+ ResourceIndex, &d3d11Desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ pDesc->Name = d3d11Desc.Name;
+ pDesc->Type = D3D10_SHADER_INPUT_TYPE(d3d11Desc.Type);
+ pDesc->BindPoint = d3d11Desc.BindPoint;
+ pDesc->BindCount = d3d11Desc.BindCount;
+ pDesc->uFlags = d3d11Desc.uFlags;
+ pDesc->ReturnType = D3D10_RESOURCE_RETURN_TYPE(d3d11Desc.ReturnType);
+ pDesc->Dimension = D3D10_SRV_DIMENSION (d3d11Desc.Dimension);
+ pDesc->NumSamples = d3d11Desc.NumSamples;
+ return S_OK;
+ }
+
+
+ ID3D10ShaderReflectionConstantBuffer* D3D10ShaderReflection::FindConstantBuffer(
+ ID3D11ShaderReflectionConstantBuffer* pConstantBuffer) {
+ if (!pConstantBuffer)
+ return nullptr;
+
+ auto entry = m_constantBuffers.find(pConstantBuffer);
+
+ if (entry == m_constantBuffers.end()) {
+ entry = m_constantBuffers.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(pConstantBuffer),
+ std::forward_as_tuple(pConstantBuffer)).first;
+ }
+
+ return &entry->second;
+ }
+
+
+ void D3D10ShaderReflection::ConvertSignatureParameterDesc(
+ const D3D11_SIGNATURE_PARAMETER_DESC* pSrcDesc,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDstDesc) {
+ pDstDesc->SemanticName = pSrcDesc->SemanticName;
+ pDstDesc->SemanticIndex = pSrcDesc->SemanticIndex;
+ pDstDesc->Register = pSrcDesc->Register;
+ pDstDesc->SystemValueType = D3D10_NAME(pSrcDesc->SystemValueType);
+ pDstDesc->ComponentType = D3D10_REGISTER_COMPONENT_TYPE(pSrcDesc->ComponentType);
+ pDstDesc->Mask = pSrcDesc->Mask;
+ pDstDesc->ReadWriteMask = pSrcDesc->ReadWriteMask;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.h
new file mode 100644
index 00000000..b25a92ce
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_reflection.h
@@ -0,0 +1,163 @@
+#pragma once
+
+#include <unordered_map>
+#include <vector>
+
+#include "d3d10_include.h"
+
+#include <d3d10shader.h>
+#include <d3d11shader.h>
+
+namespace dxvk {
+
+ class D3D10ShaderReflectionType : public ID3D10ShaderReflectionType {
+
+ public:
+
+ D3D10ShaderReflectionType(
+ ID3D11ShaderReflectionType* d3d11);
+
+ ~D3D10ShaderReflectionType();
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ D3D10_SHADER_TYPE_DESC* pDesc);
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE GetMemberTypeByIndex(
+ UINT Index);
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE GetMemberTypeByName(
+ const char* Name);
+
+ const char* STDMETHODCALLTYPE GetMemberTypeName(
+ UINT Index);
+
+ ID3D11ShaderReflectionType* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ ID3D11ShaderReflectionType* m_d3d11;
+
+ std::unordered_map<
+ ID3D11ShaderReflectionType*,
+ std::unique_ptr<D3D10ShaderReflectionType>> m_members;
+
+ ID3D10ShaderReflectionType* FindMemberType(
+ ID3D11ShaderReflectionType* pMemberType);
+
+ };
+
+
+ class D3D10ShaderReflectionVariable : public ID3D10ShaderReflectionVariable {
+
+ public:
+
+ D3D10ShaderReflectionVariable(
+ ID3D11ShaderReflectionVariable* d3d11);
+
+ ~D3D10ShaderReflectionVariable();
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ D3D10_SHADER_VARIABLE_DESC* pDesc);
+
+ ID3D10ShaderReflectionType* STDMETHODCALLTYPE GetType();
+
+ ID3D11ShaderReflectionVariable* STDMETHODCALLTYPE GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ ID3D11ShaderReflectionVariable* m_d3d11;
+ D3D10ShaderReflectionType m_type;
+
+ };
+
+
+ class D3D10ShaderReflectionConstantBuffer : public ID3D10ShaderReflectionConstantBuffer {
+
+ public:
+
+ D3D10ShaderReflectionConstantBuffer(
+ ID3D11ShaderReflectionConstantBuffer* d3d11);
+
+ ~D3D10ShaderReflectionConstantBuffer();
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ D3D10_SHADER_BUFFER_DESC* pDesc);
+
+ ID3D10ShaderReflectionVariable* STDMETHODCALLTYPE GetVariableByIndex(
+ UINT Index);
+
+ ID3D10ShaderReflectionVariable* STDMETHODCALLTYPE GetVariableByName(
+ LPCSTR Name);
+
+ ID3D11ShaderReflectionConstantBuffer* STDMETHODCALLTYPE GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ ID3D11ShaderReflectionConstantBuffer* m_d3d11;
+
+ std::unordered_map<
+ ID3D11ShaderReflectionVariable*,
+ D3D10ShaderReflectionVariable> m_variables;
+
+ ID3D10ShaderReflectionVariable* FindVariable(
+ ID3D11ShaderReflectionVariable* pVariable);
+
+ };
+
+
+ class D3D10ShaderReflection : public ComObject<ID3D10ShaderReflection> {
+
+ public:
+
+ D3D10ShaderReflection(ID3D11ShaderReflection* d3d11);
+ ~D3D10ShaderReflection();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ D3D10_SHADER_DESC* pDesc);
+
+ ID3D10ShaderReflectionConstantBuffer* STDMETHODCALLTYPE GetConstantBufferByIndex(
+ UINT Index);
+
+ ID3D10ShaderReflectionConstantBuffer* STDMETHODCALLTYPE GetConstantBufferByName(
+ LPCSTR Name);
+
+ HRESULT STDMETHODCALLTYPE GetInputParameterDesc(
+ UINT ParameterIndex,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetOutputParameterDesc(
+ UINT ParameterIndex,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetResourceBindingDesc(
+ UINT ResourceIndex,
+ D3D10_SHADER_INPUT_BIND_DESC* pDesc);
+
+ private:
+
+ Com<ID3D11ShaderReflection> m_d3d11;
+
+ std::unordered_map<
+ ID3D11ShaderReflectionConstantBuffer*,
+ D3D10ShaderReflectionConstantBuffer> m_constantBuffers;
+
+ ID3D10ShaderReflectionConstantBuffer* FindConstantBuffer(
+ ID3D11ShaderReflectionConstantBuffer* pConstantBuffer);
+
+ void ConvertSignatureParameterDesc(
+ const D3D11_SIGNATURE_PARAMETER_DESC* pSrcDesc,
+ D3D10_SIGNATURE_PARAMETER_DESC* pDstDesc);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.cpp
new file mode 100644
index 00000000..3db1450a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.cpp
@@ -0,0 +1,73 @@
+#include "d3d10_sampler.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_sampler.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10SamplerState::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10SamplerState::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10SamplerState::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10SamplerState::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10SamplerState::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10SamplerState::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10SamplerState::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10SamplerState::GetDesc(
+ D3D10_SAMPLER_DESC* pDesc) {
+ D3D11_SAMPLER_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->Filter = D3D10_FILTER(d3d11Desc.Filter);
+ pDesc->AddressU = D3D10_TEXTURE_ADDRESS_MODE(d3d11Desc.AddressU);
+ pDesc->AddressV = D3D10_TEXTURE_ADDRESS_MODE(d3d11Desc.AddressV);
+ pDesc->AddressW = D3D10_TEXTURE_ADDRESS_MODE(d3d11Desc.AddressW);
+ pDesc->MipLODBias = d3d11Desc.MipLODBias;
+ pDesc->MaxAnisotropy = d3d11Desc.MaxAnisotropy;
+ pDesc->ComparisonFunc = D3D10_COMPARISON_FUNC(d3d11Desc.ComparisonFunc);
+ pDesc->MinLOD = d3d11Desc.MinLOD;
+ pDesc->MaxLOD = d3d11Desc.MaxLOD;
+
+ for (uint32_t i = 0; i < 4; i++)
+ pDesc->BorderColor[i] = d3d11Desc.BorderColor[i];
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.h
new file mode 100644
index 00000000..82633e84
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_sampler.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11SamplerState;
+
+ class D3D10SamplerState : public ID3D10SamplerState {
+
+ public:
+
+ D3D10SamplerState(D3D11SamplerState* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_SAMPLER_DESC* pDesc);
+
+ D3D11SamplerState* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11SamplerState* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_shader.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_shader.h
new file mode 100644
index 00000000..01176a22
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_shader.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ template<typename D3D11Interface, typename D3D10Interface>
+ class D3D11Shader;
+
+ template<typename D3D10Interface, typename D3D11Interface>
+ class D3D10Shader : public D3D10Interface {
+ using D3D11ShaderClass = D3D11Shader<D3D11Interface, D3D10Interface>;
+ public:
+
+ D3D10Shader(D3D11Shader<D3D11Interface, D3D10Interface>* pParent)
+ : m_d3d11(pParent) { }
+
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+ D3D11ShaderClass* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11ShaderClass* m_d3d11;
+
+ };
+
+ using D3D10VertexShader = D3D10Shader<ID3D10VertexShader, ID3D11VertexShader>;
+ using D3D10GeometryShader = D3D10Shader<ID3D10GeometryShader, ID3D11GeometryShader>;
+ using D3D10PixelShader = D3D10Shader<ID3D10PixelShader, ID3D11PixelShader>;
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.cpp
new file mode 100644
index 00000000..af628eb4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.cpp
@@ -0,0 +1,432 @@
+#include "d3d10_state_block.h"
+
+#define MAKE_STATE_TYPE(field, count) { offsetof(D3D10_STATE_BLOCK_MASK, field), count }
+
+namespace dxvk {
+
+ static const std::array<std::pair<size_t, size_t>, 24> g_stateTypes = {{
+ MAKE_STATE_TYPE(SOBuffers, 1),
+ MAKE_STATE_TYPE(OMRenderTargets, 1),
+ MAKE_STATE_TYPE(OMDepthStencilState, 1),
+ MAKE_STATE_TYPE(OMBlendState, 1),
+ MAKE_STATE_TYPE(VS, 1),
+ MAKE_STATE_TYPE(VSSamplers, D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT),
+ MAKE_STATE_TYPE(VSShaderResources, D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT),
+ MAKE_STATE_TYPE(VSConstantBuffers, D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT),
+ MAKE_STATE_TYPE(GS, 1),
+ MAKE_STATE_TYPE(GSSamplers, D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT),
+ MAKE_STATE_TYPE(GSShaderResources, D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT),
+ MAKE_STATE_TYPE(GSConstantBuffers, D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT),
+ MAKE_STATE_TYPE(PS, 1),
+ MAKE_STATE_TYPE(PSSamplers, D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT),
+ MAKE_STATE_TYPE(PSShaderResources, D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT),
+ MAKE_STATE_TYPE(PSConstantBuffers, D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT),
+ MAKE_STATE_TYPE(IAVertexBuffers, D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT),
+ MAKE_STATE_TYPE(IAIndexBuffer, 1),
+ MAKE_STATE_TYPE(IAInputLayout, 1),
+ MAKE_STATE_TYPE(IAPrimitiveTopology, 1),
+ MAKE_STATE_TYPE(RSViewports, 1),
+ MAKE_STATE_TYPE(RSScissorRects, 1),
+ MAKE_STATE_TYPE(RSRasterizerState, 1),
+ MAKE_STATE_TYPE(Predication, 1),
+ }};
+
+
+ D3D10StateBlock::D3D10StateBlock(
+ ID3D10Device* pDevice,
+ const D3D10_STATE_BLOCK_MASK* pMask)
+ : m_device(pDevice), m_mask(*pMask) {
+
+ }
+
+
+ D3D10StateBlock::~D3D10StateBlock() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlock::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D10StateBlock)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D10StateBlock::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlock::Capture() {
+ m_state = D3D10_STATE_BLOCK_STATE();
+
+ if (TestBit(&m_mask.VS, 0)) m_device->VSGetShader(&m_state.vs);
+ if (TestBit(&m_mask.GS, 0)) m_device->GSGetShader(&m_state.gs);
+ if (TestBit(&m_mask.PS, 0)) m_device->PSGetShader(&m_state.ps);
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSSamplers, i)) m_device->VSGetSamplers(i, 1, &m_state.vsSso[i]);
+ if (TestBit(m_mask.GSSamplers, i)) m_device->GSGetSamplers(i, 1, &m_state.gsSso[i]);
+ if (TestBit(m_mask.PSSamplers, i)) m_device->PSGetSamplers(i, 1, &m_state.psSso[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSShaderResources, i)) m_device->VSGetShaderResources(i, 1, &m_state.vsSrv[i]);
+ if (TestBit(m_mask.GSShaderResources, i)) m_device->GSGetShaderResources(i, 1, &m_state.gsSrv[i]);
+ if (TestBit(m_mask.PSShaderResources, i)) m_device->PSGetShaderResources(i, 1, &m_state.psSrv[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSConstantBuffers, i)) m_device->VSGetConstantBuffers(i, 1, &m_state.vsCbo[i]);
+ if (TestBit(m_mask.GSConstantBuffers, i)) m_device->GSGetConstantBuffers(i, 1, &m_state.gsCbo[i]);
+ if (TestBit(m_mask.PSConstantBuffers, i)) m_device->PSGetConstantBuffers(i, 1, &m_state.psCbo[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.IAVertexBuffers, i)) {
+ m_device->IAGetVertexBuffers(i, 1,
+ &m_state.iaVertexBuffers[i],
+ &m_state.iaVertexOffsets[i],
+ &m_state.iaVertexStrides[i]);
+ }
+ }
+
+ if (TestBit(&m_mask.IAIndexBuffer, 0)) {
+ m_device->IAGetIndexBuffer(
+ &m_state.iaIndexBuffer,
+ &m_state.iaIndexFormat,
+ &m_state.iaIndexOffset);
+ }
+
+ if (TestBit(&m_mask.IAInputLayout, 0))
+ m_device->IAGetInputLayout(&m_state.iaInputLayout);
+
+ if (TestBit(&m_mask.IAPrimitiveTopology, 0))
+ m_device->IAGetPrimitiveTopology(&m_state.iaTopology);
+
+ if (TestBit(&m_mask.OMRenderTargets, 0)) {
+ m_device->OMGetRenderTargets(
+ D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT,
+ &m_state.omRtv[0], &m_state.omDsv);
+ }
+
+ if (TestBit(&m_mask.OMDepthStencilState, 0)) {
+ m_device->OMGetDepthStencilState(
+ &m_state.omDepthStencilState,
+ &m_state.omStencilRef);
+ }
+
+ if (TestBit(&m_mask.OMBlendState, 0)) {
+ m_device->OMGetBlendState(
+ &m_state.omBlendState,
+ m_state.omBlendFactor,
+ &m_state.omSampleMask);
+ }
+
+ if (TestBit(&m_mask.RSViewports, 0)) {
+ m_device->RSGetViewports(&m_state.rsViewportCount, nullptr);
+ m_device->RSGetViewports(&m_state.rsViewportCount, m_state.rsViewports);
+ }
+
+ if (TestBit(&m_mask.RSScissorRects, 0)) {
+ m_device->RSGetScissorRects(&m_state.rsScissorCount, nullptr);
+ m_device->RSGetScissorRects(&m_state.rsScissorCount, m_state.rsScissors);
+ }
+
+ if (TestBit(&m_mask.RSRasterizerState, 0))
+ m_device->RSGetState(&m_state.rsState);
+
+ if (TestBit(&m_mask.SOBuffers, 0)) {
+ m_device->SOGetTargets(
+ D3D10_SO_BUFFER_SLOT_COUNT,
+ &m_state.soBuffers[0],
+ &m_state.soOffsets[0]);
+ }
+
+ if (TestBit(&m_mask.Predication, 0))
+ m_device->GetPredication(&m_state.predicate, &m_state.predicateInvert);
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlock::Apply() {
+ if (TestBit(&m_mask.VS, 0)) m_device->VSSetShader(m_state.vs.ptr());
+ if (TestBit(&m_mask.GS, 0)) m_device->GSSetShader(m_state.gs.ptr());
+ if (TestBit(&m_mask.PS, 0)) m_device->PSSetShader(m_state.ps.ptr());
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSSamplers, i)) m_device->VSSetSamplers(i, 1, &m_state.vsSso[i]);
+ if (TestBit(m_mask.GSSamplers, i)) m_device->GSSetSamplers(i, 1, &m_state.gsSso[i]);
+ if (TestBit(m_mask.PSSamplers, i)) m_device->PSSetSamplers(i, 1, &m_state.psSso[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSShaderResources, i)) m_device->VSSetShaderResources(i, 1, &m_state.vsSrv[i]);
+ if (TestBit(m_mask.GSShaderResources, i)) m_device->GSSetShaderResources(i, 1, &m_state.gsSrv[i]);
+ if (TestBit(m_mask.PSShaderResources, i)) m_device->PSSetShaderResources(i, 1, &m_state.psSrv[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.VSConstantBuffers, i)) m_device->VSSetConstantBuffers(i, 1, &m_state.vsCbo[i]);
+ if (TestBit(m_mask.GSConstantBuffers, i)) m_device->GSSetConstantBuffers(i, 1, &m_state.gsCbo[i]);
+ if (TestBit(m_mask.PSConstantBuffers, i)) m_device->PSSetConstantBuffers(i, 1, &m_state.psCbo[i]);
+ }
+
+ for (uint32_t i = 0; i < D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ if (TestBit(m_mask.IAVertexBuffers, i)) {
+ m_device->IASetVertexBuffers(i, 1,
+ &m_state.iaVertexBuffers[i],
+ &m_state.iaVertexOffsets[i],
+ &m_state.iaVertexStrides[i]);
+ }
+ }
+
+ if (TestBit(&m_mask.IAIndexBuffer, 0)) {
+ m_device->IASetIndexBuffer(
+ m_state.iaIndexBuffer.ptr(),
+ m_state.iaIndexFormat,
+ m_state.iaIndexOffset);
+ }
+
+ if (TestBit(&m_mask.IAInputLayout, 0))
+ m_device->IASetInputLayout(m_state.iaInputLayout.ptr());
+
+ if (TestBit(&m_mask.IAPrimitiveTopology, 0))
+ m_device->IASetPrimitiveTopology(m_state.iaTopology);
+
+ if (TestBit(&m_mask.OMRenderTargets, 0)) {
+ m_device->OMSetRenderTargets(
+ D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT,
+ &m_state.omRtv[0], m_state.omDsv.ptr());
+ }
+
+ if (TestBit(&m_mask.OMDepthStencilState, 0)) {
+ m_device->OMSetDepthStencilState(
+ m_state.omDepthStencilState.ptr(),
+ m_state.omStencilRef);
+ }
+
+ if (TestBit(&m_mask.OMBlendState, 0)) {
+ m_device->OMSetBlendState(
+ m_state.omBlendState.ptr(),
+ m_state.omBlendFactor,
+ m_state.omSampleMask);
+ }
+
+ if (TestBit(&m_mask.RSViewports, 0))
+ m_device->RSSetViewports(m_state.rsViewportCount, m_state.rsViewports);
+
+ if (TestBit(&m_mask.RSScissorRects, 0))
+ m_device->RSSetScissorRects(m_state.rsScissorCount, m_state.rsScissors);
+
+ if (TestBit(&m_mask.RSRasterizerState, 0))
+ m_device->RSSetState(m_state.rsState.ptr());
+
+ if (TestBit(&m_mask.SOBuffers, 0)) {
+ m_device->SOSetTargets(
+ D3D10_SO_BUFFER_SLOT_COUNT,
+ &m_state.soBuffers[0],
+ &m_state.soOffsets[0]);
+ }
+
+ if (TestBit(&m_mask.Predication, 0))
+ m_device->SetPredication(m_state.predicate.ptr(), m_state.predicateInvert);
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlock::GetDevice(
+ ID3D10Device** ppDevice) {
+ Logger::err("D3D10StateBlock::GetDevice: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlock::ReleaseAllDeviceObjects() {
+ // Not entirely sure if this is correct?
+ m_state = D3D10_STATE_BLOCK_STATE();
+ return S_OK;
+ }
+
+
+ BOOL D3D10StateBlock::TestBit(
+ const BYTE* pMask,
+ UINT Idx) {
+ uint32_t byte = Idx / 8;
+ uint32_t bit = Idx % 8;
+ return (pMask[byte] & (1 << bit)) != 0;
+ }
+
+}
+
+extern "C" {
+ using namespace dxvk;
+
+ HRESULT STDMETHODCALLTYPE D3D10CreateStateBlock(
+ ID3D10Device* pDevice,
+ D3D10_STATE_BLOCK_MASK* pStateBlockMask,
+ ID3D10StateBlock** ppStateBlock) {
+ InitReturnPtr(ppStateBlock);
+
+ if (!pDevice || !pStateBlockMask || !ppStateBlock)
+ return E_INVALIDARG;
+
+ *ppStateBlock = ref(new D3D10StateBlock(pDevice, pStateBlockMask));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskEnableCapture(
+ D3D10_STATE_BLOCK_MASK* pMask,
+ D3D10_DEVICE_STATE_TYPES StateType,
+ UINT StartIdx,
+ UINT Count) {
+ if (!pMask || !StateType || StateType > g_stateTypes.size())
+ return E_INVALIDARG;
+
+ auto pair = g_stateTypes[uint32_t(StateType) - 1];
+ auto mask = reinterpret_cast<BYTE*>(pMask) + pair.first;
+
+ if (StartIdx + Count > pair.second)
+ return E_INVALIDARG;
+
+ for (uint32_t i = StartIdx; i < StartIdx + Count; i++) {
+ uint32_t byte = i / 8;
+ uint32_t bit = i % 8;
+ mask[byte] |= 1 << bit;
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskDisableCapture(
+ D3D10_STATE_BLOCK_MASK* pMask,
+ D3D10_DEVICE_STATE_TYPES StateType,
+ UINT StartIdx,
+ UINT Count) {
+ if (!pMask || !StateType || StateType > g_stateTypes.size())
+ return E_INVALIDARG;
+
+ auto pair = g_stateTypes[uint32_t(StateType) - 1];
+ auto mask = reinterpret_cast<BYTE*>(pMask) + pair.first;
+
+ if (StartIdx + Count > pair.second)
+ return E_INVALIDARG;
+
+ for (uint32_t i = StartIdx; i < StartIdx + Count; i++) {
+ uint32_t byte = i / 8;
+ uint32_t bit = i % 8;
+ mask[byte] &= ~(1 << bit);
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskEnableAll(
+ D3D10_STATE_BLOCK_MASK* pMask) {
+ if (!pMask)
+ return E_INVALIDARG;
+
+ *pMask = D3D10_STATE_BLOCK_MASK();
+ for (size_t i = 0; i < g_stateTypes.size(); i++) {
+ D3D10StateBlockMaskEnableCapture(pMask,
+ D3D10_DEVICE_STATE_TYPES(i + 1),
+ 0, g_stateTypes[i].second);
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskDisableAll(
+ D3D10_STATE_BLOCK_MASK* pMask) {
+ if (!pMask)
+ return E_INVALIDARG;
+
+ *pMask = D3D10_STATE_BLOCK_MASK();
+ return S_OK;
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D10StateBlockMaskGetSetting(
+ D3D10_STATE_BLOCK_MASK* pMask,
+ D3D10_DEVICE_STATE_TYPES StateType,
+ UINT Idx) {
+ if (!pMask || !StateType || StateType > g_stateTypes.size())
+ return FALSE;
+
+ auto pair = g_stateTypes[uint32_t(StateType) - 1];
+ auto mask = reinterpret_cast<BYTE*>(pMask) + pair.first;
+
+ if (Idx >= pair.second)
+ return FALSE;
+
+ uint32_t byte = Idx / 8;
+ uint32_t bit = Idx % 8;
+ return (mask[byte] & (1 << bit)) != 0;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskDifference(
+ D3D10_STATE_BLOCK_MASK* pA,
+ D3D10_STATE_BLOCK_MASK* pB,
+ D3D10_STATE_BLOCK_MASK* pResult) {
+ if (!pA || !pB || !pResult)
+ return E_INVALIDARG;
+
+ auto a = reinterpret_cast<const BYTE*>(pA);
+ auto b = reinterpret_cast<const BYTE*>(pB);
+ auto r = reinterpret_cast<BYTE*>(pResult);
+
+ for (size_t i = 0; i < sizeof(D3D10_STATE_BLOCK_MASK); i++)
+ r[i] = a[i] ^ b[i];
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskIntersect(
+ D3D10_STATE_BLOCK_MASK* pA,
+ D3D10_STATE_BLOCK_MASK* pB,
+ D3D10_STATE_BLOCK_MASK* pResult) {
+ if (!pA || !pB || !pResult)
+ return E_INVALIDARG;
+
+ auto a = reinterpret_cast<const BYTE*>(pA);
+ auto b = reinterpret_cast<const BYTE*>(pB);
+ auto r = reinterpret_cast<BYTE*>(pResult);
+
+ for (size_t i = 0; i < sizeof(D3D10_STATE_BLOCK_MASK); i++)
+ r[i] = a[i] & b[i];
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10StateBlockMaskUnion(
+ D3D10_STATE_BLOCK_MASK* pA,
+ D3D10_STATE_BLOCK_MASK* pB,
+ D3D10_STATE_BLOCK_MASK* pResult) {
+ if (!pA || !pB || !pResult)
+ return E_INVALIDARG;
+
+ auto a = reinterpret_cast<const BYTE*>(pA);
+ auto b = reinterpret_cast<const BYTE*>(pB);
+ auto r = reinterpret_cast<BYTE*>(pResult);
+
+ for (size_t i = 0; i < sizeof(D3D10_STATE_BLOCK_MASK); i++)
+ r[i] = a[i] | b[i];
+ return S_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.h
new file mode 100644
index 00000000..b899034d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_state_block.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "d3d10_include.h"
+#include "d3d10_interfaces.h"
+
+namespace dxvk {
+
+ struct D3D10_STATE_BLOCK_STATE {
+ Com<ID3D10VertexShader> vs = { };
+ Com<ID3D10SamplerState> vsSso[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT] = { };
+ Com<ID3D10ShaderResourceView> vsSrv[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = { };
+ Com<ID3D10Buffer> vsCbo[D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = { };
+ Com<ID3D10GeometryShader> gs = { };
+ Com<ID3D10SamplerState> gsSso[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT] = { };
+ Com<ID3D10ShaderResourceView> gsSrv[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = { };
+ Com<ID3D10Buffer> gsCbo[D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = { };
+ Com<ID3D10PixelShader> ps = { };
+ Com<ID3D10SamplerState> psSso[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT] = { };
+ Com<ID3D10ShaderResourceView> psSrv[D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = { };
+ Com<ID3D10Buffer> psCbo[D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = { };
+ Com<ID3D10Buffer> iaVertexBuffers[D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = { };
+ UINT iaVertexOffsets[D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = { };
+ UINT iaVertexStrides[D3D10_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = { };
+ Com<ID3D10Buffer> iaIndexBuffer = { };
+ DXGI_FORMAT iaIndexFormat = DXGI_FORMAT_UNKNOWN;
+ UINT iaIndexOffset = 0;
+ Com<ID3D10InputLayout> iaInputLayout = nullptr;
+ D3D10_PRIMITIVE_TOPOLOGY iaTopology = D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ Com<ID3D10RenderTargetView> omRtv[D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT] = { };
+ Com<ID3D10DepthStencilView> omDsv = { };
+ Com<ID3D10DepthStencilState> omDepthStencilState = { };
+ UINT omStencilRef = 0;
+ Com<ID3D10BlendState> omBlendState = { };
+ FLOAT omBlendFactor[4] = { };
+ UINT omSampleMask = 0;
+ UINT rsViewportCount = 0;
+ D3D10_VIEWPORT rsViewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE] = { };
+ UINT rsScissorCount = 0;
+ RECT rsScissors [D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE] = { };
+ Com<ID3D10RasterizerState> rsState = { };
+ Com<ID3D10Buffer> soBuffers[D3D10_SO_BUFFER_SLOT_COUNT] = { };
+ UINT soOffsets[D3D10_SO_BUFFER_SLOT_COUNT] = { };
+ Com<ID3D10Predicate> predicate = { };
+ BOOL predicateInvert = FALSE;
+ };
+
+
+ class D3D10StateBlock : public ComObject<ID3D10StateBlock> {
+
+ public:
+ D3D10StateBlock(
+ ID3D10Device* pDevice,
+ const D3D10_STATE_BLOCK_MASK* pMask);
+
+ ~D3D10StateBlock();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE Capture();
+
+ HRESULT STDMETHODCALLTYPE Apply();
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE ReleaseAllDeviceObjects();
+
+ private:
+
+ Com<ID3D10Device> m_device;
+ D3D10_STATE_BLOCK_MASK m_mask;
+ D3D10_STATE_BLOCK_STATE m_state;
+
+ static BOOL TestBit(
+ const BYTE* pMask,
+ UINT Idx);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.cpp
new file mode 100644
index 00000000..d04267cb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.cpp
@@ -0,0 +1,345 @@
+#include "d3d10_texture.h"
+#include "d3d10_device.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_context.h"
+#include "../d3d11/d3d11_texture.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture1D::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture1D::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture1D::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture1D::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture1D::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture1D::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture1D::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture1D::GetType(
+ D3D10_RESOURCE_DIMENSION* rType) {
+ *rType = D3D10_RESOURCE_DIMENSION_TEXTURE1D;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture1D::SetEvictionPriority(
+ UINT EvictionPriority) {
+ m_d3d11->SetEvictionPriority(EvictionPriority);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Texture1D::GetEvictionPriority() {
+ return m_d3d11->GetEvictionPriority();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture1D::Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ void** ppData) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ HRESULT hr = ctx->Map(m_d3d11, Subresource,
+ D3D11_MAP(MapType), MapFlags, &sr);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (ppData != nullptr) {
+ *ppData = sr.pData;
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture1D::Unmap(
+ UINT Subresource) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->Unmap(m_d3d11, Subresource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture1D::GetDesc(
+ D3D10_TEXTURE1D_DESC* pDesc) {
+ D3D11_TEXTURE1D_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->Width = d3d11Desc.Width;
+ pDesc->MipLevels = d3d11Desc.MipLevels;
+ pDesc->ArraySize = d3d11Desc.ArraySize;
+ pDesc->Format = d3d11Desc.Format;
+ pDesc->Usage = D3D10_USAGE(d3d11Desc.Usage);
+ pDesc->BindFlags = d3d11Desc.BindFlags;
+ pDesc->CPUAccessFlags = d3d11Desc.CPUAccessFlags;
+ pDesc->MiscFlags = ConvertD3D11ResourceFlags(d3d11Desc.MiscFlags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture2D::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture2D::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture2D::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture2D::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture2D::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture2D::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture2D::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture2D::GetType(
+ D3D10_RESOURCE_DIMENSION* rType) {
+ *rType = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture2D::SetEvictionPriority(
+ UINT EvictionPriority) {
+ m_d3d11->SetEvictionPriority(EvictionPriority);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Texture2D::GetEvictionPriority() {
+ return m_d3d11->GetEvictionPriority();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture2D::Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ D3D10_MAPPED_TEXTURE2D* pMappedTex2D) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ HRESULT hr = ctx->Map(m_d3d11, Subresource,
+ D3D11_MAP(MapType), MapFlags, &sr);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (pMappedTex2D != nullptr) {
+ pMappedTex2D->pData = sr.pData;
+ pMappedTex2D->RowPitch = sr.RowPitch;
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture2D::Unmap(
+ UINT Subresource) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->Unmap(m_d3d11, Subresource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture2D::GetDesc(
+ D3D10_TEXTURE2D_DESC* pDesc) {
+ D3D11_TEXTURE2D_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->Width = d3d11Desc.Width;
+ pDesc->Height = d3d11Desc.Height;
+ pDesc->MipLevels = d3d11Desc.MipLevels;
+ pDesc->ArraySize = d3d11Desc.ArraySize;
+ pDesc->Format = d3d11Desc.Format;
+ pDesc->SampleDesc = d3d11Desc.SampleDesc;
+ pDesc->Usage = D3D10_USAGE(d3d11Desc.Usage);
+ pDesc->BindFlags = d3d11Desc.BindFlags;
+ pDesc->CPUAccessFlags = d3d11Desc.CPUAccessFlags;
+ pDesc->MiscFlags = ConvertD3D11ResourceFlags(d3d11Desc.MiscFlags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture3D::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture3D::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10Texture3D::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture3D::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture3D::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture3D::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture3D::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture3D::GetType(
+ D3D10_RESOURCE_DIMENSION* rType) {
+ *rType = D3D10_RESOURCE_DIMENSION_TEXTURE3D;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture3D::SetEvictionPriority(
+ UINT EvictionPriority) {
+ m_d3d11->SetEvictionPriority(EvictionPriority);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D10Texture3D::GetEvictionPriority() {
+ return m_d3d11->GetEvictionPriority();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10Texture3D::Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ D3D10_MAPPED_TEXTURE3D* pMappedTex3D) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ HRESULT hr = ctx->Map(m_d3d11, Subresource,
+ D3D11_MAP(MapType), MapFlags, &sr);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (pMappedTex3D != nullptr) {
+ pMappedTex3D->pData = sr.pData;
+ pMappedTex3D->RowPitch = sr.RowPitch;
+ pMappedTex3D->DepthPitch = sr.DepthPitch;
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture3D::Unmap(
+ UINT Subresource) {
+ Com<ID3D11DeviceContext> ctx;
+ GetD3D11Context(m_d3d11, &ctx);
+
+ ctx->Unmap(m_d3d11, Subresource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10Texture3D::GetDesc(
+ D3D10_TEXTURE3D_DESC* pDesc) {
+ D3D11_TEXTURE3D_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->Width = d3d11Desc.Width;
+ pDesc->Height = d3d11Desc.Height;
+ pDesc->Depth = d3d11Desc.Depth;
+ pDesc->MipLevels = d3d11Desc.MipLevels;
+ pDesc->Format = d3d11Desc.Format;
+ pDesc->Usage = D3D10_USAGE(d3d11Desc.Usage);
+ pDesc->BindFlags = d3d11Desc.BindFlags;
+ pDesc->CPUAccessFlags = d3d11Desc.CPUAccessFlags;
+ pDesc->MiscFlags = ConvertD3D11ResourceFlags(d3d11Desc.MiscFlags);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.h
new file mode 100644
index 00000000..9c663300
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_texture.h
@@ -0,0 +1,207 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D10Device;
+ class D3D11Device;
+ class D3D11Texture1D;
+ class D3D11Texture2D;
+ class D3D11Texture3D;
+
+ ///////////////////////////////////////////
+ // D 3 D 1 0 T E X T U R E 1 D
+ class D3D10Texture1D : public ID3D10Texture1D {
+
+ public:
+
+ D3D10Texture1D(D3D11Texture1D* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetType(
+ D3D10_RESOURCE_DIMENSION* rType);
+
+ void STDMETHODCALLTYPE SetEvictionPriority(
+ UINT EvictionPriority);
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority();
+
+ HRESULT STDMETHODCALLTYPE Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ void** ppData);
+
+ void STDMETHODCALLTYPE Unmap(
+ UINT Subresource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_TEXTURE1D_DESC* pDesc);
+
+ D3D11Texture1D* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11Texture1D* m_d3d11;
+
+ };
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 0 T E X T U R E 2 D
+ class D3D10Texture2D : public ID3D10Texture2D {
+
+ public:
+
+ D3D10Texture2D(D3D11Texture2D* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetType(
+ D3D10_RESOURCE_DIMENSION* rType);
+
+ void STDMETHODCALLTYPE SetEvictionPriority(
+ UINT EvictionPriority);
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority();
+
+ HRESULT STDMETHODCALLTYPE Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ D3D10_MAPPED_TEXTURE2D* pMappedTex2D);
+
+ void STDMETHODCALLTYPE Unmap(
+ UINT Subresource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_TEXTURE2D_DESC* pDesc);
+
+ D3D11Texture2D* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11Texture2D* m_d3d11;
+
+ };
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 0 T E X T U R E 3 D
+ class D3D10Texture3D : public ID3D10Texture3D {
+
+ public:
+
+ D3D10Texture3D(D3D11Texture3D* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetType(
+ D3D10_RESOURCE_DIMENSION* rType);
+
+ void STDMETHODCALLTYPE SetEvictionPriority(
+ UINT EvictionPriority);
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority();
+
+ HRESULT STDMETHODCALLTYPE Map(
+ UINT Subresource,
+ D3D10_MAP MapType,
+ UINT MapFlags,
+ D3D10_MAPPED_TEXTURE3D* pMappedTex3D);
+
+ void STDMETHODCALLTYPE Unmap(
+ UINT Subresource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_TEXTURE3D_DESC* pDesc);
+
+ D3D11Texture3D* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11Texture3D* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.cpp
new file mode 100644
index 00000000..ad55eed9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.cpp
@@ -0,0 +1,100 @@
+#include "d3d10_util.h"
+#include "d3d10_device.h"
+
+#include "../d3d11/d3d11_device.h"
+
+namespace dxvk {
+
+ UINT ConvertD3D10ResourceFlags(UINT MiscFlags) {
+ UINT result = 0;
+ if (MiscFlags & D3D10_RESOURCE_MISC_GENERATE_MIPS)
+ result |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
+ if (MiscFlags & D3D10_RESOURCE_MISC_SHARED)
+ result |= D3D11_RESOURCE_MISC_SHARED;
+ if (MiscFlags & D3D10_RESOURCE_MISC_TEXTURECUBE)
+ result |= D3D11_RESOURCE_MISC_TEXTURECUBE;
+ if (MiscFlags & D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX)
+ result |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+ if (MiscFlags & D3D10_RESOURCE_MISC_GDI_COMPATIBLE)
+ result |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
+ return result;
+ }
+
+
+ UINT ConvertD3D11ResourceFlags(UINT MiscFlags) {
+ UINT result = 0;
+ if (MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS)
+ result |= D3D10_RESOURCE_MISC_GENERATE_MIPS;
+ if (MiscFlags & D3D11_RESOURCE_MISC_SHARED)
+ result |= D3D10_RESOURCE_MISC_SHARED;
+ if (MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE)
+ result |= D3D10_RESOURCE_MISC_TEXTURECUBE;
+ if (MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
+ result |= D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+ if (MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE)
+ result |= D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
+ return result;
+ }
+
+
+ void GetD3D10ResourceFromView(
+ ID3D11View* pSrcView,
+ ID3D10Resource** ppDstResource) {
+ Com<ID3D11Resource> d3d11Resource;
+ pSrcView->GetResource(&d3d11Resource);
+ GetD3D10Resource(d3d11Resource.ptr(), ppDstResource);
+ }
+
+
+ void GetD3D11ResourceFromView(
+ ID3D10View* pSrcView,
+ ID3D11Resource** ppDstResource) {
+ Com<ID3D10Resource> d3d10Resource;
+ pSrcView->GetResource(&d3d10Resource);
+ GetD3D11Resource(d3d10Resource.ptr(), ppDstResource);
+ }
+
+
+ void GetD3D10Resource(
+ ID3D11Resource* pSrcResource,
+ ID3D10Resource** ppDstResource) {
+ pSrcResource->QueryInterface(
+ __uuidof(ID3D10Resource),
+ reinterpret_cast<void**>(ppDstResource));
+ }
+
+
+ void GetD3D11Resource(
+ ID3D10Resource* pSrcResource,
+ ID3D11Resource** ppDstResource) {
+ pSrcResource->QueryInterface(
+ __uuidof(ID3D11Resource),
+ reinterpret_cast<void**>(ppDstResource));
+ }
+
+
+ void GetD3D10Device(
+ ID3D11DeviceChild* pObject,
+ ID3D10Device** ppDevice) {
+ ID3D11Device* d3d11Device = nullptr;
+ pObject->GetDevice(&d3d11Device);
+ *ppDevice = static_cast<D3D11Device*>(d3d11Device)->GetD3D10Interface();
+ }
+
+
+ void GetD3D11Device(
+ ID3D11DeviceChild* pObject,
+ ID3D11Device** ppDevice) {
+ pObject->GetDevice(ppDevice);
+ }
+
+
+ void GetD3D11Context(
+ ID3D11DeviceChild* pObject,
+ ID3D11DeviceContext** ppContext) {
+ Com<ID3D11Device> d3d11Device;
+ pObject->GetDevice(&d3d11Device);
+ d3d11Device->GetImmediateContext(ppContext);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.h
new file mode 100644
index 00000000..72c9c6e7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_util.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "d3d10_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Converts misc. resource flags
+ *
+ * Converts the D3D11 misc. resource flags to
+ * their D3D10 equivalents and vice versa.
+ * \param [in] MiscFlags Original bit mask
+ * \returns Converted bit mask
+ */
+ UINT ConvertD3D10ResourceFlags(UINT MiscFlags);
+ UINT ConvertD3D11ResourceFlags(UINT MiscFlags);
+
+ /**
+ * \brief Retrieves D3D10 resource from D3D11 view
+ *
+ * \param [in] pSrcView The D3D11 resource view
+ * \param [out] ppDstResource The D3D10 resource
+ */
+ void GetD3D10ResourceFromView(
+ ID3D11View* pSrcView,
+ ID3D10Resource** ppDstResource);
+
+ /**
+ * \brief Retrieves D3D11 resource from D3D10 view
+ *
+ * \param [in] pSrcView The D3D10 resource view
+ * \param [out] ppDstResource The D3D11 resource
+ */
+ void GetD3D11ResourceFromView(
+ ID3D10View* pSrcView,
+ ID3D11Resource** ppDstResource);
+
+ /**
+ * \brief Retrieves D3D10 resource from D3D11 resource
+ *
+ * \param [in] pSrcResource The D3D11 resource
+ * \param [out] ppDstResource The D3D10 resource
+ */
+ void GetD3D10Resource(
+ ID3D11Resource* pSrcResource,
+ ID3D10Resource** ppDstResource);
+
+ /**
+ * \brief Retrieves D3D11 resource from D3D10 resource
+ *
+ * \param [in] pSrcResource The D3D10 resource
+ * \param [out] ppDstResource The D3D11 resource
+ */
+ void GetD3D11Resource(
+ ID3D10Resource* pSrcResource,
+ ID3D11Resource** ppDstResource);
+
+ /**
+ * \brief Retrieves D3D10 device from D3D11 object
+ *
+ * \param [in] pObject The D3D11 device child
+ * \param [out] ppDevice The D3D10 device pointer
+ */
+ void GetD3D10Device(
+ ID3D11DeviceChild* pObject,
+ ID3D10Device** ppDevice);
+
+ /**
+ * \brief Retrieves D3D11 device from D3D11 object
+ *
+ * \param [in] pObject The D3D11 device child
+ * \param [out] ppDevice The D3D11 device pointer
+ */
+ void GetD3D11Device(
+ ID3D11DeviceChild* pObject,
+ ID3D11Device** ppDevice);
+
+ /**
+ * \brief Retrieves D3D11 context from D3D11 object
+ *
+ * \param [in] pObject The D3D11 device child
+ * \param [out] ppContext The D3D11 immediate context
+ */
+ void GetD3D11Context(
+ ID3D11DeviceChild* pObject,
+ ID3D11DeviceContext** ppContext);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.cpp
new file mode 100644
index 00000000..4d8df98a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.cpp
@@ -0,0 +1,102 @@
+#include "d3d10_view_dsv.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_view_dsv.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilView::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10DepthStencilView::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10DepthStencilView::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10DepthStencilView::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilView::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilView::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10DepthStencilView::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10DepthStencilView::GetResource(
+ ID3D10Resource** ppResource) {
+ GetD3D10ResourceFromView(m_d3d11, ppResource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10DepthStencilView::GetDesc(
+ D3D10_DEPTH_STENCIL_VIEW_DESC* pDesc) {
+ D3D11_DEPTH_STENCIL_VIEW_DESC d3d11Desc;
+ m_d3d11->GetDesc(&d3d11Desc);
+
+ pDesc->ViewDimension = D3D10_DSV_DIMENSION(d3d11Desc.ViewDimension);
+ pDesc->Format = d3d11Desc.Format;
+
+ switch (d3d11Desc.ViewDimension) {
+ case D3D11_DSV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE1D:
+ pDesc->Texture1D.MipSlice = d3d11Desc.Texture1D.MipSlice;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
+ pDesc->Texture1DArray.MipSlice = d3d11Desc.Texture1DArray.MipSlice;
+ pDesc->Texture1DArray.FirstArraySlice = d3d11Desc.Texture1DArray.FirstArraySlice;
+ pDesc->Texture1DArray.ArraySize = d3d11Desc.Texture1DArray.ArraySize;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2D:
+ pDesc->Texture2D.MipSlice = d3d11Desc.Texture2D.MipSlice;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
+ pDesc->Texture2DArray.MipSlice = d3d11Desc.Texture2DArray.MipSlice;
+ pDesc->Texture2DArray.FirstArraySlice = d3d11Desc.Texture2DArray.FirstArraySlice;
+ pDesc->Texture2DArray.ArraySize = d3d11Desc.Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DMS:
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
+ pDesc->Texture2DMSArray.FirstArraySlice = d3d11Desc.Texture2DMSArray.FirstArraySlice;
+ pDesc->Texture2DMSArray.ArraySize = d3d11Desc.Texture2DMSArray.ArraySize;
+ break;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.h
new file mode 100644
index 00000000..e78c7642
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_dsv.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11DepthStencilView;
+
+ class D3D10DepthStencilView : public ID3D10DepthStencilView {
+
+ public:
+
+ D3D10DepthStencilView(D3D11DepthStencilView* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetResource(
+ ID3D10Resource** ppResource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_DEPTH_STENCIL_VIEW_DESC* pDesc);
+
+ D3D11DepthStencilView* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11DepthStencilView* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.cpp
new file mode 100644
index 00000000..7170a649
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.cpp
@@ -0,0 +1,68 @@
+#include "d3d10_view_rtv.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_view_rtv.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10RenderTargetView::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10RenderTargetView::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10RenderTargetView::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10RenderTargetView::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RenderTargetView::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RenderTargetView::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10RenderTargetView::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10RenderTargetView::GetResource(
+ ID3D10Resource** ppResource) {
+ GetD3D10ResourceFromView(m_d3d11, ppResource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10RenderTargetView::GetDesc(
+ D3D10_RENDER_TARGET_VIEW_DESC* pDesc) {
+ static_assert(sizeof(D3D10_RENDER_TARGET_VIEW_DESC) ==
+ sizeof(D3D11_RENDER_TARGET_VIEW_DESC));
+
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_RENDER_TARGET_VIEW_DESC*>(pDesc));
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.h
new file mode 100644
index 00000000..e6a46c56
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_rtv.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11RenderTargetView;
+
+ class D3D10RenderTargetView : public ID3D10RenderTargetView {
+
+ public:
+
+ D3D10RenderTargetView(D3D11RenderTargetView* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetResource(
+ ID3D10Resource** ppResource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_RENDER_TARGET_VIEW_DESC* pDesc);
+
+ D3D11RenderTargetView* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11RenderTargetView* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.cpp
new file mode 100644
index 00000000..d8fdd24d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.cpp
@@ -0,0 +1,83 @@
+#include "d3d10_view_srv.h"
+
+#include "../d3d11/d3d11_device.h"
+#include "../d3d11/d3d11_view_srv.h"
+
+namespace dxvk {
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderResourceView::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_d3d11->QueryInterface(riid, ppvObject);
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10ShaderResourceView::AddRef() {
+ return m_d3d11->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D10ShaderResourceView::Release() {
+ return m_d3d11->Release();
+ }
+
+
+ void STDMETHODCALLTYPE D3D10ShaderResourceView::GetDevice(
+ ID3D10Device** ppDevice) {
+ GetD3D10Device(m_d3d11, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderResourceView::GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData) {
+ return m_d3d11->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderResourceView::SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData) {
+ return m_d3d11->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D10ShaderResourceView::SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData) {
+ return m_d3d11->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10ShaderResourceView::GetResource(
+ ID3D10Resource** ppResource) {
+ GetD3D10ResourceFromView(m_d3d11, ppResource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D10ShaderResourceView::GetDesc(
+ D3D10_SHADER_RESOURCE_VIEW_DESC* pDesc) {
+ static_assert(sizeof(D3D10_SHADER_RESOURCE_VIEW_DESC) ==
+ sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
+
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_SHADER_RESOURCE_VIEW_DESC*>(pDesc));
+
+ if (pDesc->ViewDimension > D3D10_SRV_DIMENSION_TEXTURECUBE)
+ pDesc->ViewDimension = D3D10_SRV_DIMENSION_UNKNOWN;
+ }
+
+
+ void STDMETHODCALLTYPE D3D10ShaderResourceView::GetDesc1(
+ D3D10_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
+ static_assert(sizeof(D3D10_SHADER_RESOURCE_VIEW_DESC1) ==
+ sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
+
+ m_d3d11->GetDesc(reinterpret_cast<D3D11_SHADER_RESOURCE_VIEW_DESC*>(pDesc));
+
+ if (pDesc->ViewDimension > D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY)
+ pDesc->ViewDimension = D3D10_1_SRV_DIMENSION_UNKNOWN;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.h b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.h
new file mode 100644
index 00000000..7cbaffe9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10_view_srv.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "d3d10_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11ShaderResourceView;
+
+ class D3D10ShaderResourceView : public ID3D10ShaderResourceView1 {
+
+ public:
+
+ D3D10ShaderResourceView(D3D11ShaderResourceView* pParent)
+ : m_d3d11(pParent) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D10Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown* pData);
+
+ void STDMETHODCALLTYPE GetResource(
+ ID3D10Resource** ppResource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D10_SHADER_RESOURCE_VIEW_DESC* pDesc);
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D10_SHADER_RESOURCE_VIEW_DESC1* pDesc);
+
+ D3D11ShaderResourceView* GetD3D11Iface() {
+ return m_d3d11;
+ }
+
+ private:
+
+ D3D11ShaderResourceView* m_d3d11;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10core.def b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10core.def
new file mode 100644
index 00000000..39c65968
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/d3d10core.def
@@ -0,0 +1,5 @@
+LIBRARY D3D10CORE.DLL
+EXPORTS
+ D3D10CoreCreateDevice
+ D3D10CoreGetVersion
+ D3D10CoreRegisterLayers
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/meson.build b/src/libs/dxvk-native-1.9.2a/src/d3d10/meson.build
new file mode 100644
index 00000000..8633cd1b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/meson.build
@@ -0,0 +1,46 @@
+d3d10_res = wrc_generator.process('version10.rc')
+d3d10_1_res = wrc_generator.process('version10_1.rc')
+d3d10_core_res = wrc_generator.process('version10_core.rc')
+
+d3d10_core_src = [
+ 'd3d10_core.cpp',
+]
+
+d3d10_main_src = [
+ 'd3d10_main.cpp',
+ 'd3d10_reflection.cpp',
+ 'd3d10_state_block.cpp',
+]
+
+d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_res,
+ name_prefix : '',
+ dependencies : [ d3d11_dep ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'd3d10core'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+d3d10_core_dep = declare_dependency(
+ link_with : [ d3d10_core_dll ])
+
+d3d10_deps = [ lib_d3dcompiler_43, lib_dxgi, dxbc_dep, dxvk_dep, d3d10_core_dep ]
+
+d3d10_dll = shared_library('d3d10'+dll_ext, d3d10_main_src, d3d10_res,
+ name_prefix : '',
+ dependencies : [ d3d10_deps ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'd3d10'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+d3d10_1_dll = shared_library('d3d10_1'+dll_ext, d3d10_main_src, d3d10_1_res,
+ name_prefix : '',
+ dependencies : [ d3d10_deps ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'd3d10_1'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+d3d10_dep = declare_dependency(
+ link_with : [ d3d10_dll, d3d10_1_dll, d3d10_core_dll ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/version10.rc b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10.rc
new file mode 100644
index 00000000..43d7a62f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "Direct3D 10 Runtime"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "D3D10.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "D3D10.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_1.rc b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_1.rc
new file mode 100644
index 00000000..92550d32
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_1.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "Direct3D 10.1 Runtime"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "D3D10_1.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "D3D10_1.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_core.rc b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_core.rc
new file mode 100644
index 00000000..30e0c056
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d10/version10_core.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "Direct3D 10 Runtime"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "D3D10Core.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "D3D10Core.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def
new file mode 100644
index 00000000..8b65655a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11.def
@@ -0,0 +1,5 @@
+LIBRARY D3D11.DLL
+EXPORTS
+ D3D11CoreCreateDevice @18
+ D3D11CreateDevice @22
+ D3D11CreateDeviceAndSwapChain @23
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp
new file mode 100644
index 00000000..010acdd8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.cpp
@@ -0,0 +1,92 @@
+#include "d3d11_annotation.h"
+#include "d3d11_context.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11UserDefinedAnnotation::D3D11UserDefinedAnnotation(D3D11DeviceContext* ctx)
+ : m_container(ctx),
+ m_eventDepth(0) { }
+
+
+ D3D11UserDefinedAnnotation::~D3D11UserDefinedAnnotation() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11UserDefinedAnnotation::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11UserDefinedAnnotation::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::BeginEvent(
+ LPCWSTR Name) {
+ if (!m_container->IsAnnotationEnabled())
+ return -1;
+
+ m_container->EmitCs([labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
+ VkDebugUtilsLabelEXT label;
+ label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+ label.pNext = nullptr;
+ label.pLabelName = labelName.c_str();
+ label.color[0] = 1.0f;
+ label.color[1] = 1.0f;
+ label.color[2] = 1.0f;
+ label.color[3] = 1.0f;
+
+ ctx->beginDebugLabel(&label);
+ });
+
+ return m_eventDepth++;
+ }
+
+
+ INT STDMETHODCALLTYPE D3D11UserDefinedAnnotation::EndEvent() {
+ if (!m_container->IsAnnotationEnabled())
+ return -1;
+
+ m_container->EmitCs([](DxvkContext *ctx) {
+ ctx->endDebugLabel();
+ });
+
+ return m_eventDepth--;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11UserDefinedAnnotation::SetMarker(
+ LPCWSTR Name) {
+ if (!m_container->IsAnnotationEnabled())
+ return;
+
+ m_container->EmitCs([labelName = dxvk::str::fromws(Name)](DxvkContext *ctx) {
+ VkDebugUtilsLabelEXT label;
+ label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
+ label.pNext = nullptr;
+ label.pLabelName = labelName.c_str();
+ label.color[0] = 1.0f;
+ label.color[1] = 1.0f;
+ label.color[2] = 1.0f;
+ label.color[3] = 1.0f;
+
+ ctx->insertDebugLabel(&label);
+ });
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D11UserDefinedAnnotation::GetStatus() {
+ return m_container->IsAnnotationEnabled();
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h
new file mode 100644
index 00000000..97ee39c4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_annotation.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ class D3D11DeviceContext;
+
+ class D3D11UserDefinedAnnotation : ID3DUserDefinedAnnotation {
+
+ public:
+
+ D3D11UserDefinedAnnotation(D3D11DeviceContext* ctx);
+ ~D3D11UserDefinedAnnotation();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ INT STDMETHODCALLTYPE BeginEvent(
+ LPCWSTR Name);
+
+ INT STDMETHODCALLTYPE EndEvent();
+
+ void STDMETHODCALLTYPE SetMarker(
+ LPCWSTR Name);
+
+ BOOL STDMETHODCALLTYPE GetStatus();
+
+ private:
+
+ D3D11DeviceContext* m_container;
+
+ // Stack depth for non-finalized BeginEvent calls
+ int32_t m_eventDepth;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp
new file mode 100644
index 00000000..caacc869
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.cpp
@@ -0,0 +1,309 @@
+#include "d3d11_blend.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11BlendState::D3D11BlendState(
+ D3D11Device* device,
+ const D3D11_BLEND_DESC1& desc)
+ : D3D11StateObject<ID3D11BlendState1>(device),
+ m_desc(desc), m_d3d10(this) {
+ // If Independent Blend is disabled, we must ignore the
+ // blend modes for render target 1 to 7. In Vulkan, all
+ // blend modes need to be identical in that case.
+ for (uint32_t i = 0; i < m_blendModes.size(); i++) {
+ m_blendModes.at(i) = DecodeBlendMode(
+ desc.IndependentBlendEnable
+ ? desc.RenderTarget[i]
+ : desc.RenderTarget[0]);
+ }
+
+ // Multisample state is part of the blend state in D3D11
+ m_msState.sampleMask = 0; // Set during bind
+ m_msState.enableAlphaToCoverage = desc.AlphaToCoverageEnable;
+
+ // Vulkan only supports a global logic op for the blend
+ // state, which might be problematic in some cases.
+ if (desc.IndependentBlendEnable && desc.RenderTarget[0].LogicOpEnable)
+ Logger::warn("D3D11: Per-target logic ops not supported");
+
+ m_loState.enableLogicOp = desc.RenderTarget[0].LogicOpEnable;
+ m_loState.logicOp = DecodeLogicOp(desc.RenderTarget[0].LogicOp);
+ }
+
+
+ D3D11BlendState::~D3D11BlendState() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11BlendState::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11BlendState)
+ || riid == __uuidof(ID3D11BlendState1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10BlendState)
+ || riid == __uuidof(ID3D10BlendState1)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11BlendState::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11BlendState::GetDesc(D3D11_BLEND_DESC* pDesc) {
+ pDesc->AlphaToCoverageEnable = m_desc.AlphaToCoverageEnable;
+ pDesc->IndependentBlendEnable = m_desc.IndependentBlendEnable;
+
+ for (uint32_t i = 0; i < 8; i++) {
+ pDesc->RenderTarget[i].BlendEnable = m_desc.RenderTarget[i].BlendEnable;
+ pDesc->RenderTarget[i].SrcBlend = m_desc.RenderTarget[i].SrcBlend;
+ pDesc->RenderTarget[i].DestBlend = m_desc.RenderTarget[i].DestBlend;
+ pDesc->RenderTarget[i].BlendOp = m_desc.RenderTarget[i].BlendOp;
+ pDesc->RenderTarget[i].SrcBlendAlpha = m_desc.RenderTarget[i].SrcBlendAlpha;
+ pDesc->RenderTarget[i].DestBlendAlpha = m_desc.RenderTarget[i].DestBlendAlpha;
+ pDesc->RenderTarget[i].BlendOpAlpha = m_desc.RenderTarget[i].BlendOpAlpha;
+ pDesc->RenderTarget[i].RenderTargetWriteMask = m_desc.RenderTarget[i].RenderTargetWriteMask;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11BlendState::GetDesc1(D3D11_BLEND_DESC1* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ void D3D11BlendState::BindToContext(
+ const Rc<DxvkContext>& ctx,
+ uint32_t sampleMask) const {
+ // We handled Independent Blend during object creation
+ // already, so if it is disabled, all elements in the
+ // blend mode array will be identical
+ for (uint32_t i = 0; i < m_blendModes.size(); i++)
+ ctx->setBlendMode(i, m_blendModes.at(i));
+
+ // The sample mask is dynamic state in D3D11
+ DxvkMultisampleState msState = m_msState;
+ msState.sampleMask = sampleMask;
+ ctx->setMultisampleState(msState);
+
+ // Set up logic op state as well
+ ctx->setLogicOpState(m_loState);
+ }
+
+
+ D3D11_BLEND_DESC1 D3D11BlendState::PromoteDesc(const D3D11_BLEND_DESC* pSrcDesc) {
+ D3D11_BLEND_DESC1 dstDesc;
+ dstDesc.AlphaToCoverageEnable = pSrcDesc->AlphaToCoverageEnable;
+ dstDesc.IndependentBlendEnable = pSrcDesc->IndependentBlendEnable;
+
+ for (uint32_t i = 0; i < 8; i++) {
+ dstDesc.RenderTarget[i].BlendEnable = pSrcDesc->RenderTarget[i].BlendEnable;
+ dstDesc.RenderTarget[i].LogicOpEnable = FALSE;
+ dstDesc.RenderTarget[i].SrcBlend = pSrcDesc->RenderTarget[i].SrcBlend;
+ dstDesc.RenderTarget[i].DestBlend = pSrcDesc->RenderTarget[i].DestBlend;
+ dstDesc.RenderTarget[i].BlendOp = pSrcDesc->RenderTarget[i].BlendOp;
+ dstDesc.RenderTarget[i].SrcBlendAlpha = pSrcDesc->RenderTarget[i].SrcBlendAlpha;
+ dstDesc.RenderTarget[i].DestBlendAlpha = pSrcDesc->RenderTarget[i].DestBlendAlpha;
+ dstDesc.RenderTarget[i].BlendOpAlpha = pSrcDesc->RenderTarget[i].BlendOpAlpha;
+ dstDesc.RenderTarget[i].LogicOp = D3D11_LOGIC_OP_NOOP;
+ dstDesc.RenderTarget[i].RenderTargetWriteMask = pSrcDesc->RenderTarget[i].RenderTargetWriteMask;
+ }
+
+ return dstDesc;
+ }
+
+
+ HRESULT D3D11BlendState::NormalizeDesc(D3D11_BLEND_DESC1* pDesc) {
+ if (pDesc->AlphaToCoverageEnable)
+ pDesc->AlphaToCoverageEnable = TRUE;
+
+ if (pDesc->IndependentBlendEnable)
+ pDesc->IndependentBlendEnable = TRUE;
+
+ const uint32_t numRenderTargets = pDesc->IndependentBlendEnable ? 8 : 1;
+
+ for (uint32_t i = 0; i < numRenderTargets; i++) {
+ D3D11_RENDER_TARGET_BLEND_DESC1* rt = &pDesc->RenderTarget[i];
+
+ if (rt->BlendEnable) {
+ rt->BlendEnable = TRUE;
+
+ if (rt->LogicOpEnable)
+ return E_INVALIDARG;
+
+ if (!ValidateBlendOperations(
+ rt->SrcBlend, rt->SrcBlendAlpha,
+ rt->DestBlend, rt->DestBlendAlpha,
+ rt->BlendOp, rt->BlendOpAlpha))
+ return E_INVALIDARG;
+ } else {
+ rt->SrcBlend = D3D11_BLEND_ONE;
+ rt->DestBlend = D3D11_BLEND_ZERO;
+ rt->BlendOp = D3D11_BLEND_OP_ADD;
+ rt->SrcBlendAlpha = D3D11_BLEND_ONE;
+ rt->DestBlendAlpha = D3D11_BLEND_ZERO;
+ rt->BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ }
+
+ if (rt->LogicOpEnable) {
+ rt->LogicOpEnable = TRUE;
+
+ // Blending must be disabled
+ // if the logic op is enabled
+ if (rt->BlendEnable
+ || pDesc->IndependentBlendEnable
+ || !ValidateLogicOp(rt->LogicOp))
+ return E_INVALIDARG;
+ } else {
+ rt->LogicOp = D3D11_LOGIC_OP_NOOP;
+ }
+
+ if (rt->RenderTargetWriteMask > D3D11_COLOR_WRITE_ENABLE_ALL)
+ return E_INVALIDARG;
+ }
+
+ for (uint32_t i = numRenderTargets; i < 8; i++) {
+ // Render targets blend operations are the same
+ // across all render targets when blend is enabled
+ // on rendertarget[0] with independent blend disabled
+ pDesc->RenderTarget[i] = pDesc->RenderTarget[0];
+ }
+
+ return S_OK;
+ }
+
+
+ DxvkBlendMode D3D11BlendState::DecodeBlendMode(
+ const D3D11_RENDER_TARGET_BLEND_DESC1& BlendDesc) {
+ DxvkBlendMode mode;
+ mode.enableBlending = BlendDesc.BlendEnable;
+ mode.colorSrcFactor = DecodeBlendFactor(BlendDesc.SrcBlend, false);
+ mode.colorDstFactor = DecodeBlendFactor(BlendDesc.DestBlend, false);
+ mode.colorBlendOp = DecodeBlendOp(BlendDesc.BlendOp);
+ mode.alphaSrcFactor = DecodeBlendFactor(BlendDesc.SrcBlendAlpha, true);
+ mode.alphaDstFactor = DecodeBlendFactor(BlendDesc.DestBlendAlpha, true);
+ mode.alphaBlendOp = DecodeBlendOp(BlendDesc.BlendOpAlpha);
+ mode.writeMask = BlendDesc.RenderTargetWriteMask;
+ return mode;
+ }
+
+
+ VkBlendFactor D3D11BlendState::DecodeBlendFactor(D3D11_BLEND BlendFactor, bool IsAlpha) {
+ switch (BlendFactor) {
+ case D3D11_BLEND_ZERO: return VK_BLEND_FACTOR_ZERO;
+ case D3D11_BLEND_ONE: return VK_BLEND_FACTOR_ONE;
+ case D3D11_BLEND_SRC_COLOR: return VK_BLEND_FACTOR_SRC_COLOR;
+ case D3D11_BLEND_INV_SRC_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
+ case D3D11_BLEND_SRC_ALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
+ case D3D11_BLEND_INV_SRC_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ case D3D11_BLEND_DEST_ALPHA: return VK_BLEND_FACTOR_DST_ALPHA;
+ case D3D11_BLEND_INV_DEST_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
+ case D3D11_BLEND_DEST_COLOR: return VK_BLEND_FACTOR_DST_COLOR;
+ case D3D11_BLEND_INV_DEST_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
+ case D3D11_BLEND_SRC_ALPHA_SAT: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
+ case D3D11_BLEND_BLEND_FACTOR: return IsAlpha ? VK_BLEND_FACTOR_CONSTANT_ALPHA : VK_BLEND_FACTOR_CONSTANT_COLOR;
+ case D3D11_BLEND_INV_BLEND_FACTOR: return IsAlpha ? VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA : VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
+ case D3D11_BLEND_SRC1_COLOR: return VK_BLEND_FACTOR_SRC1_COLOR;
+ case D3D11_BLEND_INV_SRC1_COLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
+ case D3D11_BLEND_SRC1_ALPHA: return VK_BLEND_FACTOR_SRC1_ALPHA;
+ case D3D11_BLEND_INV_SRC1_ALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
+ default: return VK_BLEND_FACTOR_ZERO;
+ }
+ }
+
+
+ VkBlendOp D3D11BlendState::DecodeBlendOp(D3D11_BLEND_OP BlendOp) {
+ switch (BlendOp) {
+ case D3D11_BLEND_OP_ADD: return VK_BLEND_OP_ADD;
+ case D3D11_BLEND_OP_SUBTRACT: return VK_BLEND_OP_SUBTRACT;
+ case D3D11_BLEND_OP_REV_SUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT;
+ case D3D11_BLEND_OP_MIN: return VK_BLEND_OP_MIN;
+ case D3D11_BLEND_OP_MAX: return VK_BLEND_OP_MAX;
+ default: return VK_BLEND_OP_ADD;
+ }
+ }
+
+
+ VkLogicOp D3D11BlendState::DecodeLogicOp(D3D11_LOGIC_OP LogicOp) {
+ switch (LogicOp) {
+ case D3D11_LOGIC_OP_CLEAR: return VK_LOGIC_OP_CLEAR;
+ case D3D11_LOGIC_OP_SET: return VK_LOGIC_OP_SET;
+ case D3D11_LOGIC_OP_COPY: return VK_LOGIC_OP_COPY;
+ case D3D11_LOGIC_OP_COPY_INVERTED: return VK_LOGIC_OP_COPY_INVERTED;
+ case D3D11_LOGIC_OP_NOOP: return VK_LOGIC_OP_NO_OP;
+ case D3D11_LOGIC_OP_INVERT: return VK_LOGIC_OP_INVERT;
+ case D3D11_LOGIC_OP_AND: return VK_LOGIC_OP_AND;
+ case D3D11_LOGIC_OP_NAND: return VK_LOGIC_OP_NAND;
+ case D3D11_LOGIC_OP_OR: return VK_LOGIC_OP_OR;
+ case D3D11_LOGIC_OP_NOR: return VK_LOGIC_OP_NOR;
+ case D3D11_LOGIC_OP_XOR: return VK_LOGIC_OP_XOR;
+ case D3D11_LOGIC_OP_EQUIV: return VK_LOGIC_OP_EQUIVALENT;
+ case D3D11_LOGIC_OP_AND_REVERSE: return VK_LOGIC_OP_AND_REVERSE;
+ case D3D11_LOGIC_OP_AND_INVERTED: return VK_LOGIC_OP_AND_INVERTED;
+ case D3D11_LOGIC_OP_OR_REVERSE: return VK_LOGIC_OP_OR_REVERSE;
+ case D3D11_LOGIC_OP_OR_INVERTED: return VK_LOGIC_OP_OR_INVERTED;
+ default: return VK_LOGIC_OP_NO_OP;
+ }
+ }
+
+
+ bool D3D11BlendState::ValidateBlendFactor(D3D11_BLEND Blend) {
+ return Blend >= D3D11_BLEND_ZERO
+ && Blend <= D3D11_BLEND_INV_SRC1_ALPHA;
+ }
+
+
+ bool D3D11BlendState::ValidateBlendFactorAlpha(D3D11_BLEND BlendAlpha) {
+ return BlendAlpha >= D3D11_BLEND_ZERO
+ && BlendAlpha <= D3D11_BLEND_INV_SRC1_ALPHA
+ && BlendAlpha != D3D11_BLEND_SRC_COLOR
+ && BlendAlpha != D3D11_BLEND_INV_SRC_COLOR
+ && BlendAlpha != D3D11_BLEND_DEST_COLOR
+ && BlendAlpha != D3D11_BLEND_INV_DEST_COLOR
+ && BlendAlpha != D3D11_BLEND_SRC1_COLOR
+ && BlendAlpha != D3D11_BLEND_INV_SRC1_COLOR;
+ }
+
+
+ bool D3D11BlendState::ValidateBlendOp(D3D11_BLEND_OP BlendOp) {
+ return BlendOp >= D3D11_BLEND_OP_ADD
+ && BlendOp <= D3D11_BLEND_OP_MAX;
+ }
+
+
+ bool D3D11BlendState::ValidateLogicOp(D3D11_LOGIC_OP LogicOp) {
+ return LogicOp >= D3D11_LOGIC_OP_CLEAR
+ && LogicOp <= D3D11_LOGIC_OP_OR_INVERTED;
+ }
+
+
+ bool D3D11BlendState::ValidateBlendOperations(
+ D3D11_BLEND SrcBlend,
+ D3D11_BLEND SrcBlendAlpha,
+ D3D11_BLEND DestBlend,
+ D3D11_BLEND DestBlendAlpha,
+ D3D11_BLEND_OP BlendOp,
+ D3D11_BLEND_OP BlendOpAlpha) {
+ return ValidateBlendOp(BlendOp)
+ && ValidateBlendOp(BlendOpAlpha)
+ && ValidateBlendFactor(SrcBlend)
+ && ValidateBlendFactor(DestBlend)
+ && ValidateBlendFactorAlpha(SrcBlendAlpha)
+ && ValidateBlendFactorAlpha(DestBlendAlpha);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h
new file mode 100644
index 00000000..5761d3ca
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_blend.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_blend.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11BlendState : public D3D11StateObject<ID3D11BlendState1> {
+
+ public:
+
+ using DescType = D3D11_BLEND_DESC1;
+
+ D3D11BlendState(
+ D3D11Device* device,
+ const D3D11_BLEND_DESC1& desc);
+ ~D3D11BlendState();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_BLEND_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D11_BLEND_DESC1* pDesc) final;
+
+ void BindToContext(
+ const Rc<DxvkContext>& ctx,
+ UINT sampleMask) const;
+
+ D3D10BlendState* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static D3D11_BLEND_DESC1 PromoteDesc(
+ const D3D11_BLEND_DESC* pSrcDesc);
+
+ static HRESULT NormalizeDesc(
+ D3D11_BLEND_DESC1* pDesc);
+
+ private:
+
+ D3D11_BLEND_DESC1 m_desc;
+
+ std::array<DxvkBlendMode, 8> m_blendModes;
+ DxvkMultisampleState m_msState;
+ DxvkLogicOpState m_loState;
+
+ D3D10BlendState m_d3d10;
+
+ static DxvkBlendMode DecodeBlendMode(
+ const D3D11_RENDER_TARGET_BLEND_DESC1& BlendDesc);
+
+ static VkBlendFactor DecodeBlendFactor(
+ D3D11_BLEND BlendFactor,
+ bool IsAlpha);
+
+ static VkBlendOp DecodeBlendOp(
+ D3D11_BLEND_OP BlendOp);
+
+ static VkLogicOp DecodeLogicOp(
+ D3D11_LOGIC_OP LogicOp);
+
+ static bool ValidateBlendFactor(
+ D3D11_BLEND Blend);
+
+ static bool ValidateBlendFactorAlpha(
+ D3D11_BLEND BlendAlpha);
+
+ static bool ValidateBlendOp(
+ D3D11_BLEND_OP BlendOp);
+
+ static bool ValidateLogicOp(
+ D3D11_LOGIC_OP LogicOp);
+
+ static bool ValidateBlendOperations(
+ D3D11_BLEND SrcBlend,
+ D3D11_BLEND SrcBlendAlpha,
+ D3D11_BLEND SestBlend,
+ D3D11_BLEND DestBlendAlpha,
+ D3D11_BLEND_OP BlendOp,
+ D3D11_BLEND_OP BlendOpAlpha);
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp
new file mode 100644
index 00000000..687be0a5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.cpp
@@ -0,0 +1,287 @@
+#include "d3d11_buffer.h"
+#include "d3d11_context.h"
+#include "d3d11_device.h"
+
+#include "../dxvk/dxvk_data.h"
+
+namespace dxvk {
+
+ D3D11Buffer::D3D11Buffer(
+ D3D11Device* pDevice,
+ const D3D11_BUFFER_DESC* pDesc)
+ : D3D11DeviceChild<ID3D11Buffer>(pDevice),
+ m_desc (*pDesc),
+ m_resource (this),
+ m_d3d10 (this) {
+ DxvkBufferCreateInfo info;
+ info.size = pDesc->ByteWidth;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ if (pDesc->BindFlags & D3D11_BIND_VERTEX_BUFFER) {
+ info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+ }
+
+ if (pDesc->BindFlags & D3D11_BIND_INDEX_BUFFER) {
+ info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ info.access |= VK_ACCESS_INDEX_READ_BIT;
+ }
+
+ if (pDesc->BindFlags & D3D11_BIND_CONSTANT_BUFFER) {
+ info.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ info.stages |= m_parent->GetEnabledShaderStages();
+ info.access |= VK_ACCESS_UNIFORM_READ_BIT;
+
+ if (m_parent->GetOptions()->constantBufferRangeCheck)
+ info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ }
+
+ if (pDesc->BindFlags & D3D11_BIND_SHADER_RESOURCE) {
+ info.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ info.stages |= m_parent->GetEnabledShaderStages();
+ info.access |= VK_ACCESS_SHADER_READ_BIT;
+ }
+
+ if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT) {
+ info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
+ info.stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT;
+ info.access |= VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT;
+ }
+
+ if (pDesc->BindFlags & D3D11_BIND_UNORDERED_ACCESS) {
+ info.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ info.stages |= m_parent->GetEnabledShaderStages();
+ info.access |= VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+
+ if (pDesc->MiscFlags & D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS) {
+ info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ info.access |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ }
+
+ // Create the buffer and set the entire buffer slice as mapped,
+ // so that we only have to update it when invalidating th buffer
+ m_buffer = m_parent->GetDXVKDevice()->createBuffer(info, GetMemoryFlags());
+ m_mapped = m_buffer->getSliceHandle();
+
+ // For Stream Output buffers we need a counter
+ if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT)
+ m_soCounter = CreateSoCounterBuffer();
+ }
+
+
+ D3D11Buffer::~D3D11Buffer() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Buffer::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11Resource)
+ || riid == __uuidof(ID3D11Buffer)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10Resource)
+ || riid == __uuidof(ID3D10Buffer)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGIResource)
+ || riid == __uuidof(IDXGIResource1)) {
+ *ppvObject = ref(&m_resource);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11Buffer::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Buffer::GetEvictionPriority() {
+ return DXGI_RESOURCE_PRIORITY_NORMAL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Buffer::SetEvictionPriority(UINT EvictionPriority) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11Buffer::SetEvictionPriority: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Buffer::GetType(D3D11_RESOURCE_DIMENSION* pResourceDimension) {
+ *pResourceDimension = D3D11_RESOURCE_DIMENSION_BUFFER;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Buffer::GetDesc(D3D11_BUFFER_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ bool D3D11Buffer::CheckViewCompatibility(
+ UINT BindFlags,
+ DXGI_FORMAT Format) const {
+ // Check whether the given bind flags are supported
+ if ((m_desc.BindFlags & BindFlags) != BindFlags)
+ return false;
+
+ // Structured buffer views use no format
+ if (Format == DXGI_FORMAT_UNKNOWN)
+ return (m_desc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) != 0;
+
+ // Check whether the given combination of buffer view
+ // type and view format is supported by the device
+ DXGI_VK_FORMAT_INFO viewFormat = m_parent->LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY);
+ VkFormatFeatureFlags features = GetBufferFormatFeatures(BindFlags);
+
+ return CheckFormatFeatureSupport(viewFormat.Format, features);
+ }
+
+
+ HRESULT D3D11Buffer::NormalizeBufferProperties(D3D11_BUFFER_DESC* pDesc) {
+ // Zero-sized buffers are illegal
+ if (!pDesc->ByteWidth)
+ return E_INVALIDARG;
+
+ // We don't support tiled resources
+ if (pDesc->MiscFlags & (D3D11_RESOURCE_MISC_TILE_POOL | D3D11_RESOURCE_MISC_TILED))
+ return E_INVALIDARG;
+
+ // Constant buffer size must be a multiple of 16
+ if ((pDesc->BindFlags & D3D11_BIND_CONSTANT_BUFFER)
+ && (pDesc->ByteWidth & 0xF))
+ return E_INVALIDARG;
+
+ // Basic validation for structured buffers
+ if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED)
+ && ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS)
+ || (pDesc->StructureByteStride == 0)
+ || (pDesc->StructureByteStride & 0x3)))
+ return E_INVALIDARG;
+
+ // Basic validation for raw buffers
+ if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS)
+ && (!(pDesc->BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS))))
+ return E_INVALIDARG;
+
+ // Mip generation obviously doesn't work for buffers
+ if (pDesc->MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS)
+ return E_INVALIDARG;
+
+ if (!(pDesc->MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED))
+ pDesc->StructureByteStride = 0;
+
+ return S_OK;
+ }
+
+
+ BOOL D3D11Buffer::CheckFormatFeatureSupport(
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const {
+ VkFormatProperties properties = m_parent->GetDXVKDevice()->adapter()->formatProperties(Format);
+ return (properties.bufferFeatures & Features) == Features;
+ }
+
+
+ VkMemoryPropertyFlags D3D11Buffer::GetMemoryFlags() const {
+ VkMemoryPropertyFlags memoryFlags = 0;
+
+ switch (m_desc.Usage) {
+ case D3D11_USAGE_IMMUTABLE:
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ break;
+
+ case D3D11_USAGE_DEFAULT:
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ if ((m_desc.BindFlags & D3D11_BIND_CONSTANT_BUFFER) || m_desc.CPUAccessFlags) {
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ }
+
+ if (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) {
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ memoryFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ }
+ break;
+
+ case D3D11_USAGE_DYNAMIC:
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ if (m_desc.BindFlags)
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ break;
+
+ case D3D11_USAGE_STAGING:
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ break;
+ }
+
+ if (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && m_parent->GetOptions()->apitraceMode) {
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ }
+
+ return memoryFlags;
+ }
+
+
+ Rc<DxvkBuffer> D3D11Buffer::CreateSoCounterBuffer() {
+ Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
+
+ DxvkBufferCreateInfo info;
+ info.size = sizeof(D3D11SOCounter);
+ info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
+ | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
+ | VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_INDIRECT_COMMAND_READ_BIT
+ | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
+ | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
+ return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ D3D11Buffer* GetCommonBuffer(ID3D11Resource* pResource) {
+ D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&dimension);
+
+ return dimension == D3D11_RESOURCE_DIMENSION_BUFFER
+ ? static_cast<D3D11Buffer*>(pResource)
+ : nullptr;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h
new file mode 100644
index 00000000..3ddd61a0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_buffer.h
@@ -0,0 +1,162 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_buffer.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_interfaces.h"
+#include "d3d11_resource.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11DeviceContext;
+
+
+ /**
+ * \brief Buffer map mode
+ */
+ enum D3D11_COMMON_BUFFER_MAP_MODE {
+ D3D11_COMMON_BUFFER_MAP_MODE_NONE,
+ D3D11_COMMON_BUFFER_MAP_MODE_DIRECT,
+ };
+
+
+ /**
+ * \brief Stream output buffer offset
+ *
+ * A byte offset into the buffer that
+ * stores the byte offset where new
+ * data will be written to.
+ */
+ struct D3D11SOCounter {
+ uint32_t byteOffset;
+ };
+
+
+ class D3D11Buffer : public D3D11DeviceChild<ID3D11Buffer> {
+ static constexpr VkDeviceSize BufferSliceAlignment = 64;
+ public:
+
+ D3D11Buffer(
+ D3D11Device* pDevice,
+ const D3D11_BUFFER_DESC* pDesc);
+ ~D3D11Buffer();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetType(
+ D3D11_RESOURCE_DIMENSION *pResourceDimension) final;
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority() final;
+
+ void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_BUFFER_DESC *pDesc) final;
+
+ bool CheckViewCompatibility(
+ UINT BindFlags,
+ DXGI_FORMAT Format) const;
+
+ const D3D11_BUFFER_DESC* Desc() const {
+ return &m_desc;
+ }
+
+ D3D11_COMMON_BUFFER_MAP_MODE GetMapMode() const {
+ return (m_buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ ? D3D11_COMMON_BUFFER_MAP_MODE_DIRECT
+ : D3D11_COMMON_BUFFER_MAP_MODE_NONE;
+ }
+
+ Rc<DxvkBuffer> GetBuffer() const {
+ return m_buffer;
+ }
+
+ DxvkBufferSlice GetBufferSlice() const {
+ return DxvkBufferSlice(m_buffer, 0, m_desc.ByteWidth);
+ }
+
+ DxvkBufferSlice GetBufferSlice(VkDeviceSize offset) const {
+ VkDeviceSize size = m_desc.ByteWidth;
+
+ return likely(offset < size)
+ ? DxvkBufferSlice(m_buffer, offset, size - offset)
+ : DxvkBufferSlice();
+ }
+
+ DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const {
+ VkDeviceSize size = m_desc.ByteWidth;
+
+ return likely(offset < size)
+ ? DxvkBufferSlice(m_buffer, offset, std::min(length, size - offset))
+ : DxvkBufferSlice();
+ }
+
+ DxvkBufferSlice GetSOCounter() {
+ return m_soCounter != nullptr
+ ? DxvkBufferSlice(m_soCounter)
+ : DxvkBufferSlice();
+ }
+
+ DxvkBufferSliceHandle AllocSlice() {
+ return m_buffer->allocSlice();
+ }
+
+ DxvkBufferSliceHandle DiscardSlice() {
+ m_mapped = m_buffer->allocSlice();
+ return m_mapped;
+ }
+
+ DxvkBufferSliceHandle GetMappedSlice() const {
+ return m_mapped;
+ }
+
+ D3D10Buffer* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ /**
+ * \brief Normalizes buffer description
+ *
+ * \param [in] pDesc Buffer description
+ * \returns \c S_OK if the parameters are valid
+ */
+ static HRESULT NormalizeBufferProperties(
+ D3D11_BUFFER_DESC* pDesc);
+
+ private:
+
+ const D3D11_BUFFER_DESC m_desc;
+
+ Rc<DxvkBuffer> m_buffer;
+ Rc<DxvkBuffer> m_soCounter;
+ DxvkBufferSliceHandle m_mapped;
+
+ D3D11DXGIResource m_resource;
+ D3D10Buffer m_d3d10;
+
+ BOOL CheckFormatFeatureSupport(
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const;
+
+ VkMemoryPropertyFlags GetMemoryFlags() const;
+
+ Rc<DxvkBuffer> CreateSoCounterBuffer();
+
+ };
+
+
+ /**
+ * \brief Retrieves buffer from resource pointer
+ *
+ * \param [in] pResource The resource to query
+ * \returns Pointer to buffer, or \c nullptr
+ */
+ D3D11Buffer* GetCommonBuffer(
+ ID3D11Resource* pResource);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp
new file mode 100644
index 00000000..8070b660
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.cpp
@@ -0,0 +1,59 @@
+#include "d3d11_class_linkage.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11ClassLinkage::D3D11ClassLinkage(
+ D3D11Device* pDevice)
+ : D3D11DeviceChild<ID3D11ClassLinkage>(pDevice) {
+
+ }
+
+
+ D3D11ClassLinkage::~D3D11ClassLinkage() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11ClassLinkage)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11ClassLinkage::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::CreateClassInstance(
+ LPCSTR pClassTypeName,
+ UINT ConstantBufferOffset,
+ UINT ConstantVectorOffset,
+ UINT TextureOffset,
+ UINT SamplerOffset,
+ ID3D11ClassInstance **ppInstance) {
+ InitReturnPtr(ppInstance);
+
+ Logger::err("D3D11ClassLinkage::CreateClassInstance: Not implemented yet");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ClassLinkage::GetClassInstance(
+ LPCSTR pClassInstanceName,
+ UINT InstanceIndex,
+ ID3D11ClassInstance **ppInstance) {
+ Logger::err("D3D11ClassLinkage::GetClassInstance: Not implemented yet");
+ return E_NOTIMPL;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h
new file mode 100644
index 00000000..7d1c324c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_class_linkage.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "d3d11_device_child.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ // TODO implement properly
+ class D3D11ClassLinkage : public D3D11DeviceChild<ID3D11ClassLinkage> {
+
+ public:
+
+ D3D11ClassLinkage(
+ D3D11Device* pDevice);
+
+ ~D3D11ClassLinkage();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE CreateClassInstance(
+ LPCSTR pClassTypeName,
+ UINT ConstantBufferOffset,
+ UINT ConstantVectorOffset,
+ UINT TextureOffset,
+ UINT SamplerOffset,
+ ID3D11ClassInstance **ppInstance);
+
+ HRESULT STDMETHODCALLTYPE GetClassInstance(
+ LPCSTR pClassInstanceName,
+ UINT InstanceIndex,
+ ID3D11ClassInstance **ppInstance);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h
new file mode 100644
index 00000000..52f2f4db
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmd.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief D3D11 command type
+ *
+ * Used to identify the type of command
+ * data most recently added to a CS chunk.
+ */
+ enum class D3D11CmdType {
+ DrawIndirect,
+ DrawIndirectIndexed,
+ };
+
+
+ /**
+ * \brief Command data header
+ *
+ * Stores the command type. All command
+ * data structs must inherit this struct.
+ */
+ struct D3D11CmdData {
+ D3D11CmdType type;
+ };
+
+
+ /**
+ * \brief Indirect draw command data
+ *
+ * Stores the offset into the draw buffer for
+ * the first draw, as well as the number of
+ * draws to execute.
+ */
+ struct D3D11CmdDrawIndirectData : public D3D11CmdData {
+ uint32_t offset;
+ uint32_t count;
+ uint32_t stride;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp
new file mode 100644
index 00000000..0ce56211
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.cpp
@@ -0,0 +1,85 @@
+#include "d3d11_cmdlist.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11CommandList::D3D11CommandList(
+ D3D11Device* pDevice,
+ UINT ContextFlags)
+ : D3D11DeviceChild<ID3D11CommandList>(pDevice),
+ m_contextFlags(ContextFlags) { }
+
+
+ D3D11CommandList::~D3D11CommandList() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11CommandList::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11CommandList)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11CommandList::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11CommandList::GetContextFlags() {
+ return m_contextFlags;
+ }
+
+
+ void D3D11CommandList::AddChunk(DxvkCsChunkRef&& Chunk) {
+ m_chunks.push_back(std::move(Chunk));
+ }
+
+
+ void D3D11CommandList::AddQuery(D3D11Query* pQuery) {
+ m_queries.emplace_back(pQuery);
+ }
+
+
+ void D3D11CommandList::EmitToCommandList(ID3D11CommandList* pCommandList) {
+ auto cmdList = static_cast<D3D11CommandList*>(pCommandList);
+
+ for (const auto& chunk : m_chunks)
+ cmdList->m_chunks.push_back(chunk);
+
+ for (const auto& query : m_queries)
+ cmdList->m_queries.push_back(query);
+
+ MarkSubmitted();
+ }
+
+
+ void D3D11CommandList::EmitToCsThread(DxvkCsThread* CsThread) {
+ for (const auto& query : m_queries)
+ query->DoDeferredEnd();
+
+ for (const auto& chunk : m_chunks)
+ CsThread->dispatchChunk(DxvkCsChunkRef(chunk));
+
+ MarkSubmitted();
+ }
+
+
+ void D3D11CommandList::MarkSubmitted() {
+ if (m_submitted.exchange(true) && !m_warned.exchange(true)
+ && m_parent->GetOptions()->dcSingleUseMode) {
+ Logger::warn(
+ "D3D11: Command list submitted multiple times,\n"
+ " but d3d11.dcSingleUseMode is enabled");
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h
new file mode 100644
index 00000000..ce207aaf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cmdlist.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "d3d11_context.h"
+
+namespace dxvk {
+
+ class D3D11CommandList : public D3D11DeviceChild<ID3D11CommandList> {
+
+ public:
+
+ D3D11CommandList(
+ D3D11Device* pDevice,
+ UINT ContextFlags);
+
+ ~D3D11CommandList();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ UINT STDMETHODCALLTYPE GetContextFlags() final;
+
+ void AddChunk(
+ DxvkCsChunkRef&& Chunk);
+
+ void AddQuery(
+ D3D11Query* pQuery);
+
+ void EmitToCommandList(
+ ID3D11CommandList* pCommandList);
+
+ void EmitToCsThread(
+ DxvkCsThread* CsThread);
+
+ private:
+
+ UINT const m_contextFlags;
+
+ std::vector<DxvkCsChunkRef> m_chunks;
+ std::vector<Com<D3D11Query, false>> m_queries;
+
+ std::atomic<bool> m_submitted = { false };
+ std::atomic<bool> m_warned = { false };
+
+ void MarkSubmitted();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp
new file mode 100644
index 00000000..45af2f7b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.cpp
@@ -0,0 +1,4507 @@
+#include <cstring>
+
+#include "d3d11_context.h"
+#include "d3d11_device.h"
+#include "d3d11_query.h"
+#include "d3d11_texture.h"
+#include "d3d11_video.h"
+
+#include "../dxbc/dxbc_util.h"
+
+namespace dxvk {
+
+ D3D11DeviceContext::D3D11DeviceContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device,
+ DxvkCsChunkFlags CsFlags)
+ : D3D11DeviceChild<ID3D11DeviceContext4>(pParent),
+ m_contextExt(this),
+ m_annotation(this),
+ m_multithread(this, false),
+ m_device (Device),
+ m_csFlags (CsFlags),
+ m_csChunk (AllocCsChunk()),
+ m_cmdData (nullptr) {
+
+ }
+
+
+ D3D11DeviceContext::~D3D11DeviceContext() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11DeviceContext)
+ || riid == __uuidof(ID3D11DeviceContext1)
+ || riid == __uuidof(ID3D11DeviceContext2)
+ || riid == __uuidof(ID3D11DeviceContext3)
+ || riid == __uuidof(ID3D11DeviceContext4)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D11VkExtContext)
+ || riid == __uuidof(ID3D11VkExtContext1)) {
+ *ppvObject = ref(&m_contextExt);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3DUserDefinedAnnotation)) {
+ *ppvObject = ref(&m_annotation);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10Multithread)) {
+ *ppvObject = ref(&m_multithread);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11DeviceContext::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardResource(ID3D11Resource* pResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pResource)
+ return;
+
+ // We don't support the Discard API for images
+ D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resType);
+
+ if (resType == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ DiscardBuffer(pResource);
+ } else {
+ auto texture = GetCommonTexture(pResource);
+
+ for (uint32_t i = 0; i < texture->CountSubresources(); i++)
+ DiscardTexture(pResource, i);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView(ID3D11View* pResourceView) {
+ DiscardView1(pResourceView, nullptr, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DiscardView1(
+ ID3D11View* pResourceView,
+ const D3D11_RECT* pRects,
+ UINT NumRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ // We don't support discarding individual rectangles
+ if (!pResourceView || (NumRects && pRects))
+ return;
+
+ // ID3D11View has no methods to query the exact type of
+ // the view, so we'll have to check each possible class
+ auto dsv = dynamic_cast<D3D11DepthStencilView*>(pResourceView);
+ auto rtv = dynamic_cast<D3D11RenderTargetView*>(pResourceView);
+ auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pResourceView);
+
+ Rc<DxvkImageView> view;
+ if (dsv) view = dsv->GetImageView();
+ if (rtv) view = rtv->GetImageView();
+ if (uav) view = uav->GetImageView();
+
+ if (view == nullptr)
+ return;
+
+ // Get information about underlying resource
+ Com<ID3D11Resource> resource;
+ pResourceView->GetResource(&resource);
+
+ uint32_t mipCount = GetCommonTexture(resource.ptr())->Desc()->MipLevels;
+
+ // Discard mip levels one by one
+ VkImageSubresourceRange sr = view->subresources();
+
+ for (uint32_t layer = 0; layer < sr.layerCount; layer++) {
+ for (uint32_t mip = 0; mip < sr.levelCount; mip++) {
+ DiscardTexture(resource.ptr(), D3D11CalcSubresource(
+ sr.baseMipLevel + mip, sr.baseArrayLayer + layer, mipCount));
+ }
+ }
+
+ // Since we don't handle SRVs here, we can assume that the
+ // view covers all aspects of the underlying resource.
+ EmitCs([cView = view] (DxvkContext* ctx) {
+ ctx->discardImageView(cView, cView->formatInfo()->aspectMask);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearState() {
+ D3D10DeviceLock lock = LockContext();
+
+ // Default shaders
+ m_state.vs.shader = nullptr;
+ m_state.hs.shader = nullptr;
+ m_state.ds.shader = nullptr;
+ m_state.gs.shader = nullptr;
+ m_state.ps.shader = nullptr;
+ m_state.cs.shader = nullptr;
+
+ // Default constant buffers
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) {
+ m_state.vs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.hs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.ds.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.gs.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.ps.constantBuffers[i] = { nullptr, 0, 0 };
+ m_state.cs.constantBuffers[i] = { nullptr, 0, 0 };
+ }
+
+ // Default samplers
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; i++) {
+ m_state.vs.samplers[i] = nullptr;
+ m_state.hs.samplers[i] = nullptr;
+ m_state.ds.samplers[i] = nullptr;
+ m_state.gs.samplers[i] = nullptr;
+ m_state.ps.samplers[i] = nullptr;
+ m_state.cs.samplers[i] = nullptr;
+ }
+
+ // Default shader resources
+ for (uint32_t i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ m_state.vs.shaderResources.views[i] = nullptr;
+ m_state.hs.shaderResources.views[i] = nullptr;
+ m_state.ds.shaderResources.views[i] = nullptr;
+ m_state.gs.shaderResources.views[i] = nullptr;
+ m_state.ps.shaderResources.views[i] = nullptr;
+ m_state.cs.shaderResources.views[i] = nullptr;
+ }
+
+ m_state.vs.shaderResources.hazardous.clear();
+ m_state.hs.shaderResources.hazardous.clear();
+ m_state.ds.shaderResources.hazardous.clear();
+ m_state.gs.shaderResources.hazardous.clear();
+ m_state.ps.shaderResources.hazardous.clear();
+ m_state.cs.shaderResources.hazardous.clear();
+
+ // Default UAVs
+ for (uint32_t i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++) {
+ m_state.ps.unorderedAccessViews[i] = nullptr;
+ m_state.cs.unorderedAccessViews[i] = nullptr;
+ }
+
+ m_state.cs.uavMask.clear();
+
+ // Default ID state
+ m_state.id.argBuffer = nullptr;
+
+ // Default IA state
+ m_state.ia.inputLayout = nullptr;
+ m_state.ia.primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+
+ for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++) {
+ m_state.ia.vertexBuffers[i].buffer = nullptr;
+ m_state.ia.vertexBuffers[i].offset = 0;
+ m_state.ia.vertexBuffers[i].stride = 0;
+ }
+
+ m_state.ia.indexBuffer.buffer = nullptr;
+ m_state.ia.indexBuffer.offset = 0;
+ m_state.ia.indexBuffer.format = DXGI_FORMAT_UNKNOWN;
+
+ // Default OM State
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ m_state.om.renderTargetViews[i] = nullptr;
+ m_state.om.depthStencilView = nullptr;
+
+ m_state.om.cbState = nullptr;
+ m_state.om.dsState = nullptr;
+
+ for (uint32_t i = 0; i < 4; i++)
+ m_state.om.blendFactor[i] = 1.0f;
+
+ m_state.om.sampleMask = D3D11_DEFAULT_SAMPLE_MASK;
+ m_state.om.stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE;
+
+ m_state.om.maxRtv = 0;
+ m_state.om.maxUav = 0;
+
+ // Default RS state
+ m_state.rs.state = nullptr;
+ m_state.rs.numViewports = 0;
+ m_state.rs.numScissors = 0;
+
+ for (uint32_t i = 0; i < D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; i++) {
+ m_state.rs.viewports[i] = D3D11_VIEWPORT { };
+ m_state.rs.scissors [i] = D3D11_RECT { };
+ }
+
+ // Default SO state
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ m_state.so.targets[i].buffer = nullptr;
+ m_state.so.targets[i].offset = 0;
+ }
+
+ // Default predication
+ m_state.pr.predicateObject = nullptr;
+ m_state.pr.predicateValue = FALSE;
+
+ // Make sure to apply all state
+ ResetState();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetPredication(
+ ID3D11Predicate* pPredicate,
+ BOOL PredicateValue) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto predicate = D3D11Query::FromPredicate(pPredicate);
+ m_state.pr.predicateObject = predicate;
+ m_state.pr.predicateValue = PredicateValue;
+
+ static bool s_errorShown = false;
+
+ if (pPredicate && !std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetPredication: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GetPredication(
+ ID3D11Predicate** ppPredicate,
+ BOOL* pPredicateValue) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppPredicate)
+ *ppPredicate = D3D11Query::AsPredicate(m_state.pr.predicateObject.ref());
+
+ if (pPredicateValue)
+ *pPredicateValue = m_state.pr.predicateValue;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox) {
+ CopySubresourceRegion1(
+ pDstResource, DstSubresource, DstX, DstY, DstZ,
+ pSrcResource, SrcSubresource, pSrcBox, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopySubresourceRegion1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox,
+ UINT CopyFlags) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource || !pSrcResource)
+ return;
+
+ if (pSrcBox
+ && (pSrcBox->left >= pSrcBox->right
+ || pSrcBox->top >= pSrcBox->bottom
+ || pSrcBox->front >= pSrcBox->back))
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+
+ pDstResource->GetType(&dstResourceDim);
+ pSrcResource->GetType(&srcResourceDim);
+
+ if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource);
+ auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource);
+
+ VkDeviceSize dstOffset = DstX;
+ VkDeviceSize srcOffset = 0;
+ VkDeviceSize byteCount = -1;
+
+ if (pSrcBox) {
+ srcOffset = pSrcBox->left;
+ byteCount = pSrcBox->right - pSrcBox->left;
+ }
+
+ CopyBuffer(dstBuffer, dstOffset, srcBuffer, srcOffset, byteCount);
+ } else if (dstResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER && srcResourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstTexture = GetCommonTexture(pDstResource);
+ auto srcTexture = GetCommonTexture(pSrcResource);
+
+ if (DstSubresource >= dstTexture->CountSubresources()
+ || SrcSubresource >= srcTexture->CountSubresources())
+ return;
+
+ auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat());
+
+ auto dstLayers = vk::makeSubresourceLayers(dstTexture->GetSubresourceFromIndex(dstFormatInfo->aspectMask, DstSubresource));
+ auto srcLayers = vk::makeSubresourceLayers(srcTexture->GetSubresourceFromIndex(srcFormatInfo->aspectMask, SrcSubresource));
+
+ VkOffset3D srcOffset = { 0, 0, 0 };
+ VkOffset3D dstOffset = { int32_t(DstX), int32_t(DstY), int32_t(DstZ) };
+
+ VkExtent3D srcExtent = srcTexture->MipLevelExtent(srcLayers.mipLevel);
+
+ if (pSrcBox != nullptr) {
+ srcOffset.x = pSrcBox->left;
+ srcOffset.y = pSrcBox->top;
+ srcOffset.z = pSrcBox->front;
+
+ srcExtent.width = pSrcBox->right - pSrcBox->left;
+ srcExtent.height = pSrcBox->bottom - pSrcBox->top;
+ srcExtent.depth = pSrcBox->back - pSrcBox->front;
+ }
+
+ CopyImage(
+ dstTexture, &dstLayers, dstOffset,
+ srcTexture, &srcLayers, srcOffset,
+ srcExtent);
+ } else {
+ Logger::err(str::format(
+ "D3D11: CopySubresourceRegion1: Incompatible resources",
+ "\n Dst resource type: ", dstResourceDim,
+ "\n Src resource type: ", srcResourceDim));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyResource(
+ ID3D11Resource* pDstResource,
+ ID3D11Resource* pSrcResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource || !pSrcResource || (pDstResource == pSrcResource))
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ D3D11_RESOURCE_DIMENSION srcResourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+
+ pDstResource->GetType(&dstResourceDim);
+ pSrcResource->GetType(&srcResourceDim);
+
+ if (dstResourceDim != srcResourceDim) {
+ Logger::err(str::format(
+ "D3D11: CopyResource: Incompatible resources",
+ "\n Dst resource type: ", dstResourceDim,
+ "\n Src resource type: ", srcResourceDim));
+ return;
+ }
+
+ if (dstResourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto dstBuffer = static_cast<D3D11Buffer*>(pDstResource);
+ auto srcBuffer = static_cast<D3D11Buffer*>(pSrcResource);
+
+ if (dstBuffer->Desc()->ByteWidth != srcBuffer->Desc()->ByteWidth)
+ return;
+
+ CopyBuffer(dstBuffer, 0, srcBuffer, 0, -1);
+ } else {
+ auto dstTexture = GetCommonTexture(pDstResource);
+ auto srcTexture = GetCommonTexture(pSrcResource);
+
+ auto dstDesc = dstTexture->Desc();
+ auto srcDesc = srcTexture->Desc();
+
+ // The subresource count must match as well
+ if (dstDesc->ArraySize != srcDesc->ArraySize
+ || dstDesc->MipLevels != srcDesc->MipLevels) {
+ Logger::err("D3D11: CopyResource: Incompatible images");
+ return;
+ }
+
+ auto dstFormatInfo = imageFormatInfo(dstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(srcTexture->GetPackedFormat());
+
+ for (uint32_t i = 0; i < dstDesc->MipLevels; i++) {
+ VkImageSubresourceLayers dstLayers = { dstFormatInfo->aspectMask, i, 0, dstDesc->ArraySize };
+ VkImageSubresourceLayers srcLayers = { srcFormatInfo->aspectMask, i, 0, srcDesc->ArraySize };
+
+ CopyImage(
+ dstTexture, &dstLayers, VkOffset3D(),
+ srcTexture, &srcLayers, VkOffset3D(),
+ srcTexture->MipLevelExtent(i));
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyStructureCount(
+ ID3D11Buffer* pDstBuffer,
+ UINT DstAlignedByteOffset,
+ ID3D11UnorderedAccessView* pSrcView) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto buf = static_cast<D3D11Buffer*>(pDstBuffer);
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pSrcView);
+
+ if (!buf || !uav)
+ return;
+
+ auto counterSlice = uav->GetCounterSlice();
+ if (!counterSlice.defined())
+ return;
+
+ EmitCs([
+ cDstSlice = buf->GetBufferSlice(DstAlignedByteOffset),
+ cSrcSlice = std::move(counterSlice)
+ ] (DxvkContext* ctx) {
+ ctx->copyBuffer(
+ cDstSlice.buffer(),
+ cDstSlice.offset(),
+ cSrcSlice.buffer(),
+ cSrcSlice.offset(),
+ sizeof(uint32_t));
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CopyTiles(
+ ID3D11Resource* pTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ ID3D11Buffer* pBuffer,
+ UINT64 BufferStartOffsetInBytes,
+ UINT Flags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::CopyTiles: Not implemented");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::CopyTileMappings(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestRegionStartCoordinate,
+ ID3D11Resource* pSourceTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pSourceRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ UINT Flags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::CopyTileMappings: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::ResizeTilePool(
+ ID3D11Buffer* pTilePool,
+ UINT64 NewSizeInBytes) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::ResizeTilePool: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::TiledResourceBarrier(
+ ID3D11DeviceChild* pTiledResourceOrViewAccessBeforeBarrier,
+ ID3D11DeviceChild* pTiledResourceOrViewAccessAfterBarrier) {
+
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearRenderTargetView(
+ ID3D11RenderTargetView* pRenderTargetView,
+ const FLOAT ColorRGBA[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto rtv = static_cast<D3D11RenderTargetView*>(pRenderTargetView);
+
+ if (!rtv)
+ return;
+
+ auto view = rtv->GetImageView();
+ auto color = ConvertColorValue(ColorRGBA, view->formatInfo());
+
+ EmitCs([
+ cClearValue = color,
+ cImageView = std::move(view)
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewUint(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const UINT Values[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
+
+ if (!uav)
+ return;
+
+ // Gather UAV format info. We'll use this to determine
+ // whether we need to create a temporary view or not.
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
+ uav->GetDesc(&uavDesc);
+
+ VkFormat uavFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_ANY).Format;
+ VkFormat rawFormat = m_parent->LookupFormat(uavDesc.Format, DXGI_VK_FORMAT_MODE_RAW).Format;
+
+ if (uavFormat != rawFormat && rawFormat == VK_FORMAT_UNDEFINED) {
+ Logger::err(str::format("D3D11: ClearUnorderedAccessViewUint: No raw format found for ", uavFormat));
+ return;
+ }
+
+ // Set up clear color struct
+ VkClearValue clearValue;
+ clearValue.color.uint32[0] = Values[0];
+ clearValue.color.uint32[1] = Values[1];
+ clearValue.color.uint32[2] = Values[2];
+ clearValue.color.uint32[3] = Values[3];
+
+ // This is the only packed format that has UAV support
+ if (uavFormat == VK_FORMAT_B10G11R11_UFLOAT_PACK32) {
+ clearValue.color.uint32[0] = ((Values[0] & 0x7FF) << 0)
+ | ((Values[1] & 0x7FF) << 11)
+ | ((Values[2] & 0x3FF) << 22);
+ }
+
+ if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ // In case of raw and structured buffers as well as typed
+ // buffers that can be used for atomic operations, we can
+ // use the fast Vulkan buffer clear function.
+ Rc<DxvkBufferView> bufferView = uav->GetBufferView();
+
+ if (bufferView->info().format == VK_FORMAT_R32_UINT
+ || bufferView->info().format == VK_FORMAT_R32_SINT
+ || bufferView->info().format == VK_FORMAT_R32_SFLOAT) {
+ EmitCs([
+ cClearValue = Values[0],
+ cDstSlice = bufferView->slice()
+ ] (DxvkContext* ctx) {
+ ctx->clearBuffer(
+ cDstSlice.buffer(),
+ cDstSlice.offset(),
+ cDstSlice.length(),
+ cClearValue);
+ });
+ } else {
+ // Create a view with an integer format if necessary
+ if (uavFormat != rawFormat) {
+ DxvkBufferViewCreateInfo info = bufferView->info();
+ info.format = rawFormat;
+
+ bufferView = m_device->createBufferView(
+ bufferView->buffer(), info);
+ }
+
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = bufferView
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cDstView, 0,
+ cDstView->elementCount(),
+ cClearValue.color);
+ });
+ }
+ } else {
+ // Create a view with an integer format if necessary
+ Rc<DxvkImageView> imageView = uav->GetImageView();
+
+ if (uavFormat != rawFormat) {
+ DxvkImageViewCreateInfo info = imageView->info();
+ info.format = rawFormat;
+
+ imageView = m_device->createImageView(
+ imageView->image(), info);
+ }
+
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = imageView
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(cDstView,
+ VkOffset3D { 0, 0, 0 },
+ cDstView->mipLevelExtent(0),
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearUnorderedAccessViewFloat(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const FLOAT Values[4]) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto uav = static_cast<D3D11UnorderedAccessView*>(pUnorderedAccessView);
+
+ if (!uav)
+ return;
+
+ auto imgView = uav->GetImageView();
+ auto bufView = uav->GetBufferView();
+
+ const DxvkFormatInfo* info = nullptr;
+ if (imgView != nullptr) info = imgView->formatInfo();
+ if (bufView != nullptr) info = bufView->formatInfo();
+
+ if (!info || info->flags.any(DxvkFormatFlag::SampledSInt, DxvkFormatFlag::SampledUInt))
+ return;
+
+ VkClearValue clearValue;
+ clearValue.color.float32[0] = Values[0];
+ clearValue.color.float32[1] = Values[1];
+ clearValue.color.float32[2] = Values[2];
+ clearValue.color.float32[3] = Values[3];
+
+ if (uav->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = std::move(bufView)
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cDstView, 0,
+ cDstView->elementCount(),
+ cClearValue.color);
+ });
+ } else {
+ EmitCs([
+ cClearValue = clearValue,
+ cDstView = std::move(imgView)
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(cDstView,
+ VkOffset3D { 0, 0, 0 },
+ cDstView->mipLevelExtent(0),
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearDepthStencilView(
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT ClearFlags,
+ FLOAT Depth,
+ UINT8 Stencil) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
+
+ if (!dsv)
+ return;
+
+ // Figure out which aspects to clear based on
+ // the image view properties and clear flags.
+ VkImageAspectFlags aspectMask = 0;
+
+ if (ClearFlags & D3D11_CLEAR_DEPTH)
+ aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ if (ClearFlags & D3D11_CLEAR_STENCIL)
+ aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ aspectMask &= dsv->GetWritableAspectMask();
+
+ if (!aspectMask)
+ return;
+
+ VkClearValue clearValue;
+ clearValue.depthStencil.depth = Depth;
+ clearValue.depthStencil.stencil = Stencil;
+
+ EmitCs([
+ cClearValue = clearValue,
+ cAspectMask = aspectMask,
+ cImageView = dsv->GetImageView()
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ cAspectMask,
+ cClearValue);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ClearView(
+ ID3D11View* pView,
+ const FLOAT Color[4],
+ const D3D11_RECT* pRect,
+ UINT NumRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (NumRects && !pRect)
+ return;
+
+ // ID3D11View has no methods to query the exact type of
+ // the view, so we'll have to check each possible class
+ auto dsv = dynamic_cast<D3D11DepthStencilView*>(pView);
+ auto rtv = dynamic_cast<D3D11RenderTargetView*>(pView);
+ auto uav = dynamic_cast<D3D11UnorderedAccessView*>(pView);
+ auto vov = dynamic_cast<D3D11VideoProcessorOutputView*>(pView);
+
+ // Retrieve underlying resource view
+ Rc<DxvkBufferView> bufView;
+ Rc<DxvkImageView> imgView;
+
+ if (dsv != nullptr)
+ imgView = dsv->GetImageView();
+
+ if (rtv != nullptr)
+ imgView = rtv->GetImageView();
+
+ if (uav != nullptr) {
+ bufView = uav->GetBufferView();
+ imgView = uav->GetImageView();
+ }
+
+ if (vov != nullptr)
+ imgView = vov->GetView();
+
+ // 3D views are unsupported
+ if (imgView != nullptr
+ && imgView->info().type == VK_IMAGE_VIEW_TYPE_3D)
+ return;
+
+ // Query the view format. We'll have to convert
+ // the clear color based on the format's data type.
+ VkFormat format = VK_FORMAT_UNDEFINED;
+
+ if (bufView != nullptr)
+ format = bufView->info().format;
+
+ if (imgView != nullptr)
+ format = imgView->info().format;
+
+ if (format == VK_FORMAT_UNDEFINED)
+ return;
+
+ // We'll need the format info to determine the buffer
+ // element size, and we also need it for depth images.
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(format);
+
+ // Convert the clear color format. ClearView takes
+ // the clear value for integer formats as a set of
+ // integral floats, so we'll have to convert.
+ VkClearValue clearValue = ConvertColorValue(Color, formatInfo);
+ VkImageAspectFlags clearAspect = formatInfo->aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT);
+
+ // Clear all the rectangles that are specified
+ for (uint32_t i = 0; i < NumRects || i < 1; i++) {
+ if (pRect) {
+ if (pRect[i].left >= pRect[i].right
+ || pRect[i].top >= pRect[i].bottom)
+ continue;
+ }
+
+ if (bufView != nullptr) {
+ VkDeviceSize offset = 0;
+ VkDeviceSize length = bufView->info().rangeLength / formatInfo->elementSize;
+
+ if (pRect) {
+ offset = pRect[i].left;
+ length = pRect[i].right - pRect[i].left;
+ }
+
+ EmitCs([
+ cBufferView = bufView,
+ cRangeOffset = offset,
+ cRangeLength = length,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ ctx->clearBufferView(
+ cBufferView,
+ cRangeOffset,
+ cRangeLength,
+ cClearValue.color);
+ });
+ }
+
+ if (imgView != nullptr) {
+ VkOffset3D offset = { 0, 0, 0 };
+ VkExtent3D extent = imgView->mipLevelExtent(0);
+
+ if (pRect) {
+ offset = { pRect[i].left, pRect[i].top, 0 };
+ extent = {
+ uint32_t(pRect[i].right - pRect[i].left),
+ uint32_t(pRect[i].bottom - pRect[i].top), 1 };
+ }
+
+ EmitCs([
+ cImageView = imgView,
+ cAreaOffset = offset,
+ cAreaExtent = extent,
+ cClearAspect = clearAspect,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ const VkImageUsageFlags rtUsage =
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ bool isFullSize = cImageView->mipLevelExtent(0) == cAreaExtent;
+
+ if ((cImageView->info().usage & rtUsage) && isFullSize) {
+ ctx->clearRenderTarget(
+ cImageView,
+ cClearAspect,
+ cClearValue);
+ } else {
+ ctx->clearImageView(
+ cImageView,
+ cAreaOffset,
+ cAreaExtent,
+ cClearAspect,
+ cClearValue);
+ }
+ });
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto view = static_cast<D3D11ShaderResourceView*>(pShaderResourceView);
+
+ if (!view || view->GetResourceType() == D3D11_RESOURCE_DIMENSION_BUFFER)
+ return;
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc = view->GetResourceDesc();
+
+ if (!(resourceDesc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS))
+ return;
+
+ EmitCs([cDstImageView = view->GetImageView()]
+ (DxvkContext* ctx) {
+ ctx->generateMipmaps(cDstImageView, VK_FILTER_LINEAR);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch) {
+ UpdateSubresource1(pDstResource,
+ DstSubresource, pDstBox, pSrcData,
+ SrcRowPitch, SrcDepthPitch, 0);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateSubresource1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch,
+ UINT CopyFlags) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (!pDstResource)
+ return;
+
+ // Filter out invalid copy flags
+ CopyFlags &= D3D11_COPY_NO_OVERWRITE | D3D11_COPY_DISCARD;
+
+ // We need a different code path for buffers
+ D3D11_RESOURCE_DIMENSION resourceType;
+ pDstResource->GetType(&resourceType);
+
+ if (resourceType == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ const auto bufferResource = static_cast<D3D11Buffer*>(pDstResource);
+ const auto bufferSlice = bufferResource->GetBufferSlice();
+
+ VkDeviceSize offset = bufferSlice.offset();
+ VkDeviceSize size = bufferSlice.length();
+
+ if (pDstBox != nullptr) {
+ offset = pDstBox->left;
+ size = pDstBox->right - pDstBox->left;
+ }
+
+ if (!size || offset + size > bufferSlice.length())
+ return;
+
+ bool useMap = (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ && (size == bufferSlice.length() || CopyFlags);
+
+ if (useMap) {
+ D3D11_MAP mapType = (CopyFlags & D3D11_COPY_NO_OVERWRITE)
+ ? D3D11_MAP_WRITE_NO_OVERWRITE
+ : D3D11_MAP_WRITE_DISCARD;
+
+ D3D11_MAPPED_SUBRESOURCE mappedSr;
+ if (likely(useMap = SUCCEEDED(Map(pDstResource, 0, mapType, 0, &mappedSr)))) {
+ std::memcpy(reinterpret_cast<char*>(mappedSr.pData) + offset, pSrcData, size);
+ Unmap(pDstResource, 0);
+ }
+ }
+
+ if (!useMap) {
+ DxvkDataSlice dataSlice = AllocUpdateBufferSlice(size);
+ std::memcpy(dataSlice.ptr(), pSrcData, size);
+
+ EmitCs([
+ cDataBuffer = std::move(dataSlice),
+ cBufferSlice = bufferSlice.subSlice(offset, size)
+ ] (DxvkContext* ctx) {
+ ctx->updateBuffer(
+ cBufferSlice.buffer(),
+ cBufferSlice.offset(),
+ cBufferSlice.length(),
+ cDataBuffer.ptr());
+ });
+ }
+ } else {
+ D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource);
+
+ if (DstSubresource >= dstTexture->CountSubresources())
+ return;
+
+ VkFormat packedFormat = dstTexture->GetPackedFormat();
+
+ auto formatInfo = imageFormatInfo(packedFormat);
+ auto subresource = dstTexture->GetSubresourceFromIndex(
+ formatInfo->aspectMask, DstSubresource);
+
+ VkExtent3D mipExtent = dstTexture->MipLevelExtent(subresource.mipLevel);
+
+ VkOffset3D offset = { 0, 0, 0 };
+ VkExtent3D extent = mipExtent;
+
+ if (pDstBox != nullptr) {
+ if (pDstBox->left >= pDstBox->right
+ || pDstBox->top >= pDstBox->bottom
+ || pDstBox->front >= pDstBox->back)
+ return; // no-op, but legal
+
+ offset.x = pDstBox->left;
+ offset.y = pDstBox->top;
+ offset.z = pDstBox->front;
+
+ extent.width = pDstBox->right - pDstBox->left;
+ extent.height = pDstBox->bottom - pDstBox->top;
+ extent.depth = pDstBox->back - pDstBox->front;
+ }
+
+ if (!util::isBlockAligned(offset, extent, formatInfo->blockSize, mipExtent)) {
+ Logger::err("D3D11: UpdateSubresource1: Unaligned region");
+ return;
+ }
+
+ auto stagingSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, extent));
+
+ util::packImageData(stagingSlice.mapPtr(0),
+ pSrcData, SrcRowPitch, SrcDepthPitch, 0, 0,
+ dstTexture->GetVkImageType(), extent, 1,
+ formatInfo, formatInfo->aspectMask);
+
+ UpdateImage(dstTexture, &subresource,
+ offset, extent, std::move(stagingSlice));
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContext::UpdateTileMappings(
+ ID3D11Resource* pTiledResource,
+ UINT NumTiledResourceRegions,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTiledResourceRegionStartCoordinates,
+ const D3D11_TILE_REGION_SIZE* pTiledResourceRegionSizes,
+ ID3D11Buffer* pTilePool,
+ UINT NumRanges,
+ const UINT* pRangeFlags,
+ const UINT* pTilePoolStartOffsets,
+ const UINT* pRangeTileCounts,
+ UINT Flags) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::UpdateTileMappings: Not implemented");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::UpdateTiles(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pDestTileRegionSize,
+ const void* pSourceTileData,
+ UINT Flags) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::UpdateTiles: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetResourceMinLOD(
+ ID3D11Resource* pResource,
+ FLOAT MinLOD) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetResourceMinLOD: Not implemented");
+ }
+
+
+ FLOAT STDMETHODCALLTYPE D3D11DeviceContext::GetResourceMinLOD(ID3D11Resource* pResource) {
+ bool s_errorShown = false;
+
+ if (std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::GetResourceMinLOD: Not implemented");
+
+ return 0.0f;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::ResolveSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ DXGI_FORMAT Format) {
+ D3D10DeviceLock lock = LockContext();
+
+ bool isSameSubresource = pDstResource == pSrcResource
+ && DstSubresource == SrcSubresource;
+
+ if (!pDstResource || !pSrcResource || isSameSubresource)
+ return;
+
+ D3D11_RESOURCE_DIMENSION dstResourceType;
+ D3D11_RESOURCE_DIMENSION srcResourceType;
+
+ pDstResource->GetType(&dstResourceType);
+ pSrcResource->GetType(&srcResourceType);
+
+ if (dstResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D
+ || srcResourceType != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
+ Logger::err(str::format(
+ "D3D11: ResolveSubresource: Incompatible resources",
+ "\n Dst resource type: ", dstResourceType,
+ "\n Src resource type: ", srcResourceType));
+ return;
+ }
+
+ auto dstTexture = static_cast<D3D11Texture2D*>(pDstResource);
+ auto srcTexture = static_cast<D3D11Texture2D*>(pSrcResource);
+
+ D3D11_TEXTURE2D_DESC dstDesc;
+ D3D11_TEXTURE2D_DESC srcDesc;
+
+ dstTexture->GetDesc(&dstDesc);
+ srcTexture->GetDesc(&srcDesc);
+
+ if (dstDesc.SampleDesc.Count != 1) {
+ Logger::err(str::format(
+ "D3D11: ResolveSubresource: Invalid sample counts",
+ "\n Dst sample count: ", dstDesc.SampleDesc.Count,
+ "\n Src sample count: ", srcDesc.SampleDesc.Count));
+ return;
+ }
+
+ const D3D11CommonTexture* dstTextureInfo = GetCommonTexture(pDstResource);
+ const D3D11CommonTexture* srcTextureInfo = GetCommonTexture(pSrcResource);
+
+ const DXGI_VK_FORMAT_INFO dstFormatInfo = m_parent->LookupFormat(dstDesc.Format, DXGI_VK_FORMAT_MODE_ANY);
+ const DXGI_VK_FORMAT_INFO srcFormatInfo = m_parent->LookupFormat(srcDesc.Format, DXGI_VK_FORMAT_MODE_ANY);
+
+ auto dstVulkanFormatInfo = imageFormatInfo(dstFormatInfo.Format);
+ auto srcVulkanFormatInfo = imageFormatInfo(srcFormatInfo.Format);
+
+ if (DstSubresource >= dstTextureInfo->CountSubresources()
+ || SrcSubresource >= srcTextureInfo->CountSubresources())
+ return;
+
+ const VkImageSubresource dstSubresource =
+ dstTextureInfo->GetSubresourceFromIndex(
+ dstVulkanFormatInfo->aspectMask, DstSubresource);
+
+ const VkImageSubresource srcSubresource =
+ srcTextureInfo->GetSubresourceFromIndex(
+ srcVulkanFormatInfo->aspectMask, SrcSubresource);
+
+ const VkImageSubresourceLayers dstSubresourceLayers = {
+ dstSubresource.aspectMask,
+ dstSubresource.mipLevel,
+ dstSubresource.arrayLayer, 1 };
+
+ const VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ if (srcDesc.SampleDesc.Count == 1 || m_parent->GetOptions()->disableMsaa) {
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstLayers = dstSubresourceLayers,
+ cSrcLayers = srcSubresourceLayers
+ ] (DxvkContext* ctx) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, VkOffset3D { 0, 0, 0 },
+ cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 },
+ cDstImage->mipLevelExtent(cDstLayers.mipLevel));
+ });
+ } else {
+ const VkFormat format = m_parent->LookupFormat(
+ Format, DXGI_VK_FORMAT_MODE_ANY).Format;
+
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstSubres = dstSubresourceLayers,
+ cSrcSubres = srcSubresourceLayers,
+ cFormat = format
+ ] (DxvkContext* ctx) {
+ VkImageResolve region;
+ region.srcSubresource = cSrcSubres;
+ region.srcOffset = VkOffset3D { 0, 0, 0 };
+ region.dstSubresource = cDstSubres;
+ region.dstOffset = VkOffset3D { 0, 0, 0 };
+ region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel);
+
+ ctx->resolveImage(cDstImage, cSrcImage, region, cFormat);
+ });
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawAuto() {
+ D3D10DeviceLock lock = LockContext();
+
+ D3D11Buffer* buffer = m_state.ia.vertexBuffers[0].buffer.ptr();
+
+ if (buffer == nullptr)
+ return;
+
+ DxvkBufferSlice vtxBuf = buffer->GetBufferSlice();
+ DxvkBufferSlice ctrBuf = buffer->GetSOCounter();
+
+ if (!ctrBuf.defined())
+ return;
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndirectXfb(ctrBuf,
+ vtxBuf.buffer()->getXfbVertexStride(),
+ vtxBuf.offset());
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::Draw(
+ UINT VertexCount,
+ UINT StartVertexLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->draw(
+ VertexCount, 1,
+ StartVertexLocation, 0);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexed(
+ UINT IndexCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndexed(
+ IndexCount, 1,
+ StartIndexLocation,
+ BaseVertexLocation, 0);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstanced(
+ UINT VertexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartVertexLocation,
+ UINT StartInstanceLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->draw(
+ VertexCountPerInstance,
+ InstanceCount,
+ StartVertexLocation,
+ StartInstanceLocation);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstanced(
+ UINT IndexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation,
+ UINT StartInstanceLocation) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->drawIndexed(
+ IndexCountPerInstance,
+ InstanceCount,
+ StartIndexLocation,
+ BaseVertexLocation,
+ StartInstanceLocation);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand)))
+ return;
+
+ // If possible, batch up multiple indirect draw calls of
+ // the same type into one single multiDrawIndirect call
+ auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
+ auto stride = 0u;
+
+ if (cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed)
+ stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndexedIndirectCommand));
+
+ if (stride) {
+ cmdData->count += 1;
+ cmdData->stride = stride;
+ } else {
+ cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
+ [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
+ ctx->drawIndexedIndirect(data->offset, data->count, data->stride);
+ });
+
+ cmdData->type = D3D11CmdType::DrawIndirectIndexed;
+ cmdData->offset = AlignedByteOffsetForArgs;
+ cmdData->count = 1;
+ cmdData->stride = 0;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand)))
+ return;
+
+ // If possible, batch up multiple indirect draw calls of
+ // the same type into one single multiDrawIndirect call
+ auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
+ auto stride = 0u;
+
+ if (cmdData && cmdData->type == D3D11CmdType::DrawIndirect)
+ stride = GetIndirectCommandStride(cmdData, AlignedByteOffsetForArgs, sizeof(VkDrawIndirectCommand));
+
+ if (stride) {
+ cmdData->count += 1;
+ cmdData->stride = stride;
+ } else {
+ cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
+ [] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
+ ctx->drawIndirect(data->offset, data->count, data->stride);
+ });
+
+ cmdData->type = D3D11CmdType::DrawIndirect;
+ cmdData->offset = AlignedByteOffsetForArgs;
+ cmdData->count = 1;
+ cmdData->stride = 0;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::Dispatch(
+ UINT ThreadGroupCountX,
+ UINT ThreadGroupCountY,
+ UINT ThreadGroupCountZ) {
+ D3D10DeviceLock lock = LockContext();
+
+ EmitCs([=] (DxvkContext* ctx) {
+ ctx->dispatch(
+ ThreadGroupCountX,
+ ThreadGroupCountY,
+ ThreadGroupCountZ);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs) {
+ D3D10DeviceLock lock = LockContext();
+ SetDrawBuffers(pBufferForArgs, nullptr);
+
+ if (!ValidateDrawBufferSize(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(VkDispatchIndirectCommand)))
+ return;
+
+ EmitCs([cOffset = AlignedByteOffsetForArgs]
+ (DxvkContext* ctx) {
+ ctx->dispatchIndirect(cOffset);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetInputLayout(ID3D11InputLayout* pInputLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto inputLayout = static_cast<D3D11InputLayout*>(pInputLayout);
+
+ if (m_state.ia.inputLayout != inputLayout) {
+ bool equal = false;
+
+ // Some games (e.g. Grim Dawn) create lots and lots of
+ // identical input layouts, so we'll only apply the state
+ // if the input layouts has actually changed between calls.
+ if (m_state.ia.inputLayout != nullptr && inputLayout != nullptr)
+ equal = m_state.ia.inputLayout->Compare(inputLayout);
+
+ m_state.ia.inputLayout = inputLayout;
+
+ if (!equal)
+ ApplyInputLayout();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (m_state.ia.primitiveTopology != Topology) {
+ m_state.ia.primitiveTopology = Topology;
+ ApplyPrimitiveTopology();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppVertexBuffers,
+ const UINT* pStrides,
+ const UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppVertexBuffers[i]);
+ bool needsUpdate = m_state.ia.vertexBuffers[StartSlot + i].buffer != newBuffer;
+
+ if (needsUpdate)
+ m_state.ia.vertexBuffers[StartSlot + i].buffer = newBuffer;
+
+ needsUpdate |= m_state.ia.vertexBuffers[StartSlot + i].offset != pOffsets[i]
+ || m_state.ia.vertexBuffers[StartSlot + i].stride != pStrides[i];
+
+ if (needsUpdate) {
+ m_state.ia.vertexBuffers[StartSlot + i].offset = pOffsets[i];
+ m_state.ia.vertexBuffers[StartSlot + i].stride = pStrides[i];
+
+ BindVertexBuffer(StartSlot + i, newBuffer, pOffsets[i], pStrides[i]);
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IASetIndexBuffer(
+ ID3D11Buffer* pIndexBuffer,
+ DXGI_FORMAT Format,
+ UINT Offset) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto newBuffer = static_cast<D3D11Buffer*>(pIndexBuffer);
+ bool needsUpdate = m_state.ia.indexBuffer.buffer != newBuffer;
+
+ if (needsUpdate)
+ m_state.ia.indexBuffer.buffer = newBuffer;
+
+ needsUpdate |= m_state.ia.indexBuffer.offset != Offset
+ || m_state.ia.indexBuffer.format != Format;
+
+ if (needsUpdate) {
+ m_state.ia.indexBuffer.offset = Offset;
+ m_state.ia.indexBuffer.format = Format;
+
+ BindIndexBuffer(newBuffer, Offset, Format);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout** ppInputLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ *ppInputLayout = m_state.ia.inputLayout.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY* pTopology) {
+ D3D10DeviceLock lock = LockContext();
+
+ *pTopology = m_state.ia.primitiveTopology;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppVertexBuffers,
+ UINT* pStrides,
+ UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = StartSlot + i < m_state.ia.vertexBuffers.size();
+
+ if (ppVertexBuffers != nullptr) {
+ ppVertexBuffers[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pStrides != nullptr) {
+ pStrides[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].stride
+ : 0u;
+ }
+
+ if (pOffsets != nullptr) {
+ pOffsets[i] = inRange
+ ? m_state.ia.vertexBuffers[StartSlot + i].offset
+ : 0u;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::IAGetIndexBuffer(
+ ID3D11Buffer** ppIndexBuffer,
+ DXGI_FORMAT* pFormat,
+ UINT* pOffset) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppIndexBuffer != nullptr)
+ *ppIndexBuffer = m_state.ia.indexBuffer.buffer.ref();
+
+ if (pFormat != nullptr)
+ *pFormat = m_state.ia.indexBuffer.format;
+
+ if (pOffset != nullptr)
+ *pOffset = m_state.ia.indexBuffer.offset;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShader(
+ ID3D11VertexShader* pVertexShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11VertexShader*>(pVertexShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.vs.shader != shader) {
+ m_state.vs.shader = shader;
+
+ BindShader<DxbcProgramType::VertexShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::VertexShader>(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::VertexShader>(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::VertexShader>(
+ m_state.vs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::VertexShader>(
+ m_state.vs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShader(
+ ID3D11VertexShader** ppVertexShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppVertexShader != nullptr)
+ *ppVertexShader = m_state.vs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.vs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.vs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::VSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.vs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShader(
+ ID3D11HullShader* pHullShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11HullShader*>(pHullShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.hs.shader != shader) {
+ m_state.hs.shader = shader;
+
+ BindShader<DxbcProgramType::HullShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::HullShader>(
+ m_state.hs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::HullShader>(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::HullShader>(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::HullShader>(
+ m_state.hs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShader(
+ ID3D11HullShader** ppHullShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppHullShader != nullptr)
+ *ppHullShader = m_state.hs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.hs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.hs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::HSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.hs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShader(
+ ID3D11DomainShader* pDomainShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11DomainShader*>(pDomainShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.ds.shader != shader) {
+ m_state.ds.shader = shader;
+
+ BindShader<DxbcProgramType::DomainShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::DomainShader>(
+ m_state.ds.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::DomainShader>(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::DomainShader>(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::DomainShader>(
+ m_state.ds.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShader(
+ ID3D11DomainShader** ppDomainShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppDomainShader != nullptr)
+ *ppDomainShader = m_state.ds.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ds.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.ds.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::DSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.ds.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShader(
+ ID3D11GeometryShader* pShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11GeometryShader*>(pShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.gs.shader != shader) {
+ m_state.gs.shader = shader;
+
+ BindShader<DxbcProgramType::GeometryShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::GeometryShader>(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::GeometryShader>(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::GeometryShader>(
+ m_state.gs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::GeometryShader>(
+ m_state.gs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShader(
+ ID3D11GeometryShader** ppGeometryShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppGeometryShader != nullptr)
+ *ppGeometryShader = m_state.gs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.gs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.gs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.gs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShader(
+ ID3D11PixelShader* pPixelShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11PixelShader*>(pPixelShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.ps.shader != shader) {
+ m_state.ps.shader = shader;
+
+ BindShader<DxbcProgramType::PixelShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::PixelShader>(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::PixelShader>(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::PixelShader>(
+ m_state.ps.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::PixelShader>(
+ m_state.ps.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShader(
+ ID3D11PixelShader** ppPixelShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppPixelShader != nullptr)
+ *ppPixelShader = m_state.ps.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.ps.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.ps.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::PSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.ps.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShader(
+ ID3D11ComputeShader* pComputeShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto shader = static_cast<D3D11ComputeShader*>(pComputeShader);
+
+ if (NumClassInstances != 0)
+ Logger::err("D3D11: Class instances not supported");
+
+ if (m_state.cs.shader != shader) {
+ m_state.cs.shader = shader;
+
+ BindShader<DxbcProgramType::ComputeShader>(GetCommonShader(shader));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers<DxbcProgramType::ComputeShader>(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetConstantBuffers1<DxbcProgramType::ComputeShader>(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetShaderResources<DxbcProgramType::ComputeShader>(
+ m_state.cs.shaderResources,
+ StartSlot, NumViews,
+ ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ SetSamplers<DxbcProgramType::ComputeShader>(
+ m_state.cs.samplers,
+ StartSlot, NumSamplers,
+ ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSSetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (TestRtvUavHazards(0, nullptr, NumUAVs, ppUnorderedAccessViews))
+ return;
+
+ // Unbind previously bound conflicting UAVs
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::ComputeShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::ComputeShader, 0);
+
+ int32_t uavId = m_state.cs.uavMask.findNext(0);
+
+ while (uavId >= 0) {
+ if (uint32_t(uavId) < StartSlot || uint32_t(uavId) >= StartSlot + NumUAVs) {
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
+
+ if (CheckViewOverlap(uav, m_state.cs.unorderedAccessViews[uavId].ptr())) {
+ m_state.cs.unorderedAccessViews[uavId] = nullptr;
+ m_state.cs.uavMask.clr(uavId);
+
+ BindUnorderedAccessView(
+ uavSlotId + uavId, nullptr,
+ ctrSlotId + uavId, ~0u);
+ }
+ }
+
+ uavId = m_state.cs.uavMask.findNext(uavId + 1);
+ } else {
+ uavId = m_state.cs.uavMask.findNext(StartSlot + NumUAVs);
+ }
+ }
+
+ // Actually bind the given UAVs
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i]);
+ auto ctr = pUAVInitialCounts ? pUAVInitialCounts[i] : ~0u;
+
+ if (m_state.cs.unorderedAccessViews[StartSlot + i] != uav || ctr != ~0u) {
+ m_state.cs.unorderedAccessViews[StartSlot + i] = uav;
+ m_state.cs.uavMask.set(StartSlot + i, uav != nullptr);
+
+ BindUnorderedAccessView(
+ uavSlotId + StartSlot + i, uav,
+ ctrSlotId + StartSlot + i, ctr);
+
+ ResolveCsSrvHazards(uav);
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShader(
+ ID3D11ComputeShader** ppComputeShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppComputeShader != nullptr)
+ *ppComputeShader = m_state.cs.shader.ref();
+
+ if (pNumClassInstances != nullptr)
+ *pNumClassInstances = 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetConstantBuffers(
+ m_state.cs.constantBuffers,
+ StartSlot, NumBuffers,
+ ppConstantBuffers,
+ pFirstConstant,
+ pNumConstants);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetShaderResources(m_state.cs.shaderResources,
+ StartSlot, NumViews, ppShaderResourceViews);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ D3D10DeviceLock lock = LockContext();
+
+ GetSamplers(m_state.cs.samplers,
+ StartSlot, NumSamplers, ppSamplers);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::CSGetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ ppUnorderedAccessViews[i] = StartSlot + i < m_state.cs.unorderedAccessViews.size()
+ ? m_state.cs.unorderedAccessViews[StartSlot + i].ref()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView) {
+ OMSetRenderTargetsAndUnorderedAccessViews(
+ NumViews, ppRenderTargetViews, pDepthStencilView,
+ NumViews, 0, nullptr, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (TestRtvUavHazards(NumRTVs, ppRenderTargetViews, NumUAVs, ppUnorderedAccessViews))
+ return;
+
+ bool needsUpdate = false;
+
+ if (likely(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)) {
+ // Native D3D11 does not change the render targets if
+ // the parameters passed to this method are invalid.
+ if (!ValidateRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView))
+ return;
+
+ for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) {
+ auto rtv = i < NumRTVs
+ ? static_cast<D3D11RenderTargetView*>(ppRenderTargetViews[i])
+ : nullptr;
+
+ if (m_state.om.renderTargetViews[i] != rtv) {
+ m_state.om.renderTargetViews[i] = rtv;
+ needsUpdate = true;
+ ResolveOmSrvHazards(rtv);
+
+ if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS)
+ ResolveOmUavHazards(rtv);
+ }
+ }
+
+ auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
+
+ if (m_state.om.depthStencilView != dsv) {
+ m_state.om.depthStencilView = dsv;
+ needsUpdate = true;
+ ResolveOmSrvHazards(dsv);
+ }
+
+ m_state.om.maxRtv = NumRTVs;
+ }
+
+ if (unlikely(NumUAVs || m_state.om.maxUav)) {
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0);
+
+ if (likely(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS)) {
+ uint32_t newMaxUav = NumUAVs ? UAVStartSlot + NumUAVs : 0;
+ uint32_t oldMaxUav = std::exchange(m_state.om.maxUav, newMaxUav);
+
+ for (uint32_t i = 0; i < std::max(oldMaxUav, newMaxUav); i++) {
+ D3D11UnorderedAccessView* uav = nullptr;
+ uint32_t ctr = ~0u;
+
+ if (i >= UAVStartSlot && i < UAVStartSlot + NumUAVs) {
+ uav = static_cast<D3D11UnorderedAccessView*>(ppUnorderedAccessViews[i - UAVStartSlot]);
+ ctr = pUAVInitialCounts ? pUAVInitialCounts[i - UAVStartSlot] : ~0u;
+ }
+
+ if (m_state.ps.unorderedAccessViews[i] != uav || ctr != ~0u) {
+ m_state.ps.unorderedAccessViews[i] = uav;
+
+ BindUnorderedAccessView(
+ uavSlotId + i, uav,
+ ctrSlotId + i, ctr);
+
+ ResolveOmSrvHazards(uav);
+
+ if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)
+ needsUpdate |= ResolveOmRtvHazards(uav);
+ }
+ }
+ }
+ }
+
+ if (needsUpdate)
+ BindFramebuffer();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetBlendState(
+ ID3D11BlendState* pBlendState,
+ const FLOAT BlendFactor[4],
+ UINT SampleMask) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto blendState = static_cast<D3D11BlendState*>(pBlendState);
+
+ if (m_state.om.cbState != blendState
+ || m_state.om.sampleMask != SampleMask) {
+ m_state.om.cbState = blendState;
+ m_state.om.sampleMask = SampleMask;
+
+ ApplyBlendState();
+ }
+
+ if (BlendFactor != nullptr) {
+ for (uint32_t i = 0; i < 4; i++)
+ m_state.om.blendFactor[i] = BlendFactor[i];
+
+ ApplyBlendFactor();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMSetDepthStencilState(
+ ID3D11DepthStencilState* pDepthStencilState,
+ UINT StencilRef) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto depthStencilState = static_cast<D3D11DepthStencilState*>(pDepthStencilState);
+
+ if (m_state.om.dsState != depthStencilState) {
+ m_state.om.dsState = depthStencilState;
+ ApplyDepthStencilState();
+ }
+
+ if (m_state.om.stencilRef != StencilRef) {
+ m_state.om.stencilRef = StencilRef;
+ ApplyStencilRef();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppRenderTargetViews != nullptr) {
+ for (UINT i = 0; i < NumViews; i++) {
+ ppRenderTargetViews[i] = i < m_state.om.renderTargetViews.size()
+ ? m_state.om.renderTargetViews[i].ref()
+ : nullptr;
+ }
+ }
+
+ if (ppDepthStencilView != nullptr)
+ *ppDepthStencilView = m_state.om.depthStencilView.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews) {
+ OMGetRenderTargets(NumRTVs, ppRenderTargetViews, ppDepthStencilView);
+
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppUnorderedAccessViews != nullptr) {
+ for (UINT i = 0; i < NumUAVs; i++) {
+ ppUnorderedAccessViews[i] = UAVStartSlot + i < m_state.ps.unorderedAccessViews.size()
+ ? m_state.ps.unorderedAccessViews[UAVStartSlot + i].ref()
+ : nullptr;
+ }
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetBlendState(
+ ID3D11BlendState** ppBlendState,
+ FLOAT BlendFactor[4],
+ UINT* pSampleMask) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppBlendState != nullptr)
+ *ppBlendState = ref(m_state.om.cbState);
+
+ if (BlendFactor != nullptr)
+ std::memcpy(BlendFactor, m_state.om.blendFactor, sizeof(FLOAT) * 4);
+
+ if (pSampleMask != nullptr)
+ *pSampleMask = m_state.om.sampleMask;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::OMGetDepthStencilState(
+ ID3D11DepthStencilState** ppDepthStencilState,
+ UINT* pStencilRef) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppDepthStencilState != nullptr)
+ *ppDepthStencilState = ref(m_state.om.dsState);
+
+ if (pStencilRef != nullptr)
+ *pStencilRef = m_state.om.stencilRef;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetState(ID3D11RasterizerState* pRasterizerState) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto rasterizerState = static_cast<D3D11RasterizerState*>(pRasterizerState);
+
+ bool currScissorEnable = m_state.rs.state != nullptr
+ ? m_state.rs.state->Desc()->ScissorEnable
+ : false;
+
+ bool nextScissorEnable = rasterizerState != nullptr
+ ? rasterizerState->Desc()->ScissorEnable
+ : false;
+
+ if (m_state.rs.state != rasterizerState) {
+ m_state.rs.state = rasterizerState;
+
+ // In D3D11, the rasterizer state defines whether the
+ // scissor test is enabled, so we have to update the
+ // scissor rectangles as well.
+ ApplyRasterizerState();
+
+ if (currScissorEnable != nextScissorEnable)
+ ApplyViewportState();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetViewports(
+ UINT NumViewports,
+ const D3D11_VIEWPORT* pViewports) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(NumViewports > m_state.rs.viewports.size()))
+ return;
+
+ bool dirty = m_state.rs.numViewports != NumViewports;
+ m_state.rs.numViewports = NumViewports;
+
+ for (uint32_t i = 0; i < NumViewports; i++) {
+ const D3D11_VIEWPORT& vp = m_state.rs.viewports[i];
+
+ dirty |= vp.TopLeftX != pViewports[i].TopLeftX
+ || vp.TopLeftY != pViewports[i].TopLeftY
+ || vp.Width != pViewports[i].Width
+ || vp.Height != pViewports[i].Height
+ || vp.MinDepth != pViewports[i].MinDepth
+ || vp.MaxDepth != pViewports[i].MaxDepth;
+
+ m_state.rs.viewports[i] = pViewports[i];
+ }
+
+ if (dirty)
+ ApplyViewportState();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSSetScissorRects(
+ UINT NumRects,
+ const D3D11_RECT* pRects) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(NumRects > m_state.rs.scissors.size()))
+ return;
+
+ bool dirty = m_state.rs.numScissors != NumRects;
+ m_state.rs.numScissors = NumRects;
+
+ for (uint32_t i = 0; i < NumRects; i++) {
+ if (pRects[i].bottom >= pRects[i].top
+ && pRects[i].right >= pRects[i].left) {
+ const D3D11_RECT& sr = m_state.rs.scissors[i];
+
+ dirty |= sr.top != pRects[i].top
+ || sr.left != pRects[i].left
+ || sr.bottom != pRects[i].bottom
+ || sr.right != pRects[i].right;
+
+ m_state.rs.scissors[i] = pRects[i];
+ }
+ }
+
+ if (m_state.rs.state != nullptr && dirty) {
+ D3D11_RASTERIZER_DESC rsDesc;
+ m_state.rs.state->GetDesc(&rsDesc);
+
+ if (rsDesc.ScissorEnable)
+ ApplyViewportState();
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetState(ID3D11RasterizerState** ppRasterizerState) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (ppRasterizerState != nullptr)
+ *ppRasterizerState = ref(m_state.rs.state);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetViewports(
+ UINT* pNumViewports,
+ D3D11_VIEWPORT* pViewports) {
+ D3D10DeviceLock lock = LockContext();
+ uint32_t numWritten = m_state.rs.numViewports;
+
+ if (pViewports) {
+ numWritten = std::min(numWritten, *pNumViewports);
+
+ for (uint32_t i = 0; i < *pNumViewports; i++) {
+ if (i < m_state.rs.numViewports) {
+ pViewports[i] = m_state.rs.viewports[i];
+ } else {
+ pViewports[i].TopLeftX = 0.0f;
+ pViewports[i].TopLeftY = 0.0f;
+ pViewports[i].Width = 0.0f;
+ pViewports[i].Height = 0.0f;
+ pViewports[i].MinDepth = 0.0f;
+ pViewports[i].MaxDepth = 0.0f;
+ }
+ }
+ }
+
+ *pNumViewports = numWritten;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::RSGetScissorRects(
+ UINT* pNumRects,
+ D3D11_RECT* pRects) {
+ D3D10DeviceLock lock = LockContext();
+ uint32_t numWritten = m_state.rs.numScissors;
+
+ if (pRects) {
+ numWritten = std::min(numWritten, *pNumRects);
+
+ for (uint32_t i = 0; i < *pNumRects; i++) {
+ if (i < m_state.rs.numScissors) {
+ pRects[i] = m_state.rs.scissors[i];
+ } else {
+ pRects[i].left = 0;
+ pRects[i].top = 0;
+ pRects[i].right = 0;
+ pRects[i].bottom = 0;
+ }
+ }
+ }
+
+ *pNumRects = m_state.rs.numScissors;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOSetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppSOTargets,
+ const UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ D3D11Buffer* buffer = static_cast<D3D11Buffer*>(ppSOTargets[i]);
+ UINT offset = pOffsets != nullptr ? pOffsets[i] : 0;
+
+ m_state.so.targets[i].buffer = buffer;
+ m_state.so.targets[i].offset = offset;
+ }
+
+ for (uint32_t i = NumBuffers; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ m_state.so.targets[i].buffer = nullptr;
+ m_state.so.targets[i].offset = 0;
+ }
+
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++) {
+ BindXfbBuffer(i,
+ m_state.so.targets[i].buffer.ptr(),
+ m_state.so.targets[i].offset);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ ppSOTargets[i] = i < m_state.so.targets.size()
+ ? m_state.so.targets[i].buffer.ref()
+ : nullptr;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SOGetTargetsWithOffsets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets,
+ UINT* pOffsets) {
+ D3D10DeviceLock lock = LockContext();
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = i < m_state.so.targets.size();
+
+ if (ppSOTargets != nullptr) {
+ ppSOTargets[i] = inRange
+ ? m_state.so.targets[i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pOffsets != nullptr) {
+ pOffsets[i] = inRange
+ ? m_state.so.targets[i].offset
+ : 0u;
+ }
+ }
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D11DeviceContext::IsAnnotationEnabled() {
+ return m_device->instance()->extensions().extDebugUtils;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetMarkerInt(
+ LPCWSTR pLabel,
+ INT Data) {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::BeginEventInt(
+ LPCWSTR pLabel,
+ INT Data) {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::EndEvent() {
+ // Not implemented in the backend, ignore
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::GetHardwareProtectionState(
+ BOOL* pHwProtectionEnable) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::GetHardwareProtectionState: Not implemented");
+
+ if (pHwProtectionEnable)
+ *pHwProtectionEnable = FALSE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::SetHardwareProtectionState(
+ BOOL HwProtectionEnable) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DeviceContext::SetHardwareProtectionState: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContext::TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout) {
+ D3D10DeviceLock lock = LockContext();
+
+ // Get the underlying D3D11 resource
+ Com<ID3D11Resource> resource;
+
+ pSurface->QueryInterface(__uuidof(ID3D11Resource),
+ reinterpret_cast<void**>(&resource));
+
+ // Get the texture from that resource
+ D3D11CommonTexture* texture = GetCommonTexture(resource.ptr());
+
+ EmitCs([
+ cImage = texture->GetImage(),
+ cSubresources = *pSubresources,
+ cOldLayout = OldLayout,
+ cNewLayout = NewLayout
+ ] (DxvkContext* ctx) {
+ ctx->transformImage(
+ cImage, cSubresources,
+ cOldLayout, cNewLayout);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyInputLayout() {
+ auto inputLayout = m_state.ia.inputLayout.prvRef();
+
+ if (likely(inputLayout != nullptr)) {
+ EmitCs([
+ cInputLayout = std::move(inputLayout)
+ ] (DxvkContext* ctx) {
+ cInputLayout->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyPrimitiveTopology() {
+ D3D11_PRIMITIVE_TOPOLOGY topology = m_state.ia.primitiveTopology;
+ DxvkInputAssemblyState iaState = { };
+
+ if (topology <= D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ) {
+ static const std::array<DxvkInputAssemblyState, 14> s_iaStates = {{
+ { VK_PRIMITIVE_TOPOLOGY_MAX_ENUM, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_TRUE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_TRUE, 0 },
+ { }, { }, { }, { }, // Random gap that exists for no reason
+ { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_FALSE, 0 },
+ { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, VK_TRUE, 0 },
+ }};
+
+ iaState = s_iaStates[uint32_t(topology)];
+ } else if (topology >= D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST
+ && topology <= D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST) {
+ // The number of control points per patch can be inferred from the enum value in D3D11
+ uint32_t vertexCount = uint32_t(topology - D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + 1);
+ iaState = { VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE, vertexCount };
+ }
+
+ EmitCs([iaState] (DxvkContext* ctx) {
+ ctx->setInputAssemblyState(iaState);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyBlendState() {
+ if (m_state.om.cbState != nullptr) {
+ EmitCs([
+ cBlendState = m_state.om.cbState,
+ cSampleMask = m_state.om.sampleMask
+ ] (DxvkContext* ctx) {
+ cBlendState->BindToContext(ctx, cSampleMask);
+ });
+ } else {
+ EmitCs([
+ cSampleMask = m_state.om.sampleMask
+ ] (DxvkContext* ctx) {
+ DxvkBlendMode cbState;
+ DxvkLogicOpState loState;
+ DxvkMultisampleState msState;
+ InitDefaultBlendState(&cbState, &loState, &msState, cSampleMask);
+
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ ctx->setBlendMode(i, cbState);
+
+ ctx->setLogicOpState(loState);
+ ctx->setMultisampleState(msState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyBlendFactor() {
+ EmitCs([
+ cBlendConstants = DxvkBlendConstants {
+ m_state.om.blendFactor[0], m_state.om.blendFactor[1],
+ m_state.om.blendFactor[2], m_state.om.blendFactor[3] }
+ ] (DxvkContext* ctx) {
+ ctx->setBlendConstants(cBlendConstants);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyDepthStencilState() {
+ if (m_state.om.dsState != nullptr) {
+ EmitCs([
+ cDepthStencilState = m_state.om.dsState
+ ] (DxvkContext* ctx) {
+ cDepthStencilState->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ DxvkDepthStencilState dsState;
+ InitDefaultDepthStencilState(&dsState);
+
+ ctx->setDepthStencilState(dsState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyStencilRef() {
+ EmitCs([
+ cStencilRef = m_state.om.stencilRef
+ ] (DxvkContext* ctx) {
+ ctx->setStencilReference(cStencilRef);
+ });
+ }
+
+
+ void D3D11DeviceContext::ApplyRasterizerState() {
+ if (m_state.rs.state != nullptr) {
+ EmitCs([
+ cRasterizerState = m_state.rs.state
+ ] (DxvkContext* ctx) {
+ cRasterizerState->BindToContext(ctx);
+ });
+ } else {
+ EmitCs([] (DxvkContext* ctx) {
+ DxvkRasterizerState rsState;
+ InitDefaultRasterizerState(&rsState);
+
+ ctx->setRasterizerState(rsState);
+ });
+ }
+ }
+
+
+ void D3D11DeviceContext::ApplyViewportState() {
+ std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports;
+ std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors;
+
+ // The backend can't handle a viewport count of zero,
+ // so we should at least specify one empty viewport
+ uint32_t viewportCount = m_state.rs.numViewports;
+
+ if (unlikely(!viewportCount)) {
+ viewportCount = 1;
+ viewports[0] = VkViewport();
+ scissors [0] = VkRect2D();
+ }
+
+ // D3D11's coordinate system has its origin in the bottom left,
+ // but the viewport coordinates are aligned to the top-left
+ // corner so we can get away with flipping the viewport.
+ for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
+ const D3D11_VIEWPORT& vp = m_state.rs.viewports[i];
+
+ viewports[i] = VkViewport {
+ vp.TopLeftX, vp.Height + vp.TopLeftY,
+ vp.Width, -vp.Height,
+ vp.MinDepth, vp.MaxDepth,
+ };
+ }
+
+ // Scissor rectangles. Vulkan does not provide an easy way
+ // to disable the scissor test, so we'll have to set scissor
+ // rects that are at least as large as the framebuffer.
+ bool enableScissorTest = false;
+
+ if (m_state.rs.state != nullptr) {
+ D3D11_RASTERIZER_DESC rsDesc;
+ m_state.rs.state->GetDesc(&rsDesc);
+ enableScissorTest = rsDesc.ScissorEnable;
+ }
+
+ for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
+ if (!enableScissorTest) {
+ scissors[i] = VkRect2D {
+ VkOffset2D { 0, 0 },
+ VkExtent2D {
+ D3D11_VIEWPORT_BOUNDS_MAX,
+ D3D11_VIEWPORT_BOUNDS_MAX } };
+ } else if (i >= m_state.rs.numScissors) {
+ scissors[i] = VkRect2D {
+ VkOffset2D { 0, 0 },
+ VkExtent2D { 0, 0 } };
+ } else {
+ D3D11_RECT sr = m_state.rs.scissors[i];
+
+ VkOffset2D srPosA;
+ srPosA.x = std::max<int32_t>(0, sr.left);
+ srPosA.y = std::max<int32_t>(0, sr.top);
+
+ VkOffset2D srPosB;
+ srPosB.x = std::max<int32_t>(srPosA.x, sr.right);
+ srPosB.y = std::max<int32_t>(srPosA.y, sr.bottom);
+
+ VkExtent2D srSize;
+ srSize.width = uint32_t(srPosB.x - srPosA.x);
+ srSize.height = uint32_t(srPosB.y - srPosA.y);
+
+ scissors[i] = VkRect2D { srPosA, srSize };
+ }
+ }
+
+ if (likely(viewportCount == 1)) {
+ EmitCs([
+ cViewport = viewports[0],
+ cScissor = scissors[0]
+ ] (DxvkContext* ctx) {
+ ctx->setViewports(1,
+ &cViewport,
+ &cScissor);
+ });
+ } else {
+ EmitCs([
+ cViewportCount = viewportCount,
+ cViewports = viewports,
+ cScissors = scissors
+ ] (DxvkContext* ctx) {
+ ctx->setViewports(
+ cViewportCount,
+ cViewports.data(),
+ cScissors.data());
+ });
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::BindShader(
+ const D3D11CommonShader* pShaderModule) {
+ // Bind the shader and the ICB at once
+ EmitCs([
+ cSlice = pShaderModule != nullptr
+ && pShaderModule->GetIcb() != nullptr
+ ? DxvkBufferSlice(pShaderModule->GetIcb())
+ : DxvkBufferSlice(),
+ cShader = pShaderModule != nullptr
+ ? pShaderModule->GetShader()
+ : nullptr
+ ] (DxvkContext* ctx) {
+ VkShaderStageFlagBits stage = GetShaderStage(ShaderStage);
+
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage,
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT);
+
+ ctx->bindShader (stage, cShader);
+ ctx->bindResourceBuffer(slotId, cSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindFramebuffer() {
+ DxvkRenderTargets attachments;
+
+ // D3D11 doesn't have the concept of a framebuffer object,
+ // so we'll just create a new one every time the render
+ // target bindings are updated. Set up the attachments.
+ for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) {
+ if (m_state.om.renderTargetViews[i] != nullptr) {
+ attachments.color[i] = {
+ m_state.om.renderTargetViews[i]->GetImageView(),
+ m_state.om.renderTargetViews[i]->GetRenderLayout() };
+ }
+ }
+
+ if (m_state.om.depthStencilView != nullptr) {
+ attachments.depth = {
+ m_state.om.depthStencilView->GetImageView(),
+ m_state.om.depthStencilView->GetRenderLayout() };
+ }
+
+ // Create and bind the framebuffer object to the context
+ EmitCs([
+ cAttachments = std::move(attachments)
+ ] (DxvkContext* ctx) {
+ ctx->bindRenderTargets(cAttachments);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindDrawBuffers(
+ D3D11Buffer* pBufferForArgs,
+ D3D11Buffer* pBufferForCount) {
+ EmitCs([
+ cArgBuffer = pBufferForArgs ? pBufferForArgs->GetBufferSlice() : DxvkBufferSlice(),
+ cCntBuffer = pBufferForCount ? pBufferForCount->GetBufferSlice() : DxvkBufferSlice()
+ ] (DxvkContext* ctx) {
+ ctx->bindDrawBuffers(cArgBuffer, cCntBuffer);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindVertexBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Stride) {
+ EmitCs([
+ cSlotId = Slot,
+ cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
+ cStride = Stride
+ ] (DxvkContext* ctx) {
+ ctx->bindVertexBuffer(cSlotId, cBufferSlice, cStride);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindIndexBuffer(
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ DXGI_FORMAT Format) {
+ VkIndexType indexType = Format == DXGI_FORMAT_R16_UINT
+ ? VK_INDEX_TYPE_UINT16
+ : VK_INDEX_TYPE_UINT32;
+
+ EmitCs([
+ cBufferSlice = pBuffer != nullptr ? pBuffer->GetBufferSlice(Offset) : DxvkBufferSlice(),
+ cIndexType = indexType
+ ] (DxvkContext* ctx) {
+ ctx->bindIndexBuffer(cBufferSlice, cIndexType);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindXfbBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset) {
+ DxvkBufferSlice bufferSlice;
+ DxvkBufferSlice counterSlice;
+
+ if (pBuffer != nullptr) {
+ bufferSlice = pBuffer->GetBufferSlice();
+ counterSlice = pBuffer->GetSOCounter();
+ }
+
+ EmitCs([
+ cSlotId = Slot,
+ cOffset = Offset,
+ cBufferSlice = bufferSlice,
+ cCounterSlice = counterSlice
+ ] (DxvkContext* ctx) {
+ if (cCounterSlice.defined() && cOffset != ~0u) {
+ ctx->updateBuffer(
+ cCounterSlice.buffer(),
+ cCounterSlice.offset(),
+ sizeof(cOffset),
+ &cOffset);
+ }
+
+ ctx->bindXfbBuffer(cSlotId, cBufferSlice, cCounterSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindConstantBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Length) {
+ EmitCs([
+ cSlotId = Slot,
+ cBufferSlice = Length ? pBuffer->GetBufferSlice(16 * Offset, 16 * Length) : DxvkBufferSlice()
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceBuffer(cSlotId, cBufferSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindSampler(
+ UINT Slot,
+ D3D11SamplerState* pSampler) {
+ EmitCs([
+ cSlotId = Slot,
+ cSampler = pSampler != nullptr ? pSampler->GetDXVKSampler() : nullptr
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceSampler(cSlotId, cSampler);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindShaderResource(
+ UINT Slot,
+ D3D11ShaderResourceView* pResource) {
+ EmitCs([
+ cSlotId = Slot,
+ cImageView = pResource != nullptr ? pResource->GetImageView() : nullptr,
+ cBufferView = pResource != nullptr ? pResource->GetBufferView() : nullptr
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceView(cSlotId, cImageView, cBufferView);
+ });
+ }
+
+
+ void D3D11DeviceContext::BindUnorderedAccessView(
+ UINT UavSlot,
+ D3D11UnorderedAccessView* pUav,
+ UINT CtrSlot,
+ UINT Counter) {
+ EmitCs([
+ cUavSlotId = UavSlot,
+ cCtrSlotId = CtrSlot,
+ cImageView = pUav != nullptr ? pUav->GetImageView() : nullptr,
+ cBufferView = pUav != nullptr ? pUav->GetBufferView() : nullptr,
+ cCounterSlice = pUav != nullptr ? pUav->GetCounterSlice() : DxvkBufferSlice(),
+ cCounterValue = Counter
+ ] (DxvkContext* ctx) {
+ if (cCounterSlice.defined() && cCounterValue != ~0u) {
+ ctx->updateBuffer(
+ cCounterSlice.buffer(),
+ cCounterSlice.offset(),
+ sizeof(uint32_t),
+ &cCounterValue);
+ }
+
+ ctx->bindResourceView (cUavSlotId, cImageView, cBufferView);
+ ctx->bindResourceBuffer (cCtrSlotId, cCounterSlice);
+ });
+ }
+
+
+ void D3D11DeviceContext::CopyBuffer(
+ D3D11Buffer* pDstBuffer,
+ VkDeviceSize DstOffset,
+ D3D11Buffer* pSrcBuffer,
+ VkDeviceSize SrcOffset,
+ VkDeviceSize ByteCount) {
+ // Clamp copy region to prevent out-of-bounds access
+ VkDeviceSize dstLength = pDstBuffer->Desc()->ByteWidth;
+ VkDeviceSize srcLength = pSrcBuffer->Desc()->ByteWidth;
+
+ if (SrcOffset >= srcLength || DstOffset >= dstLength || !ByteCount)
+ return;
+
+ ByteCount = std::min(dstLength - DstOffset, ByteCount);
+ ByteCount = std::min(srcLength - SrcOffset, ByteCount);
+
+ EmitCs([
+ cDstBuffer = pDstBuffer->GetBufferSlice(DstOffset, ByteCount),
+ cSrcBuffer = pSrcBuffer->GetBufferSlice(SrcOffset, ByteCount)
+ ] (DxvkContext* ctx) {
+ if (cDstBuffer.buffer() != cSrcBuffer.buffer()) {
+ ctx->copyBuffer(
+ cDstBuffer.buffer(),
+ cDstBuffer.offset(),
+ cSrcBuffer.buffer(),
+ cSrcBuffer.offset(),
+ cSrcBuffer.length());
+ } else {
+ ctx->copyBufferRegion(
+ cDstBuffer.buffer(),
+ cDstBuffer.offset(),
+ cSrcBuffer.offset(),
+ cSrcBuffer.length());
+ }
+ });
+ }
+
+
+ void D3D11DeviceContext::CopyImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresourceLayers* pDstLayers,
+ VkOffset3D DstOffset,
+ D3D11CommonTexture* pSrcTexture,
+ const VkImageSubresourceLayers* pSrcLayers,
+ VkOffset3D SrcOffset,
+ VkExtent3D SrcExtent) {
+ // Image formats must be size-compatible
+ auto dstFormatInfo = imageFormatInfo(pDstTexture->GetPackedFormat());
+ auto srcFormatInfo = imageFormatInfo(pSrcTexture->GetPackedFormat());
+
+ if (dstFormatInfo->elementSize != srcFormatInfo->elementSize) {
+ Logger::err("D3D11: CopyImage: Incompatible texel size");
+ return;
+ }
+
+ // Sample counts must match
+ if (pDstTexture->Desc()->SampleDesc.Count != pSrcTexture->Desc()->SampleDesc.Count) {
+ Logger::err("D3D11: CopyImage: Incompatible sample count");
+ return;
+ }
+
+ // Obviously, the copy region must not be empty
+ VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstLayers->mipLevel);
+ VkExtent3D srcMipExtent = pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel);
+
+ if (uint32_t(DstOffset.x) >= dstMipExtent.width
+ || uint32_t(DstOffset.y) >= dstMipExtent.height
+ || uint32_t(DstOffset.z) >= dstMipExtent.depth)
+ return;
+
+ if (uint32_t(SrcOffset.x) >= srcMipExtent.width
+ || uint32_t(SrcOffset.y) >= srcMipExtent.height
+ || uint32_t(SrcOffset.z) >= srcMipExtent.depth)
+ return;
+
+ // Don't perform the copy if the offsets aren't block-aligned
+ if (!util::isBlockAligned(SrcOffset, srcFormatInfo->blockSize)
+ || !util::isBlockAligned(DstOffset, dstFormatInfo->blockSize)) {
+ Logger::err(str::format("D3D11: CopyImage: Unaligned block offset"));
+ return;
+ }
+
+ // Clamp the image region in order to avoid out-of-bounds access
+ VkExtent3D blockCount = util::computeBlockCount(SrcExtent, srcFormatInfo->blockSize);
+ VkExtent3D dstBlockCount = util::computeMaxBlockCount(DstOffset, dstMipExtent, dstFormatInfo->blockSize);
+ VkExtent3D srcBlockCount = util::computeMaxBlockCount(SrcOffset, srcMipExtent, srcFormatInfo->blockSize);
+
+ blockCount = util::minExtent3D(blockCount, dstBlockCount);
+ blockCount = util::minExtent3D(blockCount, srcBlockCount);
+
+ SrcExtent = util::computeBlockExtent(blockCount, srcFormatInfo->blockSize);
+ SrcExtent = util::snapExtent3D(SrcOffset, SrcExtent, srcMipExtent);
+
+ if (!SrcExtent.width || !SrcExtent.height || !SrcExtent.depth)
+ return;
+
+ // While copying between 2D and 3D images is allowed in CopySubresourceRegion,
+ // copying more than one slice at a time is not suppoted. Layer counts are 1.
+ if ((pDstTexture->GetVkImageType() == VK_IMAGE_TYPE_3D)
+ != (pSrcTexture->GetVkImageType() == VK_IMAGE_TYPE_3D))
+ SrcExtent.depth = 1;
+
+ // Certain types of copies require us to pass the destination extent to
+ // the backend. This may be different when copying between compressed
+ // and uncompressed image formats.
+ VkExtent3D dstExtent = util::computeBlockExtent(blockCount, dstFormatInfo->blockSize);
+ dstExtent = util::snapExtent3D(DstOffset, dstExtent, dstMipExtent);
+
+ // It is possible for any of the given images to be a staging image with
+ // no actual image, so we need to account for all possibilities here.
+ bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+ bool srcIsImage = pSrcTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+
+ if (dstIsImage && srcIsImage) {
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cSrcImage = pSrcTexture->GetImage(),
+ cDstLayers = *pDstLayers,
+ cSrcLayers = *pSrcLayers,
+ cDstOffset = DstOffset,
+ cSrcOffset = SrcOffset,
+ cExtent = SrcExtent
+ ] (DxvkContext* ctx) {
+ // CopyResource can only copy between different images, and
+ // CopySubresourceRegion can only copy data from one single
+ // subresource at a time, so this check is safe.
+ if (cDstImage != cSrcImage || cDstLayers != cSrcLayers) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, cDstOffset,
+ cSrcImage, cSrcLayers, cSrcOffset,
+ cExtent);
+ } else {
+ ctx->copyImageRegion(
+ cDstImage, cDstLayers, cDstOffset,
+ cSrcOffset, cExtent);
+ }
+ });
+ } else {
+ // Since each subresource uses a dedicated buffer, we are going
+ // to need one call per subresource for staging resource copies
+ for (uint32_t i = 0; i < pDstLayers->layerCount; i++) {
+ uint32_t dstSubresource = D3D11CalcSubresource(pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, pDstTexture->Desc()->MipLevels);
+ uint32_t srcSubresource = D3D11CalcSubresource(pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, pSrcTexture->Desc()->MipLevels);
+
+ // For multi-plane image data stored in a buffer, the backend
+ // assumes that the second plane immediately follows the first
+ // plane in memory, which is only true if we copy the full image.
+ uint32_t planeCount = 1;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ bool needsSeparateCopies = !dstIsImage && !srcIsImage;
+
+ if (!dstIsImage)
+ needsSeparateCopies |= pDstTexture->MipLevelExtent(pDstLayers->mipLevel) != SrcExtent;
+ if (!srcIsImage)
+ needsSeparateCopies |= pSrcTexture->MipLevelExtent(pSrcLayers->mipLevel) != SrcExtent;
+
+ if (needsSeparateCopies)
+ planeCount = vk::getPlaneCount(srcFormatInfo->aspectMask);
+ }
+
+ for (uint32_t j = 0; j < planeCount; j++) {
+ VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask;
+ VkImageAspectFlags srcAspectMask = srcFormatInfo->aspectMask;
+
+ if (planeCount > 1) {
+ dstAspectMask = vk::getPlaneAspect(j);
+ srcAspectMask = dstAspectMask;
+ }
+
+ if (dstIsImage) {
+ VkImageSubresourceLayers dstLayer = { dstAspectMask,
+ pDstLayers->mipLevel, pDstLayers->baseArrayLayer + i, 1 };
+
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cDstLayers = dstLayer,
+ cDstOffset = DstOffset,
+ cDstExtent = dstExtent,
+ cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource),
+ cSrcLayout = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource),
+ cSrcOffset = pSrcTexture->ComputeMappedOffset(srcSubresource, j, SrcOffset),
+ cSrcCoord = SrcOffset,
+ cSrcExtent = srcMipExtent,
+ cSrcFormat = pSrcTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyBufferToImage(cDstImage, cDstLayers, cDstOffset, cDstExtent,
+ cSrcBuffer, cSrcOffset, cSrcLayout.RowPitch, cSrcLayout.DepthPitch);
+ } else {
+ ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers,
+ VkOffset2D { cDstOffset.x, cDstOffset.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cSrcBuffer, cSrcLayout.Offset,
+ VkOffset2D { cSrcCoord.x, cSrcCoord.y },
+ VkExtent2D { cSrcExtent.width, cSrcExtent.height },
+ cSrcFormat);
+ }
+ });
+ } else if (srcIsImage) {
+ VkImageSubresourceLayers srcLayer = { srcAspectMask,
+ pSrcLayers->mipLevel, pSrcLayers->baseArrayLayer + i, 1 };
+
+ EmitCs([
+ cSrcImage = pSrcTexture->GetImage(),
+ cSrcLayers = srcLayer,
+ cSrcOffset = SrcOffset,
+ cSrcExtent = SrcExtent,
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstLayout = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource),
+ cDstOffset = pDstTexture->ComputeMappedOffset(dstSubresource, j, DstOffset),
+ cDstCoord = DstOffset,
+ cDstExtent = dstMipExtent,
+ cDstFormat = pDstTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cSrcLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyImageToBuffer(cDstBuffer, cDstOffset, cDstLayout.RowPitch,
+ cDstLayout.DepthPitch, cSrcImage, cSrcLayers, cSrcOffset, cSrcExtent);
+ } else {
+ ctx->copyDepthStencilImageToPackedBuffer(cDstBuffer, cDstLayout.Offset,
+ VkOffset2D { cDstCoord.x, cDstCoord.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cSrcImage, cSrcLayers,
+ VkOffset2D { cSrcOffset.x, cSrcOffset.y },
+ VkExtent2D { cSrcExtent.width, cSrcExtent.height },
+ cDstFormat);
+ }
+ });
+ } else {
+ // The backend is not aware of image metadata in this case,
+ // so we need to handle image planes and block sizes here
+ VkDeviceSize elementSize = dstFormatInfo->elementSize;
+ VkExtent3D dstBlockSize = dstFormatInfo->blockSize;
+ VkExtent3D srcBlockSize = srcFormatInfo->blockSize;
+ VkExtent3D planeBlockSize = { 1u, 1u, 1u };
+
+ if (planeCount > 1) {
+ auto plane = &dstFormatInfo->planes[j];
+ dstBlockSize.width *= plane->blockSize.width;
+ dstBlockSize.height *= plane->blockSize.height;
+ srcBlockSize.width *= plane->blockSize.width;
+ srcBlockSize.height *= plane->blockSize.height;
+
+ planeBlockSize.width = plane->blockSize.width;
+ planeBlockSize.height = plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ EmitCs([
+ cPixelSize = elementSize,
+ cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource),
+ cSrcStart = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource).Offset,
+ cSrcOffset = util::computeBlockOffset(SrcOffset, srcBlockSize),
+ cSrcSize = util::computeBlockCount(srcMipExtent, srcBlockSize),
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset,
+ cDstOffset = util::computeBlockOffset(DstOffset, dstBlockSize),
+ cDstSize = util::computeBlockCount(dstMipExtent, dstBlockSize),
+ cExtent = util::computeBlockCount(blockCount, planeBlockSize)
+ ] (DxvkContext* ctx) {
+ ctx->copyPackedBufferImage(
+ cDstBuffer, cDstStart, cDstOffset, cDstSize,
+ cSrcBuffer, cSrcStart, cSrcOffset, cSrcSize,
+ cExtent, cPixelSize);
+ });
+ }
+ }
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::DiscardBuffer(
+ ID3D11Resource* pResource) {
+ auto buffer = static_cast<D3D11Buffer*>(pResource);
+
+ if (buffer->GetMapMode() != D3D11_COMMON_BUFFER_MAP_MODE_NONE) {
+ D3D11_MAPPED_SUBRESOURCE sr;
+
+ Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr);
+ Unmap(pResource, 0);
+ }
+ }
+
+
+ void D3D11DeviceContext::DiscardTexture(
+ ID3D11Resource* pResource,
+ UINT Subresource) {
+ auto texture = GetCommonTexture(pResource);
+
+ if (texture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
+ D3D11_MAPPED_SUBRESOURCE sr;
+
+ Map(pResource, Subresource, D3D11_MAP_WRITE_DISCARD, 0, &sr);
+ Unmap(pResource, Subresource);
+ }
+ }
+
+
+ void D3D11DeviceContext::UpdateImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresource* pDstSubresource,
+ VkOffset3D DstOffset,
+ VkExtent3D DstExtent,
+ DxvkBufferSlice StagingBuffer) {
+ bool dstIsImage = pDstTexture->GetMapMode() != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+
+ if (dstIsImage) {
+ EmitCs([
+ cDstImage = pDstTexture->GetImage(),
+ cDstLayers = vk::makeSubresourceLayers(*pDstSubresource),
+ cDstOffset = DstOffset,
+ cDstExtent = DstExtent,
+ cStagingSlice = std::move(StagingBuffer),
+ cPackedFormat = pDstTexture->GetPackedFormat()
+ ] (DxvkContext* ctx) {
+ if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyBufferToImage(cDstImage,
+ cDstLayers, cDstOffset, cDstExtent,
+ cStagingSlice.buffer(),
+ cStagingSlice.offset(), 0, 0);
+ } else {
+ ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers,
+ VkOffset2D { cDstOffset.x, cDstOffset.y },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cStagingSlice.buffer(),
+ cStagingSlice.offset(),
+ VkOffset2D { 0, 0 },
+ VkExtent2D { cDstExtent.width, cDstExtent.height },
+ cPackedFormat);
+ }
+ });
+ } else {
+ // If the destination image is backed only by a buffer, we need to use
+ // the packed buffer copy function which does not know about planes and
+ // format metadata, so deal with it manually here.
+ VkExtent3D dstMipExtent = pDstTexture->MipLevelExtent(pDstSubresource->mipLevel);
+
+ uint32_t dstSubresource = D3D11CalcSubresource(pDstSubresource->mipLevel,
+ pDstSubresource->arrayLayer, pDstTexture->Desc()->MipLevels);
+
+ auto dstFormat = pDstTexture->GetPackedFormat();
+ auto dstFormatInfo = imageFormatInfo(dstFormat);
+
+ uint32_t planeCount = 1;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane))
+ planeCount = vk::getPlaneCount(dstFormatInfo->aspectMask);
+
+ // The source data isn't stored in an image so we'll also need to
+ // track the offset for that while iterating over the planes.
+ VkDeviceSize srcPlaneOffset = 0;
+
+ for (uint32_t i = 0; i < planeCount; i++) {
+ VkImageAspectFlags dstAspectMask = dstFormatInfo->aspectMask;
+ VkDeviceSize elementSize = dstFormatInfo->elementSize;
+ VkExtent3D blockSize = dstFormatInfo->blockSize;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ dstAspectMask = vk::getPlaneAspect(i);
+
+ auto plane = &dstFormatInfo->planes[i];
+ blockSize.width *= plane->blockSize.width;
+ blockSize.height *= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ VkExtent3D blockCount = util::computeBlockCount(DstExtent, blockSize);
+
+ EmitCs([
+ cDstBuffer = pDstTexture->GetMappedBuffer(dstSubresource),
+ cDstStart = pDstTexture->GetSubresourceLayout(dstAspectMask, dstSubresource).Offset,
+ cDstOffset = util::computeBlockOffset(DstOffset, blockSize),
+ cDstSize = util::computeBlockCount(dstMipExtent, blockSize),
+ cDstExtent = blockCount,
+ cSrcBuffer = StagingBuffer.buffer(),
+ cSrcStart = StagingBuffer.offset() + srcPlaneOffset,
+ cPixelSize = elementSize
+ ] (DxvkContext* ctx) {
+ ctx->copyPackedBufferImage(
+ cDstBuffer, cDstStart, cDstOffset, cDstSize,
+ cSrcBuffer, cSrcStart, VkOffset3D(), cDstExtent,
+ cDstExtent, cPixelSize);
+ });
+
+ srcPlaneOffset += util::flattenImageExtent(blockCount) * elementSize;
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::SetDrawBuffers(
+ ID3D11Buffer* pBufferForArgs,
+ ID3D11Buffer* pBufferForCount) {
+ auto argBuffer = static_cast<D3D11Buffer*>(pBufferForArgs);
+ auto cntBuffer = static_cast<D3D11Buffer*>(pBufferForCount);
+
+ if (m_state.id.argBuffer != argBuffer
+ || m_state.id.cntBuffer != cntBuffer) {
+ m_state.id.argBuffer = argBuffer;
+ m_state.id.cntBuffer = cntBuffer;
+
+ BindDrawBuffers(argBuffer, cntBuffer);
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers) {
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
+
+ UINT constantCount = 0;
+
+ if (likely(newBuffer != nullptr))
+ constantCount = std::min(newBuffer->Desc()->ByteWidth / 16, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT));
+
+ if (Bindings[StartSlot + i].buffer != newBuffer
+ || Bindings[StartSlot + i].constantCount != constantCount) {
+ Bindings[StartSlot + i].buffer = newBuffer;
+ Bindings[StartSlot + i].constantOffset = 0;
+ Bindings[StartSlot + i].constantCount = constantCount;
+ Bindings[StartSlot + i].constantBound = constantCount;
+
+ BindConstantBuffer(slotId + i, newBuffer, 0, constantCount);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetConstantBuffers1(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants) {
+ uint32_t slotId = computeConstantBufferBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ auto newBuffer = static_cast<D3D11Buffer*>(ppConstantBuffers[i]);
+
+ UINT constantOffset;
+ UINT constantCount;
+ UINT constantBound;
+
+ if (likely(newBuffer != nullptr)) {
+ UINT bufferConstantsCount = newBuffer->Desc()->ByteWidth / 16;
+ constantBound = std::min(bufferConstantsCount, UINT(D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT));
+
+ if (likely(pFirstConstant && pNumConstants)) {
+ constantOffset = pFirstConstant[i];
+ constantCount = pNumConstants [i];
+
+ if (unlikely(constantCount > D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT))
+ continue;
+
+ constantBound = (constantOffset + constantCount > bufferConstantsCount)
+ ? bufferConstantsCount - std::min(constantOffset, bufferConstantsCount)
+ : constantCount;
+ } else {
+ constantOffset = 0;
+ constantCount = constantBound;
+ }
+ } else {
+ constantOffset = 0;
+ constantCount = 0;
+ constantBound = 0;
+ }
+
+ bool needsUpdate = Bindings[StartSlot + i].buffer != newBuffer;
+
+ if (needsUpdate)
+ Bindings[StartSlot + i].buffer = newBuffer;
+
+ needsUpdate |= Bindings[StartSlot + i].constantOffset != constantOffset
+ || Bindings[StartSlot + i].constantCount != constantCount;
+
+ if (needsUpdate) {
+ Bindings[StartSlot + i].constantOffset = constantOffset;
+ Bindings[StartSlot + i].constantCount = constantCount;
+ Bindings[StartSlot + i].constantBound = constantBound;
+
+ BindConstantBuffer(slotId + i, newBuffer, constantOffset, constantBound);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetSamplers(
+ D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers) {
+ uint32_t slotId = computeSamplerBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ auto sampler = static_cast<D3D11SamplerState*>(ppSamplers[i]);
+
+ if (Bindings[StartSlot + i] != sampler) {
+ Bindings[StartSlot + i] = sampler;
+ BindSampler(slotId + i, sampler);
+ }
+ }
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ void D3D11DeviceContext::SetShaderResources(
+ D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumResources,
+ ID3D11ShaderResourceView* const* ppResources) {
+ uint32_t slotId = computeSrvBinding(ShaderStage, StartSlot);
+
+ for (uint32_t i = 0; i < NumResources; i++) {
+ auto resView = static_cast<D3D11ShaderResourceView*>(ppResources[i]);
+
+ if (Bindings.views[StartSlot + i] != resView) {
+ if (unlikely(resView && resView->TestHazards())) {
+ if (TestSrvHazards<ShaderStage>(resView))
+ resView = nullptr;
+
+ // Only set if necessary, but don't reset it on every
+ // bind as this would be more expensive than a few
+ // redundant checks in OMSetRenderTargets and friends.
+ Bindings.hazardous.set(StartSlot + i, resView);
+ }
+
+ Bindings.views[StartSlot + i] = resView;
+ BindShaderResource(slotId + i, resView);
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::GetConstantBuffers(
+ const D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants) {
+ for (uint32_t i = 0; i < NumBuffers; i++) {
+ const bool inRange = StartSlot + i < Bindings.size();
+
+ if (ppConstantBuffers != nullptr) {
+ ppConstantBuffers[i] = inRange
+ ? Bindings[StartSlot + i].buffer.ref()
+ : nullptr;
+ }
+
+ if (pFirstConstant != nullptr) {
+ pFirstConstant[i] = inRange
+ ? Bindings[StartSlot + i].constantOffset
+ : 0u;
+ }
+
+ if (pNumConstants != nullptr) {
+ pNumConstants[i] = inRange
+ ? Bindings[StartSlot + i].constantCount
+ : 0u;
+ }
+ }
+ }
+
+
+ void D3D11DeviceContext::GetShaderResources(
+ const D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews) {
+ for (uint32_t i = 0; i < NumViews; i++) {
+ ppShaderResourceViews[i] = StartSlot + i < Bindings.views.size()
+ ? Bindings.views[StartSlot + i].ref()
+ : nullptr;
+ }
+ }
+
+
+ void D3D11DeviceContext::GetSamplers(
+ const D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers) {
+ for (uint32_t i = 0; i < NumSamplers; i++) {
+ ppSamplers[i] = StartSlot + i < Bindings.size()
+ ? ref(Bindings[StartSlot + i])
+ : nullptr;
+ }
+ }
+
+
+ void D3D11DeviceContext::ResetState() {
+ EmitCs([] (DxvkContext* ctx) {
+ // Reset render targets
+ ctx->bindRenderTargets(DxvkRenderTargets());
+
+ // Reset vertex input state
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+
+ // Reset render states
+ DxvkInputAssemblyState iaState;
+ InitDefaultPrimitiveTopology(&iaState);
+
+ DxvkDepthStencilState dsState;
+ InitDefaultDepthStencilState(&dsState);
+
+ DxvkRasterizerState rsState;
+ InitDefaultRasterizerState(&rsState);
+
+ DxvkBlendMode cbState;
+ DxvkLogicOpState loState;
+ DxvkMultisampleState msState;
+ InitDefaultBlendState(&cbState, &loState, &msState, D3D11_DEFAULT_SAMPLE_MASK);
+
+ ctx->setInputAssemblyState(iaState);
+ ctx->setDepthStencilState(dsState);
+ ctx->setRasterizerState(rsState);
+ ctx->setLogicOpState(loState);
+ ctx->setMultisampleState(msState);
+
+ for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ ctx->setBlendMode(i, cbState);
+
+ // Reset dynamic states
+ ctx->setBlendConstants(DxvkBlendConstants { 1.0f, 1.0f, 1.0f, 1.0f });
+ ctx->setStencilReference(D3D11_DEFAULT_STENCIL_REFERENCE);
+
+ // Reset viewports
+ auto viewport = VkViewport();
+ auto scissor = VkRect2D();
+
+ ctx->setViewports(1, &viewport, &scissor);
+
+ // Unbind indirect draw buffer
+ ctx->bindDrawBuffers(DxvkBufferSlice(), DxvkBufferSlice());
+
+ // Unbind index and vertex buffers
+ ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
+
+ for (uint32_t i = 0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++)
+ ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0);
+
+ // Unbind transform feedback buffers
+ for (uint32_t i = 0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++)
+ ctx->bindXfbBuffer(i, DxvkBufferSlice(), DxvkBufferSlice());
+
+ // Unbind per-shader stage resources
+ for (uint32_t i = 0; i < 6; i++) {
+ auto programType = DxbcProgramType(i);
+ ctx->bindShader(GetShaderStage(programType), nullptr);
+
+ // Unbind constant buffers, including the shader's ICB
+ auto cbSlotId = computeConstantBufferBinding(programType, 0);
+
+ for (uint32_t j = 0; j <= D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; j++)
+ ctx->bindResourceBuffer(cbSlotId + j, DxvkBufferSlice());
+
+ // Unbind shader resource views
+ auto srvSlotId = computeSrvBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; j++)
+ ctx->bindResourceView(srvSlotId + j, nullptr, nullptr);
+
+ // Unbind texture samplers
+ auto samplerSlotId = computeSamplerBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; j++)
+ ctx->bindResourceSampler(samplerSlotId + j, nullptr);
+
+ // Unbind UAVs for supported stages
+ if (programType == DxbcProgramType::PixelShader
+ || programType == DxbcProgramType::ComputeShader) {
+ auto uavSlotId = computeUavBinding(programType, 0);
+ auto ctrSlotId = computeUavCounterBinding(programType, 0);
+
+ for (uint32_t j = 0; j < D3D11_1_UAV_SLOT_COUNT; j++) {
+ ctx->bindResourceView (uavSlotId, nullptr, nullptr);
+ ctx->bindResourceBuffer (ctrSlotId, DxvkBufferSlice());
+ }
+ }
+ }
+ });
+ }
+
+
+ void D3D11DeviceContext::RestoreState() {
+ BindFramebuffer();
+
+ BindShader<DxbcProgramType::VertexShader> (GetCommonShader(m_state.vs.shader.ptr()));
+ BindShader<DxbcProgramType::HullShader> (GetCommonShader(m_state.hs.shader.ptr()));
+ BindShader<DxbcProgramType::DomainShader> (GetCommonShader(m_state.ds.shader.ptr()));
+ BindShader<DxbcProgramType::GeometryShader> (GetCommonShader(m_state.gs.shader.ptr()));
+ BindShader<DxbcProgramType::PixelShader> (GetCommonShader(m_state.ps.shader.ptr()));
+ BindShader<DxbcProgramType::ComputeShader> (GetCommonShader(m_state.cs.shader.ptr()));
+
+ ApplyInputLayout();
+ ApplyPrimitiveTopology();
+ ApplyBlendState();
+ ApplyBlendFactor();
+ ApplyDepthStencilState();
+ ApplyStencilRef();
+ ApplyRasterizerState();
+ ApplyViewportState();
+
+ BindDrawBuffers(
+ m_state.id.argBuffer.ptr(),
+ m_state.id.cntBuffer.ptr());
+
+ BindIndexBuffer(
+ m_state.ia.indexBuffer.buffer.ptr(),
+ m_state.ia.indexBuffer.offset,
+ m_state.ia.indexBuffer.format);
+
+ for (uint32_t i = 0; i < m_state.ia.vertexBuffers.size(); i++) {
+ BindVertexBuffer(i,
+ m_state.ia.vertexBuffers[i].buffer.ptr(),
+ m_state.ia.vertexBuffers[i].offset,
+ m_state.ia.vertexBuffers[i].stride);
+ }
+
+ for (uint32_t i = 0; i < m_state.so.targets.size(); i++)
+ BindXfbBuffer(i, m_state.so.targets[i].buffer.ptr(), ~0u);
+
+ RestoreConstantBuffers<DxbcProgramType::VertexShader> (m_state.vs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::HullShader> (m_state.hs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::DomainShader> (m_state.ds.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::GeometryShader> (m_state.gs.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::PixelShader> (m_state.ps.constantBuffers);
+ RestoreConstantBuffers<DxbcProgramType::ComputeShader> (m_state.cs.constantBuffers);
+
+ RestoreSamplers<DxbcProgramType::VertexShader> (m_state.vs.samplers);
+ RestoreSamplers<DxbcProgramType::HullShader> (m_state.hs.samplers);
+ RestoreSamplers<DxbcProgramType::DomainShader> (m_state.ds.samplers);
+ RestoreSamplers<DxbcProgramType::GeometryShader>(m_state.gs.samplers);
+ RestoreSamplers<DxbcProgramType::PixelShader> (m_state.ps.samplers);
+ RestoreSamplers<DxbcProgramType::ComputeShader> (m_state.cs.samplers);
+
+ RestoreShaderResources<DxbcProgramType::VertexShader> (m_state.vs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::HullShader> (m_state.hs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::DomainShader> (m_state.ds.shaderResources);
+ RestoreShaderResources<DxbcProgramType::GeometryShader> (m_state.gs.shaderResources);
+ RestoreShaderResources<DxbcProgramType::PixelShader> (m_state.ps.shaderResources);
+ RestoreShaderResources<DxbcProgramType::ComputeShader> (m_state.cs.shaderResources);
+
+ RestoreUnorderedAccessViews<DxbcProgramType::PixelShader> (m_state.ps.unorderedAccessViews);
+ RestoreUnorderedAccessViews<DxbcProgramType::ComputeShader> (m_state.cs.unorderedAccessViews);
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings) {
+ uint32_t slotId = computeConstantBufferBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++) {
+ BindConstantBuffer(slotId + i, Bindings[i].buffer.ptr(),
+ Bindings[i].constantOffset, Bindings[i].constantBound);
+ }
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreSamplers(
+ D3D11SamplerBindings& Bindings) {
+ uint32_t slotId = computeSamplerBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++)
+ BindSampler(slotId + i, Bindings[i]);
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreShaderResources(
+ D3D11ShaderResourceBindings& Bindings) {
+ uint32_t slotId = computeSrvBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.views.size(); i++)
+ BindShaderResource(slotId + i, Bindings.views[i].ptr());
+ }
+
+
+ template<DxbcProgramType Stage>
+ void D3D11DeviceContext::RestoreUnorderedAccessViews(
+ D3D11UnorderedAccessBindings& Bindings) {
+ uint32_t uavSlotId = computeUavBinding (Stage, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(Stage, 0);
+
+ for (uint32_t i = 0; i < Bindings.size(); i++) {
+ BindUnorderedAccessView(
+ uavSlotId + i,
+ Bindings[i].ptr(),
+ ctrSlotId + i, ~0u);
+ }
+ }
+
+
+ bool D3D11DeviceContext::TestRtvUavHazards(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRTVs,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUAVs) {
+ if (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) NumRTVs = 0;
+ if (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) NumUAVs = 0;
+
+ for (uint32_t i = 0; i < NumRTVs; i++) {
+ auto rtv = static_cast<D3D11RenderTargetView*>(ppRTVs[i]);
+
+ if (!rtv)
+ continue;
+
+ for (uint32_t j = 0; j < i; j++) {
+ if (CheckViewOverlap(rtv, static_cast<D3D11RenderTargetView*>(ppRTVs[j])))
+ return true;
+ }
+
+ if (rtv->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS)) {
+ for (uint32_t j = 0; j < NumUAVs; j++) {
+ if (CheckViewOverlap(rtv, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j])))
+ return true;
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < NumUAVs; i++) {
+ auto uav = static_cast<D3D11UnorderedAccessView*>(ppUAVs[i]);
+
+ if (!uav)
+ continue;
+
+ for (uint32_t j = 0; j < i; j++) {
+ if (CheckViewOverlap(uav, static_cast<D3D11UnorderedAccessView*>(ppUAVs[j])))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ template<DxbcProgramType ShaderStage>
+ bool D3D11DeviceContext::TestSrvHazards(
+ D3D11ShaderResourceView* pView) {
+ bool hazard = false;
+
+ if (ShaderStage == DxbcProgramType::ComputeShader) {
+ int32_t uav = m_state.cs.uavMask.findNext(0);
+
+ while (uav >= 0 && !hazard) {
+ hazard = CheckViewOverlap(pView, m_state.cs.unorderedAccessViews[uav].ptr());
+ uav = m_state.cs.uavMask.findNext(uav + 1);
+ }
+ } else {
+ hazard = CheckViewOverlap(pView, m_state.om.depthStencilView.ptr());
+
+ for (uint32_t i = 0; !hazard && i < m_state.om.maxRtv; i++)
+ hazard = CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr());
+
+ for (uint32_t i = 0; !hazard && i < m_state.om.maxUav; i++)
+ hazard = CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr());
+ }
+
+ return hazard;
+ }
+
+
+ template<DxbcProgramType ShaderStage, typename T>
+ void D3D11DeviceContext::ResolveSrvHazards(
+ T* pView,
+ D3D11ShaderResourceBindings& Bindings) {
+ uint32_t slotId = computeSrvBinding(ShaderStage, 0);
+ int32_t srvId = Bindings.hazardous.findNext(0);
+
+ while (srvId >= 0) {
+ auto srv = Bindings.views[srvId].ptr();
+
+ if (likely(srv && srv->TestHazards())) {
+ bool hazard = CheckViewOverlap(pView, srv);
+
+ if (unlikely(hazard)) {
+ Bindings.views[srvId] = nullptr;
+ Bindings.hazardous.clr(srvId);
+
+ BindShaderResource(slotId + srvId, nullptr);
+ }
+ } else {
+ // Avoid further redundant iterations
+ Bindings.hazardous.clr(srvId);
+ }
+
+ srvId = Bindings.hazardous.findNext(srvId + 1);
+ }
+ }
+
+
+ template<typename T>
+ void D3D11DeviceContext::ResolveCsSrvHazards(
+ T* pView) {
+ if (!pView) return;
+ ResolveSrvHazards<DxbcProgramType::ComputeShader> (pView, m_state.cs.shaderResources);
+ }
+
+
+ template<typename T>
+ void D3D11DeviceContext::ResolveOmSrvHazards(
+ T* pView) {
+ if (!pView) return;
+ ResolveSrvHazards<DxbcProgramType::VertexShader> (pView, m_state.vs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::HullShader> (pView, m_state.hs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::DomainShader> (pView, m_state.ds.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::GeometryShader> (pView, m_state.gs.shaderResources);
+ ResolveSrvHazards<DxbcProgramType::PixelShader> (pView, m_state.ps.shaderResources);
+ }
+
+
+ bool D3D11DeviceContext::ResolveOmRtvHazards(
+ D3D11UnorderedAccessView* pView) {
+ if (!pView || !pView->HasBindFlag(D3D11_BIND_RENDER_TARGET))
+ return false;
+
+ bool hazard = false;
+
+ if (CheckViewOverlap(pView, m_state.om.depthStencilView.ptr())) {
+ m_state.om.depthStencilView = nullptr;
+ hazard = true;
+ }
+
+ for (uint32_t i = 0; i < m_state.om.maxRtv; i++) {
+ if (CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr())) {
+ m_state.om.renderTargetViews[i] = nullptr;
+ hazard = true;
+ }
+ }
+
+ return hazard;
+ }
+
+
+ void D3D11DeviceContext::ResolveOmUavHazards(
+ D3D11RenderTargetView* pView) {
+ if (!pView || !pView->HasBindFlag(D3D11_BIND_UNORDERED_ACCESS))
+ return;
+
+ uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0);
+ uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0);
+
+ for (uint32_t i = 0; i < m_state.om.maxUav; i++) {
+ if (CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr())) {
+ m_state.ps.unorderedAccessViews[i] = nullptr;
+
+ BindUnorderedAccessView(
+ uavSlotId + i, nullptr,
+ ctrSlotId + i, ~0u);
+ }
+ }
+ }
+
+
+ bool D3D11DeviceContext::ValidateRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView) {
+ Rc<DxvkImageView> refView;
+
+ if (pDepthStencilView != nullptr) {
+ refView = static_cast<D3D11DepthStencilView*>(
+ pDepthStencilView)->GetImageView();
+ }
+
+ for (uint32_t i = 0; i < NumViews; i++) {
+ if (ppRenderTargetViews[i] != nullptr) {
+ auto curView = static_cast<D3D11RenderTargetView*>(
+ ppRenderTargetViews[i])->GetImageView();
+
+ if (refView != nullptr) {
+ // Render target views must all have the same
+ // size, sample count, layer count, and type
+ if (curView->info().type != refView->info().type
+ || curView->info().numLayers != refView->info().numLayers)
+ return false;
+
+ if (curView->imageInfo().sampleCount
+ != refView->imageInfo().sampleCount)
+ return false;
+ } else {
+ // Set reference view. All remaining views
+ // must be compatible to the reference view.
+ refView = curView;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ VkClearValue D3D11DeviceContext::ConvertColorValue(
+ const FLOAT Color[4],
+ const DxvkFormatInfo* pFormatInfo) {
+ VkClearValue result;
+
+ if (pFormatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
+ for (uint32_t i = 0; i < 4; i++) {
+ if (pFormatInfo->flags.test(DxvkFormatFlag::SampledUInt))
+ result.color.uint32[i] = uint32_t(std::max(0.0f, Color[i]));
+ else if (pFormatInfo->flags.test(DxvkFormatFlag::SampledSInt))
+ result.color.int32[i] = int32_t(Color[i]);
+ else
+ result.color.float32[i] = Color[i];
+ }
+ } else {
+ result.depthStencil.depth = Color[0];
+ result.depthStencil.stencil = 0;
+ }
+
+ return result;
+ }
+
+
+ DxvkDataSlice D3D11DeviceContext::AllocUpdateBufferSlice(size_t Size) {
+ constexpr size_t UpdateBufferSize = 16 * 1024 * 1024;
+
+ if (Size >= UpdateBufferSize) {
+ Rc<DxvkDataBuffer> buffer = new DxvkDataBuffer(Size);
+ return buffer->alloc(Size);
+ } else {
+ if (m_updateBuffer == nullptr)
+ m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize);
+
+ DxvkDataSlice slice = m_updateBuffer->alloc(Size);
+
+ if (slice.ptr() == nullptr) {
+ m_updateBuffer = new DxvkDataBuffer(UpdateBufferSize);
+ slice = m_updateBuffer->alloc(Size);
+ }
+
+ return slice;
+ }
+ }
+
+
+ DxvkBufferSlice D3D11DeviceContext::AllocStagingBuffer(
+ VkDeviceSize Size) {
+ DxvkBufferCreateInfo info;
+ info.size = Size;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
+ | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+
+ return DxvkBufferSlice(m_device->createBuffer(info,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
+ }
+
+
+ DxvkCsChunkRef D3D11DeviceContext::AllocCsChunk() {
+ return m_parent->AllocCsChunk(m_csFlags);
+ }
+
+
+ void D3D11DeviceContext::InitDefaultPrimitiveTopology(
+ DxvkInputAssemblyState* pIaState) {
+ pIaState->primitiveTopology = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
+ pIaState->primitiveRestart = VK_FALSE;
+ pIaState->patchVertexCount = 0;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultRasterizerState(
+ DxvkRasterizerState* pRsState) {
+ pRsState->polygonMode = VK_POLYGON_MODE_FILL;
+ pRsState->cullMode = VK_CULL_MODE_BACK_BIT;
+ pRsState->frontFace = VK_FRONT_FACE_CLOCKWISE;
+ pRsState->depthClipEnable = VK_TRUE;
+ pRsState->depthBiasEnable = VK_FALSE;
+ pRsState->conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ pRsState->sampleCount = 0;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultDepthStencilState(
+ DxvkDepthStencilState* pDsState) {
+ VkStencilOpState stencilOp;
+ stencilOp.failOp = VK_STENCIL_OP_KEEP;
+ stencilOp.passOp = VK_STENCIL_OP_KEEP;
+ stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
+ stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
+ stencilOp.compareMask = D3D11_DEFAULT_STENCIL_READ_MASK;
+ stencilOp.writeMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
+ stencilOp.reference = 0;
+
+ pDsState->enableDepthTest = VK_TRUE;
+ pDsState->enableDepthWrite = VK_TRUE;
+ pDsState->enableStencilTest = VK_FALSE;
+ pDsState->depthCompareOp = VK_COMPARE_OP_LESS;
+ pDsState->stencilOpFront = stencilOp;
+ pDsState->stencilOpBack = stencilOp;
+ }
+
+
+ void D3D11DeviceContext::InitDefaultBlendState(
+ DxvkBlendMode* pCbState,
+ DxvkLogicOpState* pLoState,
+ DxvkMultisampleState* pMsState,
+ UINT SampleMask) {
+ pCbState->enableBlending = VK_FALSE;
+ pCbState->colorSrcFactor = VK_BLEND_FACTOR_ONE;
+ pCbState->colorDstFactor = VK_BLEND_FACTOR_ZERO;
+ pCbState->colorBlendOp = VK_BLEND_OP_ADD;
+ pCbState->alphaSrcFactor = VK_BLEND_FACTOR_ONE;
+ pCbState->alphaDstFactor = VK_BLEND_FACTOR_ZERO;
+ pCbState->alphaBlendOp = VK_BLEND_OP_ADD;
+ pCbState->writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ pLoState->enableLogicOp = VK_FALSE;
+ pLoState->logicOp = VK_LOGIC_OP_NO_OP;
+
+ pMsState->sampleMask = SampleMask;
+ pMsState->enableAlphaToCoverage = VK_FALSE;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h
new file mode 100644
index 00000000..483b0415
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context.h
@@ -0,0 +1,1011 @@
+#pragma once
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_cs.h"
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_multithread.h"
+
+#include "d3d11_annotation.h"
+#include "d3d11_cmd.h"
+#include "d3d11_context_ext.h"
+#include "d3d11_context_state.h"
+#include "d3d11_device_child.h"
+#include "d3d11_texture.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11DeviceContext : public D3D11DeviceChild<ID3D11DeviceContext4> {
+ friend class D3D11DeviceContextExt;
+ // Needed in order to call EmitCs for pushing markers
+ friend class D3D11UserDefinedAnnotation;
+ public:
+
+ D3D11DeviceContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device,
+ DxvkCsChunkFlags CsFlags);
+ ~D3D11DeviceContext();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE DiscardResource(ID3D11Resource *pResource);
+
+ void STDMETHODCALLTYPE DiscardView(ID3D11View* pResourceView);
+
+ void STDMETHODCALLTYPE DiscardView1(
+ ID3D11View* pResourceView,
+ const D3D11_RECT* pRects,
+ UINT NumRects);
+
+ void STDMETHODCALLTYPE ClearState();
+
+ void STDMETHODCALLTYPE SetPredication(
+ ID3D11Predicate* pPredicate,
+ BOOL PredicateValue);
+
+ void STDMETHODCALLTYPE GetPredication(
+ ID3D11Predicate** ppPredicate,
+ BOOL* pPredicateValue);
+
+ void STDMETHODCALLTYPE CopySubresourceRegion(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox);
+
+ void STDMETHODCALLTYPE CopySubresourceRegion1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ UINT DstX,
+ UINT DstY,
+ UINT DstZ,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox,
+ UINT CopyFlags);
+
+ void STDMETHODCALLTYPE CopyResource(
+ ID3D11Resource* pDstResource,
+ ID3D11Resource* pSrcResource);
+
+ void STDMETHODCALLTYPE CopyStructureCount(
+ ID3D11Buffer* pDstBuffer,
+ UINT DstAlignedByteOffset,
+ ID3D11UnorderedAccessView* pSrcView);
+
+ void STDMETHODCALLTYPE CopyTiles(
+ ID3D11Resource* pTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ ID3D11Buffer* pBuffer,
+ UINT64 BufferStartOffsetInBytes,
+ UINT Flags);
+
+ HRESULT STDMETHODCALLTYPE CopyTileMappings(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestRegionStartCoordinate,
+ ID3D11Resource* pSourceTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pSourceRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pTileRegionSize,
+ UINT Flags);
+
+ HRESULT STDMETHODCALLTYPE ResizeTilePool(
+ ID3D11Buffer* pTilePool,
+ UINT64 NewSizeInBytes);
+
+ void STDMETHODCALLTYPE TiledResourceBarrier(
+ ID3D11DeviceChild* pTiledResourceOrViewAccessBeforeBarrier,
+ ID3D11DeviceChild* pTiledResourceOrViewAccessAfterBarrier);
+
+ void STDMETHODCALLTYPE ClearRenderTargetView(
+ ID3D11RenderTargetView* pRenderTargetView,
+ const FLOAT ColorRGBA[4]);
+
+ void STDMETHODCALLTYPE ClearUnorderedAccessViewUint(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const UINT Values[4]);
+
+ void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat(
+ ID3D11UnorderedAccessView* pUnorderedAccessView,
+ const FLOAT Values[4]);
+
+ void STDMETHODCALLTYPE ClearDepthStencilView(
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT ClearFlags,
+ FLOAT Depth,
+ UINT8 Stencil);
+
+ void STDMETHODCALLTYPE ClearView(
+ ID3D11View *pView,
+ const FLOAT Color[4],
+ const D3D11_RECT *pRect,
+ UINT NumRects);
+
+ void STDMETHODCALLTYPE GenerateMips(
+ ID3D11ShaderResourceView* pShaderResourceView);
+
+ void STDMETHODCALLTYPE UpdateSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch);
+
+ void STDMETHODCALLTYPE UpdateSubresource1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch,
+ UINT CopyFlags);
+
+ HRESULT STDMETHODCALLTYPE UpdateTileMappings(
+ ID3D11Resource* pTiledResource,
+ UINT NumTiledResourceRegions,
+ const D3D11_TILED_RESOURCE_COORDINATE* pTiledResourceRegionStartCoordinates,
+ const D3D11_TILE_REGION_SIZE* pTiledResourceRegionSizes,
+ ID3D11Buffer* pTilePool,
+ UINT NumRanges,
+ const UINT* pRangeFlags,
+ const UINT* pTilePoolStartOffsets,
+ const UINT* pRangeTileCounts,
+ UINT Flags);
+
+ void STDMETHODCALLTYPE UpdateTiles(
+ ID3D11Resource* pDestTiledResource,
+ const D3D11_TILED_RESOURCE_COORDINATE* pDestTileRegionStartCoordinate,
+ const D3D11_TILE_REGION_SIZE* pDestTileRegionSize,
+ const void* pSourceTileData,
+ UINT Flags);
+
+ void STDMETHODCALLTYPE SetResourceMinLOD(
+ ID3D11Resource* pResource,
+ FLOAT MinLOD);
+
+ FLOAT STDMETHODCALLTYPE GetResourceMinLOD(
+ ID3D11Resource* pResource);
+
+ void STDMETHODCALLTYPE ResolveSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ DXGI_FORMAT Format);
+
+ void STDMETHODCALLTYPE DrawAuto();
+
+ void STDMETHODCALLTYPE Draw(
+ UINT VertexCount,
+ UINT StartVertexLocation);
+
+ void STDMETHODCALLTYPE DrawIndexed(
+ UINT IndexCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation);
+
+ void STDMETHODCALLTYPE DrawInstanced(
+ UINT VertexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartVertexLocation,
+ UINT StartInstanceLocation);
+
+ void STDMETHODCALLTYPE DrawIndexedInstanced(
+ UINT IndexCountPerInstance,
+ UINT InstanceCount,
+ UINT StartIndexLocation,
+ INT BaseVertexLocation,
+ UINT StartInstanceLocation);
+
+ void STDMETHODCALLTYPE DrawIndexedInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs);
+
+ void STDMETHODCALLTYPE DrawInstancedIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs);
+
+ void STDMETHODCALLTYPE Dispatch(
+ UINT ThreadGroupCountX,
+ UINT ThreadGroupCountY,
+ UINT ThreadGroupCountZ);
+
+ void STDMETHODCALLTYPE DispatchIndirect(
+ ID3D11Buffer* pBufferForArgs,
+ UINT AlignedByteOffsetForArgs);
+
+ void STDMETHODCALLTYPE IASetInputLayout(
+ ID3D11InputLayout* pInputLayout);
+
+ void STDMETHODCALLTYPE IASetPrimitiveTopology(
+ D3D11_PRIMITIVE_TOPOLOGY Topology);
+
+ void STDMETHODCALLTYPE IASetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppVertexBuffers,
+ const UINT* pStrides,
+ const UINT* pOffsets);
+
+ void STDMETHODCALLTYPE IASetIndexBuffer(
+ ID3D11Buffer* pIndexBuffer,
+ DXGI_FORMAT Format,
+ UINT Offset);
+
+ void STDMETHODCALLTYPE IAGetInputLayout(
+ ID3D11InputLayout** ppInputLayout);
+
+ void STDMETHODCALLTYPE IAGetPrimitiveTopology(
+ D3D11_PRIMITIVE_TOPOLOGY* pTopology);
+
+ void STDMETHODCALLTYPE IAGetVertexBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppVertexBuffers,
+ UINT* pStrides,
+ UINT* pOffsets);
+
+ void STDMETHODCALLTYPE IAGetIndexBuffer(
+ ID3D11Buffer** ppIndexBuffer,
+ DXGI_FORMAT* pFormat,
+ UINT* pOffset);
+
+ void STDMETHODCALLTYPE VSSetShader(
+ ID3D11VertexShader* pVertexShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE VSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE VSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE VSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE VSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE VSGetShader(
+ ID3D11VertexShader** ppVertexShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE VSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE VSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE VSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE VSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE HSSetShader(
+ ID3D11HullShader* pHullShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE HSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE HSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE HSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE HSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE HSGetShader(
+ ID3D11HullShader** ppHullShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE HSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE HSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE HSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE HSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE DSSetShader(
+ ID3D11DomainShader* pDomainShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE DSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE DSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE DSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE DSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE DSGetShader(
+ ID3D11DomainShader** ppDomainShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE DSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE DSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE DSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE DSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE GSSetShader(
+ ID3D11GeometryShader* pShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE GSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE GSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE GSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE GSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE GSGetShader(
+ ID3D11GeometryShader** ppGeometryShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE GSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE GSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE GSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE GSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE PSSetShader(
+ ID3D11PixelShader* pPixelShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE PSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE PSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE PSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE PSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE PSGetShader(
+ ID3D11PixelShader** ppPixelShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE PSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE PSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE PSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE PSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE CSSetShader(
+ ID3D11ComputeShader* pComputeShader,
+ ID3D11ClassInstance* const* ppClassInstances,
+ UINT NumClassInstances);
+
+ void STDMETHODCALLTYPE CSSetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ void STDMETHODCALLTYPE CSSetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE CSSetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView* const* ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE CSSetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ void STDMETHODCALLTYPE CSSetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts);
+
+ void STDMETHODCALLTYPE CSGetShader(
+ ID3D11ComputeShader** ppComputeShader,
+ ID3D11ClassInstance** ppClassInstances,
+ UINT* pNumClassInstances);
+
+ void STDMETHODCALLTYPE CSGetConstantBuffers(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers);
+
+ void STDMETHODCALLTYPE CSGetConstantBuffers1(
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void STDMETHODCALLTYPE CSGetShaderResources(
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void STDMETHODCALLTYPE CSGetSamplers(
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void STDMETHODCALLTYPE CSGetUnorderedAccessViews(
+ UINT StartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews);
+
+ void STDMETHODCALLTYPE OMSetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView);
+
+ void STDMETHODCALLTYPE OMSetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts);
+
+ void STDMETHODCALLTYPE OMSetBlendState(
+ ID3D11BlendState* pBlendState,
+ const FLOAT BlendFactor[4],
+ UINT SampleMask);
+
+ void STDMETHODCALLTYPE OMSetDepthStencilState(
+ ID3D11DepthStencilState* pDepthStencilState,
+ UINT StencilRef);
+
+ void STDMETHODCALLTYPE OMGetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView);
+
+ void STDMETHODCALLTYPE OMGetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView** ppRenderTargetViews,
+ ID3D11DepthStencilView** ppDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView** ppUnorderedAccessViews);
+
+ void STDMETHODCALLTYPE OMGetBlendState(
+ ID3D11BlendState** ppBlendState,
+ FLOAT BlendFactor[4],
+ UINT* pSampleMask);
+
+ void STDMETHODCALLTYPE OMGetDepthStencilState(
+ ID3D11DepthStencilState** ppDepthStencilState,
+ UINT* pStencilRef);
+
+ void STDMETHODCALLTYPE RSSetState(
+ ID3D11RasterizerState* pRasterizerState);
+
+ void STDMETHODCALLTYPE RSSetViewports(
+ UINT NumViewports,
+ const D3D11_VIEWPORT* pViewports);
+
+ void STDMETHODCALLTYPE RSSetScissorRects(
+ UINT NumRects,
+ const D3D11_RECT* pRects);
+
+ void STDMETHODCALLTYPE RSGetState(
+ ID3D11RasterizerState** ppRasterizerState);
+
+ void STDMETHODCALLTYPE RSGetViewports(
+ UINT* pNumViewports,
+ D3D11_VIEWPORT* pViewports);
+
+ void STDMETHODCALLTYPE RSGetScissorRects(
+ UINT* pNumRects,
+ D3D11_RECT* pRects);
+
+ void STDMETHODCALLTYPE SOSetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppSOTargets,
+ const UINT* pOffsets);
+
+ void STDMETHODCALLTYPE SOGetTargets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets);
+
+ void STDMETHODCALLTYPE SOGetTargetsWithOffsets(
+ UINT NumBuffers,
+ ID3D11Buffer** ppSOTargets,
+ UINT* pOffsets);
+
+ BOOL STDMETHODCALLTYPE IsAnnotationEnabled();
+
+ void STDMETHODCALLTYPE SetMarkerInt(
+ LPCWSTR pLabel,
+ INT Data);
+
+ void STDMETHODCALLTYPE BeginEventInt(
+ LPCWSTR pLabel,
+ INT Data);
+
+ void STDMETHODCALLTYPE EndEvent();
+
+ void STDMETHODCALLTYPE GetHardwareProtectionState(
+ BOOL* pHwProtectionEnable);
+
+ void STDMETHODCALLTYPE SetHardwareProtectionState(
+ BOOL HwProtectionEnable);
+
+ void STDMETHODCALLTYPE TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout);
+
+ D3D10DeviceLock LockContext() {
+ return m_multithread.AcquireLock();
+ }
+
+ protected:
+
+ D3D11DeviceContextExt m_contextExt;
+ D3D11UserDefinedAnnotation m_annotation;
+ D3D10Multithread m_multithread;
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkDataBuffer> m_updateBuffer;
+
+ DxvkCsChunkFlags m_csFlags;
+ DxvkCsChunkRef m_csChunk;
+
+ D3D11ContextState m_state;
+ D3D11CmdData* m_cmdData;
+
+ void ApplyInputLayout();
+
+ void ApplyPrimitiveTopology();
+
+ void ApplyBlendState();
+
+ void ApplyBlendFactor();
+
+ void ApplyDepthStencilState();
+
+ void ApplyStencilRef();
+
+ void ApplyRasterizerState();
+
+ void ApplyViewportState();
+
+ template<DxbcProgramType ShaderStage>
+ void BindShader(
+ const D3D11CommonShader* pShaderModule);
+
+ void BindFramebuffer();
+
+ void BindDrawBuffers(
+ D3D11Buffer* pBufferForArgs,
+ D3D11Buffer* pBufferForCount);
+
+ void BindVertexBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Stride);
+
+ void BindIndexBuffer(
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ DXGI_FORMAT Format);
+
+ void BindXfbBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset);
+
+ void BindConstantBuffer(
+ UINT Slot,
+ D3D11Buffer* pBuffer,
+ UINT Offset,
+ UINT Length);
+
+ void BindSampler(
+ UINT Slot,
+ D3D11SamplerState* pSampler);
+
+ void BindShaderResource(
+ UINT Slot,
+ D3D11ShaderResourceView* pResource);
+
+ void BindUnorderedAccessView(
+ UINT UavSlot,
+ D3D11UnorderedAccessView* pUav,
+ UINT CtrSlot,
+ UINT Counter);
+
+ void CopyBuffer(
+ D3D11Buffer* pDstBuffer,
+ VkDeviceSize DstOffset,
+ D3D11Buffer* pSrcBuffer,
+ VkDeviceSize SrcOffset,
+ VkDeviceSize ByteCount);
+
+ void CopyImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresourceLayers* pDstLayers,
+ VkOffset3D DstOffset,
+ D3D11CommonTexture* pSrcTexture,
+ const VkImageSubresourceLayers* pSrcLayers,
+ VkOffset3D SrcOffset,
+ VkExtent3D SrcExtent);
+
+ void DiscardBuffer(
+ ID3D11Resource* pResource);
+
+ void DiscardTexture(
+ ID3D11Resource* pResource,
+ UINT Subresource);
+
+ void UpdateImage(
+ D3D11CommonTexture* pDstTexture,
+ const VkImageSubresource* pDstSubresource,
+ VkOffset3D DstOffset,
+ VkExtent3D DstExtent,
+ DxvkBufferSlice StagingBuffer);
+
+ void SetDrawBuffers(
+ ID3D11Buffer* pBufferForArgs,
+ ID3D11Buffer* pBufferForCount);
+
+ template<DxbcProgramType ShaderStage>
+ void SetConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers);
+
+ template<DxbcProgramType ShaderStage>
+ void SetConstantBuffers1(
+ D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer* const* ppConstantBuffers,
+ const UINT* pFirstConstant,
+ const UINT* pNumConstants);
+
+ template<DxbcProgramType ShaderStage>
+ void SetSamplers(
+ D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState* const* ppSamplers);
+
+ template<DxbcProgramType ShaderStage>
+ void SetShaderResources(
+ D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumResources,
+ ID3D11ShaderResourceView* const* ppResources);
+
+ void GetConstantBuffers(
+ const D3D11ConstantBufferBindings& Bindings,
+ UINT StartSlot,
+ UINT NumBuffers,
+ ID3D11Buffer** ppConstantBuffers,
+ UINT* pFirstConstant,
+ UINT* pNumConstants);
+
+ void GetShaderResources(
+ const D3D11ShaderResourceBindings& Bindings,
+ UINT StartSlot,
+ UINT NumViews,
+ ID3D11ShaderResourceView** ppShaderResourceViews);
+
+ void GetSamplers(
+ const D3D11SamplerBindings& Bindings,
+ UINT StartSlot,
+ UINT NumSamplers,
+ ID3D11SamplerState** ppSamplers);
+
+ void ResetState();
+
+ void RestoreState();
+
+ template<DxbcProgramType Stage>
+ void RestoreConstantBuffers(
+ D3D11ConstantBufferBindings& Bindings);
+
+ template<DxbcProgramType Stage>
+ void RestoreSamplers(
+ D3D11SamplerBindings& Bindings);
+
+ template<DxbcProgramType Stage>
+ void RestoreShaderResources(
+ D3D11ShaderResourceBindings& Bindings);
+
+ template<DxbcProgramType Stage>
+ void RestoreUnorderedAccessViews(
+ D3D11UnorderedAccessBindings& Bindings);
+
+ bool TestRtvUavHazards(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRTVs,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUAVs);
+
+ template<DxbcProgramType ShaderStage>
+ bool TestSrvHazards(
+ D3D11ShaderResourceView* pView);
+
+ template<DxbcProgramType ShaderStage, typename T>
+ void ResolveSrvHazards(
+ T* pView,
+ D3D11ShaderResourceBindings& Bindings);
+
+ template<typename T>
+ void ResolveCsSrvHazards(
+ T* pView);
+
+ template<typename T>
+ void ResolveOmSrvHazards(
+ T* pView);
+
+ bool ResolveOmRtvHazards(
+ D3D11UnorderedAccessView* pView);
+
+ void ResolveOmUavHazards(
+ D3D11RenderTargetView* pView);
+
+ bool ValidateRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView);
+
+ VkClearValue ConvertColorValue(
+ const FLOAT Color[4],
+ const DxvkFormatInfo* pFormatInfo);
+
+ DxvkDataSlice AllocUpdateBufferSlice(size_t Size);
+
+ DxvkBufferSlice AllocStagingBuffer(
+ VkDeviceSize Size);
+
+ DxvkCsChunkRef AllocCsChunk();
+
+ static void InitDefaultPrimitiveTopology(
+ DxvkInputAssemblyState* pIaState);
+
+ static void InitDefaultRasterizerState(
+ DxvkRasterizerState* pRsState);
+
+ static void InitDefaultDepthStencilState(
+ DxvkDepthStencilState* pDsState);
+
+ static void InitDefaultBlendState(
+ DxvkBlendMode* pCbState,
+ DxvkLogicOpState* pLoState,
+ DxvkMultisampleState* pMsState,
+ UINT SampleMask);
+
+ template<typename T>
+ const D3D11CommonShader* GetCommonShader(T* pShader) const {
+ return pShader != nullptr ? pShader->GetCommonShader() : nullptr;
+ }
+
+ static uint32_t GetIndirectCommandStride(const D3D11CmdDrawIndirectData* cmdData, uint32_t offset, uint32_t minStride) {
+ if (likely(cmdData->stride))
+ return cmdData->offset + cmdData->count * cmdData->stride == offset ? cmdData->stride : 0;
+
+ uint32_t stride = offset - cmdData->offset;
+ return stride >= minStride && stride <= 32 ? stride : 0;
+ }
+
+ static bool ValidateDrawBufferSize(ID3D11Buffer* pBuffer, UINT Offset, UINT Size) {
+ UINT bufferSize = 0;
+
+ if (likely(pBuffer != nullptr))
+ bufferSize = static_cast<D3D11Buffer*>(pBuffer)->Desc()->ByteWidth;
+
+ return bufferSize >= Offset + Size;
+ }
+
+ template<typename Cmd>
+ void EmitCs(Cmd&& command) {
+ m_cmdData = nullptr;
+
+ if (unlikely(!m_csChunk->push(command))) {
+ EmitCsChunk(std::move(m_csChunk));
+
+ m_csChunk = AllocCsChunk();
+ m_csChunk->push(command);
+ }
+ }
+
+ template<typename M, typename Cmd, typename... Args>
+ M* EmitCsCmd(Cmd&& command, Args&&... args) {
+ M* data = m_csChunk->pushCmd<M, Cmd, Args...>(
+ command, std::forward<Args>(args)...);
+
+ if (unlikely(!data)) {
+ EmitCsChunk(std::move(m_csChunk));
+
+ m_csChunk = AllocCsChunk();
+ data = m_csChunk->pushCmd<M, Cmd, Args...>(
+ command, std::forward<Args>(args)...);
+ }
+
+ m_cmdData = data;
+ return data;
+ }
+
+ void FlushCsChunk() {
+ if (likely(!m_csChunk->empty())) {
+ EmitCsChunk(std::move(m_csChunk));
+ m_csChunk = AllocCsChunk();
+ m_cmdData = nullptr;
+ }
+ }
+
+ virtual void EmitCsChunk(DxvkCsChunkRef&& chunk) = 0;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp
new file mode 100644
index 00000000..1ac44b06
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.cpp
@@ -0,0 +1,383 @@
+#include "d3d11_context_def.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11DeferredContext::D3D11DeferredContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device,
+ UINT ContextFlags)
+ : D3D11DeviceContext(pParent, Device, GetCsChunkFlags(pParent)),
+ m_contextFlags(ContextFlags),
+ m_commandList (CreateCommandList()) {
+ ClearState();
+ }
+
+
+ D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE D3D11DeferredContext::GetType() {
+ return D3D11_DEVICE_CONTEXT_DEFERRED;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11DeferredContext::GetContextFlags() {
+ return m_contextFlags;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeferredContext::GetData(
+ ID3D11Asynchronous* pAsync,
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: GetData called on a deferred context");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::Begin(
+ ID3D11Asynchronous* pAsync) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pAsync))
+ return;
+
+ Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync));
+
+ if (unlikely(!query->IsScoped()))
+ return;
+
+ auto entry = std::find(
+ m_queriesBegun.begin(),
+ m_queriesBegun.end(), query);
+
+ if (unlikely(entry != m_queriesBegun.end()))
+ return;
+
+ EmitCs([cQuery = query]
+ (DxvkContext* ctx) {
+ cQuery->Begin(ctx);
+ });
+
+ m_queriesBegun.push_back(std::move(query));
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::End(
+ ID3D11Asynchronous* pAsync) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pAsync))
+ return;
+
+ Com<D3D11Query, false> query(static_cast<D3D11Query*>(pAsync));
+
+ if (query->IsScoped()) {
+ auto entry = std::find(
+ m_queriesBegun.begin(),
+ m_queriesBegun.end(), query);
+
+ if (likely(entry != m_queriesBegun.end())) {
+ m_queriesBegun.erase(entry);
+ } else {
+ EmitCs([cQuery = query]
+ (DxvkContext* ctx) {
+ cQuery->Begin(ctx);
+ });
+ }
+ }
+
+ m_commandList->AddQuery(query.ptr());
+
+ EmitCs([cQuery = std::move(query)]
+ (DxvkContext* ctx) {
+ cQuery->End(ctx);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::Flush() {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: Flush called on a deferred context");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::Flush1(
+ D3D11_CONTEXT_TYPE ContextType,
+ HANDLE hEvent) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: Flush1 called on a deferred context");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Signal(
+ ID3D11Fence* pFence,
+ UINT64 Value) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: Signal called on a deferred context");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Wait(
+ ID3D11Fence* pFence,
+ UINT64 Value) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: Wait called on a deferred context");
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::ExecuteCommandList(
+ ID3D11CommandList* pCommandList,
+ BOOL RestoreContextState) {
+ D3D10DeviceLock lock = LockContext();
+
+ FlushCsChunk();
+
+ static_cast<D3D11CommandList*>(pCommandList)->EmitToCommandList(m_commandList.ptr());
+
+ if (RestoreContextState)
+ RestoreState();
+ else
+ ClearState();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeferredContext::FinishCommandList(
+ BOOL RestoreDeferredContextState,
+ ID3D11CommandList **ppCommandList) {
+ D3D10DeviceLock lock = LockContext();
+
+ FinalizeQueries();
+ FlushCsChunk();
+
+ if (ppCommandList != nullptr)
+ *ppCommandList = m_commandList.ref();
+ m_commandList = CreateCommandList();
+
+ if (RestoreDeferredContextState)
+ RestoreState();
+ else
+ ClearState();
+
+ m_mappedResources.clear();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeferredContext::Map(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pResource || !pMappedResource))
+ return E_INVALIDARG;
+
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ if (MapType == D3D11_MAP_WRITE_DISCARD) {
+ D3D11DeferredContextMapEntry entry;
+
+ HRESULT status = resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER
+ ? MapBuffer(pResource, MapType, MapFlags, &entry)
+ : MapImage (pResource, Subresource, MapType, MapFlags, &entry);
+
+ if (unlikely(FAILED(status))) {
+ *pMappedResource = D3D11_MAPPED_SUBRESOURCE();
+ return status;
+ }
+
+ // Adding a new map entry actually overrides the
+ // old one in practice because the lookup function
+ // scans the array in reverse order
+ m_mappedResources.push_back(std::move(entry));
+
+ // Fill mapped resource structure
+ pMappedResource->pData = entry.MapPointer;
+ pMappedResource->RowPitch = entry.RowPitch;
+ pMappedResource->DepthPitch = entry.DepthPitch;
+ return S_OK;
+ } else if (MapType == D3D11_MAP_WRITE_NO_OVERWRITE) {
+ // The resource must be mapped with D3D11_MAP_WRITE_DISCARD
+ // before it can be mapped with D3D11_MAP_WRITE_NO_OVERWRITE.
+ auto entry = FindMapEntry(pResource, Subresource);
+
+ if (unlikely(entry == m_mappedResources.rend())) {
+ *pMappedResource = D3D11_MAPPED_SUBRESOURCE();
+ return E_INVALIDARG;
+ }
+
+ // Return same memory region as earlier
+ entry->MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
+
+ pMappedResource->pData = entry->MapPointer;
+ pMappedResource->RowPitch = entry->RowPitch;
+ pMappedResource->DepthPitch = entry->DepthPitch;
+ return S_OK;
+ } else {
+ // Not allowed on deferred contexts
+ *pMappedResource = D3D11_MAPPED_SUBRESOURCE();
+ return E_INVALIDARG;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::Unmap(
+ ID3D11Resource* pResource,
+ UINT Subresource) {
+ // No-op, updates are committed in Map
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeferredContext::SwapDeviceContextState(
+ ID3DDeviceContextState* pState,
+ ID3DDeviceContextState** ppPreviousState) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11: SwapDeviceContextState called on a deferred context");
+ }
+
+
+ HRESULT D3D11DeferredContext::MapBuffer(
+ ID3D11Resource* pResource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11DeferredContextMapEntry* pMapEntry) {
+ D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);
+
+ if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
+ Logger::err("D3D11: Cannot map a device-local buffer");
+ return E_INVALIDARG;
+ }
+
+ pMapEntry->pResource = pResource;
+ pMapEntry->Subresource = 0;
+ pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
+ pMapEntry->RowPitch = pBuffer->Desc()->ByteWidth;
+ pMapEntry->DepthPitch = pBuffer->Desc()->ByteWidth;
+
+ if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) {
+ // For resources that cannot be written by the GPU,
+ // we may write to the buffer resource directly and
+ // just swap in the buffer slice as needed.
+ auto bufferSlice = pBuffer->AllocSlice();
+ pMapEntry->MapPointer = bufferSlice.mapPtr;
+
+ EmitCs([
+ cDstBuffer = pBuffer->GetBuffer(),
+ cPhysSlice = bufferSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cDstBuffer, cPhysSlice);
+ });
+ } else {
+ // For GPU-writable resources, we need a data slice
+ // to perform the update operation at execution time.
+ auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth);
+ pMapEntry->MapPointer = dataSlice.ptr();
+
+ EmitCs([
+ cDstBuffer = pBuffer->GetBuffer(),
+ cDataSlice = dataSlice
+ ] (DxvkContext* ctx) {
+ DxvkBufferSliceHandle slice = cDstBuffer->allocSlice();
+ std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length());
+ ctx->invalidateBuffer(cDstBuffer, slice);
+ });
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT D3D11DeferredContext::MapImage(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11DeferredContextMapEntry* pMapEntry) {
+ D3D11CommonTexture* pTexture = GetCommonTexture(pResource);
+
+ if (unlikely(pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
+ Logger::err("D3D11: Cannot map a device-local image");
+ return E_INVALIDARG;
+ }
+
+ if (unlikely(Subresource >= pTexture->CountSubresources()))
+ return E_INVALIDARG;
+
+ VkFormat packedFormat = pTexture->GetPackedFormat();
+
+ auto formatInfo = imageFormatInfo(packedFormat);
+ auto subresource = pTexture->GetSubresourceFromIndex(
+ formatInfo->aspectMask, Subresource);
+
+ VkExtent3D levelExtent = pTexture->MipLevelExtent(subresource.mipLevel);
+
+ auto layout = pTexture->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
+ auto dataSlice = AllocStagingBuffer(util::computeImageDataSize(packedFormat, levelExtent));
+
+ pMapEntry->pResource = pResource;
+ pMapEntry->Subresource = Subresource;
+ pMapEntry->MapType = D3D11_MAP_WRITE_DISCARD;
+ pMapEntry->RowPitch = layout.RowPitch;
+ pMapEntry->DepthPitch = layout.DepthPitch;
+ pMapEntry->MapPointer = dataSlice.mapPtr(0);
+
+ UpdateImage(pTexture, &subresource,
+ VkOffset3D { 0, 0, 0 }, levelExtent,
+ std::move(dataSlice));
+ return S_OK;
+ }
+
+
+ void D3D11DeferredContext::FinalizeQueries() {
+ for (auto& query : m_queriesBegun) {
+ m_commandList->AddQuery(query.ptr());
+
+ EmitCs([cQuery = std::move(query)]
+ (DxvkContext* ctx) {
+ cQuery->End(ctx);
+ });
+ }
+
+ m_queriesBegun.clear();
+ }
+
+
+ Com<D3D11CommandList> D3D11DeferredContext::CreateCommandList() {
+ return new D3D11CommandList(m_parent, m_contextFlags);
+ }
+
+
+ void D3D11DeferredContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
+ m_commandList->AddChunk(std::move(chunk));
+ }
+
+
+ DxvkCsChunkFlags D3D11DeferredContext::GetCsChunkFlags(
+ D3D11Device* pDevice) {
+ return pDevice->GetOptions()->dcSingleUseMode
+ ? DxvkCsChunkFlags(DxvkCsChunkFlag::SingleUse)
+ : DxvkCsChunkFlags();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h
new file mode 100644
index 00000000..bdfcf441
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_def.h
@@ -0,0 +1,131 @@
+#pragma once
+
+#include "d3d11_buffer.h"
+#include "d3d11_cmdlist.h"
+#include "d3d11_context.h"
+#include "d3d11_texture.h"
+
+#include <algorithm>
+#include <vector>
+
+namespace dxvk {
+
+ struct D3D11DeferredContextMapEntry {
+ Com<ID3D11Resource> pResource;
+ UINT Subresource;
+ D3D11_MAP MapType;
+ UINT RowPitch;
+ UINT DepthPitch;
+ void* MapPointer;
+ };
+
+ class D3D11DeferredContext : public D3D11DeviceContext {
+
+ public:
+
+ D3D11DeferredContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device,
+ UINT ContextFlags);
+
+ D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE GetType();
+
+ UINT STDMETHODCALLTYPE GetContextFlags();
+
+ HRESULT STDMETHODCALLTYPE GetData(
+ ID3D11Asynchronous* pAsync,
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags);
+
+ void STDMETHODCALLTYPE Begin(
+ ID3D11Asynchronous* pAsync);
+
+ void STDMETHODCALLTYPE End(
+ ID3D11Asynchronous* pAsync);
+
+ void STDMETHODCALLTYPE Flush();
+
+ void STDMETHODCALLTYPE Flush1(
+ D3D11_CONTEXT_TYPE ContextType,
+ HANDLE hEvent);
+
+ HRESULT STDMETHODCALLTYPE Signal(
+ ID3D11Fence* pFence,
+ UINT64 Value);
+
+ HRESULT STDMETHODCALLTYPE Wait(
+ ID3D11Fence* pFence,
+ UINT64 Value);
+
+ void STDMETHODCALLTYPE ExecuteCommandList(
+ ID3D11CommandList* pCommandList,
+ BOOL RestoreContextState);
+
+ HRESULT STDMETHODCALLTYPE FinishCommandList(
+ BOOL RestoreDeferredContextState,
+ ID3D11CommandList** ppCommandList);
+
+ HRESULT STDMETHODCALLTYPE Map(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource);
+
+ void STDMETHODCALLTYPE Unmap(
+ ID3D11Resource* pResource,
+ UINT Subresource);
+
+ void STDMETHODCALLTYPE SwapDeviceContextState(
+ ID3DDeviceContextState* pState,
+ ID3DDeviceContextState** ppPreviousState);
+
+ private:
+
+ const UINT m_contextFlags;
+
+ // Command list that we're recording
+ Com<D3D11CommandList> m_commandList;
+
+ // Info about currently mapped (sub)resources. Using a vector
+ // here is reasonable since there will usually only be a small
+ // number of mapped resources per command list.
+ std::vector<D3D11DeferredContextMapEntry> m_mappedResources;
+
+ // Begun and ended queries, will also be stored in command list
+ std::vector<Com<D3D11Query, false>> m_queriesBegun;
+
+ HRESULT MapBuffer(
+ ID3D11Resource* pResource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11DeferredContextMapEntry* pMapEntry);
+
+ HRESULT MapImage(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11DeferredContextMapEntry* pMapEntry);
+
+ void FinalizeQueries();
+
+ Com<D3D11CommandList> CreateCommandList();
+
+ void EmitCsChunk(DxvkCsChunkRef&& chunk);
+
+ static DxvkCsChunkFlags GetCsChunkFlags(
+ D3D11Device* pDevice);
+
+ auto FindMapEntry(ID3D11Resource* pResource, UINT Subresource) {
+ return std::find_if(m_mappedResources.rbegin(), m_mappedResources.rend(),
+ [pResource, Subresource] (const D3D11DeferredContextMapEntry& entry) {
+ return entry.pResource == pResource
+ && entry.Subresource == Subresource;
+ });
+ }
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp
new file mode 100644
index 00000000..c892f7ef
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.cpp
@@ -0,0 +1,198 @@
+#include <vector>
+#include <utility>
+#include <cstring>
+
+#include "d3d11_device.h"
+#include "d3d11_context.h"
+#include "d3d11_cuda.h"
+
+#include "../util/log/log.h"
+
+namespace dxvk {
+
+ D3D11DeviceContextExt::D3D11DeviceContextExt(
+ D3D11DeviceContext* pContext)
+ : m_ctx(pContext) {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DeviceContextExt::AddRef() {
+ return m_ctx->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DeviceContextExt::Release() {
+ return m_ctx->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContextExt::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_ctx->QueryInterface(riid, ppvObject);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+ m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
+
+ m_ctx->EmitCs([
+ cCount = DrawCount,
+ cOffset = ByteOffsetForArgs,
+ cStride = ByteStrideForArgs
+ ] (DxvkContext* ctx) {
+ ctx->drawIndirect(cOffset, cCount, cStride);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndexedIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+ m_ctx->SetDrawBuffers(pBufferForArgs, nullptr);
+
+ m_ctx->EmitCs([
+ cCount = DrawCount,
+ cOffset = ByteOffsetForArgs,
+ cStride = ByteStrideForArgs
+ ] (DxvkContext* ctx) {
+ ctx->drawIndexedIndirect(cOffset, cCount, cStride);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+ m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
+
+ m_ctx->EmitCs([
+ cMaxCount = MaxDrawCount,
+ cArgOffset = ByteOffsetForArgs,
+ cCntOffset = ByteOffsetForCount,
+ cStride = ByteStrideForArgs
+ ] (DxvkContext* ctx) {
+ ctx->drawIndirectCount(cArgOffset, cCntOffset, cMaxCount, cStride);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::MultiDrawIndexedIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+ m_ctx->SetDrawBuffers(pBufferForArgs, pBufferForCount);
+
+ m_ctx->EmitCs([
+ cMaxCount = MaxDrawCount,
+ cArgOffset = ByteOffsetForArgs,
+ cCntOffset = ByteOffsetForCount,
+ cStride = ByteStrideForArgs
+ ] (DxvkContext* ctx) {
+ ctx->drawIndexedIndirectCount(cArgOffset, cCntOffset, cMaxCount, cStride);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::SetDepthBoundsTest(
+ BOOL Enable,
+ FLOAT MinDepthBounds,
+ FLOAT MaxDepthBounds) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ DxvkDepthBounds db;
+ db.enableDepthBounds = Enable;
+ db.minDepthBounds = MinDepthBounds;
+ db.maxDepthBounds = MaxDepthBounds;
+
+ m_ctx->EmitCs([cDepthBounds = db] (DxvkContext* ctx) {
+ ctx->setDepthBounds(cDepthBounds);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DeviceContextExt::SetBarrierControl(
+ UINT ControlFlags) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+ DxvkBarrierControlFlags flags;
+
+ if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE)
+ flags.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
+
+ if (ControlFlags & D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV)
+ flags.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
+
+ m_ctx->EmitCs([cFlags = flags] (DxvkContext* ctx) {
+ ctx->setBarrierControl(cFlags);
+ });
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceContextExt::LaunchCubinShaderNVX(IUnknown* hShader, uint32_t GridX, uint32_t GridY, uint32_t GridZ,
+ const void* pParams, uint32_t ParamSize, void* const* pReadResources, uint32_t NumReadResources, void* const* pWriteResources, uint32_t NumWriteResources) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ CubinShaderWrapper* cubinShader = static_cast<CubinShaderWrapper*>(hShader);
+ CubinShaderLaunchInfo launchInfo;
+
+ const uint32_t maxResources = NumReadResources + NumWriteResources;
+ launchInfo.buffers.reserve(maxResources);
+ launchInfo.images.reserve(maxResources);
+
+ for (uint32_t i = 0; i < NumReadResources; i++)
+ launchInfo.insertResource(static_cast<ID3D11Resource*>(pReadResources[i]), DxvkAccess::Read);
+
+ for (uint32_t i = 0; i < NumWriteResources; i++)
+ launchInfo.insertResource(static_cast<ID3D11Resource*>(pWriteResources[i]), DxvkAccess::Write);
+
+ launchInfo.paramSize = ParamSize;
+ launchInfo.params.resize(launchInfo.paramSize);
+ std::memcpy(launchInfo.params.data(), pParams, ParamSize);
+
+ launchInfo.cuLaunchConfig[0] = reinterpret_cast<void*>(0x01); // CU_LAUNCH_PARAM_BUFFER_POINTER
+ launchInfo.cuLaunchConfig[1] = launchInfo.params.data();
+ launchInfo.cuLaunchConfig[2] = reinterpret_cast<void*>(0x02); // CU_LAUNCH_PARAM_BUFFER_SIZE
+ launchInfo.cuLaunchConfig[3] = &launchInfo.paramSize; // yes, this actually requires a pointer to a size_t containing the parameter size
+ launchInfo.cuLaunchConfig[4] = reinterpret_cast<void*>(0x00); // CU_LAUNCH_PARAM_END
+
+ launchInfo.nvxLaunchInfo.function = cubinShader->cuFunction();
+ launchInfo.nvxLaunchInfo.gridDimX = GridX;
+ launchInfo.nvxLaunchInfo.gridDimY = GridY;
+ launchInfo.nvxLaunchInfo.gridDimZ = GridZ;
+ launchInfo.nvxLaunchInfo.blockDimX = cubinShader->blockDim().width;
+ launchInfo.nvxLaunchInfo.blockDimY = cubinShader->blockDim().height;
+ launchInfo.nvxLaunchInfo.blockDimZ = cubinShader->blockDim().depth;
+ launchInfo.nvxLaunchInfo.sharedMemBytes = 0;
+ launchInfo.nvxLaunchInfo.paramCount = 0;
+ launchInfo.nvxLaunchInfo.pParams = nullptr;
+ launchInfo.nvxLaunchInfo.extraCount = 1;
+ launchInfo.nvxLaunchInfo.pExtras = launchInfo.cuLaunchConfig.data();
+
+ launchInfo.shader = cubinShader;
+
+ /* Need to capture by value in case this gets called from a deferred context */
+ m_ctx->EmitCs([cLaunchInfo = std::move(launchInfo)] (DxvkContext* ctx) {
+ ctx->launchCuKernelNVX(cLaunchInfo.nvxLaunchInfo, cLaunchInfo.buffers, cLaunchInfo.images);
+ });
+
+ return true;
+ }
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h
new file mode 100644
index 00000000..2109a0de
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_ext.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "d3d11_interfaces.h"
+
+namespace dxvk {
+
+ class D3D11DeviceContext;
+
+ class D3D11DeviceContextExt : public ID3D11VkExtContext1 {
+
+ public:
+
+ D3D11DeviceContextExt(
+ D3D11DeviceContext* pContext);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE MultiDrawIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs);
+
+ void STDMETHODCALLTYPE MultiDrawIndexedIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs);
+
+ void STDMETHODCALLTYPE MultiDrawIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs);
+
+ void STDMETHODCALLTYPE MultiDrawIndexedIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs);
+
+ void STDMETHODCALLTYPE SetDepthBoundsTest(
+ BOOL Enable,
+ FLOAT MinDepthBounds,
+ FLOAT MaxDepthBounds);
+
+ void STDMETHODCALLTYPE SetBarrierControl(
+ UINT ControlFlags);
+
+ bool STDMETHODCALLTYPE LaunchCubinShaderNVX(
+ IUnknown* hShader,
+ uint32_t GridX,
+ uint32_t GridY,
+ uint32_t GridZ,
+ const void* pParams,
+ uint32_t paramSize,
+ void* const* pReadResources,
+ uint32_t NumReadResources,
+ void* const* pWriteResources,
+ uint32_t NumWriteResources);
+
+ private:
+
+ D3D11DeviceContext* m_ctx;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp
new file mode 100644
index 00000000..3bac02e7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.cpp
@@ -0,0 +1,623 @@
+#include "d3d11_cmdlist.h"
+#include "d3d11_context_imm.h"
+#include "d3d11_device.h"
+#include "d3d11_texture.h"
+
+constexpr static uint32_t MinFlushIntervalUs = 750;
+constexpr static uint32_t IncFlushIntervalUs = 250;
+constexpr static uint32_t MaxPendingSubmits = 6;
+
+namespace dxvk {
+
+ D3D11ImmediateContext::D3D11ImmediateContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device)
+ : D3D11DeviceContext(pParent, Device, DxvkCsChunkFlag::SingleUse),
+ m_csThread(Device->createContext()),
+ m_videoContext(this, Device) {
+ EmitCs([
+ cDevice = m_device,
+ cRelaxedBarriers = pParent->GetOptions()->relaxedBarriers,
+ cIgnoreGraphicsBarriers = pParent->GetOptions()->ignoreGraphicsBarriers
+ ] (DxvkContext* ctx) {
+ ctx->beginRecording(cDevice->createCommandList());
+
+ DxvkBarrierControlFlags barrierControl;
+
+ if (cRelaxedBarriers)
+ barrierControl.set(DxvkBarrierControl::IgnoreWriteAfterWrite);
+
+ if (cIgnoreGraphicsBarriers)
+ barrierControl.set(DxvkBarrierControl::IgnoreGraphicsBarriers);
+
+ ctx->setBarrierControl(barrierControl);
+ });
+
+ ClearState();
+ }
+
+
+ D3D11ImmediateContext::~D3D11ImmediateContext() {
+ Flush();
+ SynchronizeCsThread();
+ SynchronizeDevice();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::QueryInterface(REFIID riid, void** ppvObject) {
+ if (riid == __uuidof(ID3D11VideoContext)) {
+ *ppvObject = ref(&m_videoContext);
+ return S_OK;
+ }
+
+ return D3D11DeviceContext::QueryInterface(riid, ppvObject);
+ }
+
+
+ D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE D3D11ImmediateContext::GetType() {
+ return D3D11_DEVICE_CONTEXT_IMMEDIATE;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11ImmediateContext::GetContextFlags() {
+ return 0;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::GetData(
+ ID3D11Asynchronous* pAsync,
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags) {
+ if (!pAsync || (DataSize && !pData))
+ return E_INVALIDARG;
+
+ // Check whether the data size is actually correct
+ if (DataSize && DataSize != pAsync->GetDataSize())
+ return E_INVALIDARG;
+
+ // Passing a non-null pData is actually allowed if
+ // DataSize is 0, but we should ignore that pointer
+ pData = DataSize ? pData : nullptr;
+
+ // Get query status directly from the query object
+ auto query = static_cast<D3D11Query*>(pAsync);
+ HRESULT hr = query->GetData(pData, GetDataFlags);
+
+ // If we're likely going to spin on the asynchronous object,
+ // flush the context so that we're keeping the GPU busy.
+ if (hr == S_FALSE) {
+ // Don't mark the event query as stalling if the app does
+ // not intend to spin on it. This reduces flushes on End.
+ if (!(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH))
+ query->NotifyStall();
+
+ // Ignore the DONOTFLUSH flag here as some games will spin
+ // on queries without ever flushing the context otherwise.
+ FlushImplicit(FALSE);
+ }
+
+ return hr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::Begin(ID3D11Asynchronous* pAsync) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pAsync))
+ return;
+
+ auto query = static_cast<D3D11Query*>(pAsync);
+
+ if (unlikely(!query->DoBegin()))
+ return;
+
+ EmitCs([cQuery = Com<D3D11Query, false>(query)]
+ (DxvkContext* ctx) {
+ cQuery->Begin(ctx);
+ });
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::End(ID3D11Asynchronous* pAsync) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pAsync))
+ return;
+
+ auto query = static_cast<D3D11Query*>(pAsync);
+
+ if (unlikely(!query->DoEnd())) {
+ EmitCs([cQuery = Com<D3D11Query, false>(query)]
+ (DxvkContext* ctx) {
+ cQuery->Begin(ctx);
+ });
+ }
+
+ EmitCs([cQuery = Com<D3D11Query, false>(query)]
+ (DxvkContext* ctx) {
+ cQuery->End(ctx);
+ });
+
+ if (unlikely(query->IsEvent())) {
+ query->NotifyEnd();
+ query->IsStalling()
+ ? Flush()
+ : FlushImplicit(TRUE);
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() {
+ Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::Flush1(
+ D3D11_CONTEXT_TYPE ContextType,
+ HANDLE hEvent) {
+ m_parent->FlushInitContext();
+
+ if (hEvent)
+ SignalEvent(hEvent);
+
+ D3D10DeviceLock lock = LockContext();
+
+ if (m_csIsBusy || !m_csChunk->empty()) {
+ // Add commands to flush the threaded
+ // context, then flush the command list
+ EmitCs([] (DxvkContext* ctx) {
+ ctx->flushCommandList();
+ });
+
+ FlushCsChunk();
+
+ // Reset flush timer used for implicit flushes
+ m_lastFlush = dxvk::high_resolution_clock::now();
+ m_csIsBusy = false;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Signal(
+ ID3D11Fence* pFence,
+ UINT64 Value) {
+ Logger::err("D3D11ImmediateContext::Signal: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Wait(
+ ID3D11Fence* pFence,
+ UINT64 Value) {
+ Logger::err("D3D11ImmediateContext::Wait: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::ExecuteCommandList(
+ ID3D11CommandList* pCommandList,
+ BOOL RestoreContextState) {
+ D3D10DeviceLock lock = LockContext();
+
+ auto commandList = static_cast<D3D11CommandList*>(pCommandList);
+
+ // Flush any outstanding commands so that
+ // we don't mess up the execution order
+ FlushCsChunk();
+
+ // As an optimization, flush everything if the
+ // number of pending draw calls is high enough.
+ FlushImplicit(FALSE);
+
+ // Dispatch command list to the CS thread and
+ // restore the immediate context's state
+ commandList->EmitToCsThread(&m_csThread);
+
+ if (RestoreContextState)
+ RestoreState();
+ else
+ ClearState();
+
+ // Mark CS thread as busy so that subsequent
+ // flush operations get executed correctly.
+ m_csIsBusy = true;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::FinishCommandList(
+ BOOL RestoreDeferredContextState,
+ ID3D11CommandList **ppCommandList) {
+ InitReturnPtr(ppCommandList);
+
+ Logger::err("D3D11: FinishCommandList called on immediate context");
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Map(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
+ D3D10DeviceLock lock = LockContext();
+
+ if (unlikely(!pResource))
+ return E_INVALIDARG;
+
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ HRESULT hr;
+
+ if (likely(resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER)) {
+ hr = MapBuffer(
+ static_cast<D3D11Buffer*>(pResource),
+ MapType, MapFlags, pMappedResource);
+ } else {
+ hr = MapImage(
+ GetCommonTexture(pResource),
+ Subresource, MapType, MapFlags,
+ pMappedResource);
+ }
+
+ if (unlikely(FAILED(hr)))
+ *pMappedResource = D3D11_MAPPED_SUBRESOURCE();
+
+ return hr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::Unmap(
+ ID3D11Resource* pResource,
+ UINT Subresource) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ if (unlikely(resourceDim != D3D11_RESOURCE_DIMENSION_BUFFER)) {
+ D3D10DeviceLock lock = LockContext();
+ UnmapImage(GetCommonTexture(pResource), Subresource);
+ }
+ }
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::UpdateSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch) {
+ FlushImplicit(FALSE);
+
+ D3D11DeviceContext::UpdateSubresource(
+ pDstResource, DstSubresource, pDstBox,
+ pSrcData, SrcRowPitch, SrcDepthPitch);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::UpdateSubresource1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch,
+ UINT CopyFlags) {
+ FlushImplicit(FALSE);
+
+ D3D11DeviceContext::UpdateSubresource1(
+ pDstResource, DstSubresource, pDstBox,
+ pSrcData, SrcRowPitch, SrcDepthPitch,
+ CopyFlags);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::OMSetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView) {
+ FlushImplicit(TRUE);
+
+ D3D11DeviceContext::OMSetRenderTargets(
+ NumViews, ppRenderTargetViews, pDepthStencilView);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::OMSetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts) {
+ FlushImplicit(TRUE);
+
+ D3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(
+ NumRTVs, ppRenderTargetViews, pDepthStencilView,
+ UAVStartSlot, NumUAVs, ppUnorderedAccessViews,
+ pUAVInitialCounts);
+ }
+
+
+ HRESULT D3D11ImmediateContext::MapBuffer(
+ D3D11Buffer* pResource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
+ if (unlikely(!pMappedResource))
+ return E_INVALIDARG;
+
+ if (unlikely(pResource->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
+ Logger::err("D3D11: Cannot map a device-local buffer");
+ return E_INVALIDARG;
+ }
+
+ if (MapType == D3D11_MAP_WRITE_DISCARD) {
+ // Allocate a new backing slice for the buffer and set
+ // it as the 'new' mapped slice. This assumes that the
+ // only way to invalidate a buffer is by mapping it.
+ auto physSlice = pResource->DiscardSlice();
+ pMappedResource->pData = physSlice.mapPtr;
+ pMappedResource->RowPitch = pResource->Desc()->ByteWidth;
+ pMappedResource->DepthPitch = pResource->Desc()->ByteWidth;
+
+ EmitCs([
+ cBuffer = pResource->GetBuffer(),
+ cBufferSlice = physSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cBufferSlice);
+ });
+
+ return S_OK;
+ } else {
+ // Wait until the resource is no longer in use
+ if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
+ if (!WaitForResource(pResource->GetBuffer(), MapType, MapFlags))
+ return DXGI_ERROR_WAS_STILL_DRAWING;
+ }
+
+ // Use map pointer from previous map operation. This
+ // way we don't have to synchronize with the CS thread
+ // if the map mode is D3D11_MAP_WRITE_NO_OVERWRITE.
+ DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
+
+ pMappedResource->pData = physSlice.mapPtr;
+ pMappedResource->RowPitch = pResource->Desc()->ByteWidth;
+ pMappedResource->DepthPitch = pResource->Desc()->ByteWidth;
+ return S_OK;
+ }
+ }
+
+
+ HRESULT D3D11ImmediateContext::MapImage(
+ D3D11CommonTexture* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
+ const Rc<DxvkImage> mappedImage = pResource->GetImage();
+ const Rc<DxvkBuffer> mappedBuffer = pResource->GetMappedBuffer(Subresource);
+
+ auto mapMode = pResource->GetMapMode();
+
+ if (unlikely(mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_NONE)) {
+ Logger::err("D3D11: Cannot map a device-local image");
+ return E_INVALIDARG;
+ }
+
+ if (unlikely(Subresource >= pResource->CountSubresources()))
+ return E_INVALIDARG;
+
+ if (likely(pMappedResource != nullptr)) {
+ // Resources with an unknown memory layout cannot return a pointer
+ if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT
+ && pResource->Desc()->TextureLayout == D3D11_TEXTURE_LAYOUT_UNDEFINED)
+ return E_INVALIDARG;
+ } else {
+ if (pResource->Desc()->Usage != D3D11_USAGE_DEFAULT)
+ return E_INVALIDARG;
+ }
+
+ VkFormat packedFormat = m_parent->LookupPackedFormat(
+ pResource->Desc()->Format, pResource->GetFormatMode()).Format;
+
+ auto formatInfo = imageFormatInfo(packedFormat);
+ void* mapPtr;
+
+ if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
+ // Wait for the resource to become available
+ if (!WaitForResource(mappedImage, MapType, MapFlags))
+ return DXGI_ERROR_WAS_STILL_DRAWING;
+
+ // Query the subresource's memory layout and hope that
+ // the application respects the returned pitch values.
+ mapPtr = mappedImage->mapPtr(0);
+ } else {
+ if (MapType == D3D11_MAP_WRITE_DISCARD) {
+ // We do not have to preserve the contents of the
+ // buffer if the entire image gets discarded.
+ DxvkBufferSliceHandle physSlice = pResource->DiscardSlice(Subresource);
+
+ EmitCs([
+ cImageBuffer = mappedBuffer,
+ cBufferSlice = physSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
+ });
+
+ mapPtr = physSlice.mapPtr;
+ } else {
+ bool wait = MapType != D3D11_MAP_WRITE_NO_OVERWRITE
+ || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
+
+ // Wait for mapped buffer to become available
+ if (wait && !WaitForResource(mappedBuffer, MapType, MapFlags))
+ return DXGI_ERROR_WAS_STILL_DRAWING;
+
+ mapPtr = pResource->GetMappedSlice(Subresource).mapPtr;
+ }
+ }
+
+ // Mark the given subresource as mapped
+ pResource->SetMapType(Subresource, MapType);
+
+ if (pMappedResource) {
+ auto layout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
+ pMappedResource->pData = reinterpret_cast<char*>(mapPtr) + layout.Offset;
+ pMappedResource->RowPitch = layout.RowPitch;
+ pMappedResource->DepthPitch = layout.DepthPitch;
+ }
+
+ return S_OK;
+ }
+
+
+ void D3D11ImmediateContext::UnmapImage(
+ D3D11CommonTexture* pResource,
+ UINT Subresource) {
+ D3D11_MAP mapType = pResource->GetMapType(Subresource);
+ pResource->SetMapType(Subresource, D3D11_MAP(~0u));
+
+ if (mapType == D3D11_MAP(~0u)
+ || mapType == D3D11_MAP_READ)
+ return;
+
+ if (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER) {
+ // Now that data has been written into the buffer,
+ // we need to copy its contents into the image
+ VkImageAspectFlags aspectMask = imageFormatInfo(pResource->GetPackedFormat())->aspectMask;
+ VkImageSubresource subresource = pResource->GetSubresourceFromIndex(aspectMask, Subresource);
+
+ UpdateImage(pResource, &subresource, VkOffset3D { 0, 0, 0 },
+ pResource->MipLevelExtent(subresource.mipLevel),
+ DxvkBufferSlice(pResource->GetMappedBuffer(Subresource)));
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ImmediateContext::SwapDeviceContextState(
+ ID3DDeviceContextState* pState,
+ ID3DDeviceContextState** ppPreviousState) {
+ InitReturnPtr(ppPreviousState);
+
+ if (!pState)
+ return;
+
+ Com<D3D11DeviceContextState> oldState = std::move(m_stateObject);
+ Com<D3D11DeviceContextState> newState = static_cast<D3D11DeviceContextState*>(pState);
+
+ if (oldState == nullptr)
+ oldState = new D3D11DeviceContextState(m_parent);
+
+ if (ppPreviousState)
+ *ppPreviousState = oldState.ref();
+
+ m_stateObject = newState;
+
+ oldState->SetState(m_state);
+ newState->GetState(m_state);
+
+ RestoreState();
+ }
+
+
+ void D3D11ImmediateContext::SynchronizeCsThread() {
+ D3D10DeviceLock lock = LockContext();
+
+ // Dispatch current chunk so that all commands
+ // recorded prior to this function will be run
+ FlushCsChunk();
+
+ if (m_csThread.isBusy())
+ m_csThread.synchronize();
+ }
+
+
+ void D3D11ImmediateContext::SynchronizeDevice() {
+ m_device->waitForIdle();
+ }
+
+
+ bool D3D11ImmediateContext::WaitForResource(
+ const Rc<DxvkResource>& Resource,
+ D3D11_MAP MapType,
+ UINT MapFlags) {
+ // Determine access type to wait for based on map mode
+ DxvkAccess access = MapType == D3D11_MAP_READ
+ ? DxvkAccess::Write
+ : DxvkAccess::Read;
+
+ // Wait for the any pending D3D11 command to be executed
+ // on the CS thread so that we can determine whether the
+ // resource is currently in use or not.
+ if (!Resource->isInUse(access))
+ SynchronizeCsThread();
+
+ if (Resource->isInUse(access)) {
+ if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) {
+ // We don't have to wait, but misbehaving games may
+ // still try to spin on `Map` until the resource is
+ // idle, so we should flush pending commands
+ FlushImplicit(FALSE);
+ return false;
+ } else {
+ // Make sure pending commands using the resource get
+ // executed on the the GPU if we have to wait for it
+ Flush();
+ SynchronizeCsThread();
+
+ Resource->waitIdle(access);
+ }
+ }
+
+ return true;
+ }
+
+
+ void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
+ m_csThread.dispatchChunk(std::move(chunk));
+ m_csIsBusy = true;
+ }
+
+
+ void D3D11ImmediateContext::FlushImplicit(BOOL StrongHint) {
+ // Flush only if the GPU is about to go idle, in
+ // order to keep the number of submissions low.
+ uint32_t pending = m_device->pendingSubmissions();
+
+ if (StrongHint || pending <= MaxPendingSubmits) {
+ auto now = dxvk::high_resolution_clock::now();
+
+ uint32_t delay = MinFlushIntervalUs
+ + IncFlushIntervalUs * pending;
+
+ // Prevent flushing too often in short intervals.
+ if (now - m_lastFlush >= std::chrono::microseconds(delay))
+ Flush();
+ }
+ }
+
+
+ void D3D11ImmediateContext::SignalEvent(HANDLE hEvent) {
+#ifndef DXVK_NATIVE
+ uint64_t value = ++m_eventCount;
+
+ if (m_eventSignal == nullptr)
+ m_eventSignal = new sync::CallbackFence();
+
+ m_eventSignal->setCallback(value, [hEvent] {
+ SetEvent(hEvent);
+ });
+
+ EmitCs([
+ cSignal = m_eventSignal,
+ cValue = value
+ ] (DxvkContext* ctx) {
+ ctx->signal(cSignal, cValue);
+ });
+#endif
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h
new file mode 100644
index 00000000..8a638da1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_imm.h
@@ -0,0 +1,166 @@
+#pragma once
+
+#include "../util/util_time.h"
+
+#ifndef DXVK_NATIVE
+#include "../util/sync/sync_signal.h"
+#endif
+
+#include "d3d11_context.h"
+#include "d3d11_state_object.h"
+#include "d3d11_video.h"
+
+namespace dxvk {
+
+ class D3D11Buffer;
+ class D3D11CommonTexture;
+
+ class D3D11ImmediateContext : public D3D11DeviceContext {
+ friend class D3D11SwapChain;
+ friend class D3D11VideoContext;
+ public:
+
+ D3D11ImmediateContext(
+ D3D11Device* pParent,
+ const Rc<DxvkDevice>& Device);
+ ~D3D11ImmediateContext();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE GetType();
+
+ UINT STDMETHODCALLTYPE GetContextFlags();
+
+ HRESULT STDMETHODCALLTYPE GetData(
+ ID3D11Asynchronous* pAsync,
+ void* pData,
+ UINT DataSize,
+ UINT GetDataFlags);
+
+ void STDMETHODCALLTYPE Begin(
+ ID3D11Asynchronous* pAsync);
+
+ void STDMETHODCALLTYPE End(
+ ID3D11Asynchronous* pAsync);
+
+ void STDMETHODCALLTYPE Flush();
+
+ void STDMETHODCALLTYPE Flush1(
+ D3D11_CONTEXT_TYPE ContextType,
+ HANDLE hEvent);
+
+ HRESULT STDMETHODCALLTYPE Signal(
+ ID3D11Fence* pFence,
+ UINT64 Value);
+
+ HRESULT STDMETHODCALLTYPE Wait(
+ ID3D11Fence* pFence,
+ UINT64 Value);
+
+ void STDMETHODCALLTYPE ExecuteCommandList(
+ ID3D11CommandList* pCommandList,
+ BOOL RestoreContextState);
+
+ HRESULT STDMETHODCALLTYPE FinishCommandList(
+ BOOL RestoreDeferredContextState,
+ ID3D11CommandList **ppCommandList);
+
+ HRESULT STDMETHODCALLTYPE Map(
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource);
+
+ void STDMETHODCALLTYPE Unmap(
+ ID3D11Resource* pResource,
+ UINT Subresource);
+
+ void STDMETHODCALLTYPE UpdateSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch);
+
+ void STDMETHODCALLTYPE UpdateSubresource1(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch,
+ UINT CopyFlags);
+
+ void STDMETHODCALLTYPE OMSetRenderTargets(
+ UINT NumViews,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView);
+
+ void STDMETHODCALLTYPE OMSetRenderTargetsAndUnorderedAccessViews(
+ UINT NumRTVs,
+ ID3D11RenderTargetView* const* ppRenderTargetViews,
+ ID3D11DepthStencilView* pDepthStencilView,
+ UINT UAVStartSlot,
+ UINT NumUAVs,
+ ID3D11UnorderedAccessView* const* ppUnorderedAccessViews,
+ const UINT* pUAVInitialCounts);
+
+ void STDMETHODCALLTYPE SwapDeviceContextState(
+ ID3DDeviceContextState* pState,
+ ID3DDeviceContextState** ppPreviousState);
+
+ void SynchronizeCsThread();
+
+ private:
+
+ DxvkCsThread m_csThread;
+ bool m_csIsBusy = false;
+
+#ifndef DXVK_NATIVE
+ Rc<sync::CallbackFence> m_eventSignal;
+#endif
+ uint64_t m_eventCount = 0;
+
+ dxvk::high_resolution_clock::time_point m_lastFlush
+ = dxvk::high_resolution_clock::now();
+
+ D3D11VideoContext m_videoContext;
+ Com<D3D11DeviceContextState> m_stateObject;
+
+ HRESULT MapBuffer(
+ D3D11Buffer* pResource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource);
+
+ HRESULT MapImage(
+ D3D11CommonTexture* pResource,
+ UINT Subresource,
+ D3D11_MAP MapType,
+ UINT MapFlags,
+ D3D11_MAPPED_SUBRESOURCE* pMappedResource);
+
+ void UnmapImage(
+ D3D11CommonTexture* pResource,
+ UINT Subresource);
+
+ void SynchronizeDevice();
+
+ bool WaitForResource(
+ const Rc<DxvkResource>& Resource,
+ D3D11_MAP MapType,
+ UINT MapFlags);
+
+ void EmitCsChunk(DxvkCsChunkRef&& chunk);
+
+ void FlushImplicit(BOOL StrongHint);
+
+ void SignalEvent(HANDLE hEvent);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h
new file mode 100644
index 00000000..eca2a3c9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_context_state.h
@@ -0,0 +1,187 @@
+#pragma once
+
+#include <array>
+
+#include "d3d11_buffer.h"
+#include "d3d11_input_layout.h"
+#include "d3d11_query.h"
+#include "d3d11_sampler.h"
+#include "d3d11_shader.h"
+#include "d3d11_state.h"
+#include "d3d11_view_dsv.h"
+#include "d3d11_view_rtv.h"
+#include "d3d11_view_srv.h"
+#include "d3d11_view_uav.h"
+
+namespace dxvk {
+
+ struct D3D11ConstantBufferBinding {
+ Com<D3D11Buffer> buffer = nullptr;
+ UINT constantOffset = 0;
+ UINT constantCount = 0;
+ UINT constantBound = 0;
+ };
+
+ using D3D11ConstantBufferBindings = std::array<
+ D3D11ConstantBufferBinding, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT>;
+
+
+ using D3D11SamplerBindings = std::array<
+ D3D11SamplerState*, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT>;
+
+
+ struct D3D11ShaderResourceBindings {
+ std::array<Com<D3D11ShaderResourceView>, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> views = { };
+ DxvkBindingSet<D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> hazardous = { };
+ };
+
+
+ using D3D11UnorderedAccessBindings = std::array<
+ Com<D3D11UnorderedAccessView>, D3D11_1_UAV_SLOT_COUNT>;
+
+
+ struct D3D11ContextStateVS {
+ Com<D3D11VertexShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ };
+
+
+ struct D3D11ContextStateHS {
+ Com<D3D11HullShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ };
+
+
+ struct D3D11ContextStateDS {
+ Com<D3D11DomainShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ };
+
+
+ struct D3D11ContextStateGS {
+ Com<D3D11GeometryShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ };
+
+
+ struct D3D11ContextStatePS {
+ Com<D3D11PixelShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ D3D11UnorderedAccessBindings unorderedAccessViews = { };
+ };
+
+
+ struct D3D11ContextStateCS {
+ Com<D3D11ComputeShader> shader = nullptr;
+ D3D11ConstantBufferBindings constantBuffers = { };
+ D3D11SamplerBindings samplers = { };
+ D3D11ShaderResourceBindings shaderResources = { };
+ D3D11UnorderedAccessBindings unorderedAccessViews = { };
+
+ DxvkBindingSet<D3D11_1_UAV_SLOT_COUNT> uavMask = { };
+ };
+
+
+ struct D3D11VertexBufferBinding {
+ Com<D3D11Buffer> buffer = nullptr;
+ UINT offset = 0;
+ UINT stride = 0;
+ };
+
+
+ struct D3D11IndexBufferBinding {
+ Com<D3D11Buffer> buffer = nullptr;
+ UINT offset = 0;
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ };
+
+
+ struct D3D11ContextStateID {
+ Com<D3D11Buffer> argBuffer = nullptr;
+ Com<D3D11Buffer> cntBuffer = nullptr;
+ };
+
+
+ struct D3D11ContextStateIA {
+ Com<D3D11InputLayout> inputLayout = nullptr;
+ D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+
+ std::array<D3D11VertexBufferBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> vertexBuffers = { };
+ D3D11IndexBufferBinding indexBuffer = { };
+ };
+
+
+ struct D3D11ContextStateOM {
+ std::array<Com<D3D11RenderTargetView, false>, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT> renderTargetViews = { };
+ Com<D3D11DepthStencilView, false> depthStencilView = { };
+
+ D3D11BlendState* cbState = nullptr;
+ D3D11DepthStencilState* dsState = nullptr;
+
+ FLOAT blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ UINT sampleMask = 0xFFFFFFFFu;
+ UINT stencilRef = 0u;
+
+ UINT maxRtv = 0u;
+ UINT maxUav = 0u;
+ };
+
+
+ struct D3D11ContextStateRS {
+ uint32_t numViewports = 0;
+ uint32_t numScissors = 0;
+
+ std::array<D3D11_VIEWPORT, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports = { };
+ std::array<D3D11_RECT, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors = { };
+
+ D3D11RasterizerState* state = nullptr;
+ };
+
+
+ struct D3D11ContextSoTarget {
+ Com<D3D11Buffer> buffer = nullptr;
+ UINT offset = 0;
+ };
+
+
+ struct D3D11ContextStateSO {
+ std::array<D3D11ContextSoTarget, D3D11_SO_BUFFER_SLOT_COUNT> targets = { };
+ };
+
+
+ struct D3D11ContextStatePR {
+ Com<D3D11Query> predicateObject = nullptr;
+ BOOL predicateValue = FALSE;
+ };
+
+
+ /**
+ * \brief Context state
+ */
+ struct D3D11ContextState {
+ D3D11ContextStateCS cs;
+ D3D11ContextStateDS ds;
+ D3D11ContextStateGS gs;
+ D3D11ContextStateHS hs;
+ D3D11ContextStatePS ps;
+ D3D11ContextStateVS vs;
+
+ D3D11ContextStateID id;
+ D3D11ContextStateIA ia;
+ D3D11ContextStateOM om;
+ D3D11ContextStateRS rs;
+ D3D11ContextStateSO so;
+ D3D11ContextStatePR pr;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp
new file mode 100644
index 00000000..4a31d347
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.cpp
@@ -0,0 +1,51 @@
+#include "d3d11_cuda.h"
+
+namespace dxvk {
+
+ CubinShaderWrapper::CubinShaderWrapper(const Rc<dxvk::DxvkDevice>& dxvkDevice, VkCuModuleNVX cuModule, VkCuFunctionNVX cuFunction, VkExtent3D blockDim)
+ : m_dxvkDevice(dxvkDevice), m_module(cuModule), m_function(cuFunction), m_blockDim(blockDim) { };
+
+
+ CubinShaderWrapper::~CubinShaderWrapper() {
+ VkDevice vkDevice = m_dxvkDevice->handle();
+ m_dxvkDevice->vkd()->vkDestroyCuFunctionNVX(vkDevice, m_function, nullptr);
+ m_dxvkDevice->vkd()->vkDestroyCuModuleNVX(vkDevice, m_module, nullptr);
+ };
+
+
+ HRESULT STDMETHODCALLTYPE CubinShaderWrapper::QueryInterface(REFIID riid, void **ppvObject) {
+ if (riid == __uuidof(IUnknown)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("CubinShaderWrapper::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void CubinShaderLaunchInfo::insertResource(ID3D11Resource* pResource, DxvkAccessFlags access) {
+ auto img = GetCommonTexture(pResource);
+ auto buf = GetCommonBuffer(pResource);
+
+ if (img)
+ insertUniqueResource(images, img->GetImage(), access);
+ if (buf)
+ insertUniqueResource(buffers, buf->GetBuffer(), access);
+ }
+
+
+ template<typename T>
+ void CubinShaderLaunchInfo::insertUniqueResource(std::vector<std::pair<T, DxvkAccessFlags>>& list, const T& resource, DxvkAccessFlags access) {
+ for (auto& entry : list) {
+ if (entry.first == resource) {
+ entry.second.set(access);
+ return;
+ }
+ }
+
+ list.push_back({ resource, access });
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h
new file mode 100644
index 00000000..a9fcdf4b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_cuda.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <utility>
+#include <vector>
+
+#include "../dxvk/dxvk_resource.h"
+
+#include "../util/com/com_guid.h"
+#include "../util/com/com_object.h"
+
+#include "d3d11_buffer.h"
+#include "d3d11_texture.h"
+
+namespace dxvk {
+
+ class CubinShaderWrapper : public ComObject<IUnknown> {
+
+ public:
+
+ CubinShaderWrapper(const Rc<dxvk::DxvkDevice>& dxvkDevice, VkCuModuleNVX cuModule, VkCuFunctionNVX cuFunction, VkExtent3D blockDim);
+ ~CubinShaderWrapper();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+
+ VkCuModuleNVX cuModule() const {
+ return m_module;
+ }
+
+ VkCuFunctionNVX cuFunction() const {
+ return m_function;
+ }
+
+ VkExtent3D blockDim() const {
+ return m_blockDim;
+ }
+
+ private:
+
+ Rc<DxvkDevice> m_dxvkDevice;
+ VkCuModuleNVX m_module;
+ VkCuFunctionNVX m_function;
+ VkExtent3D m_blockDim;
+
+ };
+
+
+ struct CubinShaderLaunchInfo {
+
+ CubinShaderLaunchInfo() = default;
+
+ CubinShaderLaunchInfo(CubinShaderLaunchInfo&& other) {
+ shader = std::move(other.shader);
+ params = std::move(other.params);
+ paramSize = std::move(other.paramSize);
+ nvxLaunchInfo = std::move(other.nvxLaunchInfo);
+ cuLaunchConfig = other.cuLaunchConfig;
+ buffers = std::move(other.buffers);
+ images = std::move(other.images);
+ other.cuLaunchConfig[1] = nullptr;
+ other.cuLaunchConfig[3] = nullptr;
+ other.nvxLaunchInfo.pExtras = nullptr;
+ // fix-up internally-pointing pointers
+ cuLaunchConfig[1] = params.data();
+ cuLaunchConfig[3] = &paramSize;
+ nvxLaunchInfo.pExtras = cuLaunchConfig.data();
+ }
+
+ Com<CubinShaderWrapper> shader;
+ std::vector<uint8_t> params;
+ size_t paramSize;
+ VkCuLaunchInfoNVX nvxLaunchInfo = { VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX };
+ std::array<void*, 5> cuLaunchConfig;
+
+ std::vector<std::pair<Rc<DxvkBuffer>, DxvkAccessFlags>> buffers;
+ std::vector<std::pair<Rc<DxvkImage>, DxvkAccessFlags>> images;
+
+ void insertResource(ID3D11Resource* pResource, DxvkAccessFlags access);
+
+ template<typename T>
+ static void insertUniqueResource(std::vector<std::pair<T, DxvkAccessFlags>>& list, const T& resource, DxvkAccessFlags access);
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp
new file mode 100644
index 00000000..b095e5ea
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.cpp
@@ -0,0 +1,166 @@
+#include "d3d11_depth_stencil.h"
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ D3D11DepthStencilState::D3D11DepthStencilState(
+ D3D11Device* device,
+ const D3D11_DEPTH_STENCIL_DESC& desc)
+ : D3D11StateObject<ID3D11DepthStencilState>(device),
+ m_desc(desc), m_d3d10(this) {
+ m_state.enableDepthTest = desc.DepthEnable;
+ m_state.enableDepthWrite = desc.DepthWriteMask == D3D11_DEPTH_WRITE_MASK_ALL;
+ m_state.enableStencilTest = desc.StencilEnable;
+ m_state.depthCompareOp = DecodeCompareOp(desc.DepthFunc);
+ m_state.stencilOpFront = DecodeStencilOpState(desc.FrontFace, desc);
+ m_state.stencilOpBack = DecodeStencilOpState(desc.BackFace, desc);
+ }
+
+
+ D3D11DepthStencilState::~D3D11DepthStencilState() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DepthStencilState::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11DepthStencilState)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10DepthStencilState)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11DepthStencilState::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DepthStencilState::GetDesc(D3D11_DEPTH_STENCIL_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ void D3D11DepthStencilState::BindToContext(const Rc<DxvkContext>& ctx) {
+ ctx->setDepthStencilState(m_state);
+ }
+
+
+ HRESULT D3D11DepthStencilState::NormalizeDesc(D3D11_DEPTH_STENCIL_DESC* pDesc) {
+ if (pDesc->DepthEnable) {
+ pDesc->DepthEnable = TRUE;
+
+ if (!ValidateDepthFunc(pDesc->DepthFunc))
+ return E_INVALIDARG;
+ } else {
+ pDesc->DepthFunc = D3D11_COMPARISON_LESS;
+ pDesc->DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ }
+
+ if (!ValidateDepthWriteMask(pDesc->DepthWriteMask))
+ return E_INVALIDARG;
+
+ if (pDesc->StencilEnable) {
+ pDesc->StencilEnable = TRUE;
+
+ if (!ValidateStencilFunc(pDesc->FrontFace.StencilFunc)
+ || !ValidateStencilOp(pDesc->FrontFace.StencilFailOp)
+ || !ValidateStencilOp(pDesc->FrontFace.StencilDepthFailOp)
+ || !ValidateStencilOp(pDesc->FrontFace.StencilPassOp))
+ return E_INVALIDARG;
+
+ if (!ValidateStencilFunc(pDesc->BackFace.StencilFunc)
+ || !ValidateStencilOp(pDesc->BackFace.StencilFailOp)
+ || !ValidateStencilOp(pDesc->BackFace.StencilDepthFailOp)
+ || !ValidateStencilOp(pDesc->BackFace.StencilPassOp))
+ return E_INVALIDARG;
+ } else {
+ D3D11_DEPTH_STENCILOP_DESC stencilOp;
+ stencilOp.StencilFailOp = D3D11_STENCIL_OP_KEEP;
+ stencilOp.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
+ stencilOp.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ stencilOp.StencilFunc = D3D11_COMPARISON_ALWAYS;
+
+ pDesc->FrontFace = stencilOp;
+ pDesc->BackFace = stencilOp;
+ pDesc->StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
+ pDesc->StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
+ }
+
+ return S_OK;
+ }
+
+
+ VkStencilOpState D3D11DepthStencilState::DecodeStencilOpState(
+ const D3D11_DEPTH_STENCILOP_DESC& StencilDesc,
+ const D3D11_DEPTH_STENCIL_DESC& Desc) const {
+ VkStencilOpState result;
+ result.failOp = VK_STENCIL_OP_KEEP;
+ result.passOp = VK_STENCIL_OP_KEEP;
+ result.depthFailOp = VK_STENCIL_OP_KEEP;
+ result.compareOp = VK_COMPARE_OP_ALWAYS;
+ result.compareMask = Desc.StencilReadMask;
+ result.writeMask = Desc.StencilWriteMask;
+ result.reference = 0;
+
+ if (Desc.StencilEnable) {
+ result.failOp = DecodeStencilOp(StencilDesc.StencilFailOp);
+ result.passOp = DecodeStencilOp(StencilDesc.StencilPassOp);
+ result.depthFailOp = DecodeStencilOp(StencilDesc.StencilDepthFailOp);
+ result.compareOp = DecodeCompareOp(StencilDesc.StencilFunc);
+ }
+
+ return result;
+ }
+
+
+ VkStencilOp D3D11DepthStencilState::DecodeStencilOp(D3D11_STENCIL_OP Op) const {
+ switch (Op) {
+ case D3D11_STENCIL_OP_KEEP: return VK_STENCIL_OP_KEEP;
+ case D3D11_STENCIL_OP_ZERO: return VK_STENCIL_OP_ZERO;
+ case D3D11_STENCIL_OP_REPLACE: return VK_STENCIL_OP_REPLACE;
+ case D3D11_STENCIL_OP_INCR_SAT: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
+ case D3D11_STENCIL_OP_DECR_SAT: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
+ case D3D11_STENCIL_OP_INVERT: return VK_STENCIL_OP_INVERT;
+ case D3D11_STENCIL_OP_INCR: return VK_STENCIL_OP_INCREMENT_AND_WRAP;
+ case D3D11_STENCIL_OP_DECR: return VK_STENCIL_OP_DECREMENT_AND_WRAP;
+ default: return VK_STENCIL_OP_KEEP;
+ }
+ }
+
+
+ bool D3D11DepthStencilState::ValidateDepthFunc(D3D11_COMPARISON_FUNC Comparison) {
+ return Comparison >= D3D11_COMPARISON_NEVER
+ && Comparison <= D3D11_COMPARISON_ALWAYS;
+ }
+
+
+ bool D3D11DepthStencilState::ValidateStencilFunc(D3D11_COMPARISON_FUNC Comparison) {
+ return Comparison >= D3D11_COMPARISON_NEVER
+ && Comparison <= D3D11_COMPARISON_ALWAYS;
+ }
+
+
+ bool D3D11DepthStencilState::ValidateStencilOp(D3D11_STENCIL_OP StencilOp) {
+ return StencilOp >= D3D11_STENCIL_OP_KEEP
+ && StencilOp <= D3D11_STENCIL_OP_DECR;
+ }
+
+
+ bool D3D11DepthStencilState::ValidateDepthWriteMask(D3D11_DEPTH_WRITE_MASK Mask) {
+ return Mask == D3D11_DEPTH_WRITE_MASK_ZERO
+ || Mask == D3D11_DEPTH_WRITE_MASK_ALL;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h
new file mode 100644
index 00000000..6311259f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_depth_stencil.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_depth_stencil.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_util.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11DepthStencilState : public D3D11StateObject<ID3D11DepthStencilState> {
+
+ public:
+
+ using DescType = D3D11_DEPTH_STENCIL_DESC;
+
+ D3D11DepthStencilState(
+ D3D11Device* device,
+ const D3D11_DEPTH_STENCIL_DESC& desc);
+ ~D3D11DepthStencilState();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_DEPTH_STENCIL_DESC* pDesc) final;
+
+ void BindToContext(
+ const Rc<DxvkContext>& ctx);
+
+ D3D10DepthStencilState* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT NormalizeDesc(
+ D3D11_DEPTH_STENCIL_DESC* pDesc);
+
+ private:
+
+ D3D11_DEPTH_STENCIL_DESC m_desc;
+ DxvkDepthStencilState m_state;
+ D3D10DepthStencilState m_d3d10;
+
+ VkStencilOpState DecodeStencilOpState(
+ const D3D11_DEPTH_STENCILOP_DESC& StencilDesc,
+ const D3D11_DEPTH_STENCIL_DESC& Desc) const;
+
+ VkStencilOp DecodeStencilOp(
+ D3D11_STENCIL_OP Op) const;
+
+ static bool ValidateDepthFunc(
+ D3D11_COMPARISON_FUNC Comparison);
+
+ static bool ValidateStencilFunc(
+ D3D11_COMPARISON_FUNC Comparison);
+
+ static bool ValidateStencilOp(
+ D3D11_STENCIL_OP StencilOp);
+
+ static bool ValidateDepthWriteMask(
+ D3D11_DEPTH_WRITE_MASK Mask);
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp
new file mode 100644
index 00000000..d55c36ba
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.cpp
@@ -0,0 +1,3447 @@
+#include <algorithm>
+#include <cstring>
+
+#include "../dxgi/dxgi_monitor.h"
+#include "../dxgi/dxgi_swapchain.h"
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_instance.h"
+
+#include "d3d11_buffer.h"
+#include "d3d11_class_linkage.h"
+#include "d3d11_context_def.h"
+#include "d3d11_context_imm.h"
+#include "d3d11_device.h"
+#include "d3d11_input_layout.h"
+#include "d3d11_interop.h"
+#include "d3d11_query.h"
+#include "d3d11_resource.h"
+#include "d3d11_sampler.h"
+#include "d3d11_shader.h"
+#include "d3d11_state_object.h"
+#include "d3d11_swapchain.h"
+#include "d3d11_texture.h"
+#include "d3d11_video.h"
+
+namespace dxvk {
+
+ constexpr uint32_t D3D11DXGIDevice::DefaultFrameLatency;
+
+
+
+ D3D11Device::D3D11Device(
+ D3D11DXGIDevice* pContainer,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ UINT FeatureFlags)
+ : m_container (pContainer),
+ m_featureLevel (FeatureLevel),
+ m_featureFlags (FeatureFlags),
+ m_dxvkDevice (pContainer->GetDXVKDevice()),
+ m_dxvkAdapter (m_dxvkDevice->adapter()),
+ m_d3d11Formats (m_dxvkAdapter),
+ m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice),
+ m_dxbcOptions (m_dxvkDevice, m_d3d11Options) {
+ m_initializer = new D3D11Initializer(this);
+ m_context = new D3D11ImmediateContext(this, m_dxvkDevice);
+ m_d3d10Device = new D3D10Device(this, m_context.ptr());
+ }
+
+
+ D3D11Device::~D3D11Device() {
+ delete m_d3d10Device;
+ m_context = nullptr;
+ delete m_initializer;
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11Device::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11Device::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::QueryInterface(REFIID riid, void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateBuffer(
+ const D3D11_BUFFER_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Buffer** ppBuffer) {
+ InitReturnPtr(ppBuffer);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_BUFFER_DESC desc = *pDesc;
+ HRESULT hr = D3D11Buffer::NormalizeBufferProperties(&desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppBuffer)
+ return S_FALSE;
+
+ try {
+ const Com<D3D11Buffer> buffer = new D3D11Buffer(this, &desc);
+ m_initializer->InitBuffer(buffer.ptr(), pInitialData);
+ *ppBuffer = buffer.ref();
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture1D(
+ const D3D11_TEXTURE1D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture1D** ppTexture1D) {
+ InitReturnPtr(ppTexture1D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_TEXTURE_DESC desc;
+ desc.Width = pDesc->Width;
+ desc.Height = 1;
+ desc.Depth = 1;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.ArraySize = pDesc->ArraySize;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = DXGI_SAMPLE_DESC { 1, 0 };
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppTexture1D)
+ return S_FALSE;
+
+ try {
+ const Com<D3D11Texture1D> texture = new D3D11Texture1D(this, &desc);
+ m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
+ *ppTexture1D = texture.ref();
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2D(
+ const D3D11_TEXTURE2D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture2D** ppTexture2D) {
+ InitReturnPtr(ppTexture2D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE2D_DESC1 desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.ArraySize = pDesc->ArraySize;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = pDesc->SampleDesc;
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ ID3D11Texture2D1* texture2D = nullptr;
+ HRESULT hr = CreateTexture2D1(&desc, pInitialData, ppTexture2D ? &texture2D : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppTexture2D = texture2D;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture2D1(
+ const D3D11_TEXTURE2D_DESC1* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture2D1** ppTexture2D) {
+ InitReturnPtr(ppTexture2D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_TEXTURE_DESC desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.Depth = 1;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.ArraySize = pDesc->ArraySize;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = pDesc->SampleDesc;
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = pDesc->TextureLayout;
+
+ HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppTexture2D)
+ return S_FALSE;
+
+ try {
+ Com<D3D11Texture2D> texture = new D3D11Texture2D(this, &desc);
+ m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
+ *ppTexture2D = texture.ref();
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3D(
+ const D3D11_TEXTURE3D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture3D** ppTexture3D) {
+ InitReturnPtr(ppTexture3D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE3D_DESC1 desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.Depth = pDesc->Depth;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.Format = pDesc->Format;
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ ID3D11Texture3D1* texture3D = nullptr;
+ HRESULT hr = CreateTexture3D1(&desc, pInitialData, ppTexture3D ? &texture3D : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppTexture3D = texture3D;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateTexture3D1(
+ const D3D11_TEXTURE3D_DESC1* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture3D1** ppTexture3D) {
+ InitReturnPtr(ppTexture3D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_TEXTURE_DESC desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.Depth = pDesc->Depth;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.ArraySize = 1;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = DXGI_SAMPLE_DESC { 1, 0 };
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = pDesc->TextureLayout;
+
+ HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppTexture3D)
+ return S_FALSE;
+
+ try {
+ Com<D3D11Texture3D> texture = new D3D11Texture3D(this, &desc);
+ m_initializer->InitTexture(texture->GetCommonTexture(), pInitialData);
+ *ppTexture3D = texture.ref();
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceView(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D11ShaderResourceView** ppSRView) {
+ InitReturnPtr(ppSRView);
+
+ uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC1 desc = pDesc
+ ? D3D11ShaderResourceView::PromoteDesc(pDesc, plane)
+ : D3D11_SHADER_RESOURCE_VIEW_DESC1();
+
+ ID3D11ShaderResourceView1* view = nullptr;
+
+ HRESULT hr = CreateShaderResourceView1(pResource,
+ pDesc ? &desc : nullptr,
+ ppSRView ? &view : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppSRView = view;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateShaderResourceView1(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
+ ID3D11ShaderResourceView1** ppSRView) {
+ InitReturnPtr(ppSRView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ // The description is optional. If omitted, we'll create
+ // a view that covers all subresources of the image.
+ D3D11_SHADER_RESOURCE_VIEW_DESC1 desc;
+
+ if (!pDesc) {
+ if (FAILED(D3D11ShaderResourceView::GetDescFromResource(pResource, &desc)))
+ return E_INVALIDARG;
+ } else {
+ desc = *pDesc;
+
+ if (FAILED(D3D11ShaderResourceView::NormalizeDesc(pResource, &desc)))
+ return E_INVALIDARG;
+ }
+
+ uint32_t plane = D3D11ShaderResourceView::GetPlaneSlice(&desc);
+
+ if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_SHADER_RESOURCE, desc.Format, plane)) {
+ Logger::err(str::format("D3D11: Cannot create shader resource view:",
+ "\n Resource type: ", resourceDesc.Dim,
+ "\n Resource usage: ", resourceDesc.BindFlags,
+ "\n Resource format: ", resourceDesc.Format,
+ "\n View format: ", desc.Format,
+ "\n View plane: ", plane));
+ return E_INVALIDARG;
+ }
+
+ if (!ppSRView)
+ return S_FALSE;
+
+ try {
+ *ppSRView = ref(new D3D11ShaderResourceView(this, pResource, &desc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessView(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ ID3D11UnorderedAccessView** ppUAView) {
+ InitReturnPtr(ppUAView);
+
+ uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
+
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc = pDesc
+ ? D3D11UnorderedAccessView::PromoteDesc(pDesc, plane)
+ : D3D11_UNORDERED_ACCESS_VIEW_DESC1();
+
+ ID3D11UnorderedAccessView1* view = nullptr;
+
+ HRESULT hr = CreateUnorderedAccessView1(pResource,
+ pDesc ? &desc : nullptr,
+ ppUAView ? &view : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppUAView = view;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateUnorderedAccessView1(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
+ ID3D11UnorderedAccessView1** ppUAView) {
+ InitReturnPtr(ppUAView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ // The description is optional. If omitted, we'll create
+ // a view that covers all subresources of the image.
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1 desc;
+
+ if (!pDesc) {
+ if (FAILED(D3D11UnorderedAccessView::GetDescFromResource(pResource, &desc)))
+ return E_INVALIDARG;
+ } else {
+ desc = *pDesc;
+
+ if (FAILED(D3D11UnorderedAccessView::NormalizeDesc(pResource, &desc)))
+ return E_INVALIDARG;
+ }
+
+ uint32_t plane = D3D11UnorderedAccessView::GetPlaneSlice(&desc);
+
+ if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_UNORDERED_ACCESS, desc.Format, plane)) {
+ Logger::err(str::format("D3D11: Cannot create unordered access view:",
+ "\n Resource type: ", resourceDesc.Dim,
+ "\n Resource usage: ", resourceDesc.BindFlags,
+ "\n Resource format: ", resourceDesc.Format,
+ "\n View format: ", desc.Format,
+ "\n View plane: ", plane));
+ return E_INVALIDARG;
+ }
+
+ if (!ppUAView)
+ return S_FALSE;
+
+ try {
+ auto uav = new D3D11UnorderedAccessView(this, pResource, &desc);
+ m_initializer->InitUavCounter(uav);
+ *ppUAView = ref(uav);
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetView(
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
+ ID3D11RenderTargetView** ppRTView) {
+ InitReturnPtr(ppRTView);
+
+ uint32_t plane = GetViewPlaneIndex(pResource, pDesc ? pDesc->Format : DXGI_FORMAT_UNKNOWN);
+
+ D3D11_RENDER_TARGET_VIEW_DESC1 desc = pDesc
+ ? D3D11RenderTargetView::PromoteDesc(pDesc, plane)
+ : D3D11_RENDER_TARGET_VIEW_DESC1();
+
+ ID3D11RenderTargetView1* view = nullptr;
+
+ HRESULT hr = CreateRenderTargetView1(pResource,
+ pDesc ? &desc : nullptr,
+ ppRTView ? &view : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppRTView = view;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateRenderTargetView1(
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
+ ID3D11RenderTargetView1** ppRTView) {
+ InitReturnPtr(ppRTView);
+
+ if (!pResource)
+ return E_INVALIDARG;
+
+ // DXVK only supports render target views for image resources
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ Logger::warn("D3D11: Cannot create render target view for a buffer");
+ return S_OK; // It is required to run Battlefield 3 and Battlefield 4.
+ }
+
+ // The view description is optional. If not defined, it
+ // will use the resource's format and all array layers.
+ D3D11_RENDER_TARGET_VIEW_DESC1 desc;
+
+ if (!pDesc) {
+ if (FAILED(D3D11RenderTargetView::GetDescFromResource(pResource, &desc)))
+ return E_INVALIDARG;
+ } else {
+ desc = *pDesc;
+
+ if (FAILED(D3D11RenderTargetView::NormalizeDesc(pResource, &desc)))
+ return E_INVALIDARG;
+ }
+
+ uint32_t plane = D3D11RenderTargetView::GetPlaneSlice(&desc);
+
+ if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_RENDER_TARGET, desc.Format, plane)) {
+ Logger::err(str::format("D3D11: Cannot create render target view:",
+ "\n Resource type: ", resourceDesc.Dim,
+ "\n Resource usage: ", resourceDesc.BindFlags,
+ "\n Resource format: ", resourceDesc.Format,
+ "\n View format: ", desc.Format,
+ "\n View plane: ", plane));
+ return E_INVALIDARG;
+ }
+
+ if (!ppRTView)
+ return S_FALSE;
+
+ try {
+ *ppRTView = ref(new D3D11RenderTargetView(this, pResource, &desc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDepthStencilView(
+ ID3D11Resource* pResource,
+ const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc,
+ ID3D11DepthStencilView** ppDepthStencilView) {
+ InitReturnPtr(ppDepthStencilView);
+
+ if (pResource == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ // The view description is optional. If not defined, it
+ // will use the resource's format and all array layers.
+ D3D11_DEPTH_STENCIL_VIEW_DESC desc;
+
+ if (pDesc == nullptr) {
+ if (FAILED(D3D11DepthStencilView::GetDescFromResource(pResource, &desc)))
+ return E_INVALIDARG;
+ } else {
+ desc = *pDesc;
+
+ if (FAILED(D3D11DepthStencilView::NormalizeDesc(pResource, &desc)))
+ return E_INVALIDARG;
+ }
+
+ if (!CheckResourceViewCompatibility(pResource, D3D11_BIND_DEPTH_STENCIL, desc.Format, 0)) {
+ Logger::err(str::format("D3D11: Cannot create depth-stencil view:",
+ "\n Resource type: ", resourceDesc.Dim,
+ "\n Resource usage: ", resourceDesc.BindFlags,
+ "\n Resource format: ", resourceDesc.Format,
+ "\n View format: ", desc.Format));
+ return E_INVALIDARG;
+ }
+
+ if (ppDepthStencilView == nullptr)
+ return S_FALSE;
+
+ try {
+ *ppDepthStencilView = ref(new D3D11DepthStencilView(this, pResource, &desc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateInputLayout(
+ const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs,
+ UINT NumElements,
+ const void* pShaderBytecodeWithInputSignature,
+ SIZE_T BytecodeLength,
+ ID3D11InputLayout** ppInputLayout) {
+ InitReturnPtr(ppInputLayout);
+
+ if (pInputElementDescs == nullptr)
+ return E_INVALIDARG;
+
+ try {
+ DxbcReader dxbcReader(reinterpret_cast<const char*>(
+ pShaderBytecodeWithInputSignature), BytecodeLength);
+ DxbcModule dxbcModule(dxbcReader);
+
+ const Rc<DxbcIsgn> inputSignature = dxbcModule.isgn();
+
+ uint32_t attrMask = 0;
+ uint32_t bindMask = 0;
+
+ std::array<DxvkVertexAttribute, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> attrList;
+ std::array<DxvkVertexBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> bindList;
+
+ for (uint32_t i = 0; i < NumElements; i++) {
+ const DxbcSgnEntry* entry = inputSignature->find(
+ pInputElementDescs[i].SemanticName,
+ pInputElementDescs[i].SemanticIndex, 0);
+
+ if (entry == nullptr) {
+ Logger::debug(str::format(
+ "D3D11Device: No such vertex shader semantic: ",
+ pInputElementDescs[i].SemanticName,
+ pInputElementDescs[i].SemanticIndex));
+ }
+
+ // Create vertex input attribute description
+ DxvkVertexAttribute attrib;
+ attrib.location = entry != nullptr ? entry->registerId : 0;
+ attrib.binding = pInputElementDescs[i].InputSlot;
+ attrib.format = LookupFormat(pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
+ attrib.offset = pInputElementDescs[i].AlignedByteOffset;
+
+ // The application may choose to let the implementation
+ // generate the exact vertex layout. In that case we'll
+ // pack attributes on the same binding in the order they
+ // are declared, aligning each attribute to four bytes.
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(attrib.format);
+ VkDeviceSize alignment = std::min<VkDeviceSize>(formatInfo->elementSize, 4);
+
+ if (attrib.offset == D3D11_APPEND_ALIGNED_ELEMENT) {
+ attrib.offset = 0;
+
+ for (uint32_t j = 1; j <= i; j++) {
+ const DxvkVertexAttribute& prev = attrList.at(i - j);
+
+ if (prev.binding == attrib.binding) {
+ attrib.offset = align(prev.offset + imageFormatInfo(prev.format)->elementSize, alignment);
+ break;
+ }
+ }
+ } else if (attrib.offset & (alignment - 1))
+ return E_INVALIDARG;
+
+ attrList.at(i) = attrib;
+
+ // Create vertex input binding description. The
+ // stride is dynamic state in D3D11 and will be
+ // set by D3D11DeviceContext::IASetVertexBuffers.
+ DxvkVertexBinding binding;
+ binding.binding = pInputElementDescs[i].InputSlot;
+ binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate;
+ binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA
+ ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
+
+ // Check if the binding was already defined. If so, the
+ // parameters must be identical (namely, the input rate).
+ bool bindingDefined = false;
+
+ for (uint32_t j = 0; j < i; j++) {
+ uint32_t bindingId = attrList.at(j).binding;
+
+ if (binding.binding == bindingId) {
+ bindingDefined = true;
+
+ if (binding.inputRate != bindList.at(bindingId).inputRate) {
+ Logger::err(str::format(
+ "D3D11Device: Conflicting input rate for binding ",
+ binding.binding));
+ return E_INVALIDARG;
+ }
+ }
+ }
+
+ if (!bindingDefined)
+ bindList.at(binding.binding) = binding;
+
+ if (entry != nullptr) {
+ attrMask |= 1u << i;
+ bindMask |= 1u << binding.binding;
+ }
+ }
+
+ // Compact the attribute and binding lists to filter
+ // out attributes and bindings not used by the shader
+ uint32_t attrCount = CompactSparseList(attrList.data(), attrMask);
+ uint32_t bindCount = CompactSparseList(bindList.data(), bindMask);
+
+ // Check if there are any semantics defined in the
+ // shader that are not included in the current input
+ // layout.
+ for (auto i = inputSignature->begin(); i != inputSignature->end(); i++) {
+ bool found = i->systemValue != DxbcSystemValue::None;
+
+ for (uint32_t j = 0; j < attrCount && !found; j++)
+ found = attrList.at(j).location == i->registerId;
+
+ if (!found) {
+ Logger::warn(str::format(
+ "D3D11Device: Vertex input '",
+ i->semanticName, i->semanticIndex,
+ "' not defined by input layout"));
+ }
+ }
+
+ // Create the actual input layout object
+ // if the application requests it.
+ if (ppInputLayout != nullptr) {
+ *ppInputLayout = ref(
+ new D3D11InputLayout(this,
+ attrCount, attrList.data(),
+ bindCount, bindList.data()));
+ }
+
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateVertexShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11VertexShader** ppVertexShader) {
+ InitReturnPtr(ppVertexShader);
+ D3D11CommonShader module;
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_VERTEX_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage,
+ &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppVertexShader)
+ return S_FALSE;
+
+ *ppVertexShader = ref(new D3D11VertexShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateGeometryShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11GeometryShader** ppGeometryShader) {
+ InitReturnPtr(ppGeometryShader);
+ D3D11CommonShader module;
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage,
+ &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppGeometryShader)
+ return S_FALSE;
+
+ *ppGeometryShader = ref(new D3D11GeometryShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateGeometryShaderWithStreamOutput(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ const D3D11_SO_DECLARATION_ENTRY* pSODeclaration,
+ UINT NumEntries,
+ const UINT* pBufferStrides,
+ UINT NumStrides,
+ UINT RasterizedStream,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11GeometryShader** ppGeometryShader) {
+ InitReturnPtr(ppGeometryShader);
+ D3D11CommonShader module;
+
+ if (!m_dxvkDevice->features().extTransformFeedback.transformFeedback)
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Zero-init some counterss so that we can increment
+ // them while walking over the stream output entries
+ DxbcXfbInfo xfb = { };
+
+ for (uint32_t i = 0; i < NumEntries; i++) {
+ const D3D11_SO_DECLARATION_ENTRY* so = &pSODeclaration[i];
+
+ if (so->OutputSlot >= D3D11_SO_BUFFER_SLOT_COUNT)
+ return E_INVALIDARG;
+
+ if (so->SemanticName != nullptr) {
+ if (so->Stream >= D3D11_SO_BUFFER_SLOT_COUNT
+ || so->StartComponent >= 4
+ || so->ComponentCount < 1
+ || so->ComponentCount > 4)
+ return E_INVALIDARG;
+
+ DxbcXfbEntry* entry = &xfb.entries[xfb.entryCount++];
+ entry->semanticName = so->SemanticName;
+ entry->semanticIndex = so->SemanticIndex;
+ entry->componentIndex = so->StartComponent;
+ entry->componentCount = so->ComponentCount;
+ entry->streamId = so->Stream;
+ entry->bufferId = so->OutputSlot;
+ entry->offset = xfb.strides[so->OutputSlot];
+ }
+
+ xfb.strides[so->OutputSlot] += so->ComponentCount * sizeof(uint32_t);
+ }
+
+ // If necessary, override the buffer strides
+ for (uint32_t i = 0; i < NumStrides; i++)
+ xfb.strides[i] = pBufferStrides[i];
+
+ // Set stream to rasterize, if any
+ xfb.rasterizedStream = -1;
+
+ if (RasterizedStream != D3D11_SO_NO_RASTERIZED_STREAM)
+ Logger::err("D3D11: CreateGeometryShaderWithStreamOutput: Rasterized stream not supported");
+
+ // Compute hash from both the xfb info and the source
+ // code, because both influence the generated code
+ DxbcXfbInfo hashXfb = xfb;
+
+ std::vector<Sha1Data> chunks = {{
+ { pShaderBytecode, BytecodeLength },
+ { &hashXfb, sizeof(hashXfb) },
+ }};
+
+ for (uint32_t i = 0; i < hashXfb.entryCount; i++) {
+ const char* semantic = hashXfb.entries[i].semanticName;
+
+ if (semantic) {
+ chunks.push_back({ semantic, std::strlen(semantic) });
+ hashXfb.entries[i].semanticName = nullptr;
+ }
+ }
+
+ Sha1Hash hash = Sha1Hash::compute(chunks.size(), chunks.data());
+
+ // Create the actual shader module
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = &xfb;
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage,
+ &moduleInfo);
+
+ if (FAILED(hr))
+ return E_INVALIDARG;
+
+ if (!ppGeometryShader)
+ return S_FALSE;
+
+ *ppGeometryShader = ref(new D3D11GeometryShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreatePixelShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11PixelShader** ppPixelShader) {
+ InitReturnPtr(ppPixelShader);
+ D3D11CommonShader module;
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_FRAGMENT_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage,
+ &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppPixelShader)
+ return S_FALSE;
+
+ *ppPixelShader = ref(new D3D11PixelShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateHullShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11HullShader** ppHullShader) {
+ InitReturnPtr(ppHullShader);
+ D3D11CommonShader module;
+
+ DxbcTessInfo tessInfo;
+ tessInfo.maxTessFactor = float(m_d3d11Options.maxTessFactor);
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ if (tessInfo.maxTessFactor >= 8.0f)
+ moduleInfo.tess = &tessInfo;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppHullShader)
+ return S_FALSE;
+
+ *ppHullShader = ref(new D3D11HullShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDomainShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11DomainShader** ppDomainShader) {
+ InitReturnPtr(ppDomainShader);
+ D3D11CommonShader module;
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (ppDomainShader == nullptr)
+ return S_FALSE;
+
+ *ppDomainShader = ref(new D3D11DomainShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateComputeShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11ComputeShader** ppComputeShader) {
+ InitReturnPtr(ppComputeShader);
+ D3D11CommonShader module;
+
+ DxbcModuleInfo moduleInfo;
+ moduleInfo.options = m_dxbcOptions;
+ moduleInfo.tess = nullptr;
+ moduleInfo.xfb = nullptr;
+
+ Sha1Hash hash = Sha1Hash::compute(
+ pShaderBytecode, BytecodeLength);
+
+ HRESULT hr = CreateShaderModule(&module,
+ DxvkShaderKey(VK_SHADER_STAGE_COMPUTE_BIT, hash),
+ pShaderBytecode, BytecodeLength, pClassLinkage,
+ &moduleInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppComputeShader)
+ return S_FALSE;
+
+ *ppComputeShader = ref(new D3D11ComputeShader(this, module));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateClassLinkage(ID3D11ClassLinkage** ppLinkage) {
+ *ppLinkage = ref(new D3D11ClassLinkage(this));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState(
+ const D3D11_BLEND_DESC* pBlendStateDesc,
+ ID3D11BlendState** ppBlendState) {
+ InitReturnPtr(ppBlendState);
+
+ if (!pBlendStateDesc)
+ return E_INVALIDARG;
+
+ D3D11_BLEND_DESC1 desc = D3D11BlendState::PromoteDesc(pBlendStateDesc);
+
+ if (FAILED(D3D11BlendState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (ppBlendState != nullptr) {
+ *ppBlendState = m_bsStateObjects.Create(this, desc);
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateBlendState1(
+ const D3D11_BLEND_DESC1* pBlendStateDesc,
+ ID3D11BlendState1** ppBlendState) {
+ InitReturnPtr(ppBlendState);
+
+ if (!pBlendStateDesc)
+ return E_INVALIDARG;
+
+ D3D11_BLEND_DESC1 desc = *pBlendStateDesc;
+
+ if (FAILED(D3D11BlendState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (ppBlendState != nullptr) {
+ *ppBlendState = m_bsStateObjects.Create(this, desc);
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDepthStencilState(
+ const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc,
+ ID3D11DepthStencilState** ppDepthStencilState) {
+ InitReturnPtr(ppDepthStencilState);
+
+ if (!pDepthStencilDesc)
+ return E_INVALIDARG;
+
+ D3D11_DEPTH_STENCIL_DESC desc = *pDepthStencilDesc;
+
+ if (FAILED(D3D11DepthStencilState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (ppDepthStencilState != nullptr) {
+ *ppDepthStencilState = m_dsStateObjects.Create(this, desc);
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateRasterizerState(
+ const D3D11_RASTERIZER_DESC* pRasterizerDesc,
+ ID3D11RasterizerState** ppRasterizerState) {
+ InitReturnPtr(ppRasterizerState);
+
+ if (!pRasterizerDesc)
+ return E_INVALIDARG;
+
+ D3D11_RASTERIZER_DESC2 desc = D3D11RasterizerState::PromoteDesc(pRasterizerDesc);
+
+ if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (!ppRasterizerState)
+ return S_FALSE;
+
+ *ppRasterizerState = m_rsStateObjects.Create(this, desc);
+ return S_OK;
+ }
+
+
+ HRESULT D3D11Device::CreateRasterizerState1(
+ const D3D11_RASTERIZER_DESC1* pRasterizerDesc,
+ ID3D11RasterizerState1** ppRasterizerState) {
+ InitReturnPtr(ppRasterizerState);
+
+ if (!pRasterizerDesc)
+ return E_INVALIDARG;
+
+ D3D11_RASTERIZER_DESC2 desc = D3D11RasterizerState::PromoteDesc(pRasterizerDesc);
+
+ if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (!ppRasterizerState)
+ return S_FALSE;
+
+ *ppRasterizerState = m_rsStateObjects.Create(this, desc);
+ return S_OK;
+ }
+
+
+ HRESULT D3D11Device::CreateRasterizerState2(
+ const D3D11_RASTERIZER_DESC2* pRasterizerDesc,
+ ID3D11RasterizerState2** ppRasterizerState) {
+ InitReturnPtr(ppRasterizerState);
+
+ if (!pRasterizerDesc)
+ return E_INVALIDARG;
+
+ D3D11_RASTERIZER_DESC2 desc = *pRasterizerDesc;
+
+ if (FAILED(D3D11RasterizerState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (desc.ConservativeRaster != D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF
+ && !m_dxvkDevice->extensions().extConservativeRasterization)
+ return E_INVALIDARG;
+
+ if (!ppRasterizerState)
+ return S_FALSE;
+
+ *ppRasterizerState = m_rsStateObjects.Create(this, desc);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateSamplerState(
+ const D3D11_SAMPLER_DESC* pSamplerDesc,
+ ID3D11SamplerState** ppSamplerState) {
+ InitReturnPtr(ppSamplerState);
+
+ if (pSamplerDesc == nullptr)
+ return E_INVALIDARG;
+
+ D3D11_SAMPLER_DESC desc = *pSamplerDesc;
+
+ if (FAILED(D3D11SamplerState::NormalizeDesc(&desc)))
+ return E_INVALIDARG;
+
+ if (ppSamplerState == nullptr)
+ return S_FALSE;
+
+ try {
+ *ppSamplerState = m_samplerObjects.Create(this, desc);
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateQuery(
+ const D3D11_QUERY_DESC* pQueryDesc,
+ ID3D11Query** ppQuery) {
+ InitReturnPtr(ppQuery);
+
+ if (!pQueryDesc)
+ return E_INVALIDARG;
+
+ D3D11_QUERY_DESC1 desc;
+ desc.Query = pQueryDesc->Query;
+ desc.MiscFlags = pQueryDesc->MiscFlags;
+ desc.ContextType = D3D11_CONTEXT_TYPE_ALL;
+
+ ID3D11Query1* query = nullptr;
+ HRESULT hr = CreateQuery1(&desc, ppQuery ? &query : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ *ppQuery = query;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateQuery1(
+ const D3D11_QUERY_DESC1* pQueryDesc,
+ ID3D11Query1** ppQuery) {
+ InitReturnPtr(ppQuery);
+
+ if (!pQueryDesc)
+ return E_INVALIDARG;
+
+ HRESULT hr = D3D11Query::ValidateDesc(pQueryDesc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppQuery)
+ return S_FALSE;
+
+ try {
+ *ppQuery = ref(new D3D11Query(this, *pQueryDesc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreatePredicate(
+ const D3D11_QUERY_DESC* pPredicateDesc,
+ ID3D11Predicate** ppPredicate) {
+ InitReturnPtr(ppPredicate);
+
+ if (!pPredicateDesc)
+ return E_INVALIDARG;
+
+ D3D11_QUERY_DESC1 desc;
+ desc.Query = pPredicateDesc->Query;
+ desc.MiscFlags = pPredicateDesc->MiscFlags;
+ desc.ContextType = D3D11_CONTEXT_TYPE_ALL;
+
+ if (desc.Query != D3D11_QUERY_OCCLUSION_PREDICATE) {
+ Logger::warn(str::format("D3D11: Unhandled predicate type: ", pPredicateDesc->Query));
+ return E_INVALIDARG;
+ }
+
+ if (!ppPredicate)
+ return S_FALSE;
+
+ try {
+ *ppPredicate = D3D11Query::AsPredicate(
+ ref(new D3D11Query(this, desc)));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateCounter(
+ const D3D11_COUNTER_DESC* pCounterDesc,
+ ID3D11Counter** ppCounter) {
+ InitReturnPtr(ppCounter);
+
+ Logger::err(str::format("D3D11: Unsupported counter: ", pCounterDesc->Counter));
+ return E_INVALIDARG;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext(
+ UINT ContextFlags,
+ ID3D11DeviceContext** ppDeferredContext) {
+ *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext1(
+ UINT ContextFlags,
+ ID3D11DeviceContext1** ppDeferredContext) {
+ *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext2(
+ UINT ContextFlags,
+ ID3D11DeviceContext2** ppDeferredContext) {
+ *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeferredContext3(
+ UINT ContextFlags,
+ ID3D11DeviceContext3** ppDeferredContext) {
+ *ppDeferredContext = ref(new D3D11DeferredContext(this, m_dxvkDevice, ContextFlags));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateDeviceContextState(
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ REFIID EmulatedInterface,
+ D3D_FEATURE_LEVEL* pChosenFeatureLevel,
+ ID3DDeviceContextState** ppContextState) {
+ InitReturnPtr(ppContextState);
+
+ if (!pFeatureLevels || FeatureLevels == 0)
+ return E_INVALIDARG;
+
+ if (EmulatedInterface != __uuidof(ID3D10Device)
+ && EmulatedInterface != __uuidof(ID3D10Device1)
+ && EmulatedInterface != __uuidof(ID3D11Device)
+ && EmulatedInterface != __uuidof(ID3D11Device1))
+ return E_INVALIDARG;
+
+ UINT flId;
+ for (flId = 0; flId < FeatureLevels; flId++) {
+ if (CheckFeatureLevelSupport(m_dxvkDevice->instance(), m_dxvkAdapter, pFeatureLevels[flId]))
+ break;
+ }
+
+ if (flId == FeatureLevels)
+ return E_INVALIDARG;
+
+ if (pFeatureLevels[flId] > m_featureLevel)
+ m_featureLevel = pFeatureLevels[flId];
+
+ if (pChosenFeatureLevel)
+ *pChosenFeatureLevel = pFeatureLevels[flId];
+
+ if (!ppContextState)
+ return S_FALSE;
+
+ *ppContextState = ref(new D3D11DeviceContextState(this));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CreateFence(
+ UINT64 InitialValue,
+ D3D11_FENCE_FLAG Flags,
+ REFIID ReturnedInterface,
+ void** ppFence) {
+ InitReturnPtr(ppFence);
+
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11Device::CreateFence: Not implemented");
+
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::ReadFromSubresource(
+ void* pDstData,
+ UINT DstRowPitch,
+ UINT DstDepthPitch,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox) {
+ CopySubresourceData(
+ pDstData, DstRowPitch, DstDepthPitch,
+ pSrcResource, SrcSubresource, pSrcBox);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::WriteToSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch) {
+ CopySubresourceData(
+ pSrcData, SrcRowPitch, SrcRowPitch,
+ pDstResource, DstSubresource, pDstBox);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResource(
+ HANDLE hResource,
+ REFIID ReturnedInterface,
+ void** ppResource) {
+ InitReturnPtr(ppResource);
+
+ Logger::err("D3D11Device::OpenSharedResource: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResource1(
+ HANDLE hResource,
+ REFIID ReturnedInterface,
+ void** ppResource) {
+ InitReturnPtr(ppResource);
+
+ Logger::err("D3D11Device::OpenSharedResource1: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedResourceByName(
+ LPCWSTR lpName,
+ DWORD dwDesiredAccess,
+ REFIID returnedInterface,
+ void** ppResource) {
+ InitReturnPtr(ppResource);
+
+ Logger::err("D3D11Device::OpenSharedResourceByName: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::OpenSharedFence(
+ HANDLE hFence,
+ REFIID ReturnedInterface,
+ void** ppFence) {
+ InitReturnPtr(ppFence);
+
+ Logger::err("D3D11Device::OpenSharedFence: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CheckFormatSupport(
+ DXGI_FORMAT Format,
+ UINT* pFormatSupport) {
+ return GetFormatSupportFlags(Format, pFormatSupport, nullptr);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CheckMultisampleQualityLevels(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT* pNumQualityLevels) {
+ return CheckMultisampleQualityLevels1(Format, SampleCount, 0, pNumQualityLevels);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CheckMultisampleQualityLevels1(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT Flags,
+ UINT* pNumQualityLevels) {
+ // There are many error conditions, so we'll just assume
+ // that we will fail and return a non-zero value in case
+ // the device does actually support the format.
+ if (!pNumQualityLevels)
+ return E_INVALIDARG;
+
+ // We don't support tiled resources, but it's unclear what
+ // we are supposed to return in this case. Be conservative.
+ if (Flags) {
+ *pNumQualityLevels = 0;
+ return E_FAIL;
+ }
+
+ // For some reason, we can query DXGI_FORMAT_UNKNOWN
+ if (Format == DXGI_FORMAT_UNKNOWN) {
+ *pNumQualityLevels = SampleCount == 1 ? 1 : 0;
+ return SampleCount ? S_OK : E_FAIL;
+ }
+
+ // All other unknown formats should result in an error return.
+ VkFormat format = LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY).Format;
+
+ if (format == VK_FORMAT_UNDEFINED)
+ return E_INVALIDARG;
+
+ // Zero-init now, leave value undefined otherwise.
+ // This does actually match native D3D11 behaviour.
+ *pNumQualityLevels = 0;
+
+ // Non-power of two sample counts are not supported, but querying
+ // support for them is legal, so we return zero quality levels.
+ VkSampleCountFlagBits sampleCountFlag = VK_SAMPLE_COUNT_1_BIT;
+
+ if (FAILED(DecodeSampleCount(SampleCount, &sampleCountFlag)))
+ return SampleCount && SampleCount <= 32 ? S_OK : E_FAIL;
+
+ // Check if the device supports the given combination of format
+ // and sample count. D3D exposes the opaque concept of quality
+ // levels to the application, we'll just define one such level.
+ VkImageFormatProperties formatProps;
+
+ VkResult status = m_dxvkAdapter->imageFormatProperties(
+ format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_SAMPLED_BIT, 0, formatProps);
+
+ if ((status == VK_SUCCESS) && (formatProps.sampleCounts & sampleCountFlag))
+ *pNumQualityLevels = 1;
+ return S_OK;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::CheckCounterInfo(D3D11_COUNTER_INFO* pCounterInfo) {
+ // We basically don't support counters
+ pCounterInfo->LastDeviceDependentCounter = D3D11_COUNTER(0);
+ pCounterInfo->NumSimultaneousCounters = 0;
+ pCounterInfo->NumDetectableParallelUnits = 0;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CheckCounter(
+ const D3D11_COUNTER_DESC* pDesc,
+ D3D11_COUNTER_TYPE* pType,
+ UINT* pActiveCounters,
+ LPSTR szName,
+ UINT* pNameLength,
+ LPSTR szUnits,
+ UINT* pUnitsLength,
+ LPSTR szDescription,
+ UINT* pDescriptionLength) {
+ Logger::err("D3D11: Counters not supported");
+ return E_INVALIDARG;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::CheckFeatureSupport(
+ D3D11_FEATURE Feature,
+ void* pFeatureSupportData,
+ UINT FeatureSupportDataSize) {
+ switch (Feature) {
+ case D3D11_FEATURE_THREADING: {
+ auto info = static_cast<D3D11_FEATURE_DATA_THREADING*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ // We report native support for command lists here so that we do not actually
+ // have to re-implement the UpdateSubresource bug from the D3D11 runtime, see
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
+ info->DriverConcurrentCreates = TRUE;
+ info->DriverCommandLists = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_DOUBLES: {
+ auto info = static_cast<D3D11_FEATURE_DATA_DOUBLES*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->DoublePrecisionFloatShaderOps = m_dxvkDevice->features().core.features.shaderFloat64
+ && m_dxvkDevice->features().core.features.shaderInt64;
+ } return S_OK;
+
+ case D3D11_FEATURE_FORMAT_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_FORMAT_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ return GetFormatSupportFlags(info->InFormat, &info->OutFormatSupport, nullptr);
+ } return S_OK;
+
+ case D3D11_FEATURE_FORMAT_SUPPORT2: {
+ auto info = static_cast<D3D11_FEATURE_DATA_FORMAT_SUPPORT2*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ return GetFormatSupportFlags(info->InFormat, nullptr, &info->OutFormatSupport2);
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D11_OPTIONS: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404457(v=vs.85).aspx
+ const auto& features = m_dxvkDevice->features();
+
+ info->OutputMergerLogicOp = features.core.features.logicOp;
+ info->UAVOnlyRenderingForcedSampleCount = features.core.features.variableMultisampleRate;
+ info->DiscardAPIsSeenByDriver = TRUE;
+ info->FlagsForUpdateAndCopySeenByDriver = TRUE;
+ info->ClearView = TRUE;
+ info->CopyWithOverlap = TRUE;
+ info->ConstantBufferPartialUpdate = TRUE;
+ info->ConstantBufferOffsetting = TRUE;
+ info->MapNoOverwriteOnDynamicConstantBuffer = TRUE;
+ info->MapNoOverwriteOnDynamicBufferSRV = TRUE;
+ info->MultisampleRTVWithForcedSampleCountOne = TRUE; /* not really */
+ info->SAD4ShaderInstructions = TRUE;
+ info->ExtendedDoublesShaderInstructions = TRUE;
+ info->ExtendedResourceSharing = TRUE; /* not really */
+ } return S_OK;
+
+ case D3D11_FEATURE_ARCHITECTURE_INFO: {
+ auto info = static_cast<D3D11_FEATURE_DATA_ARCHITECTURE_INFO*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->TileBasedDeferredRenderer = FALSE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D9_OPTIONS: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D9_OPTIONS*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->FullNonPow2TextureSupport = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ // Report that we only support full 32-bit operations
+ info->PixelShaderMinPrecision = 0;
+ info->AllOtherShaderStagesMinPrecision = 0;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D9_SHADOW_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->SupportsDepthAsTextureWithLessEqualComparisonFilter = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D11_OPTIONS1: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS1*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ // Min/Max filtering requires Tiled Resources Tier 2 for some reason,
+ // so we cannot support it even though Vulkan exposes this feature
+ info->TiledResourcesTier = D3D11_TILED_RESOURCES_NOT_SUPPORTED;
+ info->MinMaxFiltering = FALSE;
+ info->ClearViewAlsoSupportsDepthOnlyFormats = TRUE;
+ info->MapOnDefaultBuffers = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->SimpleInstancingSupported = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_MARKER_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_MARKER_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->Profile = FALSE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D9_OPTIONS1: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D9_OPTIONS1*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->FullNonPow2TextureSupported = TRUE;
+ info->DepthAsTextureWithLessEqualComparisonFilterSupported = TRUE;
+ info->SimpleInstancingSupported = TRUE;
+ info->TextureCubeFaceRenderTargetWithNonCubeDepthStencilSupported = TRUE;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D11_OPTIONS2: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS2*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ const auto& extensions = m_dxvkDevice->extensions();
+ const auto& features = m_dxvkDevice->features();
+
+ info->PSSpecifiedStencilRefSupported = extensions.extShaderStencilExport;
+ info->TypedUAVLoadAdditionalFormats = features.core.features.shaderStorageImageReadWithoutFormat;
+ info->ROVsSupported = FALSE;
+ info->ConservativeRasterizationTier = D3D11_CONSERVATIVE_RASTERIZATION_NOT_SUPPORTED;
+ info->MapOnDefaultTextures = TRUE;
+ info->TiledResourcesTier = D3D11_TILED_RESOURCES_NOT_SUPPORTED;
+ info->StandardSwizzle = FALSE;
+ info->UnifiedMemoryArchitecture = m_dxvkDevice->isUnifiedMemoryArchitecture();
+
+ if (m_dxvkDevice->extensions().extConservativeRasterization) {
+ // We don't have a way to query uncertainty regions, so just check degenerate triangle behaviour
+ info->ConservativeRasterizationTier = m_dxvkDevice->properties().extConservativeRasterization.degenerateTrianglesRasterized
+ ? D3D11_CONSERVATIVE_RASTERIZATION_TIER_2 : D3D11_CONSERVATIVE_RASTERIZATION_TIER_1;
+ }
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D11_OPTIONS3: {
+ if (FeatureSupportDataSize != sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS3))
+ return E_INVALIDARG;
+
+ const auto& extensions = m_dxvkDevice->extensions();
+
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS3*>(pFeatureSupportData);
+ info->VPAndRTArrayIndexFromAnyShaderFeedingRasterizer = extensions.extShaderViewportIndexLayer;
+ } return S_OK;
+
+ case D3D11_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT: {
+ auto info = static_cast<D3D11_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ // These numbers are not accurate, but it should not have any effect on D3D11 apps
+ info->MaxGPUVirtualAddressBitsPerResource = 32;
+ info->MaxGPUVirtualAddressBitsPerProcess = 40;
+ } return S_OK;
+
+ case D3D11_FEATURE_D3D11_OPTIONS4: {
+ auto info = static_cast<D3D11_FEATURE_DATA_D3D11_OPTIONS4*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ info->ExtendedNV12SharedTextureSupported = FALSE;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format("D3D11Device: CheckFeatureSupport: Unknown feature: ", Feature));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::GetPrivateData(
+ REFGUID guid, UINT* pDataSize, void* pData) {
+ return m_container->GetPrivateData(guid, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::SetPrivateData(
+ REFGUID guid, UINT DataSize, const void* pData) {
+ return m_container->SetPrivateData(guid, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::SetPrivateDataInterface(
+ REFGUID guid, const IUnknown* pData) {
+ return m_container->SetPrivateDataInterface(guid, pData);
+ }
+
+
+ D3D_FEATURE_LEVEL STDMETHODCALLTYPE D3D11Device::GetFeatureLevel() {
+ return m_featureLevel;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Device::GetCreationFlags() {
+ return m_featureFlags;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::GetDeviceRemovedReason() {
+ VkResult status = m_dxvkDevice->getDeviceStatus();
+
+ switch (status) {
+ case VK_SUCCESS: return S_OK;
+ default: return DXGI_ERROR_DEVICE_RESET;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::GetImmediateContext(ID3D11DeviceContext** ppImmediateContext) {
+ *ppImmediateContext = m_context.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::GetImmediateContext1(ID3D11DeviceContext1** ppImmediateContext) {
+ *ppImmediateContext = m_context.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::GetImmediateContext2(ID3D11DeviceContext2** ppImmediateContext) {
+ *ppImmediateContext = m_context.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::GetImmediateContext3(ID3D11DeviceContext3** ppImmediateContext) {
+ *ppImmediateContext = m_context.ref();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::SetExceptionMode(UINT RaiseFlags) {
+ Logger::err("D3D11Device::SetExceptionMode: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Device::GetExceptionMode() {
+ Logger::err("D3D11Device::GetExceptionMode: Not implemented");
+ return 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::GetResourceTiling(
+ ID3D11Resource* pTiledResource,
+ UINT* pNumTilesForEntireResource,
+ D3D11_PACKED_MIP_DESC* pPackedMipDesc,
+ D3D11_TILE_SHAPE* pStandardTileShapeForNonPackedMips,
+ UINT* pNumSubresourceTilings,
+ UINT FirstSubresourceTilingToGet,
+ D3D11_SUBRESOURCE_TILING* pSubresourceTilingsForNonPackedMips) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11Device::GetResourceTiling: Tiled resources not supported");
+
+ if (pNumTilesForEntireResource)
+ *pNumTilesForEntireResource = 0;
+
+ if (pPackedMipDesc)
+ *pPackedMipDesc = D3D11_PACKED_MIP_DESC();
+
+ if (pStandardTileShapeForNonPackedMips)
+ *pStandardTileShapeForNonPackedMips = D3D11_TILE_SHAPE();
+
+ if (pNumSubresourceTilings) {
+ if (pSubresourceTilingsForNonPackedMips) {
+ for (uint32_t i = 0; i < *pNumSubresourceTilings; i++)
+ pSubresourceTilingsForNonPackedMips[i] = D3D11_SUBRESOURCE_TILING();
+ }
+
+ *pNumSubresourceTilings = 0;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Device::RegisterDeviceRemovedEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11Device::RegisterDeviceRemovedEvent: Not implemented");
+
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Device::UnregisterDeviceRemoved(
+ DWORD dwCookie) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11Device::UnregisterDeviceRemovedEvent: Not implemented");
+ }
+
+
+ DXGI_VK_FORMAT_INFO D3D11Device::LookupFormat(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ return m_d3d11Formats.GetFormatInfo(Format, Mode);
+ }
+
+
+ DXGI_VK_FORMAT_INFO D3D11Device::LookupPackedFormat(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ return m_d3d11Formats.GetPackedFormatInfo(Format, Mode);
+ }
+
+
+ DXGI_VK_FORMAT_FAMILY D3D11Device::LookupFamily(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ return m_d3d11Formats.GetFormatFamily(Format, Mode);
+ }
+
+
+ void D3D11Device::FlushInitContext() {
+ m_initializer->Flush();
+ }
+
+
+ bool D3D11Device::CheckFeatureLevelSupport(
+ const Rc<DxvkInstance>& instance,
+ const Rc<DxvkAdapter>& adapter,
+ D3D_FEATURE_LEVEL featureLevel) {
+ if (featureLevel > GetMaxFeatureLevel(instance))
+ return false;
+
+ // Check whether all features are supported
+ const DxvkDeviceFeatures features
+ = GetDeviceFeatures(adapter, featureLevel);
+
+ if (!adapter->checkFeatureSupport(features))
+ return false;
+
+ // TODO also check for required limits
+ return true;
+ }
+
+
+ DxvkDeviceFeatures D3D11Device::GetDeviceFeatures(
+ const Rc<DxvkAdapter>& adapter,
+ D3D_FEATURE_LEVEL featureLevel) {
+ DxvkDeviceFeatures supported = adapter->features();
+ DxvkDeviceFeatures enabled = {};
+
+#ifndef VBOX
+ enabled.core.features.geometryShader = VK_TRUE;
+#else
+ enabled.core.features.geometryShader = supported.core.features.geometryShader;
+#endif
+ enabled.core.features.robustBufferAccess = VK_TRUE;
+ enabled.core.features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
+ enabled.core.features.depthBounds = supported.core.features.depthBounds;
+
+ enabled.shaderDrawParameters.shaderDrawParameters = VK_TRUE;
+
+ enabled.extMemoryPriority.memoryPriority = supported.extMemoryPriority.memoryPriority;
+
+ enabled.extRobustness2.robustBufferAccess2 = supported.extRobustness2.robustBufferAccess2;
+ enabled.extRobustness2.robustImageAccess2 = supported.extRobustness2.robustImageAccess2;
+ enabled.extRobustness2.nullDescriptor = supported.extRobustness2.nullDescriptor;
+
+ enabled.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation = supported.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation;
+
+ enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor;
+ enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor;
+
+ if (supported.extCustomBorderColor.customBorderColorWithoutFormat) {
+ enabled.extCustomBorderColor.customBorderColors = VK_TRUE;
+ enabled.extCustomBorderColor.customBorderColorWithoutFormat = VK_TRUE;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_9_1) {
+ enabled.core.features.depthClamp = VK_TRUE;
+ enabled.core.features.depthBiasClamp = VK_TRUE;
+ enabled.core.features.fillModeNonSolid = VK_TRUE;
+ enabled.core.features.pipelineStatisticsQuery = supported.core.features.pipelineStatisticsQuery;
+ enabled.core.features.sampleRateShading = VK_TRUE;
+ enabled.core.features.samplerAnisotropy = supported.core.features.samplerAnisotropy;
+ enabled.core.features.shaderClipDistance = VK_TRUE;
+#ifndef VBOX
+ enabled.core.features.shaderCullDistance = VK_TRUE;
+#else
+ enabled.core.features.shaderCullDistance = supported.core.features.shaderCullDistance;
+#endif
+ enabled.core.features.textureCompressionBC = VK_TRUE;
+ enabled.extDepthClipEnable.depthClipEnable = supported.extDepthClipEnable.depthClipEnable;
+ enabled.extHostQueryReset.hostQueryReset = supported.extHostQueryReset.hostQueryReset;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_9_2) {
+ enabled.core.features.occlusionQueryPrecise = VK_TRUE;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_9_3) {
+ enabled.core.features.independentBlend = VK_TRUE;
+ enabled.core.features.multiViewport = VK_TRUE;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_10_0) {
+ enabled.core.features.fullDrawIndexUint32 = VK_TRUE;
+ enabled.core.features.logicOp = supported.core.features.logicOp;
+ enabled.core.features.shaderImageGatherExtended = VK_TRUE;
+ enabled.core.features.variableMultisampleRate = supported.core.features.variableMultisampleRate;
+#ifndef VBOX
+ enabled.extTransformFeedback.transformFeedback = VK_TRUE;
+#else
+ enabled.extTransformFeedback.transformFeedback = supported.extTransformFeedback.transformFeedback;
+#endif
+ enabled.extTransformFeedback.geometryStreams = VK_TRUE;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_10_1) {
+ enabled.core.features.dualSrcBlend = VK_TRUE;
+ enabled.core.features.imageCubeArray = VK_TRUE;
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_11_0) {
+ enabled.core.features.drawIndirectFirstInstance = VK_TRUE;
+ enabled.core.features.fragmentStoresAndAtomics = VK_TRUE;
+ enabled.core.features.multiDrawIndirect = VK_TRUE;
+ enabled.core.features.shaderFloat64 = supported.core.features.shaderFloat64;
+ enabled.core.features.shaderInt64 = supported.core.features.shaderInt64;
+ enabled.core.features.shaderStorageImageReadWithoutFormat = supported.core.features.shaderStorageImageReadWithoutFormat;
+#ifndef VBOX
+ enabled.core.features.tessellationShader = VK_TRUE;
+#else
+ enabled.core.features.tessellationShader = supported.core.features.tessellationShader;
+#endif
+ }
+
+ if (featureLevel >= D3D_FEATURE_LEVEL_11_1) {
+ enabled.core.features.logicOp = VK_TRUE;
+ enabled.core.features.variableMultisampleRate = VK_TRUE;
+ enabled.core.features.vertexPipelineStoresAndAtomics = VK_TRUE;
+ }
+
+ return enabled;
+ }
+
+
+ HRESULT D3D11Device::CreateShaderModule(
+ D3D11CommonShader* pShaderModule,
+ DxvkShaderKey ShaderKey,
+ const void* pShaderBytecode,
+ size_t BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ const DxbcModuleInfo* pModuleInfo) {
+ if (pClassLinkage != nullptr)
+ Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported");
+
+ D3D11CommonShader commonShader;
+
+ HRESULT hr = m_shaderModules.GetShaderModule(this,
+ &ShaderKey, pModuleInfo, pShaderBytecode, BytecodeLength,
+ &commonShader);
+
+ if (FAILED(hr))
+ return hr;
+
+ auto shader = commonShader.GetShader();
+
+ if (shader->flags().test(DxvkShaderFlag::ExportsStencilRef)
+ && !m_dxvkDevice->extensions().extShaderStencilExport)
+ return E_INVALIDARG;
+
+ if (shader->flags().test(DxvkShaderFlag::ExportsViewportIndexLayerFromVertexStage)
+ && !m_dxvkDevice->extensions().extShaderViewportIndexLayer)
+ return E_INVALIDARG;
+
+ *pShaderModule = std::move(commonShader);
+ return S_OK;
+ }
+
+
+ HRESULT D3D11Device::GetFormatSupportFlags(DXGI_FORMAT Format, UINT* pFlags1, UINT* pFlags2) const {
+ const DXGI_VK_FORMAT_INFO fmtMapping = LookupFormat(Format, DXGI_VK_FORMAT_MODE_ANY);
+
+ // Reset output flags preemptively
+ if (pFlags1 != nullptr) *pFlags1 = 0;
+ if (pFlags2 != nullptr) *pFlags2 = 0;
+
+ // Unsupported or invalid format
+ if (Format != DXGI_FORMAT_UNKNOWN && fmtMapping.Format == VK_FORMAT_UNDEFINED)
+ return E_FAIL;
+
+ // Query Vulkan format properties and supported features for it
+ const DxvkFormatInfo* fmtProperties = imageFormatInfo(fmtMapping.Format);
+
+ VkFormatProperties fmtSupport = fmtMapping.Format != VK_FORMAT_UNDEFINED
+ ? m_dxvkAdapter->formatProperties(fmtMapping.Format)
+ : VkFormatProperties();
+
+ VkFormatFeatureFlags bufFeatures = fmtSupport.bufferFeatures;
+ VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures;
+
+ // For multi-plane images, we want to check available view formats as well
+ if (fmtProperties->flags.test(DxvkFormatFlag::MultiPlane)) {
+ const VkFormatFeatureFlags featureMask
+ = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
+ | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT
+ | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
+ | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT
+ | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
+
+ DXGI_VK_FORMAT_FAMILY formatFamily = LookupFamily(Format, DXGI_VK_FORMAT_MODE_ANY);
+
+ for (uint32_t i = 0; i < formatFamily.FormatCount; i++) {
+ VkFormatProperties viewFmtSupport = m_dxvkAdapter->formatProperties(formatFamily.Formats[i]);
+ imgFeatures |= (viewFmtSupport.optimalTilingFeatures | viewFmtSupport.linearTilingFeatures) & featureMask;
+ }
+ }
+
+ UINT flags1 = 0;
+ UINT flags2 = 0;
+
+ // Format can be used for shader resource views with buffers
+ if (bufFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT
+ || Format == DXGI_FORMAT_UNKNOWN)
+ flags1 |= D3D11_FORMAT_SUPPORT_BUFFER;
+
+ // Format can be used for vertex data
+ if (bufFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
+ flags1 |= D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER;
+
+ // Format can be used for index data. Only
+ // these two formats are supported by D3D11.
+ if (Format == DXGI_FORMAT_R16_UINT
+ || Format == DXGI_FORMAT_R32_UINT)
+ flags1 |= D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER;
+
+ // These formats are technically irrelevant since
+ // SO buffers are passed in as raw buffers and not
+ // as views, but the feature flag exists regardless
+ if (Format == DXGI_FORMAT_R32_FLOAT
+ || Format == DXGI_FORMAT_R32_UINT
+ || Format == DXGI_FORMAT_R32_SINT
+ || Format == DXGI_FORMAT_R32G32_FLOAT
+ || Format == DXGI_FORMAT_R32G32_UINT
+ || Format == DXGI_FORMAT_R32G32_SINT
+ || Format == DXGI_FORMAT_R32G32B32_FLOAT
+ || Format == DXGI_FORMAT_R32G32B32_UINT
+ || Format == DXGI_FORMAT_R32G32B32_SINT
+ || Format == DXGI_FORMAT_R32G32B32A32_FLOAT
+ || Format == DXGI_FORMAT_R32G32B32A32_UINT
+ || Format == DXGI_FORMAT_R32G32B32A32_SINT)
+ flags1 |= D3D11_FORMAT_SUPPORT_SO_BUFFER;
+
+ if (imgFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
+ || imgFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) {
+ const VkFormat depthFormat = LookupFormat(Format, DXGI_VK_FORMAT_MODE_DEPTH).Format;
+
+ if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_1D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE1D;
+ if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_2D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE2D;
+ if (GetImageTypeSupport(fmtMapping.Format, VK_IMAGE_TYPE_3D)) flags1 |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
+
+ flags1 |= D3D11_FORMAT_SUPPORT_MIP
+ | D3D11_FORMAT_SUPPORT_CAST_WITHIN_BIT_LAYOUT;
+
+ // Format can be read
+ if (imgFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
+ flags1 |= D3D11_FORMAT_SUPPORT_TEXTURECUBE
+ | D3D11_FORMAT_SUPPORT_SHADER_LOAD
+ | D3D11_FORMAT_SUPPORT_SHADER_GATHER
+ | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE
+ | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT;
+
+ if (depthFormat != VK_FORMAT_UNDEFINED) {
+ flags1 |= D3D11_FORMAT_SUPPORT_SHADER_GATHER_COMPARISON
+ | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON;
+ }
+ }
+
+ // Format is a color format that can be used for rendering
+ if (imgFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
+ flags1 |= D3D11_FORMAT_SUPPORT_RENDER_TARGET
+ | D3D11_FORMAT_SUPPORT_MIP_AUTOGEN
+ | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT;
+
+ if (m_dxvkDevice->features().core.features.logicOp)
+ flags2 |= D3D11_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP;
+ }
+
+ // Format supports blending when used for rendering
+ if (imgFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
+ flags1 |= D3D11_FORMAT_SUPPORT_BLENDABLE;
+
+ // Format is a depth-stencil format that can be used for rendering
+ if (imgFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ flags1 |= D3D11_FORMAT_SUPPORT_DEPTH_STENCIL;
+
+ // FIXME implement properly. This would require a VkSurface.
+ if (Format == DXGI_FORMAT_R8G8B8A8_UNORM
+ || Format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
+ || Format == DXGI_FORMAT_B8G8R8A8_UNORM
+ || Format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
+ || Format == DXGI_FORMAT_R16G16B16A16_FLOAT
+ || Format == DXGI_FORMAT_R10G10B10A2_UNORM
+ || Format == DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM)
+ flags1 |= D3D11_FORMAT_SUPPORT_DISPLAY;
+
+ // Query multisample support for this format
+ VkImageFormatProperties imgFmtProperties;
+
+ VkResult status = m_dxvkAdapter->imageFormatProperties(fmtMapping.Format,
+ VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
+ (fmtProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
+ ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+ 0, imgFmtProperties);
+
+ if (status == VK_SUCCESS && imgFmtProperties.sampleCounts > VK_SAMPLE_COUNT_1_BIT) {
+ flags1 |= D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET
+ | D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE
+ | D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD;
+ }
+ }
+
+ // Format can be used for storage images or storage texel buffers
+ if ((bufFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
+ && (imgFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
+ flags1 |= D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW;
+ flags2 |= D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE;
+
+ if (m_dxvkDevice->features().core.features.shaderStorageImageReadWithoutFormat
+ || Format == DXGI_FORMAT_R32_UINT
+ || Format == DXGI_FORMAT_R32_SINT
+ || Format == DXGI_FORMAT_R32_FLOAT)
+ flags2 |= D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD;
+
+ if (Format == DXGI_FORMAT_R32_UINT
+ || Format == DXGI_FORMAT_R32_SINT) {
+ flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD
+ | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS
+ | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE
+ | D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE;
+ }
+
+ if (Format == DXGI_FORMAT_R32_SINT)
+ flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX;
+
+ if (Format == DXGI_FORMAT_R32_UINT)
+ flags2 |= D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX;
+ }
+
+ // Mark everyting as CPU lockable
+ if (flags1 | flags2)
+ flags1 |= D3D11_FORMAT_SUPPORT_CPU_LOCKABLE;
+
+ // Write back format support flags
+ if (pFlags1 != nullptr) *pFlags1 = flags1;
+ if (pFlags2 != nullptr) *pFlags2 = flags2;
+ return (pFlags1 && flags1) || (pFlags2 && flags2) ? S_OK : E_FAIL;
+ }
+
+
+ BOOL D3D11Device::GetImageTypeSupport(VkFormat Format, VkImageType Type) const {
+ VkImageFormatProperties props;
+
+ VkResult status = m_dxvkAdapter->imageFormatProperties(
+ Format, Type, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_SAMPLED_BIT, 0, props);
+
+ if (status != VK_SUCCESS) {
+ status = m_dxvkAdapter->imageFormatProperties(
+ Format, Type, VK_IMAGE_TILING_LINEAR,
+ VK_IMAGE_USAGE_SAMPLED_BIT, 0, props);
+ }
+
+ return status == VK_SUCCESS;
+ }
+
+
+ uint32_t D3D11Device::GetViewPlaneIndex(
+ ID3D11Resource* pResource,
+ DXGI_FORMAT ViewFormat) {
+ auto texture = GetCommonTexture(pResource);
+
+ if (!texture)
+ return 0;
+
+ uint32_t planeCount = texture->GetPlaneCount();
+
+ if (planeCount == 1)
+ return 0;
+
+ auto formatMode = texture->GetFormatMode();
+ auto formatFamily = LookupFamily(texture->Desc()->Format, formatMode);
+ auto viewFormat = LookupFormat(ViewFormat, formatMode);
+
+ for (uint32_t i = 0; i < formatFamily.FormatCount; i++) {
+ if (formatFamily.Formats[i] == viewFormat.Format)
+ return i % planeCount;
+ }
+
+ return ~0u;
+ }
+
+
+ template<typename Void>
+ void D3D11Device::CopySubresourceData(
+ Void* pData,
+ UINT RowPitch,
+ UINT DepthPitch,
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ const D3D11_BOX* pBox) {
+ auto texture = GetCommonTexture(pResource);
+
+ if (!texture)
+ return;
+
+ // Validate texture state and skip invalid calls
+ if (texture->Desc()->Usage != D3D11_USAGE_DEFAULT
+ || texture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE
+ || texture->CountSubresources() <= Subresource
+ || texture->GetMapType(Subresource) == D3D11_MAP(~0u))
+ return;
+
+ // Retrieve image format information
+ VkFormat packedFormat = LookupPackedFormat(
+ texture->Desc()->Format,
+ texture->GetFormatMode()).Format;
+
+ auto formatInfo = imageFormatInfo(packedFormat);
+
+ // Validate box against subresource dimensions
+ Rc<DxvkImage> image = texture->GetImage();
+
+ auto subresource = texture->GetSubresourceFromIndex(
+ formatInfo->aspectMask, Subresource);
+
+ VkOffset3D offset = { 0, 0, 0 };
+ VkExtent3D extent = image->mipLevelExtent(subresource.mipLevel);
+
+ if (pBox) {
+ if (pBox->left >= pBox->right
+ || pBox->top >= pBox->bottom
+ || pBox->front >= pBox->back)
+ return; // legal, but no-op
+
+ if (pBox->right > extent.width
+ || pBox->bottom > extent.height
+ || pBox->back > extent.depth)
+ return; // out of bounds
+
+ offset = VkOffset3D {
+ int32_t(pBox->left),
+ int32_t(pBox->top),
+ int32_t(pBox->front) };
+
+ extent = VkExtent3D {
+ pBox->right - pBox->left,
+ pBox->bottom - pBox->top,
+ pBox->back - pBox->front };
+ }
+
+ // We can only operate on full blocks of compressed images
+ offset = util::computeBlockOffset(offset, formatInfo->blockSize);
+ extent = util::computeBlockCount(extent, formatInfo->blockSize);
+
+ // Determine the memory layout of the image data
+ D3D11_MAPPED_SUBRESOURCE subresourceData = { };
+
+ if (texture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
+ VkSubresourceLayout layout = image->querySubresourceLayout(subresource);
+ subresourceData.pData = image->mapPtr(layout.offset);
+ subresourceData.RowPitch = layout.rowPitch;
+ subresourceData.DepthPitch = layout.depthPitch;
+ } else {
+ subresourceData.pData = texture->GetMappedBuffer(Subresource)->mapPtr(0);
+ subresourceData.RowPitch = formatInfo->elementSize * extent.width;
+ subresourceData.DepthPitch = formatInfo->elementSize * extent.width * extent.height;
+ }
+
+ if constexpr (std::is_const<Void>::value) {
+ // WriteToSubresource
+ auto src = reinterpret_cast<const char*>(pData);
+ auto dst = reinterpret_cast< char*>(subresourceData.pData);
+
+ for (uint32_t z = 0; z < extent.depth; z++) {
+ for (uint32_t y = 0; y < extent.height; y++) {
+ std::memcpy(
+ dst + (offset.z + z) * subresourceData.DepthPitch
+ + (offset.y + y) * subresourceData.RowPitch
+ + (offset.x) * formatInfo->elementSize,
+ src + z * DepthPitch
+ + y * RowPitch,
+ formatInfo->elementSize * extent.width);
+ }
+ }
+ } else {
+ // ReadFromSubresource
+ auto src = reinterpret_cast<const char*>(subresourceData.pData);
+ auto dst = reinterpret_cast< char*>(pData);
+
+ for (uint32_t z = 0; z < extent.depth; z++) {
+ for (uint32_t y = 0; y < extent.height; y++) {
+ std::memcpy(
+ dst + z * DepthPitch
+ + y * RowPitch,
+ src + (offset.z + z) * subresourceData.DepthPitch
+ + (offset.y + y) * subresourceData.RowPitch
+ + (offset.x) * formatInfo->elementSize,
+ formatInfo->elementSize * extent.width);
+ }
+ }
+ }
+ }
+
+
+ D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(const Rc<DxvkInstance>& pInstance) {
+ static const std::array<std::pair<std::string, D3D_FEATURE_LEVEL>, 9> s_featureLevels = {{
+ { "12_1", D3D_FEATURE_LEVEL_12_1 },
+ { "12_0", D3D_FEATURE_LEVEL_12_0 },
+ { "11_1", D3D_FEATURE_LEVEL_11_1 },
+ { "11_0", D3D_FEATURE_LEVEL_11_0 },
+ { "10_1", D3D_FEATURE_LEVEL_10_1 },
+ { "10_0", D3D_FEATURE_LEVEL_10_0 },
+ { "9_3", D3D_FEATURE_LEVEL_9_3 },
+ { "9_2", D3D_FEATURE_LEVEL_9_2 },
+ { "9_1", D3D_FEATURE_LEVEL_9_1 },
+ }};
+
+ const std::string maxLevel = pInstance->config()
+ .getOption<std::string>("d3d11.maxFeatureLevel");
+
+ auto entry = std::find_if(s_featureLevels.begin(), s_featureLevels.end(),
+ [&] (const std::pair<std::string, D3D_FEATURE_LEVEL>& pair) {
+ return pair.first == maxLevel;
+ });
+
+ return entry != s_featureLevels.end()
+ ? entry->second
+ : D3D_FEATURE_LEVEL_11_1;
+ }
+
+
+
+
+ D3D11DeviceExt::D3D11DeviceExt(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice)
+ : m_container(pContainer), m_device(pDevice) {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DeviceExt::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DeviceExt::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceExt::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D11DeviceExt::GetExtensionSupport(
+ D3D11_VK_EXTENSION Extension) {
+ const auto& deviceFeatures = m_device->GetDXVKDevice()->features();
+ const auto& deviceExtensions = m_device->GetDXVKDevice()->extensions();
+
+ switch (Extension) {
+ case D3D11_VK_EXT_BARRIER_CONTROL:
+ return true;
+
+ case D3D11_VK_EXT_MULTI_DRAW_INDIRECT:
+ return deviceFeatures.core.features.multiDrawIndirect;
+
+ case D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT:
+ return deviceFeatures.core.features.multiDrawIndirect
+ && deviceExtensions.khrDrawIndirectCount;
+
+ case D3D11_VK_EXT_DEPTH_BOUNDS:
+ return deviceFeatures.core.features.depthBounds;
+
+ case D3D11_VK_NVX_IMAGE_VIEW_HANDLE:
+ return deviceExtensions.nvxImageViewHandle;
+
+ case D3D11_VK_NVX_BINARY_IMPORT:
+ return deviceExtensions.nvxBinaryImport
+ && deviceExtensions.khrBufferDeviceAddress;
+
+ default:
+ return false;
+ }
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::GetCudaTextureObjectNVX(uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle) {
+ ID3D11ShaderResourceView* srv = HandleToSrvNVX(srvDriverHandle);
+
+ if (!srv) {
+ Logger::warn(str::format("GetCudaTextureObjectNVX() failure - srv handle wasn't found: ", srvDriverHandle));
+ return false;
+ }
+
+ ID3D11SamplerState* samplerState = HandleToSamplerNVX(samplerDriverHandle);
+
+ if (!samplerState) {
+ Logger::warn(str::format("GetCudaTextureObjectNVX() failure - sampler handle wasn't found: ", samplerDriverHandle));
+ return false;
+ }
+
+ D3D11SamplerState* pSS = static_cast<D3D11SamplerState*>(samplerState);
+ Rc<DxvkSampler> pDSS = pSS->GetDXVKSampler();
+ VkSampler vkSampler = pDSS->handle();
+
+ D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(srv);
+ Rc<DxvkImageView> pIV = pSRV->GetImageView();
+ VkImageView vkImageView = pIV->handle();
+
+ VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
+ imageViewHandleInfo.imageView = vkImageView;
+ imageViewHandleInfo.sampler = vkSampler;
+ imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+
+ // note: there's no implicit lifetime management here; it's up to the
+ // app to keep the sampler and SRV alive as long as it wants to use this
+ // derived handle.
+ VkDevice vkDevice = m_device->GetDXVKDevice()->handle();
+ *pCudaTextureHandle = m_device->GetDXVKDevice()->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
+
+ if (!*pCudaTextureHandle) {
+ Logger::warn("GetCudaTextureObjectNVX() handle==0 - failed");
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::CreateCubinComputeShaderWithNameNVX(const void* pCubin, uint32_t size,
+ uint32_t blockX, uint32_t blockY, uint32_t blockZ, const char* pShaderName, IUnknown** phShader) {
+ Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
+ VkDevice vkDevice = dxvkDevice->handle();
+
+ VkCuModuleCreateInfoNVX moduleCreateInfo = { VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX };
+ moduleCreateInfo.pData = pCubin;
+ moduleCreateInfo.dataSize = size;
+
+ VkCuModuleNVX cuModule;
+ VkCuFunctionNVX cuFunction;
+ VkResult result;
+
+ if ((result = dxvkDevice->vkd()->vkCreateCuModuleNVX(vkDevice, &moduleCreateInfo, nullptr, &cuModule))) {
+ Logger::warn(str::format("CreateCubinComputeShaderWithNameNVX() - failure to create module - result=", result, " pcubindata=", pCubin, " cubinsize=", size));
+ return false; // failure
+ }
+
+ VkCuFunctionCreateInfoNVX functionCreateInfo = { VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX };
+ functionCreateInfo.module = cuModule;
+ functionCreateInfo.pName = pShaderName;
+
+ if ((result = dxvkDevice->vkd()->vkCreateCuFunctionNVX(vkDevice, &functionCreateInfo, nullptr, &cuFunction))) {
+ dxvkDevice->vkd()->vkDestroyCuModuleNVX(vkDevice, cuModule, nullptr);
+ Logger::warn(str::format("CreateCubinComputeShaderWithNameNVX() - failure to create function - result=", result));
+ return false;
+ }
+
+ *phShader = ref(new CubinShaderWrapper(dxvkDevice,
+ cuModule, cuFunction, { blockX, blockY, blockZ }));
+ return true;
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::GetResourceHandleGPUVirtualAddressAndSizeNVX(void* hObject, uint64_t* gpuVAStart, uint64_t* gpuVASize) {
+ // The hObject 'opaque driver handle' is really just a straight cast
+ // of the corresponding ID3D11Resource* in dxvk/dxvknvapi
+ ID3D11Resource* pResource = static_cast<ID3D11Resource*>(hObject);
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ if (FAILED(GetCommonResourceDesc(pResource, &resourceDesc))) {
+ Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - GetCommonResourceDesc() failed");
+ return false;
+ }
+
+ switch (resourceDesc.Dim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER:
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+ // okay - we can deal with those two dimensions
+ break;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+ case D3D11_RESOURCE_DIMENSION_UNKNOWN:
+ default:
+ Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - failure - unsupported dimension: ", resourceDesc.Dim));
+ return false;
+ }
+
+ Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
+ VkDevice vkDevice = dxvkDevice->handle();
+
+ if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
+ D3D11CommonTexture *texture = GetCommonTexture(pResource);
+ Rc<DxvkImage> dxvkImage = texture->GetImage();
+ if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
+ Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(res=", pResource,") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
+ return false;
+ }
+
+ // The d3d11 nvapi provides us a texture but vulkan only lets us get the GPU address from an imageview. So, make a private imageview and get the address from that...
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
+
+ const D3D11_COMMON_TEXTURE_DESC *texDesc = texture->Desc();
+ if (texDesc->ArraySize != 1) {
+ Logger::debug(str::format("GetResourceHandleGPUVirtualAddressAndSize(?) - unexpected array size: ", texDesc->ArraySize));
+ }
+ resourceViewDesc.Format = texDesc->Format;
+ resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ resourceViewDesc.Texture2D.MostDetailedMip = 0;
+ resourceViewDesc.Texture2D.MipLevels = texDesc->MipLevels;
+
+ Com<ID3D11ShaderResourceView> pNewSRV;
+ HRESULT hr = m_device->CreateShaderResourceView(pResource, &resourceViewDesc, &pNewSRV);
+ if (FAILED(hr)) {
+ Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() - private CreateShaderResourceView() failed");
+ return false;
+ }
+
+ Rc<DxvkImageView> dxvkImageView = static_cast<D3D11ShaderResourceView*>(pNewSRV.ptr())->GetImageView();
+ VkImageView vkImageView = dxvkImageView->handle();
+
+ VkImageViewAddressPropertiesNVX imageViewAddressProperties = {VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX};
+
+ VkResult res = dxvkDevice->vkd()->vkGetImageViewAddressNVX(vkDevice, vkImageView, &imageViewAddressProperties);
+ if (res != VK_SUCCESS) {
+ Logger::warn(str::format("GetResourceHandleGPUVirtualAddressAndSize(): vkGetImageViewAddressNVX() result is failure: ", res));
+ return false;
+ }
+
+ *gpuVAStart = imageViewAddressProperties.deviceAddress;
+ *gpuVASize = imageViewAddressProperties.size;
+ }
+ else if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ D3D11Buffer *buffer = GetCommonBuffer(pResource);
+ const DxvkBufferSliceHandle bufSliceHandle = buffer->GetBuffer()->getSliceHandle();
+ VkBuffer vkBuffer = bufSliceHandle.handle;
+
+ VkBufferDeviceAddressInfoKHR bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR };
+ bdaInfo.buffer = vkBuffer;
+ VkDeviceAddress bufAddr = dxvkDevice->vkd()->vkGetBufferDeviceAddressKHR(vkDevice, &bdaInfo);
+ *gpuVAStart = uint64_t(bufAddr) + bufSliceHandle.offset;
+ *gpuVASize = bufSliceHandle.length;
+ }
+
+ if (!*gpuVAStart)
+ Logger::warn("GetResourceHandleGPUVirtualAddressAndSize() addr==0 - unexpected"); // ... but not explicitly a failure; continue
+
+ return true;
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::CreateUnorderedAccessViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc, ID3D11UnorderedAccessView** ppUAV, uint32_t* pDriverHandle) {
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
+ Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
+ return false;
+ }
+ if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
+ Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
+ return false;
+ }
+
+ auto texture = GetCommonTexture(pResource);
+ Rc<DxvkImage> dxvkImage = texture->GetImage();
+ if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
+ Logger::warn(str::format("CreateUnorderedAccessViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
+ return false;
+ }
+
+ if (!SUCCEEDED(m_device->CreateUnorderedAccessView(pResource, pDesc, ppUAV))) {
+ return false;
+ }
+
+ D3D11UnorderedAccessView *pUAV = static_cast<D3D11UnorderedAccessView *>(*ppUAV);
+ Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
+ VkDevice vkDevice = dxvkDevice->handle();
+
+ VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
+ Rc<DxvkImageView> dxvkImageView = pUAV->GetImageView();
+ VkImageView vkImageView = dxvkImageView->handle();
+
+ imageViewHandleInfo.imageView = vkImageView;
+ imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+
+ *pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
+
+ if (!*pDriverHandle) {
+ Logger::warn("CreateUnorderedAccessViewAndGetDriverHandleNVX() handle==0 - failure");
+ pUAV->Release();
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::CreateShaderResourceViewAndGetDriverHandleNVX(ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRV, uint32_t* pDriverHandle) {
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ if (!SUCCEEDED(GetCommonResourceDesc(pResource, &resourceDesc))) {
+ Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() - GetCommonResourceDesc() failed");
+ return false;
+ }
+ if (resourceDesc.Dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) {
+ Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX() - failure - unsupported dimension: ", resourceDesc.Dim));
+ return false;
+ }
+
+ auto texture = GetCommonTexture(pResource);
+ Rc<DxvkImage> dxvkImage = texture->GetImage();
+ if (0 == (dxvkImage->info().usage & (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
+ Logger::warn(str::format("CreateShaderResourceViewAndGetDriverHandleNVX(res=", pResource, ") image info missing required usage bit(s); can't be used for vkGetImageViewHandleNVX - failure"));
+ return false;
+ }
+
+ if (!SUCCEEDED(m_device->CreateShaderResourceView(pResource, pDesc, ppSRV))) {
+ return false;
+ }
+
+ D3D11ShaderResourceView* pSRV = static_cast<D3D11ShaderResourceView*>(*ppSRV);
+ Rc<DxvkDevice> dxvkDevice = m_device->GetDXVKDevice();
+ VkDevice vkDevice = dxvkDevice->handle();
+
+ VkImageViewHandleInfoNVX imageViewHandleInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX};
+ Rc<DxvkImageView> dxvkImageView = pSRV->GetImageView();
+ VkImageView vkImageView = dxvkImageView->handle();
+
+ imageViewHandleInfo.imageView = vkImageView;
+ imageViewHandleInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+
+ *pDriverHandle = dxvkDevice->vkd()->vkGetImageViewHandleNVX(vkDevice, &imageViewHandleInfo);
+
+ if (!*pDriverHandle) {
+ Logger::warn("CreateShaderResourceViewAndGetDriverHandleNVX() handle==0 - failure");
+ pSRV->Release();
+ return false;
+ }
+
+ // will need to look-up resource from uint32 handle later
+ AddSrvAndHandleNVX(*ppSRV, *pDriverHandle);
+ return true;
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11DeviceExt::CreateSamplerStateAndGetDriverHandleNVX(const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState, uint32_t* pDriverHandle) {
+ if (!SUCCEEDED(m_device->CreateSamplerState(pSamplerDesc, ppSamplerState))) {
+ return false;
+ }
+
+ // for our purposes the actual value doesn't matter, only its uniqueness
+ static std::atomic<ULONG> s_seqNum = 0;
+ *pDriverHandle = ++s_seqNum;
+
+ // will need to look-up sampler from uint32 handle later
+ AddSamplerAndHandleNVX(*ppSamplerState, *pDriverHandle);
+ return true;
+ }
+
+
+ void D3D11DeviceExt::AddSamplerAndHandleNVX(ID3D11SamplerState* pSampler, uint32_t Handle) {
+ std::lock_guard lock(m_mapLock);
+ m_samplerHandleToPtr[Handle] = pSampler;
+ }
+
+
+ ID3D11SamplerState* D3D11DeviceExt::HandleToSamplerNVX(uint32_t Handle) {
+ std::lock_guard lock(m_mapLock);
+ auto got = m_samplerHandleToPtr.find(Handle);
+
+ if (got == m_samplerHandleToPtr.end())
+ return nullptr;
+
+ return static_cast<ID3D11SamplerState*>(got->second);
+ }
+
+
+ void D3D11DeviceExt::AddSrvAndHandleNVX(ID3D11ShaderResourceView* pSrv, uint32_t Handle) {
+ std::lock_guard lock(m_mapLock);
+ m_srvHandleToPtr[Handle] = pSrv;
+ }
+
+
+ ID3D11ShaderResourceView* D3D11DeviceExt::HandleToSrvNVX(uint32_t Handle) {
+ std::lock_guard lock(m_mapLock);
+ auto got = m_srvHandleToPtr.find(Handle);
+
+ if (got == m_srvHandleToPtr.end())
+ return nullptr;
+
+ return static_cast<ID3D11ShaderResourceView*>(got->second);
+ }
+
+
+
+
+
+ D3D11VideoDevice::D3D11VideoDevice(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice)
+ : m_container(pContainer), m_device(pDevice) {
+
+ }
+
+
+ D3D11VideoDevice::~D3D11VideoDevice() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VideoDevice::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VideoDevice::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoDecoder(
+ const D3D11_VIDEO_DECODER_DESC* pVideoDesc,
+ const D3D11_VIDEO_DECODER_CONFIG* pConfig,
+ ID3D11VideoDecoder** ppDecoder) {
+ Logger::err("D3D11VideoDevice::CreateVideoDecoder: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessor(
+ ID3D11VideoProcessorEnumerator* pEnum,
+ UINT RateConversionIndex,
+ ID3D11VideoProcessor** ppVideoProcessor) {
+ try {
+ auto enumerator = static_cast<D3D11VideoProcessorEnumerator*>(pEnum);
+ *ppVideoProcessor = ref(new D3D11VideoProcessor(m_device, enumerator, RateConversionIndex));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_FAIL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateAuthenticatedChannel(
+ D3D11_AUTHENTICATED_CHANNEL_TYPE ChannelType,
+ ID3D11AuthenticatedChannel** ppAuthenticatedChannel) {
+ Logger::err("D3D11VideoDevice::CreateAuthenticatedChannel: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateCryptoSession(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ const GUID* pKeyExchangeType,
+ ID3D11CryptoSession** ppCryptoSession) {
+ Logger::err("D3D11VideoDevice::CreateCryptoSession: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoDecoderOutputView(
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC* pDesc,
+ ID3D11VideoDecoderOutputView** ppVDOVView) {
+ Logger::err("D3D11VideoDevice::CreateVideoDecoderOutputView: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorInputView(
+ ID3D11Resource* pResource,
+ ID3D11VideoProcessorEnumerator* pEnum,
+ const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc,
+ ID3D11VideoProcessorInputView** ppVPIView) {
+ try {
+ *ppVPIView = ref(new D3D11VideoProcessorInputView(m_device, pResource, *pDesc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_FAIL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorOutputView(
+ ID3D11Resource* pResource,
+ ID3D11VideoProcessorEnumerator* pEnum,
+ const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc,
+ ID3D11VideoProcessorOutputView** ppVPOView) {
+ try {
+ *ppVPOView = ref(new D3D11VideoProcessorOutputView(m_device, pResource, *pDesc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_FAIL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CreateVideoProcessorEnumerator(
+ const D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pDesc,
+ ID3D11VideoProcessorEnumerator** ppEnum) {
+ try {
+ *ppEnum = ref(new D3D11VideoProcessorEnumerator(m_device, *pDesc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_FAIL;
+ }
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderProfileCount() {
+ Logger::err("D3D11VideoDevice::GetVideoDecoderProfileCount: Stub");
+ return 0;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderProfile(
+ UINT Index,
+ GUID* pDecoderProfile) {
+ Logger::err("D3D11VideoDevice::GetVideoDecoderProfile: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CheckVideoDecoderFormat(
+ const GUID* pDecoderProfile,
+ DXGI_FORMAT Format,
+ BOOL* pSupported) {
+ Logger::err("D3D11VideoDevice::CheckVideoDecoderFormat: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderConfigCount(
+ const D3D11_VIDEO_DECODER_DESC* pDesc,
+ UINT* pCount) {
+ Logger::err("D3D11VideoDevice::GetVideoDecoderConfigCount: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetVideoDecoderConfig(
+ const D3D11_VIDEO_DECODER_DESC* pDesc,
+ UINT Index,
+ D3D11_VIDEO_DECODER_CONFIG* pConfig) {
+ Logger::err("D3D11VideoDevice::GetVideoDecoderConfig: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::GetContentProtectionCaps(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ D3D11_VIDEO_CONTENT_PROTECTION_CAPS* pCaps) {
+ Logger::err("D3D11VideoDevice::GetContentProtectionCaps: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::CheckCryptoKeyExchange(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ UINT Index,
+ GUID* pKeyExchangeType) {
+ Logger::err("D3D11VideoDevice::CheckCryptoKeyExchange: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) {
+ return m_container->SetPrivateData(Name, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoDevice::SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pData) {
+ return m_container->SetPrivateDataInterface(Name, pData);
+ }
+
+
+
+
+ WineDXGISwapChainFactory::WineDXGISwapChainFactory(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice)
+ : m_container(pContainer), m_device(pDevice) {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE WineDXGISwapChainFactory::AddRef() {
+ return m_device->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE WineDXGISwapChainFactory::Release() {
+ return m_device->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE WineDXGISwapChainFactory::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_device->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE WineDXGISwapChainFactory::CreateSwapChainForHwnd(
+ IDXGIFactory* pFactory,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) {
+ InitReturnPtr(ppSwapChain);
+
+ if (!ppSwapChain || !pDesc || !hWnd)
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Make sure the back buffer size is not zero
+ DXGI_SWAP_CHAIN_DESC1 desc = *pDesc;
+
+ wsi::getWindowSize(hWnd,
+ desc.Width ? nullptr : &desc.Width,
+ desc.Height ? nullptr : &desc.Height);
+
+ // If necessary, set up a default set of
+ // fullscreen parameters for the swap chain
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsDesc;
+
+ if (pFullscreenDesc) {
+ fsDesc = *pFullscreenDesc;
+ } else {
+ fsDesc.RefreshRate = { 0, 0 };
+ fsDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ fsDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ fsDesc.Windowed = TRUE;
+ }
+
+ try {
+ // Create presenter for the device
+ Com<D3D11SwapChain> presenter = new D3D11SwapChain(
+ m_container, m_device, hWnd, &desc);
+
+ // Create the actual swap chain
+ *ppSwapChain = ref(new DxgiSwapChain(
+ pFactory, presenter.ptr(), hWnd, &desc, &fsDesc));
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+
+
+
+ DXGIDXVKDevice::DXGIDXVKDevice(D3D11DXGIDevice* pContainer)
+ : m_container(pContainer), m_apiVersion(11) {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE DXGIDXVKDevice::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE DXGIDXVKDevice::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DXGIDXVKDevice::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ void STDMETHODCALLTYPE DXGIDXVKDevice::SetAPIVersion(
+ UINT Version) {
+ m_apiVersion = Version;
+ }
+
+
+ UINT STDMETHODCALLTYPE DXGIDXVKDevice::GetAPIVersion() {
+ return m_apiVersion;
+ }
+
+
+
+
+ D3D11DXGIDevice::D3D11DXGIDevice(
+ IDXGIAdapter* pAdapter,
+ const Rc<DxvkInstance>& pDxvkInstance,
+ const Rc<DxvkAdapter>& pDxvkAdapter,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ UINT FeatureFlags)
+ : m_dxgiAdapter (pAdapter),
+ m_dxvkInstance (pDxvkInstance),
+ m_dxvkAdapter (pDxvkAdapter),
+ m_dxvkDevice (CreateDevice(FeatureLevel)),
+ m_d3d11Device (this, FeatureLevel, FeatureFlags),
+ m_d3d11DeviceExt(this, &m_d3d11Device),
+ m_d3d11Interop (this, &m_d3d11Device),
+ m_d3d11Video (this, &m_d3d11Device),
+ m_metaDevice (this),
+ m_wineFactory (this, &m_d3d11Device) {
+
+ }
+
+
+ D3D11DXGIDevice::~D3D11DXGIDevice() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDevice)
+ || riid == __uuidof(IDXGIDevice1)
+ || riid == __uuidof(IDXGIDevice2)
+ || riid == __uuidof(IDXGIDevice3)
+ || riid == __uuidof(IDXGIDevice4)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkInteropDevice)
+ || riid == __uuidof(IDXGIVkInteropDevice1)) {
+ *ppvObject = ref(&m_d3d11Interop);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10Device)
+ || riid == __uuidof(ID3D10Device1)) {
+ *ppvObject = ref(m_d3d11Device.GetD3D10Interface());
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D11Device)
+ || riid == __uuidof(ID3D11Device1)
+ || riid == __uuidof(ID3D11Device2)
+ || riid == __uuidof(ID3D11Device3)
+ || riid == __uuidof(ID3D11Device4)
+ || riid == __uuidof(ID3D11Device5)) {
+ *ppvObject = ref(&m_d3d11Device);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D11VkExtDevice)
+ || riid == __uuidof(ID3D11VkExtDevice1)) {
+ *ppvObject = ref(&m_d3d11DeviceExt);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIDXVKDevice)) {
+ *ppvObject = ref(&m_metaDevice);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IWineDXGISwapChainFactory)) {
+ *ppvObject = ref(&m_wineFactory);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D11VideoDevice)) {
+ *ppvObject = ref(&m_d3d11Video);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10Multithread)) {
+ Com<ID3D11DeviceContext> context;
+ m_d3d11Device.GetImmediateContext(&context);
+ return context->QueryInterface(riid, ppvObject);
+ }
+
+ if (riid == __uuidof(ID3D11Debug))
+ return E_NOINTERFACE;
+
+ // Undocumented interfaces that are queried by some games
+ if (riid == GUID{0xd56e2a4c,0x5127,0x8437,{0x65,0x8a,0x98,0xc5,0xbb,0x78,0x94,0x98}})
+ return E_NOINTERFACE;
+
+ Logger::warn("D3D11DXGIDevice::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetParent(
+ REFIID riid,
+ void** ppParent) {
+ return m_dxgiAdapter->QueryInterface(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::CreateSurface(
+ const DXGI_SURFACE_DESC* pDesc,
+ UINT NumSurfaces,
+ DXGI_USAGE Usage,
+ const DXGI_SHARED_RESOURCE* pSharedResource,
+ IDXGISurface** ppSurface) {
+ if (!pDesc || (NumSurfaces && !ppSurface))
+ return E_INVALIDARG;
+
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = pDesc->SampleDesc;
+ desc.BindFlags = 0;
+ desc.MiscFlags = 0;
+
+ // Handle bind flags
+ if (Usage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
+ desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+
+ if (Usage & DXGI_USAGE_SHADER_INPUT)
+ desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
+
+ if (Usage & DXGI_USAGE_UNORDERED_ACCESS)
+ desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
+
+ // Handle CPU access flags
+ switch (Usage & DXGI_CPU_ACCESS_FIELD) {
+ case DXGI_CPU_ACCESS_NONE:
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.CPUAccessFlags = 0;
+ break;
+
+ case DXGI_CPU_ACCESS_DYNAMIC:
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ break;
+
+ case DXGI_CPU_ACCESS_READ_WRITE:
+ case DXGI_CPU_ACCESS_SCRATCH:
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ break;
+
+ default:
+ return E_INVALIDARG;
+ }
+
+ // Restrictions and limitations of CreateSurface are not
+ // well-documented, so we'll be a lenient on validation.
+ HRESULT hr = m_d3d11Device.CreateTexture2D(&desc, nullptr, nullptr);
+
+ if (FAILED(hr))
+ return hr;
+
+ // We don't support shared resources
+ if (NumSurfaces && pSharedResource)
+ Logger::err("D3D11: CreateSurface: Shared surfaces not supported");
+
+ // Try to create the given number of surfaces
+ uint32_t surfacesCreated = 0;
+ hr = S_OK;
+
+ for (uint32_t i = 0; i < NumSurfaces; i++) {
+ Com<ID3D11Texture2D> texture;
+
+ hr = m_d3d11Device.CreateTexture2D(&desc, nullptr, &texture);
+
+ if (SUCCEEDED(hr)) {
+ hr = texture->QueryInterface(__uuidof(IDXGISurface),
+ reinterpret_cast<void**>(&ppSurface[i]));
+ surfacesCreated = i + 1;
+ }
+
+ if (FAILED(hr))
+ break;
+ }
+
+ // Don't leak surfaces if we failed to create one
+ if (FAILED(hr)) {
+ for (uint32_t i = 0; i < surfacesCreated; i++)
+ ppSurface[i]->Release();
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetAdapter(
+ IDXGIAdapter** pAdapter) {
+ if (pAdapter == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ *pAdapter = m_dxgiAdapter.ref();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetGPUThreadPriority(
+ INT* pPriority) {
+ *pPriority = 0;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::QueryResourceResidency(
+ IUnknown* const* ppResources,
+ DXGI_RESIDENCY* pResidencyStatus,
+ UINT NumResources) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D11DXGIDevice::QueryResourceResidency: Stub");
+
+ if (!ppResources || !pResidencyStatus)
+ return E_INVALIDARG;
+
+ for (uint32_t i = 0; i < NumResources; i++)
+ pResidencyStatus[i] = DXGI_RESIDENCY_FULLY_RESIDENT;
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::SetGPUThreadPriority(
+ INT Priority) {
+ if (Priority < -7 || Priority > 7)
+ return E_INVALIDARG;
+
+ Logger::err("DXGI: SetGPUThreadPriority: Ignoring");
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::GetMaximumFrameLatency(
+ UINT* pMaxLatency) {
+ if (!pMaxLatency)
+ return DXGI_ERROR_INVALID_CALL;
+
+ *pMaxLatency = m_frameLatency;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::SetMaximumFrameLatency(
+ UINT MaxLatency) {
+ if (MaxLatency == 0)
+ MaxLatency = DefaultFrameLatency;
+
+ if (MaxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS)
+ return DXGI_ERROR_INVALID_CALL;
+
+ m_frameLatency = MaxLatency;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::OfferResources(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_OFFER_RESOURCE_PRIORITY Priority) {
+ return OfferResources1(NumResources, ppResources, Priority, 0);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::OfferResources1(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_OFFER_RESOURCE_PRIORITY Priority,
+ UINT Flags) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11DXGIDevice::OfferResources1: Stub");
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::ReclaimResources(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ BOOL* pDiscarded) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11DXGIDevice::ReclaimResources: Stub");
+
+ if (pDiscarded)
+ *pDiscarded = false;
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::ReclaimResources1(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_RECLAIM_RESOURCE_RESULTS* pResults) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11DXGIDevice::ReclaimResources1: Stub");
+
+ if (pResults) {
+ for (uint32_t i = 0; i < NumResources; i++)
+ pResults[i] = DXGI_RECLAIM_RESOURCE_RESULT_OK;
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) {
+ Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DXGIDevice::Trim() {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11DXGIDevice::Trim: Stub");
+ }
+
+
+ Rc<DxvkDevice> STDMETHODCALLTYPE D3D11DXGIDevice::GetDXVKDevice() {
+ return m_dxvkDevice;
+ }
+
+
+ Rc<DxvkDevice> D3D11DXGIDevice::CreateDevice(D3D_FEATURE_LEVEL FeatureLevel) {
+ DxvkDeviceFeatures deviceFeatures = D3D11Device::GetDeviceFeatures(m_dxvkAdapter, FeatureLevel);
+ return m_dxvkAdapter->createDevice(m_dxvkInstance, deviceFeatures);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h
new file mode 100644
index 00000000..7de5cf91
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device.h
@@ -0,0 +1,857 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include "../dxbc/dxbc_options.h"
+
+#include "../dxgi/dxgi_object.h"
+#include "../dxgi/dxgi_interfaces.h"
+
+#include "../dxvk/dxvk_cs.h"
+
+#include "../d3d10/d3d10_device.h"
+
+#include "../util/com/com_private_data.h"
+
+#include "d3d11_cmdlist.h"
+#include "d3d11_cuda.h"
+#include "d3d11_initializer.h"
+#include "d3d11_interfaces.h"
+#include "d3d11_interop.h"
+#include "d3d11_options.h"
+#include "d3d11_shader.h"
+#include "d3d11_state.h"
+#include "d3d11_util.h"
+
+namespace dxvk {
+ class DxgiAdapter;
+
+ class D3D11Buffer;
+ class D3D11CommonShader;
+ class D3D11CommonTexture;
+ class D3D11Counter;
+ class D3D11DeviceContext;
+ class D3D11DXGIDevice;
+ class D3D11ImmediateContext;
+ class D3D11Predicate;
+ class D3D11Query;
+ class D3D11Texture1D;
+ class D3D11Texture2D;
+ class D3D11Texture3D;
+
+ /**
+ * \brief D3D11 device implementation
+ *
+ * Implements the ID3D11Device interfaces
+ * as part of a \ref D3D11DeviceContainer.
+ */
+ class D3D11Device final : public ID3D11Device5 {
+ /// Maximum number of resource init commands per command buffer
+ constexpr static uint64_t InitCommandThreshold = 50;
+ public:
+
+ D3D11Device(
+ D3D11DXGIDevice* pContainer,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ UINT FeatureFlags);
+
+ ~D3D11Device();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE CreateBuffer(
+ const D3D11_BUFFER_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Buffer** ppBuffer);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture1D(
+ const D3D11_TEXTURE1D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture1D** ppTexture1D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture2D(
+ const D3D11_TEXTURE2D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture2D** ppTexture2D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture2D1(
+ const D3D11_TEXTURE2D_DESC1* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture2D1** ppTexture2D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture3D(
+ const D3D11_TEXTURE3D_DESC* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture3D** ppTexture3D);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture3D1(
+ const D3D11_TEXTURE3D_DESC1* pDesc,
+ const D3D11_SUBRESOURCE_DATA* pInitialData,
+ ID3D11Texture3D1** ppTexture3D);
+
+ HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D11ShaderResourceView** ppSRView);
+
+ HRESULT STDMETHODCALLTYPE CreateShaderResourceView1(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc,
+ ID3D11ShaderResourceView1** ppSRView);
+
+ HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ ID3D11UnorderedAccessView** ppUAView);
+
+ HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView1(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc,
+ ID3D11UnorderedAccessView1** ppUAView);
+
+ HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
+ ID3D11RenderTargetView** ppRTView);
+
+ HRESULT STDMETHODCALLTYPE CreateRenderTargetView1(
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc,
+ ID3D11RenderTargetView1** ppRTView);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
+ ID3D11Resource* pResource,
+ const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc,
+ ID3D11DepthStencilView** ppDepthStencilView);
+
+ HRESULT STDMETHODCALLTYPE CreateInputLayout(
+ const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs,
+ UINT NumElements,
+ const void* pShaderBytecodeWithInputSignature,
+ SIZE_T BytecodeLength,
+ ID3D11InputLayout** ppInputLayout);
+
+ HRESULT STDMETHODCALLTYPE CreateVertexShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11VertexShader** ppVertexShader);
+
+ HRESULT STDMETHODCALLTYPE CreateGeometryShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11GeometryShader** ppGeometryShader);
+
+ HRESULT STDMETHODCALLTYPE CreateGeometryShaderWithStreamOutput(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ const D3D11_SO_DECLARATION_ENTRY* pSODeclaration,
+ UINT NumEntries,
+ const UINT* pBufferStrides,
+ UINT NumStrides,
+ UINT RasterizedStream,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11GeometryShader** ppGeometryShader);
+
+ HRESULT STDMETHODCALLTYPE CreatePixelShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11PixelShader** ppPixelShader);
+
+ HRESULT STDMETHODCALLTYPE CreateHullShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11HullShader** ppHullShader);
+
+ HRESULT STDMETHODCALLTYPE CreateDomainShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11DomainShader** ppDomainShader);
+
+ HRESULT STDMETHODCALLTYPE CreateComputeShader(
+ const void* pShaderBytecode,
+ SIZE_T BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ ID3D11ComputeShader** ppComputeShader);
+
+ HRESULT STDMETHODCALLTYPE CreateClassLinkage(
+ ID3D11ClassLinkage** ppLinkage);
+
+ HRESULT STDMETHODCALLTYPE CreateBlendState(
+ const D3D11_BLEND_DESC* pBlendStateDesc,
+ ID3D11BlendState** ppBlendState);
+
+ HRESULT STDMETHODCALLTYPE CreateBlendState1(
+ const D3D11_BLEND_DESC1* pBlendStateDesc,
+ ID3D11BlendState1** ppBlendState);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilState(
+ const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc,
+ ID3D11DepthStencilState** ppDepthStencilState);
+
+ HRESULT STDMETHODCALLTYPE CreateRasterizerState(
+ const D3D11_RASTERIZER_DESC* pRasterizerDesc,
+ ID3D11RasterizerState** ppRasterizerState);
+
+ HRESULT STDMETHODCALLTYPE CreateRasterizerState1(
+ const D3D11_RASTERIZER_DESC1* pRasterizerDesc,
+ ID3D11RasterizerState1** ppRasterizerState);
+
+ HRESULT STDMETHODCALLTYPE CreateRasterizerState2(
+ const D3D11_RASTERIZER_DESC2* pRasterizerDesc,
+ ID3D11RasterizerState2** ppRasterizerState);
+
+ HRESULT STDMETHODCALLTYPE CreateSamplerState(
+ const D3D11_SAMPLER_DESC* pSamplerDesc,
+ ID3D11SamplerState** ppSamplerState);
+
+ HRESULT STDMETHODCALLTYPE CreateQuery(
+ const D3D11_QUERY_DESC* pQueryDesc,
+ ID3D11Query** ppQuery);
+
+ HRESULT STDMETHODCALLTYPE CreateQuery1(
+ const D3D11_QUERY_DESC1* pQueryDesc,
+ ID3D11Query1** ppQuery);
+
+ HRESULT STDMETHODCALLTYPE CreatePredicate(
+ const D3D11_QUERY_DESC* pPredicateDesc,
+ ID3D11Predicate** ppPredicate);
+
+ HRESULT STDMETHODCALLTYPE CreateCounter(
+ const D3D11_COUNTER_DESC* pCounterDesc,
+ ID3D11Counter** ppCounter);
+
+ HRESULT STDMETHODCALLTYPE CreateDeferredContext(
+ UINT ContextFlags,
+ ID3D11DeviceContext** ppDeferredContext);
+
+ HRESULT STDMETHODCALLTYPE CreateDeferredContext1(
+ UINT ContextFlags,
+ ID3D11DeviceContext1** ppDeferredContext);
+
+ HRESULT STDMETHODCALLTYPE CreateDeferredContext2(
+ UINT ContextFlags,
+ ID3D11DeviceContext2** ppDeferredContext);
+
+ HRESULT STDMETHODCALLTYPE CreateDeferredContext3(
+ UINT ContextFlags,
+ ID3D11DeviceContext3** ppDeferredContext);
+
+ HRESULT STDMETHODCALLTYPE CreateDeviceContextState(
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ REFIID EmulatedInterface,
+ D3D_FEATURE_LEVEL* pChosenFeatureLevel,
+ ID3DDeviceContextState** ppContextState);
+
+ HRESULT STDMETHODCALLTYPE CreateFence(
+ UINT64 InitialValue,
+ D3D11_FENCE_FLAG Flags,
+ REFIID ReturnedInterface,
+ void** ppFence);
+
+ void STDMETHODCALLTYPE ReadFromSubresource(
+ void* pDstData,
+ UINT DstRowPitch,
+ UINT DstDepthPitch,
+ ID3D11Resource* pSrcResource,
+ UINT SrcSubresource,
+ const D3D11_BOX* pSrcBox);
+
+ void STDMETHODCALLTYPE WriteToSubresource(
+ ID3D11Resource* pDstResource,
+ UINT DstSubresource,
+ const D3D11_BOX* pDstBox,
+ const void* pSrcData,
+ UINT SrcRowPitch,
+ UINT SrcDepthPitch);
+
+ HRESULT STDMETHODCALLTYPE OpenSharedResource(
+ HANDLE hResource,
+ REFIID ReturnedInterface,
+ void** ppResource);
+
+ HRESULT STDMETHODCALLTYPE OpenSharedResource1(
+ HANDLE hResource,
+ REFIID returnedInterface,
+ void** ppResource);
+
+ HRESULT STDMETHODCALLTYPE OpenSharedResourceByName(
+ LPCWSTR lpName,
+ DWORD dwDesiredAccess,
+ REFIID returnedInterface,
+ void** ppResource);
+
+ HRESULT STDMETHODCALLTYPE OpenSharedFence(
+ HANDLE hFence,
+ REFIID ReturnedInterface,
+ void** ppFence);
+
+ HRESULT STDMETHODCALLTYPE CheckFormatSupport(
+ DXGI_FORMAT Format,
+ UINT* pFormatSupport);
+
+ HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT* pNumQualityLevels);
+
+ HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels1(
+ DXGI_FORMAT Format,
+ UINT SampleCount,
+ UINT Flags,
+ UINT* pNumQualityLevels);
+
+ void STDMETHODCALLTYPE CheckCounterInfo(
+ D3D11_COUNTER_INFO* pCounterInfo);
+
+ HRESULT STDMETHODCALLTYPE CheckCounter(
+ const D3D11_COUNTER_DESC* pDesc,
+ D3D11_COUNTER_TYPE* pType,
+ UINT* pActiveCounters,
+ LPSTR szName,
+ UINT* pNameLength,
+ LPSTR szUnits,
+ UINT* pUnitsLength,
+ LPSTR szDescription,
+ UINT* pDescriptionLength);
+
+ HRESULT STDMETHODCALLTYPE CheckFeatureSupport(
+ D3D11_FEATURE Feature,
+ void* pFeatureSupportData,
+ UINT FeatureSupportDataSize);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT *pDataSize,
+ void *pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void *pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown *pUnknown);
+
+ D3D_FEATURE_LEVEL STDMETHODCALLTYPE GetFeatureLevel();
+
+ UINT STDMETHODCALLTYPE GetCreationFlags();
+
+ HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason();
+
+ void STDMETHODCALLTYPE GetImmediateContext(
+ ID3D11DeviceContext** ppImmediateContext);
+
+ void STDMETHODCALLTYPE GetImmediateContext1(
+ ID3D11DeviceContext1** ppImmediateContext);
+
+ void STDMETHODCALLTYPE GetImmediateContext2(
+ ID3D11DeviceContext2** ppImmediateContext);
+
+ void STDMETHODCALLTYPE GetImmediateContext3(
+ ID3D11DeviceContext3** ppImmediateContext);
+
+ HRESULT STDMETHODCALLTYPE SetExceptionMode(UINT RaiseFlags);
+
+ UINT STDMETHODCALLTYPE GetExceptionMode();
+
+ void STDMETHODCALLTYPE GetResourceTiling(
+ ID3D11Resource* pTiledResource,
+ UINT* pNumTilesForEntireResource,
+ D3D11_PACKED_MIP_DESC* pPackedMipDesc,
+ D3D11_TILE_SHAPE* pStandardTileShapeForNonPackedMips,
+ UINT* pNumSubresourceTilings,
+ UINT FirstSubresourceTilingToGet,
+ D3D11_SUBRESOURCE_TILING* pSubresourceTilingsForNonPackedMips);
+
+ HRESULT STDMETHODCALLTYPE RegisterDeviceRemovedEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie);
+
+ void STDMETHODCALLTYPE UnregisterDeviceRemoved(
+ DWORD dwCookie);
+
+ Rc<DxvkDevice> GetDXVKDevice() {
+ return m_dxvkDevice;
+ }
+
+ void FlushInitContext();
+
+ VkPipelineStageFlags GetEnabledShaderStages() const {
+ return m_dxvkDevice->getShaderPipelineStages();
+ }
+
+ DXGI_VK_FORMAT_INFO LookupFormat(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ DXGI_VK_FORMAT_INFO LookupPackedFormat(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ DXGI_VK_FORMAT_FAMILY LookupFamily(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ DxvkCsChunkRef AllocCsChunk(DxvkCsChunkFlags flags) {
+ DxvkCsChunk* chunk = m_csChunkPool.allocChunk(flags);
+ return DxvkCsChunkRef(chunk, &m_csChunkPool);
+ }
+
+ const D3D11Options* GetOptions() const {
+ return &m_d3d11Options;
+ }
+
+ D3D10Device* GetD3D10Interface() const {
+ return m_d3d10Device;
+ }
+
+ static bool CheckFeatureLevelSupport(
+ const Rc<DxvkInstance>& instance,
+ const Rc<DxvkAdapter>& adapter,
+ D3D_FEATURE_LEVEL featureLevel);
+
+ static DxvkDeviceFeatures GetDeviceFeatures(
+ const Rc<DxvkAdapter>& adapter,
+ D3D_FEATURE_LEVEL featureLevel);
+
+ private:
+
+ IDXGIObject* m_container;
+
+ D3D_FEATURE_LEVEL m_featureLevel;
+ UINT m_featureFlags;
+
+ const Rc<DxvkDevice> m_dxvkDevice;
+ const Rc<DxvkAdapter> m_dxvkAdapter;
+
+ const DXGIVkFormatTable m_d3d11Formats;
+ const D3D11Options m_d3d11Options;
+ const DxbcOptions m_dxbcOptions;
+
+ DxvkCsChunkPool m_csChunkPool;
+
+ D3D11Initializer* m_initializer = nullptr;
+ D3D10Device* m_d3d10Device = nullptr;
+ Com<D3D11ImmediateContext, false> m_context;
+
+ D3D11StateObjectSet<D3D11BlendState> m_bsStateObjects;
+ D3D11StateObjectSet<D3D11DepthStencilState> m_dsStateObjects;
+ D3D11StateObjectSet<D3D11RasterizerState> m_rsStateObjects;
+ D3D11StateObjectSet<D3D11SamplerState> m_samplerObjects;
+ D3D11ShaderModuleSet m_shaderModules;
+
+ HRESULT CreateShaderModule(
+ D3D11CommonShader* pShaderModule,
+ DxvkShaderKey ShaderKey,
+ const void* pShaderBytecode,
+ size_t BytecodeLength,
+ ID3D11ClassLinkage* pClassLinkage,
+ const DxbcModuleInfo* pModuleInfo);
+
+ HRESULT GetFormatSupportFlags(
+ DXGI_FORMAT Format,
+ UINT* pFlags1,
+ UINT* pFlags2) const;
+
+ BOOL GetImageTypeSupport(
+ VkFormat Format,
+ VkImageType Type) const;
+
+ uint32_t GetViewPlaneIndex(
+ ID3D11Resource* pResource,
+ DXGI_FORMAT ViewFormat);
+
+ template<typename Void>
+ void CopySubresourceData(
+ Void* pData,
+ UINT RowPitch,
+ UINT DepthPitch,
+ ID3D11Resource* pResource,
+ UINT Subresource,
+ const D3D11_BOX* pBox);
+
+ static D3D_FEATURE_LEVEL GetMaxFeatureLevel(
+ const Rc<DxvkInstance>& pInstance);
+
+ };
+
+
+ /**
+ * \brief Extended D3D11 device
+ */
+ class D3D11DeviceExt : public ID3D11VkExtDevice1 {
+
+ public:
+
+ D3D11DeviceExt(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ BOOL STDMETHODCALLTYPE GetExtensionSupport(
+ D3D11_VK_EXTENSION Extension);
+
+ bool STDMETHODCALLTYPE GetCudaTextureObjectNVX(
+ uint32_t srvDriverHandle,
+ uint32_t samplerDriverHandle,
+ uint32_t* pCudaTextureHandle);
+
+ bool STDMETHODCALLTYPE CreateCubinComputeShaderWithNameNVX(
+ const void* pCubin,
+ uint32_t size,
+ uint32_t blockX,
+ uint32_t blockY,
+ uint32_t blockZ,
+ const char* pShaderName,
+ IUnknown** phShader);
+
+ bool STDMETHODCALLTYPE GetResourceHandleGPUVirtualAddressAndSizeNVX(
+ void* hObject,
+ uint64_t* gpuVAStart,
+ uint64_t* gpuVASize);
+
+ bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ ID3D11UnorderedAccessView** ppUAV,
+ uint32_t* pDriverHandle);
+
+ bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D11ShaderResourceView** ppSRV,
+ uint32_t* pDriverHandle);
+
+ bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX(
+ const D3D11_SAMPLER_DESC* pSamplerDesc,
+ ID3D11SamplerState** ppSamplerState,
+ uint32_t* pDriverHandle);
+
+ private:
+
+ D3D11DXGIDevice* m_container;
+ D3D11Device* m_device;
+
+ void AddSamplerAndHandleNVX(
+ ID3D11SamplerState* pSampler,
+ uint32_t Handle);
+
+ ID3D11SamplerState* HandleToSamplerNVX(
+ uint32_t Handle);
+
+ void AddSrvAndHandleNVX(
+ ID3D11ShaderResourceView* pSrv,
+ uint32_t Handle);
+
+ ID3D11ShaderResourceView* HandleToSrvNVX(
+ uint32_t Handle);
+
+ dxvk::mutex m_mapLock;
+ std::unordered_map<uint32_t, ID3D11SamplerState*> m_samplerHandleToPtr;
+ std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr;
+ };
+
+
+ /**
+ * \brief D3D11 video device
+ */
+ class D3D11VideoDevice : public ID3D11VideoDevice {
+
+ public:
+
+ D3D11VideoDevice(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice);
+
+ ~D3D11VideoDevice();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoDecoder(
+ const D3D11_VIDEO_DECODER_DESC* pVideoDesc,
+ const D3D11_VIDEO_DECODER_CONFIG* pConfig,
+ ID3D11VideoDecoder** ppDecoder);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoProcessor(
+ ID3D11VideoProcessorEnumerator* pEnum,
+ UINT RateConversionIndex,
+ ID3D11VideoProcessor** ppVideoProcessor);
+
+ HRESULT STDMETHODCALLTYPE CreateAuthenticatedChannel(
+ D3D11_AUTHENTICATED_CHANNEL_TYPE ChannelType,
+ ID3D11AuthenticatedChannel** ppAuthenticatedChannel);
+
+ HRESULT STDMETHODCALLTYPE CreateCryptoSession(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ const GUID* pKeyExchangeType,
+ ID3D11CryptoSession** ppCryptoSession);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoDecoderOutputView(
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC* pDesc,
+ ID3D11VideoDecoderOutputView** ppVDOVView);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoProcessorInputView(
+ ID3D11Resource* pResource,
+ ID3D11VideoProcessorEnumerator* pEnum,
+ const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc,
+ ID3D11VideoProcessorInputView** ppVPIView);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoProcessorOutputView(
+ ID3D11Resource* pResource,
+ ID3D11VideoProcessorEnumerator* pEnum,
+ const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc,
+ ID3D11VideoProcessorOutputView** ppVPOView);
+
+ HRESULT STDMETHODCALLTYPE CreateVideoProcessorEnumerator(
+ const D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pDesc,
+ ID3D11VideoProcessorEnumerator** ppEnum);
+
+ UINT STDMETHODCALLTYPE GetVideoDecoderProfileCount();
+
+ HRESULT STDMETHODCALLTYPE GetVideoDecoderProfile(
+ UINT Index,
+ GUID* pDecoderProfile);
+
+ HRESULT STDMETHODCALLTYPE CheckVideoDecoderFormat(
+ const GUID* pDecoderProfile,
+ DXGI_FORMAT Format,
+ BOOL* pSupported);
+
+ HRESULT STDMETHODCALLTYPE GetVideoDecoderConfigCount(
+ const D3D11_VIDEO_DECODER_DESC* pDesc,
+ UINT* pCount);
+
+ HRESULT STDMETHODCALLTYPE GetVideoDecoderConfig(
+ const D3D11_VIDEO_DECODER_DESC* pDesc,
+ UINT Index,
+ D3D11_VIDEO_DECODER_CONFIG* pConfig);
+
+ HRESULT STDMETHODCALLTYPE GetContentProtectionCaps(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ D3D11_VIDEO_CONTENT_PROTECTION_CAPS* pCaps);
+
+ HRESULT STDMETHODCALLTYPE CheckCryptoKeyExchange(
+ const GUID* pCryptoType,
+ const GUID* pDecoderProfile,
+ UINT Index,
+ GUID* pKeyExchangeType);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pData);
+
+ private:
+
+ D3D11DXGIDevice* m_container;
+ D3D11Device* m_device;
+
+ };
+
+
+ /**
+ * \brief DXGI swap chain factory
+ */
+ class WineDXGISwapChainFactory : public IWineDXGISwapChainFactory {
+
+ public:
+
+ WineDXGISwapChainFactory(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd(
+ IDXGIFactory* pFactory,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain);
+
+ private:
+
+ D3D11DXGIDevice* m_container;
+ D3D11Device* m_device;
+
+ };
+
+
+ /**
+ * \brief D3D11 device metadata shenanigans
+ */
+ class DXGIDXVKDevice : public IDXGIDXVKDevice {
+
+ public:
+
+ DXGIDXVKDevice(D3D11DXGIDevice* pContainer);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE SetAPIVersion(
+ UINT Version);
+
+ UINT STDMETHODCALLTYPE GetAPIVersion();
+
+ private:
+
+ D3D11DXGIDevice* m_container;
+ UINT m_apiVersion;
+
+ };
+
+
+ /**
+ * \brief D3D11 device container
+ *
+ * Stores all the objects that contribute to the D3D11
+ * device implementation, including the DXGI device.
+ */
+ class D3D11DXGIDevice : public DxgiObject<IDXGIDevice4> {
+ constexpr static uint32_t DefaultFrameLatency = 3;
+ public:
+
+ D3D11DXGIDevice(
+ IDXGIAdapter* pAdapter,
+ const Rc<DxvkInstance>& pDxvkInstance,
+ const Rc<DxvkAdapter>& pDxvkAdapter,
+ D3D_FEATURE_LEVEL FeatureLevel,
+ UINT FeatureFlags);
+
+ ~D3D11DXGIDevice();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent);
+
+ HRESULT STDMETHODCALLTYPE CreateSurface(
+ const DXGI_SURFACE_DESC* pDesc,
+ UINT NumSurfaces,
+ DXGI_USAGE Usage,
+ const DXGI_SHARED_RESOURCE* pSharedResource,
+ IDXGISurface** ppSurface) final;
+
+ HRESULT STDMETHODCALLTYPE GetAdapter(
+ IDXGIAdapter** pAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(
+ INT* pPriority) final;
+
+ HRESULT STDMETHODCALLTYPE QueryResourceResidency(
+ IUnknown* const* ppResources,
+ DXGI_RESIDENCY* pResidencyStatus,
+ UINT NumResources) final;
+
+ HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(
+ INT Priority) final;
+
+ HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(
+ UINT* pMaxLatency) final;
+
+ HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(
+ UINT MaxLatency) final;
+
+ HRESULT STDMETHODCALLTYPE OfferResources(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_OFFER_RESOURCE_PRIORITY Priority) final;
+
+ HRESULT STDMETHODCALLTYPE OfferResources1(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_OFFER_RESOURCE_PRIORITY Priority,
+ UINT Flags) final;
+
+ HRESULT STDMETHODCALLTYPE ReclaimResources(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ BOOL* pDiscarded) final;
+
+ HRESULT STDMETHODCALLTYPE ReclaimResources1(
+ UINT NumResources,
+ IDXGIResource* const* ppResources,
+ DXGI_RECLAIM_RESOURCE_RESULTS* pResults) final;
+
+ HRESULT STDMETHODCALLTYPE EnqueueSetEvent(
+ HANDLE hEvent) final;
+
+ void STDMETHODCALLTYPE Trim() final;
+
+ Rc<DxvkDevice> STDMETHODCALLTYPE GetDXVKDevice();
+
+ private:
+
+ Com<IDXGIAdapter> m_dxgiAdapter;
+
+ Rc<DxvkInstance> m_dxvkInstance;
+ Rc<DxvkAdapter> m_dxvkAdapter;
+ Rc<DxvkDevice> m_dxvkDevice;
+
+ D3D11Device m_d3d11Device;
+ D3D11DeviceExt m_d3d11DeviceExt;
+ D3D11VkInterop m_d3d11Interop;
+ D3D11VideoDevice m_d3d11Video;
+ DXGIDXVKDevice m_metaDevice;
+
+ WineDXGISwapChainFactory m_wineFactory;
+
+ uint32_t m_frameLatency = DefaultFrameLatency;
+
+ Rc<DxvkDevice> CreateDevice(D3D_FEATURE_LEVEL FeatureLevel);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h
new file mode 100644
index 00000000..60eff07a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_device_child.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#include "d3d11_include.h"
+
+#include "../util/com/com_private_data.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ template<typename Base>
+ class D3D11DeviceObject : public Base {
+
+ public:
+
+ D3D11DeviceObject(D3D11Device* pDevice)
+ : m_parent(pDevice) {
+
+ }
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT *pDataSize,
+ void *pData) final {
+ return m_privateData.getData(
+ guid, pDataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void *pData) final {
+ return m_privateData.setData(
+ guid, DataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown *pUnknown) final {
+ return m_privateData.setInterface(
+ guid, pUnknown);
+ }
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D11Device** ppDevice) final {
+ *ppDevice = ref(GetParentInterface());
+ }
+
+ protected:
+
+ ID3D11Device* GetParentInterface() const {
+ // We don't know the definition of ID3D11Device
+ // here, because D3D11Device includes this file.
+ return reinterpret_cast<ID3D11Device*>(m_parent);
+ }
+
+ D3D11Device* const m_parent;
+
+ private:
+
+ ComPrivateData m_privateData;
+
+ };
+
+
+ template<typename Base>
+ class D3D11DeviceChild : public D3D11DeviceObject<ComObject<Base>> {
+
+ public:
+
+ D3D11DeviceChild(D3D11Device* pDevice)
+ : D3D11DeviceObject<ComObject<Base>>(pDevice) {
+
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ uint32_t refCount = this->m_refCount++;
+ if (unlikely(!refCount)) {
+ this->AddRefPrivate();
+ this->GetParentInterface()->AddRef();
+ }
+
+ return refCount + 1;
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ uint32_t refCount = --this->m_refCount;
+ if (unlikely(!refCount)) {
+ auto* parent = this->GetParentInterface();
+ this->ReleasePrivate();
+ parent->Release();
+ }
+ return refCount;
+ }
+
+ };
+
+ template<typename Base>
+ class D3D11StateObject : public D3D11DeviceObject<Base> {
+
+ public:
+
+ D3D11StateObject(D3D11Device* pDevice)
+ : D3D11DeviceObject<Base>(pDevice) {
+
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ uint32_t refCount = this->m_refCount++;
+ if (unlikely(!refCount))
+ this->GetParentInterface()->AddRef();
+
+ return refCount + 1;
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ uint32_t refCount = --this->m_refCount;
+ if (unlikely(!refCount))
+ this->GetParentInterface()->Release();
+
+ return refCount;
+ }
+
+ private:
+
+ std::atomic<uint32_t> m_refCount = { 0u };
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp
new file mode 100644
index 00000000..0b9fc0f6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.cpp
@@ -0,0 +1,14 @@
+#include "d3d11_enums.h"
+
+std::ostream& operator << (std::ostream& os, D3D_FEATURE_LEVEL e) {
+ switch (e) {
+ ENUM_NAME(D3D_FEATURE_LEVEL_9_1);
+ ENUM_NAME(D3D_FEATURE_LEVEL_9_2);
+ ENUM_NAME(D3D_FEATURE_LEVEL_9_3);
+ ENUM_NAME(D3D_FEATURE_LEVEL_10_0);
+ ENUM_NAME(D3D_FEATURE_LEVEL_10_1);
+ ENUM_NAME(D3D_FEATURE_LEVEL_11_0);
+ ENUM_NAME(D3D_FEATURE_LEVEL_11_1);
+ ENUM_DEFAULT(e);
+ }
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h
new file mode 100644
index 00000000..d67d0cdd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_enums.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <ostream>
+
+#include "d3d11_include.h"
+
+std::ostream& operator << (std::ostream& os, D3D_FEATURE_LEVEL e); \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp
new file mode 100644
index 00000000..83e0618d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.cpp
@@ -0,0 +1,208 @@
+#include "d3d11_context.h"
+#include "d3d11_device.h"
+#include "d3d11_gdi.h"
+
+#ifndef DXVK_NATIVE
+#include "../util/util_gdi.h"
+#endif
+
+namespace dxvk {
+
+ D3D11GDISurface::D3D11GDISurface(
+ ID3D11Resource* pResource,
+ UINT Subresource)
+ : m_resource (pResource),
+ m_subresource (Subresource),
+ m_readback (nullptr),
+ m_hdc (nullptr),
+ m_hbitmap (nullptr),
+ m_acquired (false) {
+ // Allocate memory for the bitmap
+ auto tex = GetCommonTexture(m_resource)->Desc();
+ m_data.resize(tex->Width * tex->Height);
+
+ // Create GDI DC
+ D3DKMT_CREATEDCFROMMEMORY desc;
+ desc.pMemory = m_data.data();
+ desc.Format = D3DFMT_A8R8G8B8;
+ desc.Width = tex->Width;
+ desc.Height = tex->Height;
+ desc.Pitch = tex->Width * sizeof(uint32_t);
+ desc.hDeviceDc = CreateCompatibleDC(nullptr);
+ desc.pColorTable = nullptr;
+ desc.hDc = nullptr;
+ desc.hBitmap = nullptr;
+
+ if (D3DKMTCreateDCFromMemory(&desc))
+ Logger::err(str::format("D3D11: Failed to create GDI DC"));
+
+ m_hdc = desc.hDc;
+ m_hbitmap = desc.hBitmap;
+ }
+
+
+ D3D11GDISurface::~D3D11GDISurface() {
+ if (m_readback)
+ m_readback->Release();
+
+ D3DKMT_DESTROYDCFROMMEMORY desc;
+ desc.hDC = m_hdc;
+ desc.hBitmap = m_hbitmap;
+ D3DKMTDestroyDCFromMemory(&desc);
+ }
+
+
+ HRESULT D3D11GDISurface::Acquire(BOOL Discard, HDC* phdc) {
+ if (!phdc)
+ return E_INVALIDARG;
+
+ *phdc = nullptr;
+
+ if (m_acquired)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (!Discard) {
+ // Create a staging resource that we can map
+ if (!m_readback && FAILED(CreateReadbackResource())) {
+ Logger::err("D3D11: Failed to create GDI readback resource");
+ return E_FAIL;
+ }
+
+ // Copy subresource to staging image
+ Com<ID3D11Device> device;
+ Com<ID3D11DeviceContext> context;
+
+ m_resource->GetDevice(&device);
+ device->GetImmediateContext(&context);
+
+ context->CopySubresourceRegion(m_readback, 0,
+ 0, 0, 0, m_resource, m_subresource, nullptr);
+
+ // Copy staging image to DC memory
+ auto tex = GetCommonTexture(m_resource)->Desc();
+ auto rowData = reinterpret_cast<char*>(m_data.data());
+ auto rowLength = sizeof(uint32_t) * tex->Width;
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ context->Map(m_readback, 0, D3D11_MAP_READ, 0, &sr);
+
+ for (uint32_t i = 0; i < tex->Height; i++) {
+ std::memcpy(rowData + rowLength * i,
+ reinterpret_cast<const char*>(sr.pData) + sr.RowPitch * i,
+ rowLength);
+ }
+
+ context->Unmap(m_readback, 0);
+ }
+
+ m_acquired = true;
+ *phdc = m_hdc;
+ return S_OK;
+ }
+
+
+ HRESULT D3D11GDISurface::Release(const RECT* pDirtyRect) {
+ if (!m_acquired)
+ return DXGI_ERROR_INVALID_CALL;
+
+ Com<ID3D11Device> device;
+ Com<ID3D11DeviceContext> context;
+
+ m_resource->GetDevice(&device);
+ device->GetImmediateContext(&context);
+
+ // Commit changes made to the DC
+ auto tex = GetCommonTexture(m_resource)->Desc();
+
+ RECT rect;
+
+ if (pDirtyRect) {
+ rect.left = std::max<LONG>(pDirtyRect->left, 0);
+ rect.top = std::max<LONG>(pDirtyRect->top, 0);
+ rect.right = std::min<LONG>(pDirtyRect->right, tex->Width);
+ rect.bottom = std::min<LONG>(pDirtyRect->bottom, tex->Height);
+ } else {
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = tex->Width;
+ rect.bottom = tex->Height;
+ }
+
+ if (rect.left < rect.right && rect.top < rect.bottom) {
+ D3D11_BOX box;
+ box.left = rect.left;
+ box.top = rect.top;
+ box.front = 0;
+ box.right = rect.right;
+ box.bottom = rect.bottom;
+ box.back = 1;
+
+ context->UpdateSubresource(m_resource, m_subresource,
+ &box, m_data.data() + rect.left,
+ sizeof(uint32_t) * tex->Width,
+ sizeof(uint32_t) * tex->Width * tex->Height);
+ }
+
+ m_acquired = false;
+ return S_OK;
+ }
+
+
+ HRESULT D3D11GDISurface::CreateReadbackResource() {
+ auto tex = GetCommonTexture(m_resource);
+
+ Com<ID3D11Device> device;
+ Com<ID3D11DeviceContext> context;
+
+ m_resource->GetDevice(&device);
+ device->GetImmediateContext(&context);
+
+ D3D11_RESOURCE_DIMENSION dim = { };
+ m_resource->GetType(&dim);
+
+ VkImageSubresource sr = tex->GetSubresourceFromIndex(
+ VK_IMAGE_ASPECT_COLOR_BIT, m_subresource);
+
+ switch (dim) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC desc;
+ desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1);
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = tex->Desc()->Format;
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ desc.MiscFlags = 0;
+
+ ID3D11Texture1D* tex1D = nullptr;
+ HRESULT hr = device->CreateTexture1D(&desc, nullptr, &tex1D);
+ m_readback = tex1D;
+ return hr;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = std::max<UINT>(tex->Desc()->Width >> sr.mipLevel, 1);
+ desc.Height = std::max<UINT>(tex->Desc()->Height >> sr.mipLevel, 1);
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = tex->Desc()->Format;
+ desc.SampleDesc= { 1, 0 };
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ desc.MiscFlags = 0;
+
+ ID3D11Texture2D* tex2D = nullptr;
+ HRESULT hr = device->CreateTexture2D(&desc, nullptr, &tex2D);
+ m_readback = tex2D;
+ return hr;
+ } break;
+
+ default:
+ return E_INVALIDARG;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h
new file mode 100644
index 00000000..a2656c0a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_gdi.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <vector>
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ class D3D11GDISurface {
+
+ public:
+
+ D3D11GDISurface(
+ ID3D11Resource* pResource,
+ UINT Subresource);
+
+ ~D3D11GDISurface();
+
+ HRESULT Acquire(
+ BOOL Discard,
+ HDC* phdc);
+
+ HRESULT Release(
+ const RECT* pDirtyRect);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ uint32_t m_subresource;
+ ID3D11Resource* m_readback;
+ HDC m_hdc;
+ HANDLE m_hbitmap;
+ bool m_acquired;
+
+ std::vector<uint32_t> m_data;
+
+ HRESULT CreateReadbackResource();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h
new file mode 100644
index 00000000..1598088a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_include.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "../dxgi/dxgi_include.h"
+
+#include <d3d11_4.h>
+
+// This is not defined in the mingw headers
+#ifndef D3D11_1_UAV_SLOT_COUNT
+#define D3D11_1_UAV_SLOT_COUNT 64
+#endif
+
+#ifndef D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL
+#define D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL 0xFFFFFFFF
+#endif
+
+#ifndef D3D11_KEEP_UNORDERED_ACCESS_VIEWS
+#define D3D11_KEEP_UNORDERED_ACCESS_VIEWS 0xFFFFFFFF
+#endif
+
+#define D3D11_DXVK_USE_REMAINING_LAYERS 0xFFFFFFFF
+#define D3D11_DXVK_USE_REMAINING_LEVELS 0xFFFFFFFF
+
+// Most of these were copied from d3d11.h
+// For some strange reason, we cannot use the structures
+// directly, although others from the same header work.
+// Some structures are missing from the mingw headers.
+#ifndef _MSC_VER
+#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 9
+typedef enum D3D11_FORMAT_SUPPORT2 {
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x1,
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x2,
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x4,
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x8,
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x10,
+ D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x20,
+ D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x40,
+ D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x80,
+ D3D11_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x100,
+ D3D11_FORMAT_SUPPORT2_TILED = 0x200,
+ D3D11_FORMAT_SUPPORT2_SHAREABLE = 0x400,
+ D3D11_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x4000
+} D3D11_FORMAT_SUPPORT2;
+#define D3D11_RESOURCE_MISC_TILE_POOL (0x20000)
+#define D3D11_RESOURCE_MISC_TILED (0x40000)
+#endif // !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 9
+#endif // _MSC_VER
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp
new file mode 100644
index 00000000..d1d66f19
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.cpp
@@ -0,0 +1,290 @@
+#include <cstring>
+
+#include "d3d11_device.h"
+#include "d3d11_initializer.h"
+
+namespace dxvk {
+
+ D3D11Initializer::D3D11Initializer(
+ D3D11Device* pParent)
+ : m_parent(pParent),
+ m_device(pParent->GetDXVKDevice()),
+ m_context(m_device->createContext()) {
+ m_context->beginRecording(
+ m_device->createCommandList());
+ }
+
+
+ D3D11Initializer::~D3D11Initializer() {
+
+ }
+
+
+ void D3D11Initializer::Flush() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_transferCommands != 0)
+ FlushInternal();
+ }
+
+ void D3D11Initializer::InitBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer()->memFlags();
+
+ (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ ? InitHostVisibleBuffer(pBuffer, pInitialData)
+ : InitDeviceLocalBuffer(pBuffer, pInitialData);
+ }
+
+
+ void D3D11Initializer::InitTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ (pTexture->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
+ ? InitHostVisibleTexture(pTexture, pInitialData)
+ : InitDeviceLocalTexture(pTexture, pInitialData);
+ }
+
+
+ void D3D11Initializer::InitUavCounter(
+ D3D11UnorderedAccessView* pUav) {
+ auto counterBuffer = pUav->GetCounterSlice();
+
+ if (!counterBuffer.defined())
+ return;
+
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ m_transferCommands += 1;
+
+ const uint32_t zero = 0;
+ m_context->updateBuffer(
+ counterBuffer.buffer(),
+ 0, sizeof(zero), &zero);
+
+ FlushImplicit();
+ }
+
+
+ void D3D11Initializer::InitDeviceLocalBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
+
+ if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
+ m_transferMemory += bufferSlice.length();
+ m_transferCommands += 1;
+
+ m_context->uploadBuffer(
+ bufferSlice.buffer(),
+ pInitialData->pSysMem);
+ } else {
+ m_transferCommands += 1;
+
+ m_context->clearBuffer(
+ bufferSlice.buffer(),
+ bufferSlice.offset(),
+ bufferSlice.length(),
+ 0u);
+ }
+
+ FlushImplicit();
+ }
+
+
+ void D3D11Initializer::InitHostVisibleBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ // If the buffer is mapped, we can write data directly
+ // to the mapped memory region instead of doing it on
+ // the GPU. Same goes for zero-initialization.
+ DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice();
+
+ if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
+ std::memcpy(
+ bufferSlice.mapPtr(0),
+ pInitialData->pSysMem,
+ bufferSlice.length());
+ } else {
+ std::memset(
+ bufferSlice.mapPtr(0), 0,
+ bufferSlice.length());
+ }
+ }
+
+
+ void D3D11Initializer::InitDeviceLocalTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ Rc<DxvkImage> image = pTexture->GetImage();
+
+ auto mapMode = pTexture->GetMapMode();
+ auto desc = pTexture->Desc();
+
+ VkFormat packedFormat = m_parent->LookupPackedFormat(desc->Format, pTexture->GetFormatMode()).Format;
+ auto formatInfo = imageFormatInfo(packedFormat);
+
+ if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
+ // pInitialData is an array that stores an entry for
+ // every single subresource. Since we will define all
+ // subresources, this counts as initialization.
+ for (uint32_t layer = 0; layer < desc->ArraySize; layer++) {
+ for (uint32_t level = 0; level < desc->MipLevels; level++) {
+ const uint32_t id = D3D11CalcSubresource(
+ level, layer, desc->MipLevels);
+
+ VkOffset3D mipLevelOffset = { 0, 0, 0 };
+ VkExtent3D mipLevelExtent = pTexture->MipLevelExtent(level);
+
+ if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
+ m_transferCommands += 1;
+ m_transferMemory += pTexture->GetSubresourceLayout(formatInfo->aspectMask, id).Size;
+
+ VkImageSubresourceLayers subresourceLayers;
+ subresourceLayers.aspectMask = formatInfo->aspectMask;
+ subresourceLayers.mipLevel = level;
+ subresourceLayers.baseArrayLayer = layer;
+ subresourceLayers.layerCount = 1;
+
+ if (formatInfo->aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ m_context->uploadImage(
+ image, subresourceLayers,
+ pInitialData[id].pSysMem,
+ pInitialData[id].SysMemPitch,
+ pInitialData[id].SysMemSlicePitch);
+ } else {
+ m_context->updateDepthStencilImage(
+ image, subresourceLayers,
+ VkOffset2D { mipLevelOffset.x, mipLevelOffset.y },
+ VkExtent2D { mipLevelExtent.width, mipLevelExtent.height },
+ pInitialData[id].pSysMem,
+ pInitialData[id].SysMemPitch,
+ pInitialData[id].SysMemSlicePitch,
+ packedFormat);
+ }
+ }
+
+ if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
+ util::packImageData(pTexture->GetMappedBuffer(id)->mapPtr(0),
+ pInitialData[id].pSysMem, pInitialData[id].SysMemPitch, pInitialData[id].SysMemSlicePitch,
+ 0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
+ }
+ }
+ }
+ } else {
+ if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
+ m_transferCommands += 1;
+
+ // While the Microsoft docs state that resource contents are
+ // undefined if no initial data is provided, some applications
+ // expect a resource to be pre-cleared. We can only do that
+ // for non-compressed images, but that should be fine.
+ VkImageSubresourceRange subresources;
+ subresources.aspectMask = formatInfo->aspectMask;
+ subresources.baseMipLevel = 0;
+ subresources.levelCount = desc->MipLevels;
+ subresources.baseArrayLayer = 0;
+ subresources.layerCount = desc->ArraySize;
+
+ if (formatInfo->flags.any(DxvkFormatFlag::BlockCompressed, DxvkFormatFlag::MultiPlane)) {
+ m_context->clearCompressedColorImage(image, subresources);
+ } else {
+ if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
+ VkClearColorValue value = { };
+
+ m_context->clearColorImage(
+ image, value, subresources);
+ } else {
+ VkClearDepthStencilValue value;
+ value.depth = 0.0f;
+ value.stencil = 0;
+
+ m_context->clearDepthStencilImage(
+ image, value, subresources);
+ }
+ }
+ }
+
+ if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
+ for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) {
+ auto buffer = pTexture->GetMappedBuffer(i);
+ std::memset(buffer->mapPtr(0), 0, buffer->info().size);
+ }
+ }
+ }
+
+ FlushImplicit();
+ }
+
+
+ void D3D11Initializer::InitHostVisibleTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData) {
+ Rc<DxvkImage> image = pTexture->GetImage();
+
+ for (uint32_t layer = 0; layer < image->info().numLayers; layer++) {
+ for (uint32_t level = 0; level < image->info().mipLevels; level++) {
+ VkImageSubresource subresource;
+ subresource.aspectMask = image->formatInfo()->aspectMask;
+ subresource.mipLevel = level;
+ subresource.arrayLayer = layer;
+
+ VkExtent3D blockCount = util::computeBlockCount(
+ image->mipLevelExtent(level),
+ image->formatInfo()->blockSize);
+
+ VkSubresourceLayout layout = image->querySubresourceLayout(subresource);
+
+ auto initialData = pInitialData
+ ? &pInitialData[D3D11CalcSubresource(level, layer, image->info().mipLevels)]
+ : nullptr;
+
+ for (uint32_t z = 0; z < blockCount.depth; z++) {
+ for (uint32_t y = 0; y < blockCount.height; y++) {
+ auto size = blockCount.width * image->formatInfo()->elementSize;
+ auto dst = image->mapPtr(layout.offset + y * layout.rowPitch + z * layout.depthPitch);
+
+ if (initialData) {
+ auto src = reinterpret_cast<const char*>(initialData->pSysMem)
+ + y * initialData->SysMemPitch
+ + z * initialData->SysMemSlicePitch;
+ std::memcpy(dst, src, size);
+ } else {
+ std::memset(dst, 0, size);
+ }
+ }
+ }
+ }
+ }
+
+ // Initialize the image on the GPU
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ VkImageSubresourceRange subresources = image->getAvailableSubresources();
+
+ m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED);
+
+ m_transferCommands += 1;
+ FlushImplicit();
+ }
+
+
+ void D3D11Initializer::FlushImplicit() {
+ if (m_transferCommands > MaxTransferCommands
+ || m_transferMemory > MaxTransferMemory)
+ FlushInternal();
+ }
+
+
+ void D3D11Initializer::FlushInternal() {
+ m_context->flushCommandList();
+
+ m_transferCommands = 0;
+ m_transferMemory = 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h
new file mode 100644
index 00000000..8c96babd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_initializer.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "d3d11_buffer.h"
+#include "d3d11_texture.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Resource initialization context
+ *
+ * Manages a context which is used for resource
+ * initialization. This includes initialization
+ * with application-defined data, as well as
+ * zero-initialization for buffers and images.
+ */
+ class D3D11Initializer {
+ constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
+ constexpr static size_t MaxTransferCommands = 512;
+ public:
+
+ D3D11Initializer(
+ D3D11Device* pParent);
+
+ ~D3D11Initializer();
+
+ void Flush();
+
+ void InitBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void InitTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void InitUavCounter(
+ D3D11UnorderedAccessView* pUav);
+
+ private:
+
+ dxvk::mutex m_mutex;
+
+ D3D11Device* m_parent;
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkContext> m_context;
+
+ size_t m_transferCommands = 0;
+ size_t m_transferMemory = 0;
+
+ void InitDeviceLocalBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void InitHostVisibleBuffer(
+ D3D11Buffer* pBuffer,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void InitDeviceLocalTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void InitHostVisibleTexture(
+ D3D11CommonTexture* pTexture,
+ const D3D11_SUBRESOURCE_DATA* pInitialData);
+
+ void FlushImplicit();
+ void FlushInternal();
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp
new file mode 100644
index 00000000..abf3d125
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.cpp
@@ -0,0 +1,84 @@
+#include "d3d11_device.h"
+#include "d3d11_input_layout.h"
+
+namespace dxvk {
+
+ D3D11InputLayout::D3D11InputLayout(
+ D3D11Device* pDevice,
+ uint32_t numAttributes,
+ const DxvkVertexAttribute* pAttributes,
+ uint32_t numBindings,
+ const DxvkVertexBinding* pBindings)
+ : D3D11DeviceChild<ID3D11InputLayout>(pDevice),
+ m_d3d10(this) {
+ m_attributes.resize(numAttributes);
+ m_bindings.resize(numBindings);
+
+ for (uint32_t i = 0; i < numAttributes; i++)
+ m_attributes.at(i) = pAttributes[i];
+
+ for (uint32_t i = 0; i < numBindings; i++)
+ m_bindings.at(i) = pBindings[i];
+ }
+
+
+ D3D11InputLayout::~D3D11InputLayout() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11InputLayout::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11InputLayout)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10InputLayout)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11InputLayout::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void D3D11InputLayout::BindToContext(const Rc<DxvkContext>& ctx) {
+ ctx->setInputLayout(
+ m_attributes.size(),
+ m_attributes.data(),
+ m_bindings.size(),
+ m_bindings.data());
+ }
+
+
+ bool D3D11InputLayout::Compare(const D3D11InputLayout* pOther) const {
+ bool eq = m_attributes.size() == pOther->m_attributes.size()
+ && m_bindings.size() == pOther->m_bindings.size();
+
+ for (uint32_t i = 0; eq && i < m_attributes.size(); i++) {
+ eq &= m_attributes[i].location == pOther->m_attributes[i].location
+ && m_attributes[i].binding == pOther->m_attributes[i].binding
+ && m_attributes[i].format == pOther->m_attributes[i].format
+ && m_attributes[i].offset == pOther->m_attributes[i].offset;
+ }
+
+ for (uint32_t i = 0; eq && i < m_bindings.size(); i++) {
+ eq &= m_bindings[i].binding == pOther->m_bindings[i].binding
+ && m_bindings[i].fetchRate == pOther->m_bindings[i].fetchRate
+ && m_bindings[i].inputRate == pOther->m_bindings[i].inputRate;
+ }
+
+ return eq;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h
new file mode 100644
index 00000000..8e472e2e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_input_layout.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "d3d11_device_child.h"
+
+#include "../d3d10/d3d10_input_layout.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11InputLayout : public D3D11DeviceChild<ID3D11InputLayout> {
+
+ public:
+
+ D3D11InputLayout(
+ D3D11Device* pDevice,
+ uint32_t numAttributes,
+ const DxvkVertexAttribute* pAttributes,
+ uint32_t numBindings,
+ const DxvkVertexBinding* pBindings);
+
+ ~D3D11InputLayout();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void BindToContext(
+ const Rc<DxvkContext>& ctx);
+
+ bool Compare(
+ const D3D11InputLayout* pOther) const;
+
+ D3D10InputLayout* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ private:
+
+ std::vector<DxvkVertexAttribute> m_attributes;
+ std::vector<DxvkVertexBinding> m_bindings;
+
+ D3D10InputLayout m_d3d10;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h
new file mode 100644
index 00000000..3b0629bb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interfaces.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "../dxgi/dxgi_interfaces.h"
+
+#include "d3d11_include.h"
+
+/**
+ * \brief D3D11 extension
+ *
+ * Lists D3D11 extensions supported by DXVK.
+ */
+enum D3D11_VK_EXTENSION : uint32_t {
+ D3D11_VK_EXT_MULTI_DRAW_INDIRECT = 0,
+ D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT = 1,
+ D3D11_VK_EXT_DEPTH_BOUNDS = 2,
+ D3D11_VK_EXT_BARRIER_CONTROL = 3,
+ D3D11_VK_NVX_BINARY_IMPORT = 4,
+ D3D11_VK_NVX_IMAGE_VIEW_HANDLE = 5,
+};
+
+
+/**
+ * \brief Barrier control flags
+ */
+enum D3D11_VK_BARRIER_CONTROL : uint32_t {
+ D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 1 << 0,
+ D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
+};
+
+
+/**
+ * \brief Extended D3D11 device
+ *
+ * Introduces a method to check for extension support.
+ */
+MIDL_INTERFACE("8a6e3c42-f74c-45b7-8265-a231b677ca17")
+ID3D11VkExtDevice : public IUnknown {
+ /**
+ * \brief Checks whether an extension is supported
+ *
+ * \param [in] Extension The extension to check
+ * \returns \c TRUE if the extension is supported
+ */
+ virtual BOOL STDMETHODCALLTYPE GetExtensionSupport(
+ D3D11_VK_EXTENSION Extension) = 0;
+
+};
+
+
+/**
+ * \brief Extended extended D3D11 device
+ *
+ * Introduces methods to get virtual addresses and driver
+ * handles for resources, and create and destroy objects
+ * for D3D11-Cuda interop.
+ */
+MIDL_INTERFACE("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")
+ID3D11VkExtDevice1 : public ID3D11VkExtDevice {
+
+ virtual bool STDMETHODCALLTYPE GetResourceHandleGPUVirtualAddressAndSizeNVX(
+ void* hObject,
+ uint64_t* gpuVAStart,
+ uint64_t* gpuVASize) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ ID3D11UnorderedAccessView** ppUAV,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX(
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ ID3D11ShaderResourceView** ppSRV,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX(
+ const D3D11_SAMPLER_DESC* pSamplerDesc,
+ ID3D11SamplerState** ppSamplerState,
+ uint32_t* pDriverHandle) = 0;
+
+ virtual bool STDMETHODCALLTYPE CreateCubinComputeShaderWithNameNVX(
+ const void* pCubin,
+ uint32_t size,
+ uint32_t blockX,
+ uint32_t blockY,
+ uint32_t blockZ,
+ const char* pShaderName,
+ IUnknown** phShader) = 0;
+
+ virtual bool STDMETHODCALLTYPE GetCudaTextureObjectNVX(
+ uint32_t srvDriverHandle,
+ uint32_t samplerDriverHandle,
+ uint32_t* pCudaTextureHandle) = 0;
+};
+
+
+/**
+ * \brief Extended D3D11 context
+ *
+ * Provides functionality for various D3D11
+ * extensions.
+ */
+MIDL_INTERFACE("fd0bca13-5cb6-4c3a-987e-4750de2ca791")
+ID3D11VkExtContext : public IUnknown {
+ virtual void STDMETHODCALLTYPE MultiDrawIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) = 0;
+
+ virtual void STDMETHODCALLTYPE MultiDrawIndexedIndirect(
+ UINT DrawCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) = 0;
+
+ virtual void STDMETHODCALLTYPE MultiDrawIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) = 0;
+
+ virtual void STDMETHODCALLTYPE MultiDrawIndexedIndirectCount(
+ UINT MaxDrawCount,
+ ID3D11Buffer* pBufferForCount,
+ UINT ByteOffsetForCount,
+ ID3D11Buffer* pBufferForArgs,
+ UINT ByteOffsetForArgs,
+ UINT ByteStrideForArgs) = 0;
+
+ virtual void STDMETHODCALLTYPE SetDepthBoundsTest(
+ BOOL Enable,
+ FLOAT MinDepthBounds,
+ FLOAT MaxDepthBounds) = 0;
+
+ virtual void STDMETHODCALLTYPE SetBarrierControl(
+ UINT ControlFlags) = 0;
+};
+
+
+/**
+ * \brief Extended extended D3D11 context
+ *
+ * Provides functionality to launch a Cuda kernel
+ */
+MIDL_INTERFACE("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")
+ID3D11VkExtContext1 : public ID3D11VkExtContext {
+
+ virtual bool STDMETHODCALLTYPE LaunchCubinShaderNVX(
+ IUnknown* hShader,
+ uint32_t gridX,
+ uint32_t gridY,
+ uint32_t gridZ,
+ const void* pParams,
+ uint32_t paramSize,
+ void* const* pReadResources,
+ uint32_t numReadResources,
+ void* const* pWriteResources,
+ uint32_t numWriteResources) = 0;
+};
+
+
+#ifdef _MSC_VER
+struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice;
+struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1;
+struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext;
+struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1;
+#else
+__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17);
+__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06);
+__CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91);
+__CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d);
+#endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp
new file mode 100644
index 00000000..9584b6ab
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.cpp
@@ -0,0 +1,166 @@
+#include "d3d11_context_imm.h"
+#include "d3d11_interop.h"
+#include "d3d11_device.h"
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_device.h"
+#include "../dxvk/dxvk_instance.h"
+
+namespace dxvk {
+
+ D3D11VkInterop::D3D11VkInterop(
+ IDXGIObject* pContainer,
+ D3D11Device* pDevice)
+ : m_container (pContainer),
+ m_device (pDevice) { }
+
+
+ D3D11VkInterop::~D3D11VkInterop() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VkInterop::AddRef() {
+ return m_container->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VkInterop::Release() {
+ return m_container->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VkInterop::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_container->QueryInterface(riid, ppvObject);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev,
+ VkDevice* pDevice) {
+ auto device = m_device->GetDXVKDevice();
+ auto adapter = device->adapter();
+ auto instance = device->instance();
+
+ if (pDevice != nullptr)
+ *pDevice = device->handle();
+
+ if (pPhysDev != nullptr)
+ *pPhysDev = adapter->handle();
+
+ if (pInstance != nullptr)
+ *pInstance = instance->handle();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::GetSubmissionQueue(
+ VkQueue* pQueue,
+ uint32_t* pQueueFamilyIndex) {
+ auto device = static_cast<D3D11Device*>(m_device)->GetDXVKDevice();
+ DxvkDeviceQueue queue = device->queues().graphics;
+
+ if (pQueue != nullptr)
+ *pQueue = queue.queueHandle;
+
+ if (pQueueFamilyIndex != nullptr)
+ *pQueueFamilyIndex = queue.queueFamily;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout) {
+ Com<ID3D11DeviceContext> deviceContext = nullptr;
+ m_device->GetImmediateContext(&deviceContext);
+
+ auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
+
+ immediateContext->TransitionSurfaceLayout(
+ pSurface, pSubresources, OldLayout, NewLayout);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::FlushRenderingCommands() {
+ Com<ID3D11DeviceContext> deviceContext = nullptr;
+ m_device->GetImmediateContext(&deviceContext);
+
+ auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
+ immediateContext->Flush();
+ immediateContext->SynchronizeCsThread();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::LockSubmissionQueue() {
+ m_device->GetDXVKDevice()->lockSubmission();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::ReleaseSubmissionQueue() {
+ m_device->GetDXVKDevice()->unlockSubmission();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VkInterop::GetSubmissionQueue1(
+ VkQueue* pQueue,
+ uint32_t* pQueueIndex,
+ uint32_t* pQueueFamilyIndex) {
+ auto device = static_cast<D3D11Device*>(m_device)->GetDXVKDevice();
+ DxvkDeviceQueue queue = device->queues().graphics;
+
+ if (pQueue != nullptr)
+ *pQueue = queue.queueHandle;
+
+ if (pQueueIndex != nullptr)
+ *pQueueIndex = queue.queueIndex;
+
+ if (pQueueFamilyIndex != nullptr)
+ *pQueueFamilyIndex = queue.queueFamily;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D11VkInterop::CreateTexture2DFromVkImage(
+ const D3D11_TEXTURE2D_DESC1 *pDesc,
+ VkImage vkImage,
+ ID3D11Texture2D **ppTexture2D) {
+
+ InitReturnPtr(ppTexture2D);
+
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ D3D11_COMMON_TEXTURE_DESC desc;
+ desc.Width = pDesc->Width;
+ desc.Height = pDesc->Height;
+ desc.Depth = 1;
+ desc.MipLevels = pDesc->MipLevels;
+ desc.ArraySize = pDesc->ArraySize;
+ desc.Format = pDesc->Format;
+ desc.SampleDesc = pDesc->SampleDesc;
+ desc.Usage = pDesc->Usage;
+ desc.BindFlags = pDesc->BindFlags;
+ desc.CPUAccessFlags = pDesc->CPUAccessFlags;
+ desc.MiscFlags = pDesc->MiscFlags;
+ desc.TextureLayout = pDesc->TextureLayout;
+
+ HRESULT hr = D3D11CommonTexture::NormalizeTextureProperties(&desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!ppTexture2D)
+ return S_FALSE;
+
+ try {
+ Com<D3D11Texture2D> texture = new D3D11Texture2D(m_device, &desc, 0, vkImage);
+ *ppTexture2D = texture.ref();
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h
new file mode 100644
index 00000000..48ee4c3b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_interop.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "../dxgi/dxgi_interfaces.h"
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11VkInterop : public ComObject<IDXGIVkInteropDevice1> {
+
+ public:
+
+ D3D11VkInterop(
+ IDXGIObject* pContainer,
+ D3D11Device* pDevice);
+
+ ~D3D11VkInterop();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev,
+ VkDevice* pDevice);
+
+ void STDMETHODCALLTYPE GetSubmissionQueue(
+ VkQueue* pQueue,
+ uint32_t* pQueueFamilyIndex);
+
+ void STDMETHODCALLTYPE TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout);
+
+ void STDMETHODCALLTYPE FlushRenderingCommands();
+
+ void STDMETHODCALLTYPE LockSubmissionQueue();
+
+ void STDMETHODCALLTYPE ReleaseSubmissionQueue();
+
+ void STDMETHODCALLTYPE GetSubmissionQueue1(
+ VkQueue* pQueue,
+ uint32_t* pQueueIndex,
+ uint32_t* pQueueFamilyIndex);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture2DFromVkImage(
+ const D3D11_TEXTURE2D_DESC1* pDesc,
+ VkImage vkImage,
+ ID3D11Texture2D** ppTexture2D);
+
+ private:
+
+ IDXGIObject* m_container;
+ D3D11Device* m_device;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp
new file mode 100644
index 00000000..c0be5283
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_main.cpp
@@ -0,0 +1,247 @@
+#include <array>
+
+#include "../dxgi/dxgi_adapter.h"
+
+#include "../dxvk/dxvk_instance.h"
+
+#include "d3d11_device.h"
+#include "d3d11_enums.h"
+#include "d3d11_interop.h"
+
+namespace dxvk {
+#ifndef VBOX
+ Logger Logger::s_instance("d3d11.log");
+#endif
+}
+
+extern "C" {
+ using namespace dxvk;
+
+ DLLEXPORT HRESULT __stdcall D3D11CoreCreateDevice(
+ IDXGIFactory* pFactory,
+ IDXGIAdapter* pAdapter,
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ ID3D11Device** ppDevice) {
+ InitReturnPtr(ppDevice);
+
+ Rc<DxvkAdapter> dxvkAdapter;
+ Rc<DxvkInstance> dxvkInstance;
+
+ Com<IDXGIDXVKAdapter> dxgiVkAdapter;
+
+ // Try to find the corresponding Vulkan device for the DXGI adapter
+ if (SUCCEEDED(pAdapter->QueryInterface(__uuidof(IDXGIDXVKAdapter), reinterpret_cast<void**>(&dxgiVkAdapter)))) {
+ dxvkAdapter = dxgiVkAdapter->GetDXVKAdapter();
+ dxvkInstance = dxgiVkAdapter->GetDXVKInstance();
+ } else {
+ Logger::warn("D3D11CoreCreateDevice: Adapter is not a DXVK adapter");
+ DXGI_ADAPTER_DESC desc;
+ pAdapter->GetDesc(&desc);
+
+ dxvkInstance = new DxvkInstance();
+ dxvkAdapter = dxvkInstance->findAdapterByLuid(&desc.AdapterLuid);
+
+ if (dxvkAdapter == nullptr)
+ dxvkAdapter = dxvkInstance->findAdapterByDeviceId(desc.VendorId, desc.DeviceId);
+
+ if (dxvkAdapter == nullptr)
+ dxvkAdapter = dxvkInstance->enumAdapters(0);
+
+ if (dxvkAdapter == nullptr)
+ return E_FAIL;
+ }
+
+ // Feature levels to probe if the
+ // application does not specify any.
+ std::array<D3D_FEATURE_LEVEL, 6> defaultFeatureLevels = {
+ D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1,
+ };
+
+ if (pFeatureLevels == nullptr || FeatureLevels == 0) {
+ pFeatureLevels = defaultFeatureLevels.data();
+ FeatureLevels = defaultFeatureLevels.size();
+ }
+
+ // Find the highest feature level supported by the device.
+ // This works because the feature level array is ordered.
+ UINT flId;
+
+ for (flId = 0 ; flId < FeatureLevels; flId++) {
+ Logger::info(str::format("D3D11CoreCreateDevice: Probing ", pFeatureLevels[flId]));
+
+ if (D3D11Device::CheckFeatureLevelSupport(dxvkInstance, dxvkAdapter, pFeatureLevels[flId]))
+ break;
+ }
+
+ if (flId == FeatureLevels) {
+ Logger::err("D3D11CoreCreateDevice: Requested feature level not supported");
+ return E_INVALIDARG;
+ }
+
+ // Try to create the device with the given parameters.
+ const D3D_FEATURE_LEVEL fl = pFeatureLevels[flId];
+
+ try {
+ Logger::info(str::format("D3D11CoreCreateDevice: Using feature level ", fl));
+ Com<D3D11DXGIDevice> device = new D3D11DXGIDevice(
+ pAdapter, dxvkInstance, dxvkAdapter, fl, Flags);
+
+ return device->QueryInterface(
+ __uuidof(ID3D11Device),
+ reinterpret_cast<void**>(ppDevice));
+ } catch (const DxvkError& e) {
+ Logger::err("D3D11CoreCreateDevice: Failed to create D3D11 device");
+ return E_FAIL;
+ }
+ }
+
+
+ static HRESULT D3D11InternalCreateDeviceAndSwapChain(
+ IDXGIAdapter* pAdapter,
+ D3D_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
+ IDXGISwapChain** ppSwapChain,
+ ID3D11Device** ppDevice,
+ D3D_FEATURE_LEVEL* pFeatureLevel,
+ ID3D11DeviceContext** ppImmediateContext) {
+ InitReturnPtr(ppDevice);
+ InitReturnPtr(ppSwapChain);
+ InitReturnPtr(ppImmediateContext);
+
+ if (pFeatureLevel)
+ *pFeatureLevel = D3D_FEATURE_LEVEL(0);
+
+ HRESULT hr;
+
+ Com<IDXGIFactory> dxgiFactory = nullptr;
+ Com<IDXGIAdapter> dxgiAdapter = pAdapter;
+ Com<ID3D11Device> device = nullptr;
+
+ if (ppSwapChain && !pSwapChainDesc)
+ return E_INVALIDARG;
+
+ if (!pAdapter) {
+ // We'll treat everything as hardware, even if the
+ // Vulkan device is actually a software device.
+ if (DriverType != D3D_DRIVER_TYPE_HARDWARE)
+ Logger::warn("D3D11CreateDevice: Unsupported driver type");
+
+ // We'll use the first adapter returned by a DXGI factory
+ hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory));
+
+ if (FAILED(hr)) {
+ Logger::err("D3D11CreateDevice: Failed to create a DXGI factory");
+ return hr;
+ }
+
+ hr = dxgiFactory->EnumAdapters(0, &dxgiAdapter);
+
+ if (FAILED(hr)) {
+ Logger::err("D3D11CreateDevice: No default adapter available");
+ return hr;
+ }
+ } else {
+ // We should be able to query the DXGI factory from the adapter
+ if (FAILED(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory)))) {
+ Logger::err("D3D11CreateDevice: Failed to query DXGI factory from DXGI adapter");
+ return E_INVALIDARG;
+ }
+
+ // In theory we could ignore these, but the Microsoft docs explicitly
+ // state that we need to return E_INVALIDARG in case the arguments are
+ // invalid. Both the driver type and software parameter can only be
+ // set if the adapter itself is unspecified.
+ // See: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476082(v=vs.85).aspx
+ if (DriverType != D3D_DRIVER_TYPE_UNKNOWN || Software)
+ return E_INVALIDARG;
+ }
+
+ // Create the actual device
+ hr = D3D11CoreCreateDevice(
+ dxgiFactory.ptr(), dxgiAdapter.ptr(),
+ Flags, pFeatureLevels, FeatureLevels,
+ &device);
+
+ if (FAILED(hr))
+ return hr;
+
+ // Create the swap chain, if requested
+ if (ppSwapChain) {
+ DXGI_SWAP_CHAIN_DESC desc = *pSwapChainDesc;
+ hr = dxgiFactory->CreateSwapChain(device.ptr(), &desc, ppSwapChain);
+
+ if (FAILED(hr)) {
+ Logger::err("D3D11CreateDevice: Failed to create swap chain");
+ return hr;
+ }
+ }
+
+ // Write back whatever info the application requested
+ if (pFeatureLevel)
+ *pFeatureLevel = device->GetFeatureLevel();
+
+ if (ppDevice)
+ *ppDevice = device.ref();
+
+ if (ppImmediateContext)
+ device->GetImmediateContext(ppImmediateContext);
+
+ // If we were unable to write back the device and the
+ // swap chain, the application has no way of working
+ // with the device so we should report S_FALSE here.
+ if (!ppDevice && !ppImmediateContext && !ppSwapChain)
+ return S_FALSE;
+
+ return S_OK;
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D11CreateDevice(
+ IDXGIAdapter* pAdapter,
+ D3D_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ ID3D11Device** ppDevice,
+ D3D_FEATURE_LEVEL* pFeatureLevel,
+ ID3D11DeviceContext** ppImmediateContext) {
+ return D3D11InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ pFeatureLevels, FeatureLevels, SDKVersion,
+ nullptr, nullptr,
+ ppDevice, pFeatureLevel, ppImmediateContext);
+ }
+
+
+ DLLEXPORT HRESULT __stdcall D3D11CreateDeviceAndSwapChain(
+ IDXGIAdapter* pAdapter,
+ D3D_DRIVER_TYPE DriverType,
+ HMODULE Software,
+ UINT Flags,
+ const D3D_FEATURE_LEVEL* pFeatureLevels,
+ UINT FeatureLevels,
+ UINT SDKVersion,
+ const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc,
+ IDXGISwapChain** ppSwapChain,
+ ID3D11Device** ppDevice,
+ D3D_FEATURE_LEVEL* pFeatureLevel,
+ ID3D11DeviceContext** ppImmediateContext) {
+ return D3D11InternalCreateDeviceAndSwapChain(
+ pAdapter, DriverType, Software, Flags,
+ pFeatureLevels, FeatureLevels, SDKVersion,
+ pSwapChainDesc, ppSwapChain,
+ ppDevice, pFeatureLevel, ppImmediateContext);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp
new file mode 100644
index 00000000..3bef2365
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.cpp
@@ -0,0 +1,44 @@
+#include <unordered_map>
+
+#include "d3d11_options.h"
+
+namespace dxvk {
+
+ D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) {
+ const DxvkDeviceInfo& devInfo = device->properties();
+
+ this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
+ this->enableRtOutputNanFixup = config.getOption<bool>("d3d11.enableRtOutputNanFixup", false);
+ this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
+ this->forceTgsmBarriers = config.getOption<bool>("d3d11.forceTgsmBarriers", false);
+ this->relaxedBarriers = config.getOption<bool>("d3d11.relaxedBarriers", false);
+ this->ignoreGraphicsBarriers = config.getOption<bool>("d3d11.ignoreGraphicsBarriers", false);
+ this->maxTessFactor = config.getOption<int32_t>("d3d11.maxTessFactor", 0);
+ this->samplerAnisotropy = config.getOption<int32_t>("d3d11.samplerAnisotropy", -1);
+ this->invariantPosition = config.getOption<bool>("d3d11.invariantPosition", true);
+ this->floatControls = config.getOption<bool>("d3d11.floatControls", true);
+ this->disableMsaa = config.getOption<bool>("d3d11.disableMsaa", false);
+ this->deferSurfaceCreation = config.getOption<bool>("dxgi.deferSurfaceCreation", false);
+ this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
+ this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
+ this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
+ this->syncInterval = config.getOption<int32_t>("dxgi.syncInterval", -1);
+ this->tearFree = config.getOption<Tristate>("dxgi.tearFree", Tristate::Auto);
+
+ this->constantBufferRangeCheck = config.getOption<bool>("d3d11.constantBufferRangeCheck", false)
+ && DxvkGpuVendor(devInfo.core.properties.vendorID) != DxvkGpuVendor::Amd;
+
+ bool apitraceAttached = false;
+ #if !defined(DXVK_NATIVE)
+ apitraceAttached = ::GetModuleHandle("dxgitrace.dll") != nullptr;
+ #endif
+
+ this->apitraceMode = config.getOption<bool>("d3d11.apitraceMode", apitraceAttached);
+
+ // Inform user in case they have the option enabled or a game
+ // ships a file called dxgitrace.dll for whatever reason.
+ if (this->apitraceMode)
+ Logger::warn("D3D11: Apitrace mode enabled, may affect performance!");
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h
new file mode 100644
index 00000000..40a76aca
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_options.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "../util/config/config.h"
+
+#include "../dxgi/dxgi_options.h"
+
+#include "../dxvk/dxvk_device.h"
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ struct D3D11Options {
+ D3D11Options(const Config& config, const Rc<DxvkDevice>& device);
+
+ /// Enables speed hack for mapping on deferred contexts
+ ///
+ /// This can substantially speed up some games, but may
+ /// cause issues if the game submits command lists more
+ /// than once.
+ bool dcSingleUseMode;
+
+ /// Enables workaround to replace NaN render target
+ /// outputs with zero
+ bool enableRtOutputNanFixup;
+
+ /// Enables out-of-bounds access check for constant
+ /// buffers. Workaround for a few broken games that
+ /// access random data inside their shaders.
+ bool constantBufferRangeCheck;
+
+ /// Zero-initialize workgroup memory
+ ///
+ /// Workargound for games that don't initialize
+ /// TGSM in compute shaders before reading it.
+ bool zeroInitWorkgroupMemory;
+
+ /// Force thread-group shared memory barriers
+ ///
+ /// Workaround for compute shaders that read and
+ /// write from the same shared memory location
+ /// without explicit synchronization.
+ bool forceTgsmBarriers;
+
+ /// Use relaxed memory barriers
+ ///
+ /// May improve performance in some games,
+ /// but might also cause rendering issues.
+ bool relaxedBarriers;
+
+ /// Ignore graphics barriers
+ ///
+ /// May improve performance in some games,
+ /// but might also cause rendering issues.
+ bool ignoreGraphicsBarriers;
+
+ /// Maximum tessellation factor.
+ ///
+ /// Limits tessellation factors in tessellation
+ /// control shaders. Values from 8 to 64 are
+ /// supported, other values will be ignored.
+ int32_t maxTessFactor;
+
+ /// Anisotropic filter override
+ ///
+ /// Enforces anisotropic filtering with the
+ /// given anisotropy value for all samplers.
+ int32_t samplerAnisotropy;
+
+ /// Declare vertex positions in shaders as invariant
+ bool invariantPosition;
+
+ /// Enable float control bits
+ bool floatControls;
+
+ /// Back buffer count for the Vulkan swap chain.
+ /// Overrides DXGI_SWAP_CHAIN_DESC::BufferCount.
+ int32_t numBackBuffers;
+
+ /// Sync interval. Overrides the value
+ /// passed to IDXGISwapChain::Present.
+ int32_t syncInterval;
+
+ /// Tear-free mode if vsync is disabled
+ /// Tearing mode if vsync is enabled
+ Tristate tearFree;
+
+ /// Override maximum frame latency if the app specifies
+ /// a higher value. May help with frame timing issues.
+ int32_t maxFrameLatency;
+
+ /// Limit frame rate
+ int32_t maxFrameRate;
+
+ /// Defer surface creation until first present call. This
+ /// fixes issues with games that create multiple swap chains
+ /// for a single window that may interfere with each other.
+ bool deferSurfaceCreation;
+
+ /// Forces the sample count of all textures to be 1, and
+ /// performs the required shader and resolve fixups.
+ bool disableMsaa;
+
+ /// Apitrace mode: Maps all buffers in cached memory.
+ /// Enabled automatically if dxgitrace.dll is attached.
+ bool apitraceMode;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp
new file mode 100644
index 00000000..b7145739
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.cpp
@@ -0,0 +1,352 @@
+#include "d3d11_device.h"
+#include "d3d11_query.h"
+
+namespace dxvk {
+
+ D3D11Query::D3D11Query(
+ D3D11Device* device,
+ const D3D11_QUERY_DESC1& desc)
+ : D3D11DeviceChild<ID3D11Query1>(device),
+ m_desc(desc),
+ m_state(D3D11_VK_QUERY_INITIAL),
+ m_d3d10(this) {
+ Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice();
+
+ switch (m_desc.Query) {
+ case D3D11_QUERY_EVENT:
+ m_event[0] = dxvkDevice->createGpuEvent();
+ break;
+
+ case D3D11_QUERY_OCCLUSION:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_OCCLUSION,
+ VK_QUERY_CONTROL_PRECISE_BIT, 0);
+ break;
+
+ case D3D11_QUERY_OCCLUSION_PREDICATE:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_OCCLUSION, 0, 0);
+ break;
+
+ case D3D11_QUERY_TIMESTAMP:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TIMESTAMP, 0, 0);
+ break;
+
+ case D3D11_QUERY_TIMESTAMP_DISJOINT:
+ for (uint32_t i = 0; i < 2; i++) {
+ m_query[i] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TIMESTAMP, 0, 0);
+ }
+ break;
+
+ case D3D11_QUERY_PIPELINE_STATISTICS:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
+ break;
+
+ case D3D11_QUERY_SO_STATISTICS:
+ case D3D11_QUERY_SO_STATISTICS_STREAM0:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
+ // FIXME it is technically incorrect to map
+ // SO_OVERFLOW_PREDICATE to the first stream,
+ // but this is good enough for D3D10 behaviour
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 0);
+ break;
+
+ case D3D11_QUERY_SO_STATISTICS_STREAM1:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 1);
+ break;
+
+ case D3D11_QUERY_SO_STATISTICS_STREAM2:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 2);
+ break;
+
+ case D3D11_QUERY_SO_STATISTICS_STREAM3:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 3);
+ break;
+
+ default:
+ throw DxvkError(str::format("D3D11: Unhandled query type: ", desc.Query));
+ }
+ }
+
+
+ D3D11Query::~D3D11Query() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Query::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11Asynchronous)
+ || riid == __uuidof(ID3D11Query)
+ || riid == __uuidof(ID3D11Query1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10Asynchronous)
+ || riid == __uuidof(ID3D10Query)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ if (m_desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE) {
+ if (riid == __uuidof(ID3D11Predicate)) {
+ *ppvObject = AsPredicate(ref(this));
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10Predicate)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+ }
+
+ Logger::warn("D3D11Query: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Query::GetDataSize() {
+ switch (m_desc.Query) {
+ case D3D11_QUERY_EVENT:
+ return sizeof(BOOL);
+
+ case D3D11_QUERY_OCCLUSION:
+ return sizeof(UINT64);
+
+ case D3D11_QUERY_TIMESTAMP:
+ return sizeof(UINT64);
+
+ case D3D11_QUERY_TIMESTAMP_DISJOINT:
+ return sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT);
+
+ case D3D11_QUERY_PIPELINE_STATISTICS:
+ return sizeof(D3D11_QUERY_DATA_PIPELINE_STATISTICS);
+
+ case D3D11_QUERY_OCCLUSION_PREDICATE:
+ return sizeof(BOOL);
+
+ case D3D11_QUERY_SO_STATISTICS:
+ case D3D11_QUERY_SO_STATISTICS_STREAM0:
+ case D3D11_QUERY_SO_STATISTICS_STREAM1:
+ case D3D11_QUERY_SO_STATISTICS_STREAM2:
+ case D3D11_QUERY_SO_STATISTICS_STREAM3:
+ return sizeof(D3D11_QUERY_DATA_SO_STATISTICS);
+
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3:
+ return sizeof(BOOL);
+ }
+
+ Logger::err("D3D11Query: Failed to query data size");
+ return 0;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Query::GetDesc(D3D11_QUERY_DESC* pDesc) {
+ pDesc->Query = m_desc.Query;
+ pDesc->MiscFlags = m_desc.MiscFlags;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Query::GetDesc1(D3D11_QUERY_DESC1* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ void D3D11Query::Begin(DxvkContext* ctx) {
+ switch (m_desc.Query) {
+ case D3D11_QUERY_EVENT:
+ case D3D11_QUERY_TIMESTAMP:
+ break;
+
+ case D3D11_QUERY_TIMESTAMP_DISJOINT:
+ ctx->writeTimestamp(m_query[1]);
+ break;
+
+ default:
+ ctx->beginQuery(m_query[0]);
+ }
+ }
+
+
+ void D3D11Query::End(DxvkContext* ctx) {
+ switch (m_desc.Query) {
+ case D3D11_QUERY_EVENT:
+ ctx->signalGpuEvent(m_event[0]);
+ break;
+
+ case D3D11_QUERY_TIMESTAMP:
+ case D3D11_QUERY_TIMESTAMP_DISJOINT:
+ ctx->writeTimestamp(m_query[0]);
+ break;
+
+ default:
+ ctx->endQuery(m_query[0]);
+ }
+
+ m_resetCtr.fetch_sub(1, std::memory_order_release);
+ }
+
+
+ bool STDMETHODCALLTYPE D3D11Query::DoBegin() {
+ if (!IsScoped() || m_state == D3D11_VK_QUERY_BEGUN)
+ return false;
+
+ m_state = D3D11_VK_QUERY_BEGUN;
+ return true;
+ }
+
+ bool STDMETHODCALLTYPE D3D11Query::DoEnd() {
+ // Apparently the D3D11 runtime implicitly begins the query
+ // if it is in the wrong state at the time End is called, so
+ // let the caller react to it instead of just failing here.
+ bool result = m_state == D3D11_VK_QUERY_BEGUN || !IsScoped();
+
+ m_state = D3D11_VK_QUERY_ENDED;
+ m_resetCtr.fetch_add(1, std::memory_order_acquire);
+ return result;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Query::GetData(
+ void* pData,
+ UINT GetDataFlags) {
+ if (m_state != D3D11_VK_QUERY_ENDED)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (m_resetCtr != 0u)
+ return S_FALSE;
+
+ if (m_desc.Query == D3D11_QUERY_EVENT) {
+ DxvkGpuEventStatus status = m_event[0]->test();
+
+ if (status == DxvkGpuEventStatus::Invalid)
+ return DXGI_ERROR_INVALID_CALL;
+
+ bool signaled = status == DxvkGpuEventStatus::Signaled;
+
+ if (pData != nullptr)
+ *static_cast<BOOL*>(pData) = signaled;
+
+ return signaled ? S_OK : S_FALSE;
+ } else {
+ std::array<DxvkQueryData, MaxGpuQueries> queryData = { };
+
+ for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) {
+ DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]);
+
+ if (status == DxvkGpuQueryStatus::Invalid
+ || status == DxvkGpuQueryStatus::Failed)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (status == DxvkGpuQueryStatus::Pending)
+ return S_FALSE;
+ }
+
+ if (pData == nullptr)
+ return S_OK;
+
+ switch (m_desc.Query) {
+ case D3D11_QUERY_OCCLUSION:
+ *static_cast<UINT64*>(pData) = queryData[0].occlusion.samplesPassed;
+ return S_OK;
+
+ case D3D11_QUERY_OCCLUSION_PREDICATE:
+ *static_cast<BOOL*>(pData) = queryData[0].occlusion.samplesPassed != 0;
+ return S_OK;
+
+ case D3D11_QUERY_TIMESTAMP:
+ *static_cast<UINT64*>(pData) = queryData[0].timestamp.time;
+ return S_OK;
+
+ case D3D11_QUERY_TIMESTAMP_DISJOINT: {
+ auto data = static_cast<D3D11_QUERY_DATA_TIMESTAMP_DISJOINT*>(pData);
+ data->Frequency = GetTimestampQueryFrequency();
+ data->Disjoint = queryData[0].timestamp.time < queryData[1].timestamp.time;
+ } return S_OK;
+
+ case D3D11_QUERY_PIPELINE_STATISTICS: {
+ auto data = static_cast<D3D11_QUERY_DATA_PIPELINE_STATISTICS*>(pData);
+ data->IAVertices = queryData[0].statistic.iaVertices;
+ data->IAPrimitives = queryData[0].statistic.iaPrimitives;
+ data->VSInvocations = queryData[0].statistic.vsInvocations;
+ data->GSInvocations = queryData[0].statistic.gsInvocations;
+ data->GSPrimitives = queryData[0].statistic.gsPrimitives;
+ data->CInvocations = queryData[0].statistic.clipInvocations;
+ data->CPrimitives = queryData[0].statistic.clipPrimitives;
+ data->PSInvocations = queryData[0].statistic.fsInvocations;
+ data->HSInvocations = queryData[0].statistic.tcsPatches;
+ data->DSInvocations = queryData[0].statistic.tesInvocations;
+ data->CSInvocations = queryData[0].statistic.csInvocations;
+ } return S_OK;
+
+ case D3D11_QUERY_SO_STATISTICS:
+ case D3D11_QUERY_SO_STATISTICS_STREAM0:
+ case D3D11_QUERY_SO_STATISTICS_STREAM1:
+ case D3D11_QUERY_SO_STATISTICS_STREAM2:
+ case D3D11_QUERY_SO_STATISTICS_STREAM3: {
+ auto data = static_cast<D3D11_QUERY_DATA_SO_STATISTICS*>(pData);
+ data->NumPrimitivesWritten = queryData[0].xfbStream.primitivesWritten;
+ data->PrimitivesStorageNeeded = queryData[0].xfbStream.primitivesNeeded;
+ } return S_OK;
+
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
+ case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3: {
+ auto data = static_cast<BOOL*>(pData);
+ *data = queryData[0].xfbStream.primitivesNeeded
+ > queryData[0].xfbStream.primitivesWritten;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format("D3D11: Unhandled query type in GetData: ", m_desc.Query));
+ return E_INVALIDARG;
+ }
+ }
+ }
+
+
+ UINT64 D3D11Query::GetTimestampQueryFrequency() const {
+ Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
+ Rc<DxvkAdapter> adapter = device->adapter();
+
+ VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits;
+ return uint64_t(1'000'000'000.0f / limits.timestampPeriod);
+ }
+
+
+ HRESULT D3D11Query::ValidateDesc(const D3D11_QUERY_DESC1* pDesc) {
+ if (pDesc->Query >= D3D11_QUERY_PIPELINE_STATISTICS
+ && pDesc->ContextType > D3D11_CONTEXT_TYPE_3D)
+ return E_INVALIDARG;
+
+ return S_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h
new file mode 100644
index 00000000..06ac4a1a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_query.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include "../dxvk/dxvk_gpu_event.h"
+#include "../dxvk/dxvk_gpu_query.h"
+
+#include "../d3d10/d3d10_query.h"
+
+#include "d3d11_device_child.h"
+
+namespace dxvk {
+
+ enum D3D11_VK_QUERY_STATE : uint32_t {
+ D3D11_VK_QUERY_INITIAL,
+ D3D11_VK_QUERY_BEGUN,
+ D3D11_VK_QUERY_ENDED,
+ };
+
+ class D3D11Query : public D3D11DeviceChild<ID3D11Query1> {
+ constexpr static uint32_t MaxGpuQueries = 2;
+ constexpr static uint32_t MaxGpuEvents = 1;
+ public:
+
+ D3D11Query(
+ D3D11Device* device,
+ const D3D11_QUERY_DESC1& desc);
+
+ ~D3D11Query();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ UINT STDMETHODCALLTYPE GetDataSize();
+
+ void STDMETHODCALLTYPE GetDesc(D3D11_QUERY_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(D3D11_QUERY_DESC1* pDesc) final;
+
+ void Begin(DxvkContext* ctx);
+
+ void End(DxvkContext* ctx);
+
+ bool STDMETHODCALLTYPE DoBegin();
+
+ bool STDMETHODCALLTYPE DoEnd();
+
+ HRESULT STDMETHODCALLTYPE GetData(
+ void* pData,
+ UINT GetDataFlags);
+
+ void DoDeferredEnd() {
+ m_state = D3D11_VK_QUERY_ENDED;
+ m_resetCtr.fetch_add(1, std::memory_order_acquire);
+ }
+
+ bool IsScoped() const {
+ return m_desc.Query != D3D11_QUERY_EVENT
+ && m_desc.Query != D3D11_QUERY_TIMESTAMP;
+ }
+
+ bool IsEvent() const {
+ return m_desc.Query == D3D11_QUERY_EVENT;
+ }
+
+ bool IsStalling() const {
+ return m_stallFlag;
+ }
+
+ void NotifyEnd() {
+ m_stallMask <<= 1;
+ }
+
+ void NotifyStall() {
+ m_stallMask |= 1;
+ m_stallFlag |= bit::popcnt(m_stallMask) >= 16;
+ }
+
+ D3D10Query* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT ValidateDesc(const D3D11_QUERY_DESC1* pDesc);
+
+ static ID3D11Predicate* AsPredicate(ID3D11Query* pQuery) {
+ // ID3D11Predicate and ID3D11Query have the same vtable. This
+ // saves us some headache in all query-related functions.
+ return static_cast<ID3D11Predicate*>(pQuery);
+ }
+
+ static D3D11Query* FromPredicate(ID3D11Predicate* pPredicate) {
+ return static_cast<D3D11Query*>(static_cast<ID3D11Query*>(pPredicate));
+ }
+
+ private:
+
+ D3D11_QUERY_DESC1 m_desc;
+
+ D3D11_VK_QUERY_STATE m_state;
+
+ std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
+ std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
+
+ D3D10Query m_d3d10;
+
+ uint32_t m_stallMask = 0;
+ bool m_stallFlag = false;
+
+ std::atomic<uint32_t> m_resetCtr = { 0u };
+
+ UINT64 GetTimestampQueryFrequency() const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp
new file mode 100644
index 00000000..6d70847e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.cpp
@@ -0,0 +1,195 @@
+#include "d3d11_device.h"
+#include "d3d11_rasterizer.h"
+
+namespace dxvk {
+
+ D3D11RasterizerState::D3D11RasterizerState(
+ D3D11Device* device,
+ const D3D11_RASTERIZER_DESC2& desc)
+ : D3D11StateObject<ID3D11RasterizerState2>(device),
+ m_desc(desc), m_d3d10(this) {
+ // Polygon mode. Determines whether the rasterizer fills
+ // a polygon or renders lines connecting the vertices.
+ switch (desc.FillMode) {
+ default:
+ case D3D11_FILL_SOLID: m_state.polygonMode = VK_POLYGON_MODE_FILL; break;
+ case D3D11_FILL_WIREFRAME: m_state.polygonMode = VK_POLYGON_MODE_LINE; break;
+ }
+
+ // Face culling properties. The rasterizer may discard
+ // polygons that are facing towards or away from the
+ // viewer, depending on the options below.
+ switch (desc.CullMode) {
+ default:
+ case D3D11_CULL_NONE: m_state.cullMode = VK_CULL_MODE_NONE; break;
+ case D3D11_CULL_FRONT: m_state.cullMode = VK_CULL_MODE_FRONT_BIT; break;
+ case D3D11_CULL_BACK: m_state.cullMode = VK_CULL_MODE_BACK_BIT; break;
+ }
+
+ m_state.frontFace = desc.FrontCounterClockwise
+ ? VK_FRONT_FACE_COUNTER_CLOCKWISE
+ : VK_FRONT_FACE_CLOCKWISE;
+
+ // In the backend we treat depth bias as a dynamic state because
+ // some games like to put random/uninitialized numbers here, but
+ // we do not need to enable it in case the parameters are both 0.
+ m_state.depthBiasEnable = desc.DepthBias != 0 || desc.SlopeScaledDepthBias != 0.0f;
+ m_state.depthClipEnable = desc.DepthClipEnable;
+ m_state.conservativeMode = DecodeConservativeRasterizationMode(desc.ConservativeRaster);
+ m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount);
+
+ m_depthBias.depthBiasConstant = float(desc.DepthBias);
+ m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias;
+ m_depthBias.depthBiasClamp = desc.DepthBiasClamp;
+
+ if (desc.AntialiasedLineEnable)
+ Logger::err("D3D11RasterizerState: Antialiased lines not supported");
+ }
+
+
+ D3D11RasterizerState::~D3D11RasterizerState() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11RasterizerState::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11RasterizerState)
+ || riid == __uuidof(ID3D11RasterizerState1)
+ || riid == __uuidof(ID3D11RasterizerState2)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10RasterizerState)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc(D3D11_RASTERIZER_DESC* pDesc) {
+ pDesc->FillMode = m_desc.FillMode;
+ pDesc->CullMode = m_desc.CullMode;
+ pDesc->FrontCounterClockwise = m_desc.FrontCounterClockwise;
+ pDesc->DepthBias = m_desc.DepthBias;
+ pDesc->DepthBiasClamp = m_desc.DepthBiasClamp;
+ pDesc->SlopeScaledDepthBias = m_desc.SlopeScaledDepthBias;
+ pDesc->DepthClipEnable = m_desc.DepthClipEnable;
+ pDesc->ScissorEnable = m_desc.ScissorEnable;
+ pDesc->MultisampleEnable = m_desc.MultisampleEnable;
+ pDesc->AntialiasedLineEnable = m_desc.AntialiasedLineEnable;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc1(D3D11_RASTERIZER_DESC1* pDesc) {
+ pDesc->FillMode = m_desc.FillMode;
+ pDesc->CullMode = m_desc.CullMode;
+ pDesc->FrontCounterClockwise = m_desc.FrontCounterClockwise;
+ pDesc->DepthBias = m_desc.DepthBias;
+ pDesc->DepthBiasClamp = m_desc.DepthBiasClamp;
+ pDesc->SlopeScaledDepthBias = m_desc.SlopeScaledDepthBias;
+ pDesc->DepthClipEnable = m_desc.DepthClipEnable;
+ pDesc->ScissorEnable = m_desc.ScissorEnable;
+ pDesc->MultisampleEnable = m_desc.MultisampleEnable;
+ pDesc->AntialiasedLineEnable = m_desc.AntialiasedLineEnable;
+ pDesc->ForcedSampleCount = m_desc.ForcedSampleCount;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RasterizerState::GetDesc2(D3D11_RASTERIZER_DESC2* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ void D3D11RasterizerState::BindToContext(const Rc<DxvkContext>& ctx) {
+ ctx->setRasterizerState(m_state);
+
+ if (m_state.depthBiasEnable)
+ ctx->setDepthBias(m_depthBias);
+ }
+
+
+ D3D11_RASTERIZER_DESC2 D3D11RasterizerState::PromoteDesc(
+ const D3D11_RASTERIZER_DESC* pSrcDesc) {
+ D3D11_RASTERIZER_DESC2 dstDesc;
+ dstDesc.FillMode = pSrcDesc->FillMode;
+ dstDesc.CullMode = pSrcDesc->CullMode;
+ dstDesc.FrontCounterClockwise = pSrcDesc->FrontCounterClockwise;
+ dstDesc.DepthBias = pSrcDesc->DepthBias;
+ dstDesc.DepthBiasClamp = pSrcDesc->DepthBiasClamp;
+ dstDesc.SlopeScaledDepthBias = pSrcDesc->SlopeScaledDepthBias;
+ dstDesc.DepthClipEnable = pSrcDesc->DepthClipEnable;
+ dstDesc.ScissorEnable = pSrcDesc->ScissorEnable;
+ dstDesc.MultisampleEnable = pSrcDesc->MultisampleEnable;
+ dstDesc.AntialiasedLineEnable = pSrcDesc->AntialiasedLineEnable;
+ dstDesc.ForcedSampleCount = 0;
+ dstDesc.ConservativeRaster = D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ return dstDesc;
+ }
+
+
+ D3D11_RASTERIZER_DESC2 D3D11RasterizerState::PromoteDesc(
+ const D3D11_RASTERIZER_DESC1* pSrcDesc) {
+ D3D11_RASTERIZER_DESC2 dstDesc;
+ dstDesc.FillMode = pSrcDesc->FillMode;
+ dstDesc.CullMode = pSrcDesc->CullMode;
+ dstDesc.FrontCounterClockwise = pSrcDesc->FrontCounterClockwise;
+ dstDesc.DepthBias = pSrcDesc->DepthBias;
+ dstDesc.DepthBiasClamp = pSrcDesc->DepthBiasClamp;
+ dstDesc.SlopeScaledDepthBias = pSrcDesc->SlopeScaledDepthBias;
+ dstDesc.DepthClipEnable = pSrcDesc->DepthClipEnable;
+ dstDesc.ScissorEnable = pSrcDesc->ScissorEnable;
+ dstDesc.MultisampleEnable = pSrcDesc->MultisampleEnable;
+ dstDesc.AntialiasedLineEnable = pSrcDesc->AntialiasedLineEnable;
+ dstDesc.ForcedSampleCount = 0;
+ dstDesc.ConservativeRaster = D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ return dstDesc;
+ }
+
+
+ HRESULT D3D11RasterizerState::NormalizeDesc(
+ D3D11_RASTERIZER_DESC2* pDesc) {
+ if (pDesc->FillMode < D3D11_FILL_WIREFRAME
+ || pDesc->FillMode > D3D11_FILL_SOLID)
+ return E_INVALIDARG;
+
+ if (pDesc->CullMode < D3D11_CULL_NONE
+ || pDesc->CullMode > D3D11_CULL_BACK)
+ return E_INVALIDARG;
+
+ if (pDesc->FrontCounterClockwise)
+ pDesc->FrontCounterClockwise = TRUE;
+
+ if (pDesc->DepthClipEnable)
+ pDesc->DepthClipEnable = TRUE;
+
+ if (pDesc->ScissorEnable)
+ pDesc->ScissorEnable = TRUE;
+
+ if (pDesc->MultisampleEnable)
+ pDesc->MultisampleEnable = TRUE;
+
+ if (pDesc->AntialiasedLineEnable)
+ pDesc->AntialiasedLineEnable = TRUE;
+
+ if (pDesc->ForcedSampleCount != 0) {
+ if (FAILED(DecodeSampleCount(pDesc->ForcedSampleCount, nullptr)))
+ return E_INVALIDARG;
+ }
+
+ return S_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h
new file mode 100644
index 00000000..7b542f2c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_rasterizer.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_rasterizer.h"
+
+#include "d3d11_device_child.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11RasterizerState : public D3D11StateObject<ID3D11RasterizerState2> {
+
+ public:
+
+ using DescType = D3D11_RASTERIZER_DESC2;
+
+ D3D11RasterizerState(
+ D3D11Device* device,
+ const D3D11_RASTERIZER_DESC2& desc);
+ ~D3D11RasterizerState();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_RASTERIZER_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D11_RASTERIZER_DESC1* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc2(
+ D3D11_RASTERIZER_DESC2* pDesc) final;
+
+ const D3D11_RASTERIZER_DESC2* Desc() const {
+ return &m_desc;
+ }
+
+ void BindToContext(
+ const Rc<DxvkContext>& ctx);
+
+ D3D10RasterizerState* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static D3D11_RASTERIZER_DESC2 PromoteDesc(
+ const D3D11_RASTERIZER_DESC* pDesc);
+
+ static D3D11_RASTERIZER_DESC2 PromoteDesc(
+ const D3D11_RASTERIZER_DESC1* pDesc);
+
+ static HRESULT NormalizeDesc(
+ D3D11_RASTERIZER_DESC2* pDesc);
+
+ private:
+
+ D3D11_RASTERIZER_DESC2 m_desc;
+ DxvkRasterizerState m_state;
+ DxvkDepthBias m_depthBias;
+ D3D10RasterizerState m_d3d10;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp
new file mode 100644
index 00000000..7ba71367
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.cpp
@@ -0,0 +1,228 @@
+#include "d3d11_buffer.h"
+#include "d3d11_texture.h"
+#include "d3d11_resource.h"
+
+namespace dxvk {
+
+ D3D11DXGIResource::D3D11DXGIResource(
+ ID3D11Resource* pResource)
+ : m_resource(pResource) {
+
+ }
+
+
+ D3D11DXGIResource::~D3D11DXGIResource() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DXGIResource::AddRef() {
+ return m_resource->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DXGIResource::Release() {
+ return m_resource->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_resource->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData) {
+ return m_resource->GetPrivateData(Name, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) {
+ return m_resource->SetPrivateData(Name, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown) {
+ return m_resource->SetPrivateDataInterface(Name, pUnknown);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetParent(
+ REFIID riid,
+ void** ppParent) {
+ return GetDevice(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetDevice(
+ REFIID riid,
+ void** ppDevice) {
+ Com<ID3D11Device> device;
+ m_resource->GetDevice(&device);
+ return device->QueryInterface(riid, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetEvictionPriority(
+ UINT* pEvictionPriority) {
+ *pEvictionPriority = m_resource->GetEvictionPriority();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetSharedHandle(
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(pSharedHandle);
+ Logger::err("D3D11DXGIResource::GetSharedHandle: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::GetUsage(
+ DXGI_USAGE* pUsage) {
+ D3D11_COMMON_RESOURCE_DESC desc;
+
+ HRESULT hr = GetCommonResourceDesc(m_resource, &desc);
+
+ if (FAILED(hr))
+ return hr;
+
+ DXGI_USAGE usage = desc.DxgiUsage;
+
+ switch (desc.Usage) {
+ case D3D11_USAGE_IMMUTABLE: usage |= DXGI_CPU_ACCESS_NONE; break;
+ case D3D11_USAGE_DEFAULT: usage |= DXGI_CPU_ACCESS_NONE; break;
+ case D3D11_USAGE_DYNAMIC: usage |= DXGI_CPU_ACCESS_DYNAMIC; break;
+ case D3D11_USAGE_STAGING: usage |= DXGI_CPU_ACCESS_READ_WRITE; break;
+ }
+
+ // TODO add flags for swap chain back buffers
+ if (desc.BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_CONSTANT_BUFFER))
+ usage |= DXGI_USAGE_SHADER_INPUT;
+
+ if (desc.BindFlags & D3D11_BIND_RENDER_TARGET)
+ usage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
+
+ if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS)
+ usage |= DXGI_USAGE_UNORDERED_ACCESS;
+
+ *pUsage = usage;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::SetEvictionPriority(
+ UINT EvictionPriority) {
+ m_resource->SetEvictionPriority(EvictionPriority);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::CreateSharedHandle(
+ const SECURITY_ATTRIBUTES* pAttributes,
+ DWORD dwAccess,
+ LPCWSTR lpName,
+ HANDLE* pHandle) {
+ InitReturnPtr(pHandle);
+ Logger::err("D3D11DXGIResource::CreateSharedHandle: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGIResource::CreateSubresourceSurface(
+ UINT index,
+ IDXGISurface2** ppSurface) {
+ InitReturnPtr(ppSurface);
+ Logger::err("D3D11DXGIResource::CreateSubresourceSurface: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT GetCommonResourceDesc(
+ ID3D11Resource* pResource,
+ D3D11_COMMON_RESOURCE_DESC* pDesc) {
+ auto buffer = GetCommonBuffer (pResource);
+ auto texture = GetCommonTexture(pResource);
+
+ if (buffer != nullptr) {
+ pDesc->Dim = D3D11_RESOURCE_DIMENSION_BUFFER;
+ pDesc->Format = DXGI_FORMAT_UNKNOWN;
+ pDesc->Usage = buffer->Desc()->Usage;
+ pDesc->BindFlags = buffer->Desc()->BindFlags;
+ pDesc->CPUAccessFlags = buffer->Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = buffer->Desc()->MiscFlags;
+ pDesc->DxgiUsage = 0;
+ return S_OK;
+ } else if (texture != nullptr) {
+ pResource->GetType(&pDesc->Dim);
+ pDesc->Format = texture->Desc()->Format;
+ pDesc->Usage = texture->Desc()->Usage;
+ pDesc->BindFlags = texture->Desc()->BindFlags;
+ pDesc->CPUAccessFlags = texture->Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = texture->Desc()->MiscFlags;
+ pDesc->DxgiUsage = texture->GetDxgiUsage();
+ return S_OK;
+ } else {
+ pDesc->Dim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pDesc->Format = DXGI_FORMAT_UNKNOWN;
+ pDesc->Usage = D3D11_USAGE_DEFAULT;
+ pDesc->BindFlags = 0;
+ pDesc->CPUAccessFlags = 0;
+ pDesc->MiscFlags = 0;
+ pDesc->DxgiUsage = 0;
+ return E_INVALIDARG;
+ }
+ }
+
+
+ BOOL CheckResourceViewCompatibility(
+ ID3D11Resource* pResource,
+ UINT BindFlags,
+ DXGI_FORMAT Format,
+ UINT Plane) {
+ auto texture = GetCommonTexture(pResource);
+ auto buffer = GetCommonBuffer (pResource);
+
+ return texture != nullptr
+ ? texture->CheckViewCompatibility(BindFlags, Format, Plane)
+ : buffer ->CheckViewCompatibility(BindFlags, Format);
+ }
+
+
+ HRESULT ResourceAddRefPrivate(ID3D11Resource* pResource) {
+ D3D11_RESOURCE_DIMENSION dim;
+ pResource->GetType(&dim);
+
+ switch (dim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: static_cast<D3D11Buffer*> (pResource)->AddRefPrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: static_cast<D3D11Texture1D*>(pResource)->AddRefPrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: static_cast<D3D11Texture2D*>(pResource)->AddRefPrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: static_cast<D3D11Texture3D*>(pResource)->AddRefPrivate(); return S_OK;
+ default: return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT ResourceReleasePrivate(ID3D11Resource* pResource) {
+ D3D11_RESOURCE_DIMENSION dim;
+ pResource->GetType(&dim);
+
+ switch (dim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: static_cast<D3D11Buffer*> (pResource)->ReleasePrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: static_cast<D3D11Texture1D*>(pResource)->ReleasePrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: static_cast<D3D11Texture2D*>(pResource)->ReleasePrivate(); return S_OK;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: static_cast<D3D11Texture3D*>(pResource)->ReleasePrivate(); return S_OK;
+ default: return E_INVALIDARG;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h
new file mode 100644
index 00000000..7d91a305
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_resource.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Common resource description
+ *
+ * Stores the usage and bind flags of a resource
+ * Can be used to quickly determine whether it is
+ * legal to create a view for a given resource.
+ */
+ struct D3D11_COMMON_RESOURCE_DESC {
+ D3D11_RESOURCE_DIMENSION Dim;
+ DXGI_FORMAT Format;
+ D3D11_USAGE Usage;
+ UINT BindFlags;
+ UINT CPUAccessFlags;
+ UINT MiscFlags;
+ UINT DxgiUsage;
+ };
+
+
+ /**
+ * \brief IDXGIResource implementation for D3D11 resources
+ */
+ class D3D11DXGIResource : public IDXGIResource1 {
+
+ public:
+
+ D3D11DXGIResource(
+ ID3D11Resource* pResource);
+
+ ~D3D11DXGIResource();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown);
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent);
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetEvictionPriority(
+ UINT* pEvictionPriority);
+
+ HRESULT STDMETHODCALLTYPE GetSharedHandle(
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE GetUsage(
+ DXGI_USAGE* pUsage);
+
+ HRESULT STDMETHODCALLTYPE SetEvictionPriority(
+ UINT EvictionPriority);
+
+ HRESULT STDMETHODCALLTYPE CreateSharedHandle(
+ const SECURITY_ATTRIBUTES* pAttributes,
+ DWORD dwAccess,
+ LPCWSTR lpName,
+ HANDLE* pHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateSubresourceSurface(
+ UINT index,
+ IDXGISurface2** ppSurface);
+
+ private:
+
+ ID3D11Resource* m_resource;
+
+ };
+
+
+ /**
+ * \brief Queries common resource description
+ *
+ * \param [in] pResource The resource to query
+ * \param [out] pDesc Resource description
+ * \returns \c S_OK on success, or \c E_INVALIDARG
+ */
+ HRESULT GetCommonResourceDesc(
+ ID3D11Resource* pResource,
+ D3D11_COMMON_RESOURCE_DESC* pDesc);
+
+ /**
+ * \brief Checks whether a format can be used to view a resource
+ *
+ * Depending on whether the resource is a buffer or a
+ * texture, certain restrictions apply on which formats
+ * can be used to view the resource.
+ * \param [in] pResource The resource to check
+ * \param [in] BindFlags Bind flags required for the view
+ * \param [in] Format The desired view format
+ * \param [in] Plane Plane slice for planar formats
+ * \returns \c true if the format is compatible
+ */
+ BOOL CheckResourceViewCompatibility(
+ ID3D11Resource* pResource,
+ UINT BindFlags,
+ DXGI_FORMAT Format,
+ UINT Plane);
+
+ /**
+ * \brief Increments private reference count of a resource
+ *
+ * Helper method that figures out the exact type of
+ * the resource and calls its \c AddRefPrivate method.
+ * \param [in] pResource The resource to reference
+ * \returns \c S_OK, or \c E_INVALIDARG for an invalid resource
+ */
+ HRESULT ResourceAddRefPrivate(
+ ID3D11Resource* pResource);
+
+ /**
+ * \brief Decrements private reference count of a resource
+ *
+ * Helper method that figures out the exact type of
+ * the resource and calls its \c ReleasePrivate method.
+ * \param [in] pResource The resource to reference
+ * \returns \c S_OK, or \c E_INVALIDARG for an invalid resource
+ */
+ HRESULT ResourceReleasePrivate(
+ ID3D11Resource* pResource);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp
new file mode 100644
index 00000000..397dc47b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.cpp
@@ -0,0 +1,147 @@
+#include "d3d11_device.h"
+#include "d3d11_sampler.h"
+#include "d3d11_util.h"
+
+namespace dxvk {
+
+ D3D11SamplerState::D3D11SamplerState(
+ D3D11Device* device,
+ const D3D11_SAMPLER_DESC& desc)
+ : D3D11StateObject<ID3D11SamplerState>(device),
+ m_desc(desc), m_d3d10(this) {
+ DxvkSamplerCreateInfo info;
+
+ // While D3D11_FILTER is technically an enum, its value bits
+ // can be used to decode the filter properties more efficiently.
+ const uint32_t filterBits = uint32_t(desc.Filter);
+ info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
+ info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
+
+ // Set up the remaining properties, which are
+ // stored directly in the sampler description
+ info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.mipmapLodBias = desc.MipLODBias;
+ info.mipmapLodMin = desc.MinLOD;
+ info.mipmapLodMax = desc.MaxLOD;
+
+ info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE;
+ info.maxAnisotropy = float(desc.MaxAnisotropy);
+
+ info.addressModeU = DecodeAddressMode(desc.AddressU);
+ info.addressModeV = DecodeAddressMode(desc.AddressV);
+ info.addressModeW = DecodeAddressMode(desc.AddressW);
+
+ info.compareToDepth = (filterBits & 0x80) ? VK_TRUE : VK_FALSE;
+ info.compareOp = DecodeCompareOp(desc.ComparisonFunc);
+
+ for (uint32_t i = 0; i < 4; i++)
+ info.borderColor.float32[i] = desc.BorderColor[i];
+
+ info.usePixelCoord = VK_FALSE; // Not supported in D3D11
+
+ // Make sure to use a valid anisotropy value
+ if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;
+ if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f;
+
+ // Enforce anisotropy specified in the device options
+ int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
+
+ if (samplerAnisotropyOption >= 0) {
+ info.useAnisotropy = samplerAnisotropyOption > 0;
+ info.maxAnisotropy = float(samplerAnisotropyOption);
+ }
+
+ m_sampler = device->GetDXVKDevice()->createSampler(info);
+ }
+
+
+ D3D11SamplerState::~D3D11SamplerState() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SamplerState::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11SamplerState)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10SamplerState)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11SamplerState::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11SamplerState::GetDesc(D3D11_SAMPLER_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ HRESULT D3D11SamplerState::NormalizeDesc(D3D11_SAMPLER_DESC* pDesc) {
+ const uint32_t filterBits = uint32_t(pDesc->Filter);
+
+ if (filterBits & 0xFFFFFF2A) {
+ Logger::err(str::format(
+ "D3D11SamplerState: Unhandled filter: ", filterBits));
+ return E_INVALIDARG;
+ }
+
+ if (pDesc->MaxAnisotropy < 0
+ || pDesc->MaxAnisotropy > 16) {
+ return E_INVALIDARG;
+ } else if ((filterBits & 0x40) == 0 /* not anisotropic */) {
+ // Reset anisotropy if it is not used
+ pDesc->MaxAnisotropy = 0;
+ }
+
+ if (filterBits & 0x80 /* compare-to-depth */) {
+ if (!ValidateComparisonFunc(pDesc->ComparisonFunc))
+ return E_INVALIDARG;
+ } else {
+ // Reset compare func if it is not used
+ pDesc->ComparisonFunc = D3D11_COMPARISON_NEVER;
+ }
+
+ if (!ValidateAddressMode(pDesc->AddressU)
+ || !ValidateAddressMode(pDesc->AddressV)
+ || !ValidateAddressMode(pDesc->AddressW))
+ return E_INVALIDARG;
+
+ // Clear BorderColor to 0 if none of the address
+ // modes are D3D11_TEXTURE_ADDRESS_BORDER
+ if (pDesc->AddressU != D3D11_TEXTURE_ADDRESS_BORDER
+ && pDesc->AddressV != D3D11_TEXTURE_ADDRESS_BORDER
+ && pDesc->AddressW != D3D11_TEXTURE_ADDRESS_BORDER) {
+ for (int i = 0; i < 4; i++)
+ pDesc->BorderColor[i] = 0.0f;
+ }
+
+ return S_OK;
+ }
+
+
+ bool D3D11SamplerState::ValidateAddressMode(D3D11_TEXTURE_ADDRESS_MODE Mode) {
+ return Mode >= D3D11_TEXTURE_ADDRESS_WRAP
+ && Mode <= D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
+ }
+
+
+ bool D3D11SamplerState::ValidateComparisonFunc(D3D11_COMPARISON_FUNC Comparison) {
+ return Comparison >= D3D11_COMPARISON_NEVER
+ && Comparison <= D3D11_COMPARISON_ALWAYS;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h
new file mode 100644
index 00000000..57fa139b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_sampler.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_sampler.h"
+
+#include "d3d11_device_child.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ class D3D11SamplerState : public D3D11StateObject<ID3D11SamplerState> {
+
+ public:
+
+ using DescType = D3D11_SAMPLER_DESC;
+
+ D3D11SamplerState(
+ D3D11Device* device,
+ const D3D11_SAMPLER_DESC& desc);
+ ~D3D11SamplerState();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_SAMPLER_DESC* pDesc) final;
+
+ Rc<DxvkSampler> GetDXVKSampler() const {
+ return m_sampler;
+ }
+
+ D3D10SamplerState* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT NormalizeDesc(
+ D3D11_SAMPLER_DESC* pDesc);
+
+ private:
+
+ D3D11_SAMPLER_DESC m_desc;
+ Rc<DxvkSampler> m_sampler;
+ D3D10SamplerState m_d3d10;
+
+ std::atomic<uint32_t> m_refCount = { 0u };
+
+ static bool ValidateAddressMode(
+ D3D11_TEXTURE_ADDRESS_MODE Mode);
+
+ static bool ValidateComparisonFunc(
+ D3D11_COMPARISON_FUNC Comparison);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp
new file mode 100644
index 00000000..056044dd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.cpp
@@ -0,0 +1,140 @@
+#include "d3d11_device.h"
+#include "d3d11_shader.h"
+
+namespace dxvk {
+
+ D3D11CommonShader:: D3D11CommonShader() { }
+ D3D11CommonShader::~D3D11CommonShader() { }
+
+
+ D3D11CommonShader::D3D11CommonShader(
+ D3D11Device* pDevice,
+ const DxvkShaderKey* pShaderKey,
+ const DxbcModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode,
+ size_t BytecodeLength) {
+ const std::string name = pShaderKey->toString();
+ Logger::debug(str::format("Compiling shader ", name));
+
+ DxbcReader reader(
+ reinterpret_cast<const char*>(pShaderBytecode),
+ BytecodeLength);
+
+ DxbcModule module(reader);
+
+ // If requested by the user, dump both the raw DXBC
+ // shader and the compiled SPIR-V module to a file.
+ const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
+
+ if (dumpPath.size() != 0) {
+#ifdef _WIN32
+ reader.store(std::ofstream(str::tows(str::format(dumpPath, "/", name, ".dxbc").c_str()).c_str(),
+ std::ios_base::binary | std::ios_base::trunc));
+#else
+ reader.store(std::ofstream(str::format(dumpPath, "/", name, ".dxbc").c_str(),
+ std::ios_base::binary | std::ios_base::trunc));
+#endif
+ }
+
+ // Decide whether we need to create a pass-through
+ // geometry shader for vertex shader stream output
+ bool passthroughShader = pDxbcModuleInfo->xfb != nullptr
+ && (module.programInfo().type() == DxbcProgramType::VertexShader
+ || module.programInfo().type() == DxbcProgramType::DomainShader);
+
+ if (module.programInfo().shaderStage() != pShaderKey->type() && !passthroughShader)
+ throw DxvkError("Mismatching shader type.");
+
+ m_shader = passthroughShader
+ ? module.compilePassthroughShader(*pDxbcModuleInfo, name)
+ : module.compile (*pDxbcModuleInfo, name);
+ m_shader->setShaderKey(*pShaderKey);
+
+ if (dumpPath.size() != 0) {
+#ifdef _WIN32
+ std::ofstream dumpStream(
+ str::tows(str::format(dumpPath, "/", name, ".spv").c_str()).c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#else
+ std::ofstream dumpStream(
+ str::format(dumpPath, "/", name, ".spv").c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#endif
+
+ m_shader->dump(dumpStream);
+ }
+
+ // Create shader constant buffer if necessary
+ if (m_shader->shaderConstants().data() != nullptr) {
+ DxvkBufferCreateInfo info;
+ info.size = m_shader->shaderConstants().sizeInBytes();
+ info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ info.stages = util::pipelineStages(m_shader->stage());
+ info.access = VK_ACCESS_UNIFORM_READ_BIT;
+
+ VkMemoryPropertyFlags memFlags
+ = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
+ | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ m_buffer = pDevice->GetDXVKDevice()->createBuffer(info, memFlags);
+
+ std::memcpy(m_buffer->mapPtr(0),
+ m_shader->shaderConstants().data(),
+ m_shader->shaderConstants().sizeInBytes());
+ }
+
+ pDevice->GetDXVKDevice()->registerShader(m_shader);
+ }
+
+
+ D3D11ShaderModuleSet:: D3D11ShaderModuleSet() { }
+ D3D11ShaderModuleSet::~D3D11ShaderModuleSet() { }
+
+
+ HRESULT D3D11ShaderModuleSet::GetShaderModule(
+ D3D11Device* pDevice,
+ const DxvkShaderKey* pShaderKey,
+ const DxbcModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode,
+ size_t BytecodeLength,
+ D3D11CommonShader* pShader) {
+ // Use the shader's unique key for the lookup
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto entry = m_modules.find(*pShaderKey);
+ if (entry != m_modules.end()) {
+ *pShader = entry->second;
+ return S_OK;
+ }
+ }
+
+ // This shader has not been compiled yet, so we have to create a
+ // new module. This takes a while, so we won't lock the structure.
+ D3D11CommonShader module;
+
+ try {
+ module = D3D11CommonShader(pDevice, pShaderKey,
+ pDxbcModuleInfo, pShaderBytecode, BytecodeLength);
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_INVALIDARG;
+ }
+
+ // Insert the new module into the lookup table. If another thread
+ // has compiled the same shader in the meantime, we should return
+ // that object instead and discard the newly created module.
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto status = m_modules.insert({ *pShaderKey, module });
+ if (!status.second) {
+ *pShader = status.first->second;
+ return S_OK;
+ }
+ }
+
+ *pShader = std::move(module);
+ return S_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h
new file mode 100644
index 00000000..3ab16854
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_shader.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "../dxbc/dxbc_module.h"
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_shader.h"
+
+#include "../util/sha1/sha1_util.h"
+
+#include "../util/util_env.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_interfaces.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Common shader object
+ *
+ * Stores the compiled SPIR-V shader and the SHA-1
+ * hash of the original DXBC shader, which can be
+ * used to identify the shader.
+ */
+ class D3D11CommonShader {
+
+ public:
+
+ D3D11CommonShader();
+ D3D11CommonShader(
+ D3D11Device* pDevice,
+ const DxvkShaderKey* pShaderKey,
+ const DxbcModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode,
+ size_t BytecodeLength);
+ ~D3D11CommonShader();
+
+ Rc<DxvkShader> GetShader() const {
+ return m_shader;
+ }
+
+ Rc<DxvkBuffer> GetIcb() const {
+ return m_buffer;
+ }
+
+ std::string GetName() const {
+ return m_shader->debugName();
+ }
+
+ private:
+
+ Rc<DxvkShader> m_shader;
+ Rc<DxvkBuffer> m_buffer;
+
+ };
+
+
+ /**
+ * \brief Common shader interface
+ *
+ * Implements methods for all D3D11*Shader
+ * interfaces and stores the actual shader
+ * module object.
+ */
+ template<typename D3D11Interface, typename D3D10Interface>
+ class D3D11Shader : public D3D11DeviceChild<D3D11Interface> {
+ using D3D10ShaderClass = D3D10Shader<D3D10Interface, D3D11Interface>;
+ public:
+
+ D3D11Shader(D3D11Device* device, const D3D11CommonShader& shader)
+ : D3D11DeviceChild<D3D11Interface>(device),
+ m_shader(shader), m_d3d10(this) { }
+
+ ~D3D11Shader() { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final {
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(D3D11Interface)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(D3D10Interface)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11Shader::QueryInterface: Unknown interface query");
+ return E_NOINTERFACE;
+ }
+
+ const D3D11CommonShader* GetCommonShader() const {
+ return &m_shader;
+ }
+
+ D3D10ShaderClass* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ private:
+
+ D3D11CommonShader m_shader;
+ D3D10ShaderClass m_d3d10;
+
+ };
+
+ using D3D11VertexShader = D3D11Shader<ID3D11VertexShader, ID3D10VertexShader>;
+ using D3D11HullShader = D3D11Shader<ID3D11HullShader, ID3D10DeviceChild>;
+ using D3D11DomainShader = D3D11Shader<ID3D11DomainShader, ID3D10DeviceChild>;
+ using D3D11GeometryShader = D3D11Shader<ID3D11GeometryShader, ID3D10GeometryShader>;
+ using D3D11PixelShader = D3D11Shader<ID3D11PixelShader, ID3D10PixelShader>;
+ using D3D11ComputeShader = D3D11Shader<ID3D11ComputeShader, ID3D10DeviceChild>;
+
+
+ /**
+ * \brief Shader module set
+ *
+ * Some applications may compile the same shader multiple
+ * times, so we should cache the resulting shader modules
+ * and reuse them rather than creating new ones. This
+ * class is thread-safe.
+ */
+ class D3D11ShaderModuleSet {
+
+ public:
+
+ D3D11ShaderModuleSet();
+ ~D3D11ShaderModuleSet();
+
+ HRESULT GetShaderModule(
+ D3D11Device* pDevice,
+ const DxvkShaderKey* pShaderKey,
+ const DxbcModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode,
+ size_t BytecodeLength,
+ D3D11CommonShader* pShader);
+
+ private:
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkShaderKey,
+ D3D11CommonShader,
+ DxvkHash, DxvkEq> m_modules;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp
new file mode 100644
index 00000000..161566c0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.cpp
@@ -0,0 +1,199 @@
+#include "d3d11_state.h"
+
+namespace dxvk {
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_BLEND_DESC1& desc) const {
+ DxvkHashState hash;
+ hash.add(desc.AlphaToCoverageEnable);
+ hash.add(desc.IndependentBlendEnable);
+
+ // Render targets 1 to 7 are ignored and may contain
+ // undefined data if independent blend is disabled
+ const uint32_t usedRenderTargets = desc.IndependentBlendEnable ? 8 : 1;
+
+ for (uint32_t i = 0; i < usedRenderTargets; i++)
+ hash.add(this->operator () (desc.RenderTarget[i]));
+
+ return hash;
+ }
+
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_DEPTH_STENCILOP_DESC& desc) const {
+ DxvkHashState hash;
+ hash.add(desc.StencilFunc);
+ hash.add(desc.StencilDepthFailOp);
+ hash.add(desc.StencilPassOp);
+ hash.add(desc.StencilFailOp);
+ return hash;
+ }
+
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_DEPTH_STENCIL_DESC& desc) const {
+ DxvkHashState hash;
+ hash.add(desc.DepthEnable);
+ hash.add(desc.DepthWriteMask);
+ hash.add(desc.DepthFunc);
+ hash.add(desc.StencilEnable);
+ hash.add(desc.StencilReadMask);
+ hash.add(desc.StencilWriteMask);
+ hash.add(this->operator () (desc.FrontFace));
+ hash.add(this->operator () (desc.BackFace));
+ return hash;
+ }
+
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_RASTERIZER_DESC2& desc) const {
+ std::hash<float> fhash;
+
+ DxvkHashState hash;
+ hash.add(desc.FillMode);
+ hash.add(desc.CullMode);
+ hash.add(desc.FrontCounterClockwise);
+ hash.add(desc.DepthBias);
+ hash.add(fhash(desc.SlopeScaledDepthBias));
+ hash.add(fhash(desc.DepthBiasClamp));
+ hash.add(desc.DepthClipEnable);
+ hash.add(desc.ScissorEnable);
+ hash.add(desc.MultisampleEnable);
+ hash.add(desc.AntialiasedLineEnable);
+ hash.add(desc.ForcedSampleCount);
+ hash.add(desc.ConservativeRaster);
+ return hash;
+ }
+
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_RENDER_TARGET_BLEND_DESC1& desc) const {
+ DxvkHashState hash;
+ hash.add(desc.BlendEnable);
+ hash.add(desc.LogicOpEnable);
+ hash.add(desc.SrcBlend);
+ hash.add(desc.DestBlend);
+ hash.add(desc.BlendOp);
+ hash.add(desc.SrcBlendAlpha);
+ hash.add(desc.DestBlendAlpha);
+ hash.add(desc.BlendOpAlpha);
+ hash.add(desc.LogicOp);
+ hash.add(desc.RenderTargetWriteMask);
+ return hash;
+ }
+
+
+ size_t D3D11StateDescHash::operator () (
+ const D3D11_SAMPLER_DESC& desc) const {
+ std::hash<float> fhash;
+
+ DxvkHashState hash;
+ hash.add(desc.Filter);
+ hash.add(desc.AddressU);
+ hash.add(desc.AddressV);
+ hash.add(desc.AddressW);
+ hash.add(fhash(desc.MipLODBias));
+ hash.add(desc.MaxAnisotropy);
+ hash.add(desc.ComparisonFunc);
+ for (uint32_t i = 0; i < 4; i++)
+ hash.add(fhash(desc.BorderColor[i]));
+ hash.add(fhash(desc.MinLOD));
+ hash.add(fhash(desc.MaxLOD));
+ return hash;
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_BLEND_DESC1& a,
+ const D3D11_BLEND_DESC1& b) const {
+ bool eq = a.AlphaToCoverageEnable == b.AlphaToCoverageEnable
+ && a.IndependentBlendEnable == b.IndependentBlendEnable;
+
+ // Render targets 1 to 7 are ignored and may contain
+ // undefined data if independent blend is disabled
+ const uint32_t usedRenderTargets = a.IndependentBlendEnable ? 8 : 1;
+
+ for (uint32_t i = 0; eq && (i < usedRenderTargets); i++)
+ eq &= this->operator () (a.RenderTarget[i], b.RenderTarget[i]);
+
+ return eq;
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_DEPTH_STENCILOP_DESC& a,
+ const D3D11_DEPTH_STENCILOP_DESC& b) const {
+ return a.StencilFunc == b.StencilFunc
+ && a.StencilDepthFailOp == b.StencilDepthFailOp
+ && a.StencilPassOp == b.StencilPassOp
+ && a.StencilFailOp == b.StencilFailOp;
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_DEPTH_STENCIL_DESC& a,
+ const D3D11_DEPTH_STENCIL_DESC& b) const {
+ return a.DepthEnable == b.DepthEnable
+ && a.DepthWriteMask == b.DepthWriteMask
+ && a.DepthFunc == b.DepthFunc
+ && a.StencilEnable == b.StencilEnable
+ && a.StencilReadMask == b.StencilReadMask
+ && a.StencilWriteMask == b.StencilWriteMask
+ && this->operator () (a.FrontFace, b.FrontFace)
+ && this->operator () (a.BackFace, b.BackFace);
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_RASTERIZER_DESC2& a,
+ const D3D11_RASTERIZER_DESC2& b) const {
+ return a.FillMode == b.FillMode
+ && a.CullMode == b.CullMode
+ && a.FrontCounterClockwise == b.FrontCounterClockwise
+ && a.DepthBias == b.DepthBias
+ && a.SlopeScaledDepthBias == b.SlopeScaledDepthBias
+ && a.DepthBiasClamp == b.DepthBiasClamp
+ && a.DepthClipEnable == b.DepthClipEnable
+ && a.ScissorEnable == b.ScissorEnable
+ && a.MultisampleEnable == b.MultisampleEnable
+ && a.AntialiasedLineEnable == b.AntialiasedLineEnable
+ && a.ForcedSampleCount == b.ForcedSampleCount
+ && a.ConservativeRaster == b.ConservativeRaster;
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_RENDER_TARGET_BLEND_DESC1& a,
+ const D3D11_RENDER_TARGET_BLEND_DESC1& b) const {
+ return a.BlendEnable == b.BlendEnable
+ && a.LogicOpEnable == b.LogicOpEnable
+ && a.SrcBlend == b.SrcBlend
+ && a.DestBlend == b.DestBlend
+ && a.BlendOp == b.BlendOp
+ && a.SrcBlendAlpha == b.SrcBlendAlpha
+ && a.DestBlendAlpha == b.DestBlendAlpha
+ && a.BlendOpAlpha == b.BlendOpAlpha
+ && a.LogicOp == b.LogicOp
+ && a.RenderTargetWriteMask == b.RenderTargetWriteMask;
+ }
+
+
+ bool D3D11StateDescEqual::operator () (
+ const D3D11_SAMPLER_DESC& a,
+ const D3D11_SAMPLER_DESC& b) const {
+ return a.Filter == b.Filter
+ && a.AddressU == b.AddressU
+ && a.AddressV == b.AddressV
+ && a.AddressW == b.AddressW
+ && a.MipLODBias == b.MipLODBias
+ && a.MaxAnisotropy == b.MaxAnisotropy
+ && a.ComparisonFunc == b.ComparisonFunc
+ && a.BorderColor[0] == b.BorderColor[0]
+ && a.BorderColor[1] == b.BorderColor[1]
+ && a.BorderColor[2] == b.BorderColor[2]
+ && a.BorderColor[3] == b.BorderColor[3]
+ && a.MinLOD == b.MinLOD
+ && a.MaxLOD == b.MaxLOD;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h
new file mode 100644
index 00000000..e807d1ad
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <unordered_map>
+
+#include "d3d11_blend.h"
+#include "d3d11_depth_stencil.h"
+#include "d3d11_rasterizer.h"
+#include "d3d11_sampler.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ struct D3D11StateDescHash {
+ size_t operator () (const D3D11_BLEND_DESC1& desc) const;
+ size_t operator () (const D3D11_DEPTH_STENCILOP_DESC& desc) const;
+ size_t operator () (const D3D11_DEPTH_STENCIL_DESC& desc) const;
+ size_t operator () (const D3D11_RASTERIZER_DESC2& desc) const;
+ size_t operator () (const D3D11_RENDER_TARGET_BLEND_DESC1& desc) const;
+ size_t operator () (const D3D11_SAMPLER_DESC& desc) const;
+ };
+
+
+ struct D3D11StateDescEqual {
+ bool operator () (const D3D11_BLEND_DESC1& a, const D3D11_BLEND_DESC1& b) const;
+ bool operator () (const D3D11_DEPTH_STENCILOP_DESC& a, const D3D11_DEPTH_STENCILOP_DESC& b) const;
+ bool operator () (const D3D11_DEPTH_STENCIL_DESC& a, const D3D11_DEPTH_STENCIL_DESC& b) const;
+ bool operator () (const D3D11_RASTERIZER_DESC2& a, const D3D11_RASTERIZER_DESC2& b) const;
+ bool operator () (const D3D11_RENDER_TARGET_BLEND_DESC1& a, const D3D11_RENDER_TARGET_BLEND_DESC1& b) const;
+ bool operator () (const D3D11_SAMPLER_DESC& a, const D3D11_SAMPLER_DESC& b) const;
+ };
+
+
+ /**
+ * \brief Unique state object set
+ *
+ * When creating state objects, D3D11 first checks if
+ * an object with the same description already exists
+ * and returns it if that is the case. This class
+ * implements that behaviour.
+ */
+ template<typename T>
+ class D3D11StateObjectSet {
+ using DescType = typename T::DescType;
+ public:
+
+ /**
+ * \brief Retrieves a state object
+ *
+ * Returns an object with the same description or
+ * creates a new one if no such object exists.
+ * \param [in] device The calling D3D11 device
+ * \param [in] desc State object description
+ * \returns Pointer to the state object
+ */
+ T* Create(D3D11Device* device, const DescType& desc) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ auto entry = m_objects.find(desc);
+
+ if (entry != m_objects.end())
+ return ref(&entry->second);
+
+ auto result = m_objects.emplace(
+ std::piecewise_construct,
+ std::tuple(desc),
+ std::tuple(device, desc));
+ return ref(&result.first->second);
+ }
+
+ private:
+
+ dxvk::mutex m_mutex;
+ std::unordered_map<DescType, T,
+ D3D11StateDescHash, D3D11StateDescEqual> m_objects;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp
new file mode 100644
index 00000000..33cc8a33
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.cpp
@@ -0,0 +1,37 @@
+#include "d3d11_state_object.h"
+
+namespace dxvk {
+
+ D3D11DeviceContextState::D3D11DeviceContextState(
+ D3D11Device* pDevice)
+ : D3D11DeviceChild<ID3DDeviceContextState>(pDevice) {
+
+ }
+
+
+ D3D11DeviceContextState::~D3D11DeviceContextState() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DeviceContextState::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3DDeviceContextState)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11DeviceContextState::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h
new file mode 100644
index 00000000..775a0951
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_state_object.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "d3d11_device.h"
+#include "d3d11_context_state.h"
+#include "d3d11_device_child.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Device context state implementation
+ *
+ * This is an opaque interface in D3D11, and we only
+ * implement the state block-like functionality, not
+ * the methods to disable certain context and device
+ * interfaces based on the emulated device IID.
+ */
+ class D3D11DeviceContextState : public D3D11DeviceChild<ID3DDeviceContextState> {
+
+ public:
+
+ D3D11DeviceContextState(
+ D3D11Device* pDevice);
+
+ ~D3D11DeviceContextState();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void SetState(const D3D11ContextState& State) {
+ m_state = State;
+ }
+
+ void GetState(D3D11ContextState& State) const {
+ State = m_state;
+ }
+
+ private:
+
+ D3D11ContextState m_state;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp
new file mode 100644
index 00000000..d7483593
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.cpp
@@ -0,0 +1,681 @@
+#include "d3d11_context_imm.h"
+#include "d3d11_device.h"
+#include "d3d11_swapchain.h"
+
+namespace dxvk {
+
+ static uint16_t MapGammaControlPoint(float x) {
+ if (x < 0.0f) x = 0.0f;
+ if (x > 1.0f) x = 1.0f;
+ return uint16_t(65535.0f * x);
+ }
+
+
+ D3D11SwapChain::D3D11SwapChain(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc)
+ : m_dxgiDevice(pContainer),
+ m_parent (pDevice),
+ m_window (hWnd),
+ m_desc (*pDesc),
+ m_device (pDevice->GetDXVKDevice()),
+ m_context (m_device->createContext()),
+ m_frameLatencyCap(pDevice->GetOptions()->maxFrameLatency) {
+ CreateFrameLatencyEvent();
+
+ if (!pDevice->GetOptions()->deferSurfaceCreation)
+ CreatePresenter();
+
+ CreateBackBuffer();
+ CreateBlitter();
+ CreateHud();
+ }
+
+
+ D3D11SwapChain::~D3D11SwapChain() {
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+
+ if (m_backBuffer)
+ m_backBuffer->ReleasePrivate();
+
+ DestroyFrameLatencyEvent();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ InitReturnPtr(ppvObject);
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIVkSwapChain)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11SwapChain::QueryInterface: Unknown interface query");
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetDesc(
+ DXGI_SWAP_CHAIN_DESC1* pDesc) {
+ *pDesc = m_desc;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetAdapter(
+ REFIID riid,
+ void** ppvObject) {
+ return m_dxgiDevice->GetParent(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetDevice(
+ REFIID riid,
+ void** ppDevice) {
+ return m_dxgiDevice->QueryInterface(riid, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::GetImage(
+ UINT BufferId,
+ REFIID riid,
+ void** ppBuffer) {
+ InitReturnPtr(ppBuffer);
+
+ if (BufferId > 0) {
+ Logger::err("D3D11: GetImage: BufferId > 0 not supported");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+ return m_backBuffer->QueryInterface(riid, ppBuffer);
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11SwapChain::GetImageIndex() {
+ return 0;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatency() {
+ return m_frameLatency;
+ }
+
+
+ HANDLE STDMETHODCALLTYPE D3D11SwapChain::GetFrameLatencyEvent() {
+ return m_frameLatencyEvent;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::ChangeProperties(
+ const DXGI_SWAP_CHAIN_DESC1* pDesc) {
+
+ m_dirty |= m_desc.Format != pDesc->Format
+ || m_desc.Width != pDesc->Width
+ || m_desc.Height != pDesc->Height
+ || m_desc.BufferCount != pDesc->BufferCount
+ || m_desc.Flags != pDesc->Flags;
+
+ m_desc = *pDesc;
+ CreateBackBuffer();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetPresentRegion(
+ const RECT* pRegion) {
+ // TODO implement
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetGammaControl(
+ UINT NumControlPoints,
+ const DXGI_RGB* pControlPoints) {
+ bool isIdentity = true;
+
+ if (NumControlPoints > 1) {
+ std::array<DxvkGammaCp, 1025> cp;
+
+ if (NumControlPoints > cp.size())
+ return E_INVALIDARG;
+
+ for (uint32_t i = 0; i < NumControlPoints; i++) {
+ uint16_t identity = MapGammaControlPoint(float(i) / float(NumControlPoints - 1));
+
+ cp[i].r = MapGammaControlPoint(pControlPoints[i].Red);
+ cp[i].g = MapGammaControlPoint(pControlPoints[i].Green);
+ cp[i].b = MapGammaControlPoint(pControlPoints[i].Blue);
+ cp[i].a = 0;
+
+ isIdentity &= cp[i].r == identity
+ && cp[i].g == identity
+ && cp[i].b == identity;
+ }
+
+ if (!isIdentity)
+ m_blitter->setGammaRamp(NumControlPoints, cp.data());
+ }
+
+ if (isIdentity)
+ m_blitter->setGammaRamp(0, nullptr);
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::SetFrameLatency(
+ UINT MaxLatency) {
+ if (MaxLatency == 0 || MaxLatency > DXGI_MAX_SWAP_CHAIN_BUFFERS)
+ return DXGI_ERROR_INVALID_CALL;
+
+#ifdef _WIN32
+ if (m_frameLatencyEvent) {
+ // Windows DXGI does not seem to handle the case where the new maximum
+ // latency is less than the current value, and some games relying on
+ // this behaviour will hang if we attempt to decrement the semaphore.
+ // Thus, only increment the semaphore as necessary.
+ if (MaxLatency > m_frameLatency)
+ ReleaseSemaphore(m_frameLatencyEvent, MaxLatency - m_frameLatency, nullptr);
+ }
+#endif
+
+ m_frameLatency = MaxLatency;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11SwapChain::Present(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
+ auto options = m_parent->GetOptions();
+
+ if (options->syncInterval >= 0)
+ SyncInterval = options->syncInterval;
+
+ if (!(PresentFlags & DXGI_PRESENT_TEST)) {
+ bool vsync = SyncInterval != 0;
+
+ m_dirty |= vsync != m_vsync;
+ m_vsync = vsync;
+ }
+
+ if (m_presenter == nullptr)
+ CreatePresenter();
+
+ HRESULT hr = S_OK;
+
+ if (!m_presenter->hasSwapChain()) {
+ RecreateSwapChain(m_vsync);
+ m_dirty = false;
+ }
+
+ if (!m_presenter->hasSwapChain())
+ hr = DXGI_STATUS_OCCLUDED;
+
+ if (m_device->getDeviceStatus() != VK_SUCCESS)
+ hr = DXGI_ERROR_DEVICE_RESET;
+
+ if ((PresentFlags & DXGI_PRESENT_TEST) || hr != S_OK)
+ return hr;
+
+ if (std::exchange(m_dirty, false))
+ RecreateSwapChain(m_vsync);
+
+ try {
+ PresentImage(SyncInterval);
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ hr = E_FAIL;
+ }
+
+ return hr;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11SwapChain::NotifyModeChange(
+ BOOL Windowed,
+ const DXGI_MODE_DESC* pDisplayMode) {
+ if (Windowed || !pDisplayMode) {
+ // Display modes aren't meaningful in windowed mode
+ m_displayRefreshRate = 0.0;
+ } else {
+ DXGI_RATIONAL rate = pDisplayMode->RefreshRate;
+ m_displayRefreshRate = double(rate.Numerator) / double(rate.Denominator);
+ }
+
+ if (m_presenter != nullptr)
+ m_presenter->setFrameRateLimiterRefreshRate(m_displayRefreshRate);
+ }
+
+
+ HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
+ Com<ID3D11DeviceContext> deviceContext = nullptr;
+ m_parent->GetImmediateContext(&deviceContext);
+
+ // Flush pending rendering commands before
+ auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
+ immediateContext->Flush();
+
+ // Bump our frame id.
+ ++m_frameId;
+
+ for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
+ SynchronizePresent();
+
+ if (!m_presenter->hasSwapChain())
+ return DXGI_STATUS_OCCLUDED;
+
+ // Presentation semaphores and WSI swap chain image
+ vk::PresenterInfo info = m_presenter->info();
+ vk::PresenterSync sync;
+
+ uint32_t imageIndex = 0;
+
+ VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
+
+ while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
+ RecreateSwapChain(m_vsync);
+
+ if (!m_presenter->hasSwapChain())
+ return DXGI_STATUS_OCCLUDED;
+
+ info = m_presenter->info();
+ status = m_presenter->acquireNextImage(sync, imageIndex);
+ }
+
+ // Resolve back buffer if it is multisampled. We
+ // only have to do it only for the first frame.
+ m_context->beginRecording(
+ m_device->createCommandList());
+
+ m_blitter->presentImage(m_context.ptr(),
+ m_imageViews.at(imageIndex), VkRect2D(),
+ m_swapImageView, VkRect2D());
+
+ if (m_hud != nullptr)
+ m_hud->render(m_context, info.format, info.imageExtent);
+
+ if (i + 1 >= SyncInterval)
+ m_context->signal(m_frameLatencySignal, m_frameId);
+
+ SubmitPresent(immediateContext, sync, i);
+ }
+
+ SyncFrameLatency();
+ return S_OK;
+ }
+
+
+ void D3D11SwapChain::SubmitPresent(
+ D3D11ImmediateContext* pContext,
+ const vk::PresenterSync& Sync,
+ uint32_t FrameId) {
+ auto lock = pContext->LockContext();
+
+ // Present from CS thread so that we don't
+ // have to synchronize with it first.
+ m_presentStatus.result = VK_NOT_READY;
+
+ pContext->EmitCs([this,
+ cFrameId = FrameId,
+ cSync = Sync,
+ cHud = m_hud,
+ cCommandList = m_context->endRecording()
+ ] (DxvkContext* ctx) {
+ m_device->submitCommandList(cCommandList,
+ cSync.acquire, cSync.present);
+
+ if (cHud != nullptr && !cFrameId)
+ cHud->update();
+
+ m_device->presentImage(m_presenter, &m_presentStatus);
+ });
+
+ pContext->FlushCsChunk();
+ }
+
+
+ void D3D11SwapChain::SynchronizePresent() {
+ // Recreate swap chain if the previous present call failed
+ VkResult status = m_device->waitForSubmission(&m_presentStatus);
+
+ if (status != VK_SUCCESS)
+ RecreateSwapChain(m_vsync);
+ }
+
+
+ void D3D11SwapChain::RecreateSwapChain(BOOL Vsync) {
+ // Ensure that we can safely destroy the swap chain
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+
+ m_presentStatus.result = VK_SUCCESS;
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
+ presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
+ presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
+ presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = PickFullscreenMode();
+
+ if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS)
+ throw DxvkError("D3D11SwapChain: Failed to recreate swap chain");
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D11SwapChain::CreateFrameLatencyEvent() {
+ m_frameLatencySignal = new sync::CallbackFence(m_frameId);
+
+ if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) {
+#ifndef DXVK_NATIVE
+ m_frameLatencyEvent = CreateEvent(nullptr, false, true, nullptr);
+#else
+ throw DxvkError("DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT not supported on this platform.");
+#endif
+ }
+ }
+
+
+ void D3D11SwapChain::CreatePresenter() {
+ DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
+
+ vk::PresenterDevice presenterDevice;
+ presenterDevice.queueFamily = graphicsQueue.queueFamily;
+ presenterDevice.queue = graphicsQueue.queueHandle;
+ presenterDevice.adapter = m_device->adapter()->handle();
+ presenterDevice.features.fullScreenExclusive = m_device->extensions().extFullScreenExclusive;
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
+ presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
+ presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
+ presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = PickFullscreenMode();
+
+ m_presenter = new vk::Presenter(m_window,
+ m_device->adapter()->vki(),
+ m_device->vkd(),
+ presenterDevice,
+ presenterDesc);
+
+ m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
+ m_presenter->setFrameRateLimiterRefreshRate(m_displayRefreshRate);
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D11SwapChain::CreateRenderTargetViews() {
+ vk::PresenterInfo info = m_presenter->info();
+
+ m_imageViews.clear();
+ m_imageViews.resize(info.imageCount);
+
+ DxvkImageCreateInfo imageInfo;
+ imageInfo.type = VK_IMAGE_TYPE_2D;
+ imageInfo.format = info.format.format;
+ imageInfo.flags = 0;
+ imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
+ imageInfo.numLayers = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ imageInfo.stages = 0;
+ imageInfo.access = 0;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ imageInfo.shared = VK_TRUE;
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = info.format.format;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+
+ for (uint32_t i = 0; i < info.imageCount; i++) {
+ VkImage imageHandle = m_presenter->getImage(i).image;
+
+ Rc<DxvkImage> image = new DxvkImage(
+ m_device->vkd(), imageInfo, imageHandle);
+
+ m_imageViews[i] = new DxvkImageView(
+ m_device->vkd(), image, viewInfo);
+ }
+ }
+
+
+ void D3D11SwapChain::CreateBackBuffer() {
+ // Explicitly destroy current swap image before
+ // creating a new one to free up resources
+ if (m_backBuffer)
+ m_backBuffer->ReleasePrivate();
+
+ m_swapImage = nullptr;
+ m_swapImageView = nullptr;
+ m_backBuffer = nullptr;
+
+ // Create new back buffer
+ D3D11_COMMON_TEXTURE_DESC desc;
+ desc.Width = std::max(m_desc.Width, 1u);
+ desc.Height = std::max(m_desc.Height, 1u);
+ desc.Depth = 1;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = m_desc.Format;
+ desc.SampleDesc = m_desc.SampleDesc;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ if (m_desc.BufferUsage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
+ desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
+
+ if (m_desc.BufferUsage & DXGI_USAGE_SHADER_INPUT)
+ desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
+
+ if (m_desc.BufferUsage & DXGI_USAGE_UNORDERED_ACCESS)
+ desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
+
+ if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE)
+ desc.MiscFlags |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
+
+ DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER;
+
+ if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD
+ || m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
+ dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT;
+
+ m_backBuffer = new D3D11Texture2D(m_parent, &desc, dxgiUsage, VK_NULL_HANDLE);
+ m_backBuffer->AddRefPrivate();
+
+ m_swapImage = GetCommonTexture(m_backBuffer)->GetImage();
+
+ // Create an image view that allows the
+ // image to be bound as a shader resource.
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = m_swapImage->info().format;
+ viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ m_swapImageView = m_device->createImageView(m_swapImage, viewInfo);
+
+ // Initialize the image so that we can use it. Clearing
+ // to black prevents garbled output for the first frame.
+ VkImageSubresourceRange subresources;
+ subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ subresources.baseMipLevel = 0;
+ subresources.levelCount = 1;
+ subresources.baseArrayLayer = 0;
+ subresources.layerCount = 1;
+
+ VkClearColorValue clearColor;
+ clearColor.float32[0] = 0.0f;
+ clearColor.float32[1] = 0.0f;
+ clearColor.float32[2] = 0.0f;
+ clearColor.float32[3] = 0.0f;
+
+ m_context->beginRecording(
+ m_device->createCommandList());
+
+ m_context->clearColorImage(
+ m_swapImage, clearColor, subresources);
+
+ m_device->submitCommandList(
+ m_context->endRecording(),
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE);
+ }
+
+
+ void D3D11SwapChain::CreateBlitter() {
+ m_blitter = new DxvkSwapchainBlitter(m_device);
+ }
+
+
+ void D3D11SwapChain::CreateHud() {
+ m_hud = hud::Hud::createHud(m_device);
+
+ if (m_hud != nullptr)
+ m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
+ }
+
+
+ void D3D11SwapChain::DestroyFrameLatencyEvent() {
+#ifndef DXVK_NATIVE
+ CloseHandle(m_frameLatencyEvent);
+#endif
+ }
+
+
+ void D3D11SwapChain::SyncFrameLatency() {
+ // Wait for the sync event so that we respect the maximum frame latency
+ m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
+
+#ifndef DXVK_NATIVE
+ if (m_frameLatencyEvent) {
+ m_frameLatencySignal->setCallback(m_frameId, [cFrameLatencyEvent = m_frameLatencyEvent] () {
+ ReleaseSemaphore(cFrameLatencyEvent, 1, nullptr);
+ });
+ }
+#endif
+ }
+
+
+ uint32_t D3D11SwapChain::GetActualFrameLatency() {
+ uint32_t maxFrameLatency = m_frameLatency;
+
+ if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+ m_dxgiDevice->GetMaximumFrameLatency(&maxFrameLatency);
+
+ if (m_frameLatencyCap)
+ maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap);
+
+ maxFrameLatency = std::min(maxFrameLatency, m_desc.BufferCount + 1);
+ return maxFrameLatency;
+ }
+
+
+ uint32_t D3D11SwapChain::PickFormats(
+ DXGI_FORMAT Format,
+ VkSurfaceFormatKHR* pDstFormats) {
+ uint32_t n = 0;
+
+ switch (Format) {
+ default:
+ Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format));
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_UNORM: {
+ pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: {
+ pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+
+ case DXGI_FORMAT_R10G10B10A2_UNORM: {
+ pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+
+ case DXGI_FORMAT_R16G16B16A16_FLOAT: {
+ pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+ }
+
+ return n;
+ }
+
+
+ uint32_t D3D11SwapChain::PickPresentModes(
+ BOOL Vsync,
+ VkPresentModeKHR* pDstModes) {
+ uint32_t n = 0;
+
+ if (Vsync) {
+ if (m_parent->GetOptions()->tearFree == Tristate::False)
+ pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
+ pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
+ } else {
+ if (m_parent->GetOptions()->tearFree != Tristate::True)
+ pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
+ pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
+ }
+
+ return n;
+ }
+
+
+ uint32_t D3D11SwapChain::PickImageCount(
+ UINT Preferred) {
+ int32_t option = m_parent->GetOptions()->numBackBuffers;
+ return option > 0 ? uint32_t(option) : uint32_t(Preferred);
+ }
+
+
+ VkFullScreenExclusiveEXT D3D11SwapChain::PickFullscreenMode() {
+ return m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+ ? VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT
+ : VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
+ }
+
+
+ std::string D3D11SwapChain::GetApiName() const {
+ Com<IDXGIDXVKDevice> device;
+ m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast<void**>(&device));
+
+ uint32_t apiVersion = device->GetAPIVersion();
+ uint32_t featureLevel = m_parent->GetFeatureLevel();
+
+ uint32_t flHi = (featureLevel >> 12);
+ uint32_t flLo = (featureLevel >> 8) & 0x7;
+
+ return str::format("D3D", apiVersion, " FL", flHi, "_", flLo);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h
new file mode 100644
index 00000000..8fc9fe10
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_swapchain.h
@@ -0,0 +1,164 @@
+#pragma once
+
+#include "d3d11_texture.h"
+
+#include "../dxvk/hud/dxvk_hud.h"
+
+#include "../dxvk/dxvk_swapchain_blitter.h"
+
+#include "../util/sync/sync_signal.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11DXGIDevice;
+
+ class D3D11SwapChain : public ComObject<IDXGIVkSwapChain> {
+ constexpr static uint32_t DefaultFrameLatency = 1;
+ public:
+
+ D3D11SwapChain(
+ D3D11DXGIDevice* pContainer,
+ D3D11Device* pDevice,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc);
+
+ ~D3D11SwapChain();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_SWAP_CHAIN_DESC1* pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetAdapter(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetImage(
+ UINT BufferId,
+ REFIID riid,
+ void** ppBuffer);
+
+ UINT STDMETHODCALLTYPE GetImageIndex();
+
+ UINT STDMETHODCALLTYPE GetFrameLatency();
+
+ HANDLE STDMETHODCALLTYPE GetFrameLatencyEvent();
+
+ HRESULT STDMETHODCALLTYPE ChangeProperties(
+ const DXGI_SWAP_CHAIN_DESC1* pDesc);
+
+ HRESULT STDMETHODCALLTYPE SetPresentRegion(
+ const RECT* pRegion);
+
+ HRESULT STDMETHODCALLTYPE SetGammaControl(
+ UINT NumControlPoints,
+ const DXGI_RGB* pControlPoints);
+
+ HRESULT STDMETHODCALLTYPE SetFrameLatency(
+ UINT MaxLatency);
+
+ HRESULT STDMETHODCALLTYPE Present(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters);
+
+ void STDMETHODCALLTYPE NotifyModeChange(
+ BOOL Windowed,
+ const DXGI_MODE_DESC* pDisplayMode);
+
+ private:
+
+ enum BindingIds : uint32_t {
+ Image = 0,
+ Gamma = 1,
+ };
+
+ Com<D3D11DXGIDevice, false> m_dxgiDevice;
+
+ D3D11Device* m_parent;
+ HWND m_window;
+
+ DXGI_SWAP_CHAIN_DESC1 m_desc;
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkContext> m_context;
+
+ Rc<vk::Presenter> m_presenter;
+
+ Rc<DxvkImage> m_swapImage;
+ Rc<DxvkImageView> m_swapImageView;
+ Rc<DxvkSwapchainBlitter> m_blitter;
+
+ Rc<hud::Hud> m_hud;
+
+ D3D11Texture2D* m_backBuffer = nullptr;
+ DxvkSubmitStatus m_presentStatus;
+
+ std::vector<Rc<DxvkImageView>> m_imageViews;
+
+ uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
+ uint32_t m_frameLatency = DefaultFrameLatency;
+ uint32_t m_frameLatencyCap = 0;
+ HANDLE m_frameLatencyEvent = nullptr;
+ Rc<sync::CallbackFence> m_frameLatencySignal;
+
+ bool m_dirty = true;
+ bool m_vsync = true;
+
+ double m_displayRefreshRate = 0.0;
+
+ HRESULT PresentImage(UINT SyncInterval);
+
+ void SubmitPresent(
+ D3D11ImmediateContext* pContext,
+ const vk::PresenterSync& Sync,
+ uint32_t FrameId);
+
+ void SynchronizePresent();
+
+ void RecreateSwapChain(
+ BOOL Vsync);
+
+ void CreateFrameLatencyEvent();
+
+ void CreatePresenter();
+
+ void CreateRenderTargetViews();
+
+ void CreateBackBuffer();
+
+ void CreateBlitter();
+
+ void CreateHud();
+
+ void DestroyFrameLatencyEvent();
+
+ void SyncFrameLatency();
+
+ uint32_t GetActualFrameLatency();
+
+ uint32_t PickFormats(
+ DXGI_FORMAT Format,
+ VkSurfaceFormatKHR* pDstFormats);
+
+ uint32_t PickPresentModes(
+ BOOL Vsync,
+ VkPresentModeKHR* pDstModes);
+
+ uint32_t PickImageCount(
+ UINT Preferred);
+
+ VkFullScreenExclusiveEXT PickFullscreenMode();
+
+ std::string GetApiName() const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp
new file mode 100644
index 00000000..35c6afd8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.cpp
@@ -0,0 +1,1269 @@
+#include "d3d11_device.h"
+#include "d3d11_gdi.h"
+#include "d3d11_texture.h"
+
+namespace dxvk {
+
+ D3D11CommonTexture::D3D11CommonTexture(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc,
+ D3D11_RESOURCE_DIMENSION Dimension,
+ DXGI_USAGE DxgiUsage,
+ VkImage vkImage)
+ : m_device(pDevice), m_dimension(Dimension), m_desc(*pDesc), m_dxgiUsage(DxgiUsage) {
+ DXGI_VK_FORMAT_MODE formatMode = GetFormatMode();
+ DXGI_VK_FORMAT_INFO formatInfo = m_device->LookupFormat(m_desc.Format, formatMode);
+ DXGI_VK_FORMAT_FAMILY formatFamily = m_device->LookupFamily(m_desc.Format, formatMode);
+ DXGI_VK_FORMAT_INFO formatPacked = m_device->LookupPackedFormat(m_desc.Format, formatMode);
+ m_packedFormat = formatPacked.Format;
+
+ DxvkImageCreateInfo imageInfo;
+ imageInfo.type = GetVkImageType();
+ imageInfo.format = formatInfo.Format;
+ imageInfo.flags = 0;
+ imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.extent.width = m_desc.Width;
+ imageInfo.extent.height = m_desc.Height;
+ imageInfo.extent.depth = m_desc.Depth;
+ imageInfo.numLayers = m_desc.ArraySize;
+ imageInfo.mipLevels = m_desc.MipLevels;
+ imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_GENERAL;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ imageInfo.shared = vkImage != VK_NULL_HANDLE;
+
+ if (!pDevice->GetOptions()->disableMsaa)
+ DecodeSampleCount(m_desc.SampleDesc.Count, &imageInfo.sampleCount);
+
+ // Integer clear operations on UAVs are implemented using
+ // a view with a bit-compatible integer format, so we'll
+ // have to include that format in the format family
+ if (m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) {
+ DXGI_VK_FORMAT_INFO formatBase = m_device->LookupFormat(
+ m_desc.Format, DXGI_VK_FORMAT_MODE_RAW);
+
+ if (formatBase.Format != formatInfo.Format
+ && formatBase.Format != VK_FORMAT_UNDEFINED) {
+ formatFamily.Add(formatBase.Format);
+ formatFamily.Add(formatInfo.Format);
+ }
+ }
+
+ // The image must be marked as mutable if it can be reinterpreted
+ // by a view with a different format. Depth-stencil formats cannot
+ // be reinterpreted in Vulkan, so we'll ignore those.
+ auto formatProperties = imageFormatInfo(formatInfo.Format);
+
+ bool isTypeless = formatInfo.Aspect == 0;
+ bool isMutable = formatFamily.FormatCount > 1;
+ bool isMultiPlane = (formatProperties->aspectMask & VK_IMAGE_ASPECT_PLANE_0_BIT) != 0;
+ bool isColorFormat = (formatProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
+
+ if (isMutable && (isColorFormat || isMultiPlane)) {
+ imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+ // Typeless UAV images have relaxed reinterpretation rules
+ if (!isTypeless || !(m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS)) {
+ imageInfo.viewFormatCount = formatFamily.FormatCount;
+ imageInfo.viewFormats = formatFamily.Formats;
+ }
+ }
+
+ // Adjust image flags based on the corresponding D3D flags
+ if (m_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) {
+ imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageInfo.stages |= pDevice->GetEnabledShaderStages();
+ imageInfo.access |= VK_ACCESS_SHADER_READ_BIT;
+ }
+
+ if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) {
+ imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ }
+
+ if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) {
+ imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
+ | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+ }
+
+ if (m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) {
+ imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+ imageInfo.stages |= pDevice->GetEnabledShaderStages();
+ imageInfo.access |= VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT;
+
+ // UAVs are not supported for sRGB formats on most drivers,
+ // but we can still create linear views for the image
+ if (formatProperties->flags.test(DxvkFormatFlag::ColorSpaceSrgb))
+ imageInfo.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
+ }
+
+ // Multi-plane formats need views to be created with color formats, and
+ // may not report all relevant usage flags as supported on their own.
+ // Also, enable sampled bit to enable use with video processor APIs.
+ if (isMultiPlane) {
+ imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
+ | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
+ }
+
+ // Access pattern for meta-resolve operations
+ if (imageInfo.sampleCount != VK_SAMPLE_COUNT_1_BIT && isColorFormat) {
+ imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ imageInfo.access |= VK_ACCESS_SHADER_READ_BIT;
+ }
+
+ if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE)
+ imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+
+ if (Dimension == D3D11_RESOURCE_DIMENSION_TEXTURE3D &&
+ (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET))
+ imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
+
+ // Swap chain back buffers need to be shader readable
+ if (DxgiUsage & DXGI_USAGE_BACK_BUFFER) {
+ imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ imageInfo.access |= VK_ACCESS_SHADER_READ_BIT;
+ imageInfo.shared = VK_TRUE;
+ }
+
+ // Some image formats (i.e. the R32G32B32 ones) are
+ // only supported with linear tiling on most GPUs
+ if (!CheckImageSupport(&imageInfo, VK_IMAGE_TILING_OPTIMAL))
+ imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
+
+ // Determine map mode based on our findings
+ m_mapMode = DetermineMapMode(&imageInfo);
+
+ // If the image is mapped directly to host memory, we need
+ // to enable linear tiling, and DXVK needs to be aware that
+ // the image can be accessed by the host.
+ if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
+ imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+ }
+
+ // If necessary, create the mapped linear buffer
+ if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
+ for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
+ for (uint32_t j = 0; j < m_desc.MipLevels; j++) {
+ if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT)
+ m_buffers.push_back(CreateMappedBuffer(j));
+
+ m_mapTypes.push_back(D3D11_MAP(~0u));
+ }
+ }
+ }
+
+ // Skip image creation if possible
+ if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING)
+ return;
+
+ // We must keep LINEAR images in GENERAL layout, but we
+ // can choose a better layout for the image based on how
+ // it is going to be used by the game.
+ if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL && !isMultiPlane)
+ imageInfo.layout = OptimizeLayout(imageInfo.usage);
+
+ // For some formats, we need to enable sampled and/or
+ // render target capabilities if available, but these
+ // should in no way affect the default image layout
+ imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
+ imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
+
+ // Check if we can actually create the image
+ if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
+ throw DxvkError(str::format(
+ "D3D11: Cannot create texture:",
+ "\n Format: ", m_desc.Format,
+ "\n Extent: ", m_desc.Width,
+ "x", m_desc.Height,
+ "x", m_desc.Depth,
+ "\n Samples: ", m_desc.SampleDesc.Count,
+ "\n Layers: ", m_desc.ArraySize,
+ "\n Levels: ", m_desc.MipLevels,
+ "\n Usage: ", std::hex, m_desc.BindFlags,
+ "\n Flags: ", std::hex, m_desc.MiscFlags));
+ }
+
+ // Create the image on a host-visible memory type
+ // in case it is going to be mapped directly.
+ VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
+ memoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ }
+
+ if (vkImage == VK_NULL_HANDLE)
+ m_image = m_device->GetDXVKDevice()->createImage(imageInfo, memoryProperties);
+ else
+ m_image = m_device->GetDXVKDevice()->createImageFromVkImage(imageInfo, vkImage);
+ }
+
+
+ D3D11CommonTexture::~D3D11CommonTexture() {
+
+ }
+
+
+ VkDeviceSize D3D11CommonTexture::ComputeMappedOffset(UINT Subresource, UINT Plane, VkOffset3D Offset) const {
+ auto packedFormatInfo = imageFormatInfo(m_packedFormat);
+
+ VkImageAspectFlags aspectMask = packedFormatInfo->aspectMask;
+ VkDeviceSize elementSize = packedFormatInfo->elementSize;
+
+ if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &packedFormatInfo->planes[Plane];
+ elementSize = plane->elementSize;
+ Offset.x /= plane->blockSize.width;
+ Offset.y /= plane->blockSize.height;
+ aspectMask = vk::getPlaneAspect(Plane);
+ }
+
+ auto layout = GetSubresourceLayout(aspectMask, Subresource);
+ auto blockOffset = util::computeBlockOffset(Offset, packedFormatInfo->blockSize);
+
+ return VkDeviceSize(blockOffset.z) * layout.DepthPitch
+ + VkDeviceSize(blockOffset.y) * layout.RowPitch
+ + VkDeviceSize(blockOffset.x) * elementSize
+ + VkDeviceSize(layout.Offset);
+ }
+
+
+ VkImageSubresource D3D11CommonTexture::GetSubresourceFromIndex(
+ VkImageAspectFlags Aspect,
+ UINT Subresource) const {
+ VkImageSubresource result;
+ result.aspectMask = Aspect;
+ result.mipLevel = Subresource % m_desc.MipLevels;
+ result.arrayLayer = Subresource / m_desc.MipLevels;
+ return result;
+ }
+
+
+ D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT D3D11CommonTexture::GetSubresourceLayout(
+ VkImageAspectFlags AspectMask,
+ UINT Subresource) const {
+ VkImageSubresource subresource = GetSubresourceFromIndex(AspectMask, Subresource);
+ D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { };
+
+ switch (m_mapMode) {
+ case D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT: {
+ auto vkLayout = m_image->querySubresourceLayout(subresource);
+ layout.Offset = vkLayout.offset;
+ layout.Size = vkLayout.size;
+ layout.RowPitch = vkLayout.rowPitch;
+ layout.DepthPitch = vkLayout.depthPitch;
+ } break;
+
+ case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER:
+ case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: {
+ auto packedFormatInfo = imageFormatInfo(m_packedFormat);
+
+ VkImageAspectFlags aspects = packedFormatInfo->aspectMask;
+ VkExtent3D mipExtent = MipLevelExtent(subresource.mipLevel);
+
+ while (aspects) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto extent = mipExtent;
+ auto elementSize = packedFormatInfo->elementSize;
+
+ if (packedFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &packedFormatInfo->planes[vk::getPlaneIndex(aspect)];
+ extent.width /= plane->blockSize.width;
+ extent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ auto blockCount = util::computeBlockCount(extent, packedFormatInfo->blockSize);
+
+ if (!layout.RowPitch) {
+ layout.RowPitch = elementSize * blockCount.width;
+ layout.DepthPitch = elementSize * blockCount.width * blockCount.height;
+ }
+
+ VkDeviceSize size = elementSize * blockCount.width * blockCount.height * blockCount.depth;
+
+ if (aspect & AspectMask)
+ layout.Size += size;
+ else if (!layout.Size)
+ layout.Offset += size;
+ }
+ } break;
+
+ case D3D11_COMMON_TEXTURE_MAP_MODE_NONE:
+ break; /* no op */
+ }
+
+ // D3D wants us to return the total subresource size in some instances
+ if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE2D) layout.RowPitch = layout.Size;
+ if (m_dimension < D3D11_RESOURCE_DIMENSION_TEXTURE3D) layout.DepthPitch = layout.Size;
+ return layout;
+ }
+
+
+ DXGI_VK_FORMAT_MODE D3D11CommonTexture::GetFormatMode() const {
+ if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET)
+ return DXGI_VK_FORMAT_MODE_COLOR;
+
+ if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL)
+ return DXGI_VK_FORMAT_MODE_DEPTH;
+
+ return DXGI_VK_FORMAT_MODE_ANY;
+ }
+
+
+ uint32_t D3D11CommonTexture::GetPlaneCount() const {
+ return vk::getPlaneCount(m_image->formatInfo()->aspectMask);
+ }
+
+
+ bool D3D11CommonTexture::CheckViewCompatibility(UINT BindFlags, DXGI_FORMAT Format, UINT Plane) const {
+ const DxvkImageCreateInfo& imageInfo = m_image->info();
+
+ // Check whether the given bind flags are supported
+ if ((m_desc.BindFlags & BindFlags) != BindFlags)
+ return false;
+
+ // Check whether the view format is compatible
+ DXGI_VK_FORMAT_MODE formatMode = GetFormatMode();
+ DXGI_VK_FORMAT_INFO viewFormat = m_device->LookupFormat(Format, formatMode);
+ DXGI_VK_FORMAT_INFO baseFormat = m_device->LookupFormat(m_desc.Format, formatMode);
+
+ // Check whether the plane index is valid for the given format
+ uint32_t planeCount = GetPlaneCount();
+
+ if (Plane >= planeCount)
+ return false;
+
+ if (imageInfo.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
+ // Check whether the given combination of image
+ // view type and view format is actually supported
+ VkFormatFeatureFlags features = GetImageFormatFeatures(BindFlags);
+
+ if (!CheckFormatFeatureSupport(viewFormat.Format, features))
+ return false;
+
+ // Using the image format itself is supported for non-planar formats
+ if (viewFormat.Format == baseFormat.Format && planeCount == 1)
+ return true;
+
+ // If there is a list of compatible formats, the view format must be
+ // included in that list. For planar formats, the list is laid out in
+ // such a way that the n-th format is supported for the n-th plane.
+ for (size_t i = Plane; i < imageInfo.viewFormatCount; i += planeCount) {
+ if (imageInfo.viewFormats[i] == viewFormat.Format) {
+ return true;
+ }
+ }
+
+ // Otherwise, all bit-compatible formats can be used.
+ if (imageInfo.viewFormatCount == 0 && planeCount == 1) {
+ auto baseFormatInfo = imageFormatInfo(baseFormat.Format);
+ auto viewFormatInfo = imageFormatInfo(viewFormat.Format);
+
+ return baseFormatInfo->aspectMask == viewFormatInfo->aspectMask
+ && baseFormatInfo->elementSize == viewFormatInfo->elementSize;
+ }
+
+ return false;
+ } else {
+ // For non-mutable images, the view format
+ // must be identical to the image format.
+ return viewFormat.Format == baseFormat.Format && planeCount == 1;
+ }
+ }
+
+
+ HRESULT D3D11CommonTexture::NormalizeTextureProperties(D3D11_COMMON_TEXTURE_DESC* pDesc) {
+ if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0 || pDesc->ArraySize == 0)
+ return E_INVALIDARG;
+
+ if (FAILED(DecodeSampleCount(pDesc->SampleDesc.Count, nullptr)))
+ return E_INVALIDARG;
+
+ if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE)
+ && (pDesc->Usage == D3D11_USAGE_STAGING
+ || (pDesc->Format != DXGI_FORMAT_B8G8R8A8_TYPELESS
+ && pDesc->Format != DXGI_FORMAT_B8G8R8A8_UNORM
+ && pDesc->Format != DXGI_FORMAT_B8G8R8A8_UNORM_SRGB)))
+ return E_INVALIDARG;
+
+ if ((pDesc->MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS)
+ && (pDesc->BindFlags & (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET))
+ != (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET))
+ return E_INVALIDARG;
+
+ // TILE_POOL is invalid, but we don't support TILED either
+ if (pDesc->MiscFlags & (D3D11_RESOURCE_MISC_TILE_POOL | D3D11_RESOURCE_MISC_TILED))
+ return E_INVALIDARG;
+
+ // Use the maximum possible mip level count if the supplied
+ // mip level count is either unspecified (0) or invalid
+ const uint32_t maxMipLevelCount = pDesc->SampleDesc.Count <= 1
+ ? util::computeMipLevelCount({ pDesc->Width, pDesc->Height, pDesc->Depth })
+ : 1u;
+
+ if (pDesc->MipLevels == 0 || pDesc->MipLevels > maxMipLevelCount)
+ pDesc->MipLevels = maxMipLevelCount;
+
+ // Row-major is only supported for textures with one single
+ // subresource and one sample and cannot have bind flags.
+ if (pDesc->TextureLayout == D3D11_TEXTURE_LAYOUT_ROW_MAJOR
+ && (pDesc->MipLevels != 1 || pDesc->SampleDesc.Count != 1 || pDesc->BindFlags))
+ return E_INVALIDARG;
+
+ // Standard swizzle is unsupported
+ if (pDesc->TextureLayout == D3D11_TEXTURE_LAYOUT_64K_STANDARD_SWIZZLE)
+ return E_INVALIDARG;
+
+ return S_OK;
+ }
+
+
+ BOOL D3D11CommonTexture::CheckImageSupport(
+ const DxvkImageCreateInfo* pImageInfo,
+ VkImageTiling Tiling) const {
+ const Rc<DxvkAdapter> adapter = m_device->GetDXVKDevice()->adapter();
+
+ VkImageUsageFlags usage = pImageInfo->usage;
+
+ if (pImageInfo->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
+ usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
+ VkImageFormatProperties formatProps = { };
+ VkResult status = adapter->imageFormatProperties(
+ pImageInfo->format, pImageInfo->type, Tiling,
+ usage, pImageInfo->flags, formatProps);
+
+ if (status != VK_SUCCESS)
+ return FALSE;
+
+ return (pImageInfo->extent.width <= formatProps.maxExtent.width)
+ && (pImageInfo->extent.height <= formatProps.maxExtent.height)
+ && (pImageInfo->extent.depth <= formatProps.maxExtent.depth)
+ && (pImageInfo->numLayers <= formatProps.maxArrayLayers)
+ && (pImageInfo->mipLevels <= formatProps.maxMipLevels)
+ && (pImageInfo->sampleCount & formatProps.sampleCounts);
+ }
+
+
+ BOOL D3D11CommonTexture::CheckFormatFeatureSupport(
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const {
+ VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format);
+
+ return (properties.linearTilingFeatures & Features) == Features
+ || (properties.optimalTilingFeatures & Features) == Features;
+ }
+
+
+ VkImageUsageFlags D3D11CommonTexture::EnableMetaCopyUsage(
+ VkFormat Format,
+ VkImageTiling Tiling) const {
+ VkFormatFeatureFlags requestedFeatures = 0;
+
+ if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT) {
+ requestedFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
+ | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ }
+
+ if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT) {
+ requestedFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
+ | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+ }
+
+ if (Format == VK_FORMAT_D32_SFLOAT_S8_UINT || Format == VK_FORMAT_D24_UNORM_S8_UINT)
+ requestedFeatures |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (requestedFeatures == 0)
+ return 0;
+
+ // Enable usage flags for all supported and requested features
+ VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format);
+
+ requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
+ ? properties.optimalTilingFeatures
+ : properties.linearTilingFeatures;
+
+ VkImageUsageFlags requestedUsage = 0;
+
+ if (requestedFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
+ requestedUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ if (requestedFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (requestedFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
+ requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ return requestedUsage;
+ }
+
+
+ VkImageUsageFlags D3D11CommonTexture::EnableMetaPackUsage(
+ VkFormat Format,
+ UINT CpuAccess) const {
+ if ((CpuAccess & D3D11_CPU_ACCESS_READ) == 0)
+ return 0;
+
+ const auto dsMask = VK_IMAGE_ASPECT_DEPTH_BIT
+ | VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ auto formatInfo = imageFormatInfo(Format);
+
+ return formatInfo->aspectMask == dsMask
+ ? VK_IMAGE_USAGE_SAMPLED_BIT
+ : 0;
+ }
+
+
+ D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode(
+ const DxvkImageCreateInfo* pImageInfo) const {
+ // Don't map an image unless the application requests it
+ if (!m_desc.CPUAccessFlags)
+ return D3D11_COMMON_TEXTURE_MAP_MODE_NONE;
+
+ // If the resource cannot be used in the actual rendering pipeline, we
+ // do not need to create an actual image and can instead implement copy
+ // functions as buffer-to-image and image-to-buffer copies.
+ if (!m_desc.BindFlags && m_desc.Usage != D3D11_USAGE_DEFAULT)
+ return D3D11_COMMON_TEXTURE_MAP_MODE_STAGING;
+
+ // Write-only images should go through a buffer for multiple reasons:
+ // 1. Some games do not respect the row and depth pitch that is returned
+ // by the Map() method, which leads to incorrect rendering (e.g. Nier)
+ // 2. Since the image will most likely be read for rendering by the GPU,
+ // writing the image to device-local image may be more efficient than
+ // reading its contents from host memory.
+ if (m_desc.Usage == D3D11_USAGE_DYNAMIC
+ && m_desc.TextureLayout != D3D11_TEXTURE_LAYOUT_ROW_MAJOR)
+ return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
+
+ // Depth-stencil formats in D3D11 can be mapped and follow special
+ // packing rules, so we need to copy that data into a buffer first
+ if (GetPackedDepthStencilFormat(m_desc.Format))
+ return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
+
+ // Multi-plane images have a special memory layout in D3D11
+ if (imageFormatInfo(pImageInfo->format)->flags.test(DxvkFormatFlag::MultiPlane))
+ return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
+
+ // Images that can be read by the host should be mapped directly in
+ // order to avoid expensive synchronization with the GPU. This does
+ // however require linear tiling, which may not be supported for all
+ // combinations of image parameters.
+ return this->CheckImageSupport(pImageInfo, VK_IMAGE_TILING_LINEAR)
+ ? D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT
+ : D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
+ }
+
+
+ D3D11CommonTexture::MappedBuffer D3D11CommonTexture::CreateMappedBuffer(UINT MipLevel) const {
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(
+ m_device->LookupPackedFormat(m_desc.Format, GetFormatMode()).Format);
+
+ DxvkBufferCreateInfo info;
+ info.size = GetSubresourceLayout(formatInfo->aspectMask, MipLevel).Size;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT;
+
+ VkMemoryPropertyFlags memType = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ if (m_desc.Usage == D3D11_USAGE_STAGING)
+ memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+
+ MappedBuffer result;
+ result.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType);
+ result.slice = result.buffer->getSliceHandle();
+ return result;
+ }
+
+
+ VkImageType D3D11CommonTexture::GetImageTypeFromResourceDim(D3D11_RESOURCE_DIMENSION Dimension) {
+ switch (Dimension) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: return VK_IMAGE_TYPE_1D;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: return VK_IMAGE_TYPE_2D;
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: return VK_IMAGE_TYPE_3D;
+ default: throw DxvkError("D3D11CommonTexture: Unhandled resource dimension");
+ }
+ }
+
+
+ VkImageLayout D3D11CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) {
+ const VkImageUsageFlags usageFlags = Usage;
+
+ // Filter out unnecessary flags. Transfer operations
+ // are handled by the backend in a transparent manner.
+ Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+
+ // If the image is used only as an attachment, we never
+ // have to transform the image back to a different layout
+ if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+
+ // If the image is used for reading but not as a storage
+ // image, we can optimize the image for texture access
+ if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
+ return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
+ ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+
+ // Otherwise, we have to stick with the default layout
+ return VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+
+
+
+ D3D11DXGISurface::D3D11DXGISurface(
+ ID3D11Resource* pResource,
+ D3D11CommonTexture* pTexture)
+ : m_resource (pResource),
+ m_texture (pTexture),
+ m_gdiSurface(nullptr) {
+#ifndef DXVK_NATIVE
+ if (pTexture->Desc()->MiscFlags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE)
+ m_gdiSurface = new D3D11GDISurface(m_resource, 0);
+#endif
+ }
+
+
+ D3D11DXGISurface::~D3D11DXGISurface() {
+#ifndef DXVK_NATIVE
+ if (m_gdiSurface)
+ delete m_gdiSurface;
+#endif
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DXGISurface::AddRef() {
+ return m_resource->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11DXGISurface::Release() {
+ return m_resource->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_resource->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData) {
+ return m_resource->GetPrivateData(Name, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) {
+ return m_resource->SetPrivateData(Name, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown) {
+ return m_resource->SetPrivateDataInterface(Name, pUnknown);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetParent(
+ REFIID riid,
+ void** ppParent) {
+ return GetDevice(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDevice(
+ REFIID riid,
+ void** ppDevice) {
+ Com<ID3D11Device> device;
+ m_resource->GetDevice(&device);
+ return device->QueryInterface(riid, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDesc(
+ DXGI_SURFACE_DESC* pDesc) {
+ if (!pDesc)
+ return DXGI_ERROR_INVALID_CALL;
+
+ auto desc = m_texture->Desc();
+ pDesc->Width = desc->Width;
+ pDesc->Height = desc->Height;
+ pDesc->Format = desc->Format;
+ pDesc->SampleDesc = desc->SampleDesc;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::Map(
+ DXGI_MAPPED_RECT* pLockedRect,
+ UINT MapFlags) {
+ Com<ID3D11Device> device;
+ Com<ID3D11DeviceContext> context;
+
+ m_resource->GetDevice(&device);
+ device->GetImmediateContext(&context);
+
+ if (pLockedRect) {
+ pLockedRect->Pitch = 0;
+ pLockedRect->pBits = nullptr;
+ }
+
+ D3D11_MAP mapType;
+
+ if (MapFlags & (DXGI_MAP_READ | DXGI_MAP_WRITE))
+ mapType = D3D11_MAP_READ_WRITE;
+ else if (MapFlags & DXGI_MAP_READ)
+ mapType = D3D11_MAP_READ;
+ else if (MapFlags & (DXGI_MAP_WRITE | DXGI_MAP_DISCARD))
+ mapType = D3D11_MAP_WRITE_DISCARD;
+ else if (MapFlags & DXGI_MAP_WRITE)
+ mapType = D3D11_MAP_WRITE;
+ else
+ return DXGI_ERROR_INVALID_CALL;
+
+ D3D11_MAPPED_SUBRESOURCE sr;
+ HRESULT hr = context->Map(m_resource, 0,
+ mapType, 0, pLockedRect ? &sr : nullptr);
+
+ if (hr != S_OK)
+ return hr;
+
+ pLockedRect->Pitch = sr.RowPitch;
+ pLockedRect->pBits = reinterpret_cast<unsigned char*>(sr.pData);
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::Unmap() {
+ Com<ID3D11Device> device;
+ Com<ID3D11DeviceContext> context;
+
+ m_resource->GetDevice(&device);
+ device->GetImmediateContext(&context);
+
+ context->Unmap(m_resource, 0);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetDC(
+ BOOL Discard,
+ HDC* phdc) {
+#ifndef DXVK_NATIVE
+ if (m_gdiSurface)
+ return m_gdiSurface->Acquire(Discard, phdc);
+#endif
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::ReleaseDC(
+ RECT* pDirtyRect) {
+#ifndef DXVK_NATIVE
+ if (m_gdiSurface)
+ return m_gdiSurface->Release(pDirtyRect);
+#endif
+
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DXGISurface::GetResource(
+ REFIID riid,
+ void** ppParentResource,
+ UINT* pSubresourceIndex) {
+ HRESULT hr = m_resource->QueryInterface(riid, ppParentResource);
+ if (pSubresourceIndex)
+ *pSubresourceIndex = 0;
+ return hr;
+ }
+
+
+ bool D3D11DXGISurface::isSurfaceCompatible() const {
+ auto desc = m_texture->Desc();
+
+ return desc->ArraySize == 1
+ && desc->MipLevels == 1;
+ }
+
+
+
+
+ D3D11VkInteropSurface::D3D11VkInteropSurface(
+ ID3D11Resource* pResource,
+ D3D11CommonTexture* pTexture)
+ : m_resource(pResource),
+ m_texture (pTexture) {
+
+ }
+
+
+ D3D11VkInteropSurface::~D3D11VkInteropSurface() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VkInteropSurface::AddRef() {
+ return m_resource->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VkInteropSurface::Release() {
+ return m_resource->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_resource->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::GetDevice(
+ IDXGIVkInteropDevice** ppDevice) {
+ Com<ID3D11Device> device;
+ m_resource->GetDevice(&device);
+
+ return device->QueryInterface(
+ __uuidof(IDXGIVkInteropDevice),
+ reinterpret_cast<void**>(ppDevice));
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VkInteropSurface::GetVulkanImageInfo(
+ VkImage* pHandle,
+ VkImageLayout* pLayout,
+ VkImageCreateInfo* pInfo) {
+ const Rc<DxvkImage> image = m_texture->GetImage();
+ const DxvkImageCreateInfo& info = image->info();
+
+ if (pHandle != nullptr)
+ *pHandle = image->handle();
+
+ if (pLayout != nullptr)
+ *pLayout = info.layout;
+
+ if (pInfo != nullptr) {
+ // We currently don't support any extended structures
+ if (pInfo->sType != VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
+ || pInfo->pNext != nullptr)
+ return E_INVALIDARG;
+
+ pInfo->flags = 0;
+ pInfo->imageType = info.type;
+ pInfo->format = info.format;
+ pInfo->extent = info.extent;
+ pInfo->mipLevels = info.mipLevels;
+ pInfo->arrayLayers = info.numLayers;
+ pInfo->samples = info.sampleCount;
+ pInfo->tiling = info.tiling;
+ pInfo->usage = info.usage;
+ pInfo->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ pInfo->queueFamilyIndexCount = 0;
+ pInfo->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ return S_OK;
+ }
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 1 D
+ D3D11Texture1D::D3D11Texture1D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc)
+ : D3D11DeviceChild<ID3D11Texture1D>(pDevice),
+ m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, VK_NULL_HANDLE),
+ m_interop (this, &m_texture),
+ m_surface (this, &m_texture),
+ m_resource(this),
+ m_d3d10 (this) {
+
+ }
+
+
+ D3D11Texture1D::~D3D11Texture1D() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Texture1D::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11Resource)
+ || riid == __uuidof(ID3D11Texture1D)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10Resource)
+ || riid == __uuidof(ID3D10Texture1D)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ if (m_surface.isSurfaceCompatible()
+ && (riid == __uuidof(IDXGISurface)
+ || riid == __uuidof(IDXGISurface1)
+ || riid == __uuidof(IDXGISurface2))) {
+ *ppvObject = ref(&m_surface);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGIResource)
+ || riid == __uuidof(IDXGIResource1)) {
+ *ppvObject = ref(&m_resource);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkInteropSurface)) {
+ *ppvObject = ref(&m_interop);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11Texture1D::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture1D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) {
+ *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE1D;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Texture1D::GetEvictionPriority() {
+ return DXGI_RESOURCE_PRIORITY_NORMAL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture1D::SetEvictionPriority(UINT EvictionPriority) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11Texture1D::SetEvictionPriority: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture1D::GetDesc(D3D11_TEXTURE1D_DESC *pDesc) {
+ pDesc->Width = m_texture.Desc()->Width;
+ pDesc->MipLevels = m_texture.Desc()->MipLevels;
+ pDesc->ArraySize = m_texture.Desc()->ArraySize;
+ pDesc->Format = m_texture.Desc()->Format;
+ pDesc->Usage = m_texture.Desc()->Usage;
+ pDesc->BindFlags = m_texture.Desc()->BindFlags;
+ pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
+ }
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 2 D
+ D3D11Texture2D::D3D11Texture2D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc)
+ : D3D11DeviceChild<ID3D11Texture2D1>(pDevice),
+ m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, VK_NULL_HANDLE),
+ m_interop (this, &m_texture),
+ m_surface (this, &m_texture),
+ m_resource(this),
+ m_d3d10 (this) {
+
+ }
+
+
+ D3D11Texture2D::D3D11Texture2D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc,
+ DXGI_USAGE DxgiUsage,
+ VkImage vkImage)
+ : D3D11DeviceChild<ID3D11Texture2D1>(pDevice),
+ m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DxgiUsage, vkImage),
+ m_interop (this, &m_texture),
+ m_surface (this, &m_texture),
+ m_resource(this),
+ m_d3d10 (this) {
+
+ }
+
+
+ D3D11Texture2D::~D3D11Texture2D() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Texture2D::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11Resource)
+ || riid == __uuidof(ID3D11Texture2D)
+ || riid == __uuidof(ID3D11Texture2D1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10Resource)
+ || riid == __uuidof(ID3D10Texture2D)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ if (m_surface.isSurfaceCompatible()
+ && (riid == __uuidof(IDXGISurface)
+ || riid == __uuidof(IDXGISurface1)
+ || riid == __uuidof(IDXGISurface2))) {
+ *ppvObject = ref(&m_surface);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGIResource)
+ || riid == __uuidof(IDXGIResource1)) {
+ *ppvObject = ref(&m_resource);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkInteropSurface)) {
+ *ppvObject = ref(&m_interop);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11Texture2D::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture2D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) {
+ *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Texture2D::GetEvictionPriority() {
+ return DXGI_RESOURCE_PRIORITY_NORMAL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture2D::SetEvictionPriority(UINT EvictionPriority) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11Texture2D::SetEvictionPriority: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture2D::GetDesc(D3D11_TEXTURE2D_DESC* pDesc) {
+ pDesc->Width = m_texture.Desc()->Width;
+ pDesc->Height = m_texture.Desc()->Height;
+ pDesc->MipLevels = m_texture.Desc()->MipLevels;
+ pDesc->ArraySize = m_texture.Desc()->ArraySize;
+ pDesc->Format = m_texture.Desc()->Format;
+ pDesc->SampleDesc = m_texture.Desc()->SampleDesc;
+ pDesc->Usage = m_texture.Desc()->Usage;
+ pDesc->BindFlags = m_texture.Desc()->BindFlags;
+ pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture2D::GetDesc1(D3D11_TEXTURE2D_DESC1* pDesc) {
+ pDesc->Width = m_texture.Desc()->Width;
+ pDesc->Height = m_texture.Desc()->Height;
+ pDesc->MipLevels = m_texture.Desc()->MipLevels;
+ pDesc->ArraySize = m_texture.Desc()->ArraySize;
+ pDesc->Format = m_texture.Desc()->Format;
+ pDesc->SampleDesc = m_texture.Desc()->SampleDesc;
+ pDesc->Usage = m_texture.Desc()->Usage;
+ pDesc->BindFlags = m_texture.Desc()->BindFlags;
+ pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
+ pDesc->TextureLayout = m_texture.Desc()->TextureLayout;
+ }
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 3 D
+ D3D11Texture3D::D3D11Texture3D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc)
+ : D3D11DeviceChild<ID3D11Texture3D1>(pDevice),
+ m_texture (pDevice, pDesc, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, VK_NULL_HANDLE),
+ m_interop (this, &m_texture),
+ m_resource(this),
+ m_d3d10 (this) {
+
+ }
+
+
+ D3D11Texture3D::~D3D11Texture3D() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11Texture3D::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11Resource)
+ || riid == __uuidof(ID3D11Texture3D)
+ || riid == __uuidof(ID3D11Texture3D1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10Resource)
+ || riid == __uuidof(ID3D10Texture3D)) {
+ *ppvObject = ref(&m_d3d10);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGIResource)
+ || riid == __uuidof(IDXGIResource1)) {
+ *ppvObject = ref(&m_resource);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkInteropSurface)) {
+ *ppvObject = ref(&m_interop);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11Texture3D::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture3D::GetType(D3D11_RESOURCE_DIMENSION *pResourceDimension) {
+ *pResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE3D;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D11Texture3D::GetEvictionPriority() {
+ return DXGI_RESOURCE_PRIORITY_NORMAL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture3D::SetEvictionPriority(UINT EvictionPriority) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D11Texture3D::SetEvictionPriority: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture3D::GetDesc(D3D11_TEXTURE3D_DESC* pDesc) {
+ pDesc->Width = m_texture.Desc()->Width;
+ pDesc->Height = m_texture.Desc()->Height;
+ pDesc->Depth = m_texture.Desc()->Depth;
+ pDesc->MipLevels = m_texture.Desc()->MipLevels;
+ pDesc->Format = m_texture.Desc()->Format;
+ pDesc->Usage = m_texture.Desc()->Usage;
+ pDesc->BindFlags = m_texture.Desc()->BindFlags;
+ pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11Texture3D::GetDesc1(D3D11_TEXTURE3D_DESC1* pDesc) {
+ pDesc->Width = m_texture.Desc()->Width;
+ pDesc->Height = m_texture.Desc()->Height;
+ pDesc->Depth = m_texture.Desc()->Depth;
+ pDesc->MipLevels = m_texture.Desc()->MipLevels;
+ pDesc->Format = m_texture.Desc()->Format;
+ pDesc->Usage = m_texture.Desc()->Usage;
+ pDesc->BindFlags = m_texture.Desc()->BindFlags;
+ pDesc->CPUAccessFlags = m_texture.Desc()->CPUAccessFlags;
+ pDesc->MiscFlags = m_texture.Desc()->MiscFlags;
+ }
+
+
+ D3D11CommonTexture* GetCommonTexture(ID3D11Resource* pResource) {
+ D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&dimension);
+
+ switch (dimension) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+ return static_cast<D3D11Texture1D*>(pResource)->GetCommonTexture();
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+ return static_cast<D3D11Texture2D*>(pResource)->GetCommonTexture();
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+ return static_cast<D3D11Texture3D*>(pResource)->GetCommonTexture();
+
+ default:
+ return nullptr;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h
new file mode 100644
index 00000000..80901a85
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_texture.h
@@ -0,0 +1,628 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_texture.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_interfaces.h"
+#include "d3d11_resource.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+ class D3D11GDISurface;
+
+ /**
+ * \brief Image memory mapping mode
+ *
+ * Determines how exactly \c Map will
+ * behave when mapping an image.
+ */
+ enum D3D11_COMMON_TEXTURE_MAP_MODE {
+ D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped
+ D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer
+ D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem
+ D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image
+ };
+
+
+ /**
+ * \brief Common texture description
+ *
+ * Contains all members that can be
+ * defined for 1D, 2D and 3D textures.
+ */
+ struct D3D11_COMMON_TEXTURE_DESC {
+ UINT Width;
+ UINT Height;
+ UINT Depth;
+ UINT MipLevels;
+ UINT ArraySize;
+ DXGI_FORMAT Format;
+ DXGI_SAMPLE_DESC SampleDesc;
+ D3D11_USAGE Usage;
+ UINT BindFlags;
+ UINT CPUAccessFlags;
+ UINT MiscFlags;
+ D3D11_TEXTURE_LAYOUT TextureLayout;
+ };
+
+
+ /**
+ * \brief Packed subresource layout
+ */
+ struct D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT {
+ UINT64 Offset;
+ UINT64 Size;
+ UINT RowPitch;
+ UINT DepthPitch;
+ };
+
+
+ /**
+ * \brief D3D11 common texture object
+ *
+ * This class implements common texture methods and
+ * aims to work around the issue that there are three
+ * different interfaces for basically the same thing.
+ */
+ class D3D11CommonTexture {
+
+ public:
+
+ D3D11CommonTexture(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc,
+ D3D11_RESOURCE_DIMENSION Dimension,
+ DXGI_USAGE DxgiUsage,
+ VkImage vkImage);
+
+ ~D3D11CommonTexture();
+
+ /**
+ * \brief Texture properties
+ *
+ * The returned data can be used to fill in
+ * \c D3D11_TEXTURE2D_DESC and similar structs.
+ * \returns Pointer to texture description
+ */
+ const D3D11_COMMON_TEXTURE_DESC* Desc() const {
+ return &m_desc;
+ }
+
+ /**
+ * \brief Retrieves Vulkan image type
+ *
+ * Returns the image type based on the D3D11 resource
+ * dimension. Also works if there is no actual image.
+ * \returns Vulkan image type
+ */
+ VkImageType GetVkImageType() const {
+ return GetImageTypeFromResourceDim(m_dimension);
+ }
+
+ /**
+ * \brief Computes extent of a given mip level
+ *
+ * This also works for staging resources that have no image.
+ * \param [in] Level Mip level to compute the size of
+ */
+ VkExtent3D MipLevelExtent(uint32_t Level) const {
+ return util::computeMipLevelExtent(
+ VkExtent3D { m_desc.Width, m_desc.Height, m_desc.Depth }, Level);
+ }
+
+ /**
+ * \brief Special DXGI usage flags
+ *
+ * Flags that are set in addition to the bind
+ * flags. Zero for application-created textures.
+ * \returns DXGI usage flags
+ */
+ DXGI_USAGE GetDxgiUsage() const {
+ return m_dxgiUsage;
+ }
+
+ /**
+ * \brief Counts number of subresources
+ * \returns Number of subresources
+ */
+ UINT CountSubresources() const {
+ return m_desc.ArraySize * m_desc.MipLevels;
+ }
+
+ /**
+ * \brief Map mode
+ * \returns Map mode
+ */
+ D3D11_COMMON_TEXTURE_MAP_MODE GetMapMode() const {
+ return m_mapMode;
+ }
+
+ /**
+ * \brief Map type of a given subresource
+ *
+ * \param [in] Subresource Subresource index
+ * \returns Current map mode of that subresource
+ */
+ D3D11_MAP GetMapType(UINT Subresource) const {
+ return Subresource < m_mapTypes.size()
+ ? D3D11_MAP(m_mapTypes[Subresource])
+ : D3D11_MAP(~0u);
+ }
+
+ /**
+ * \brief Sets map type for a given subresource
+ *
+ * \param [in] Subresource The subresource
+ * \param [in] MapType The map type
+ */
+ void SetMapType(UINT Subresource, D3D11_MAP MapType) {
+ if (Subresource < m_mapTypes.size())
+ m_mapTypes[Subresource] = MapType;
+ }
+
+ /**
+ * \brief The DXVK image
+ * \returns The DXVK image
+ */
+ Rc<DxvkImage> GetImage() const {
+ return m_image;
+ }
+
+ /**
+ * \brief Mapped subresource buffer
+ *
+ * \param [in] Subresource Subresource index
+ * \returns Mapped subresource buffer
+ */
+ Rc<DxvkBuffer> GetMappedBuffer(UINT Subresource) const {
+ return Subresource < m_buffers.size()
+ ? m_buffers[Subresource].buffer
+ : Rc<DxvkBuffer>();
+ }
+
+ /**
+ * \brief Discards mapped buffer slice for a given subresource
+ *
+ * \param [in] Subresource Subresource to discard
+ * \returns Newly allocated mapped buffer slice
+ */
+ DxvkBufferSliceHandle DiscardSlice(UINT Subresource) {
+ if (Subresource < m_buffers.size()) {
+ DxvkBufferSliceHandle slice = m_buffers[Subresource].buffer->allocSlice();
+ m_buffers[Subresource].slice = slice;
+ return slice;
+ } else {
+ return DxvkBufferSliceHandle();
+ }
+ }
+
+ /**
+ * \brief Retrieves mapped buffer slice for a given subresource
+ *
+ * \param [in] Subresource Subresource index to query
+ * \returns Currently mapped buffer slice
+ */
+ DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) const {
+ return Subresource < m_buffers.size()
+ ? m_buffers[Subresource].slice
+ : DxvkBufferSliceHandle();
+ }
+
+ /**
+ * \brief Returns underlying packed Vulkan format
+ *
+ * This works even for staging resources that have no image.
+ * Note that for depth-stencil resources, the returned format
+ * may be different from the image format on some systems.
+ * \returns Packed Vulkan format
+ */
+ VkFormat GetPackedFormat() const {
+ return m_packedFormat;
+ }
+
+ /**
+ * \brief Computes pixel offset into mapped buffer
+ *
+ * \param [in] Subresource Subresource index
+ * \param [in] Subresource Plane index
+ * \param [in] Offset Pixel coordinate to compute offset for
+ * \returns Offset into mapped subresource buffer, in pixels
+ */
+ VkDeviceSize ComputeMappedOffset(UINT Subresource, UINT Plane, VkOffset3D Offset) const;
+
+ /**
+ * \brief Computes subresource from the subresource index
+ *
+ * Used by some functions that operate on only
+ * one subresource, such as \c UpdateSubresource.
+ * \param [in] Aspect The image aspect
+ * \param [in] Subresource Subresource index
+ * \returns The Vulkan image subresource
+ */
+ VkImageSubresource GetSubresourceFromIndex(
+ VkImageAspectFlags Aspect,
+ UINT Subresource) const;
+
+ /**
+ * \brief Computes subresource layout for the given subresource
+ *
+ * \param [in] AspectMask The image aspect
+ * \param [in] Subresource Subresource index
+ * \returns Memory layout of the mapped subresource
+ */
+ D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT GetSubresourceLayout(
+ VkImageAspectFlags AspectMask,
+ UINT Subresource) const;
+
+ /**
+ * \brief Format mode
+ *
+ * Determines whether the image is going to
+ * be used as a color image or a depth image.
+ * \returns Format mode
+ */
+ DXGI_VK_FORMAT_MODE GetFormatMode() const;
+
+ /**
+ * \brief Computes plane count
+ *
+ * For non-planar formats, the plane count will be 1.
+ * \returns Image plane count
+ */
+ uint32_t GetPlaneCount() const;
+
+ /**
+ * \brief Checks whether a view can be created for this textue
+ *
+ * View formats are only compatible if they are either identical
+ * or from the same family of typeless formats, where the resource
+ * format must be typeless and the view format must be typed. This
+ * will also check whether the required bind flags are supported.
+ * \param [in] BindFlags Bind flags for the view
+ * \param [in] Format The desired view format
+ * \param [in] Plane Plane slice for planar formats
+ * \returns \c true if the format is compatible
+ */
+ bool CheckViewCompatibility(
+ UINT BindFlags,
+ DXGI_FORMAT Format,
+ UINT Plane) const;
+
+ /**
+ * \brief Normalizes and validates texture description
+ *
+ * Fills in undefined values and validates the texture
+ * parameters. Any error returned by this method should
+ * be forwarded to the application.
+ * \param [in,out] pDesc Texture description
+ * \returns \c S_OK if the parameters are valid
+ */
+ static HRESULT NormalizeTextureProperties(
+ D3D11_COMMON_TEXTURE_DESC* pDesc);
+
+ private:
+
+ struct MappedBuffer {
+ Rc<DxvkBuffer> buffer;
+ DxvkBufferSliceHandle slice;
+ };
+
+ D3D11Device* const m_device;
+ D3D11_RESOURCE_DIMENSION m_dimension;
+ D3D11_COMMON_TEXTURE_DESC m_desc;
+ D3D11_COMMON_TEXTURE_MAP_MODE m_mapMode;
+ DXGI_USAGE m_dxgiUsage;
+ VkFormat m_packedFormat;
+
+ Rc<DxvkImage> m_image;
+ std::vector<MappedBuffer> m_buffers;
+ std::vector<D3D11_MAP> m_mapTypes;
+
+ MappedBuffer CreateMappedBuffer(
+ UINT MipLevel) const;
+
+ BOOL CheckImageSupport(
+ const DxvkImageCreateInfo* pImageInfo,
+ VkImageTiling Tiling) const;
+
+ BOOL CheckFormatFeatureSupport(
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const;
+
+ VkImageUsageFlags EnableMetaCopyUsage(
+ VkFormat Format,
+ VkImageTiling Tiling) const;
+
+ VkImageUsageFlags EnableMetaPackUsage(
+ VkFormat Format,
+ UINT CpuAccess) const;
+
+ D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode(
+ const DxvkImageCreateInfo* pImageInfo) const;
+
+ static VkImageType GetImageTypeFromResourceDim(
+ D3D11_RESOURCE_DIMENSION Dimension);
+
+ static VkImageLayout OptimizeLayout(
+ VkImageUsageFlags Usage);
+
+ };
+
+
+ /**
+ * \brief IDXGISurface implementation for D3D11 textures
+ *
+ * Provides an implementation for 2D textures that
+ * have only one array layer and one mip level.
+ */
+ class D3D11DXGISurface : public IDXGISurface2 {
+
+ public:
+
+ D3D11DXGISurface(
+ ID3D11Resource* pResource,
+ D3D11CommonTexture* pTexture);
+
+ ~D3D11DXGISurface();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown);
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent);
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_SURFACE_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE Map(
+ DXGI_MAPPED_RECT* pLockedRect,
+ UINT MapFlags);
+
+ HRESULT STDMETHODCALLTYPE Unmap();
+
+ HRESULT STDMETHODCALLTYPE GetDC(
+ BOOL Discard,
+ HDC* phdc);
+
+ HRESULT STDMETHODCALLTYPE ReleaseDC(
+ RECT* pDirtyRect);
+
+ HRESULT STDMETHODCALLTYPE GetResource(
+ REFIID riid,
+ void** ppParentResource,
+ UINT* pSubresourceIndex);
+
+ bool isSurfaceCompatible() const;
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11CommonTexture* m_texture;
+ D3D11GDISurface* m_gdiSurface;
+
+ };
+
+
+ /**
+ * \brief Common texture interop class
+ *
+ * Provides access to the underlying Vulkan
+ * texture to external Vulkan libraries.
+ */
+ class D3D11VkInteropSurface : public IDXGIVkInteropSurface {
+
+ public:
+
+ D3D11VkInteropSurface(
+ ID3D11Resource* pResource,
+ D3D11CommonTexture* pTexture);
+
+ ~D3D11VkInteropSurface();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ IDXGIVkInteropDevice** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetVulkanImageInfo(
+ VkImage* pHandle,
+ VkImageLayout* pLayout,
+ VkImageCreateInfo* pInfo);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11CommonTexture* m_texture;
+
+ };
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 1 D
+ class D3D11Texture1D : public D3D11DeviceChild<ID3D11Texture1D> {
+
+ public:
+
+ D3D11Texture1D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc);
+
+ ~D3D11Texture1D();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetType(
+ D3D11_RESOURCE_DIMENSION *pResourceDimension) final;
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority() final;
+
+ void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_TEXTURE1D_DESC *pDesc) final;
+
+ D3D11CommonTexture* GetCommonTexture() {
+ return &m_texture;
+ }
+
+ D3D10Texture1D* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ private:
+
+ D3D11CommonTexture m_texture;
+ D3D11VkInteropSurface m_interop;
+ D3D11DXGISurface m_surface;
+ D3D11DXGIResource m_resource;
+ D3D10Texture1D m_d3d10;
+
+ };
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 2 D
+ class D3D11Texture2D : public D3D11DeviceChild<ID3D11Texture2D1> {
+
+ public:
+
+ D3D11Texture2D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc);
+
+ D3D11Texture2D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc,
+ DXGI_USAGE DxgiUsage,
+ VkImage vkImage);
+
+ ~D3D11Texture2D();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetType(
+ D3D11_RESOURCE_DIMENSION *pResourceDimension) final;
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority() final;
+
+ void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_TEXTURE2D_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D11_TEXTURE2D_DESC1* pDesc) final;
+
+ D3D11CommonTexture* GetCommonTexture() {
+ return &m_texture;
+ }
+
+ D3D10Texture2D* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ private:
+
+ D3D11CommonTexture m_texture;
+ D3D11VkInteropSurface m_interop;
+ D3D11DXGISurface m_surface;
+ D3D11DXGIResource m_resource;
+ D3D10Texture2D m_d3d10;
+
+ };
+
+
+ ///////////////////////////////////////////
+ // D 3 D 1 1 T E X T U R E 3 D
+ class D3D11Texture3D : public D3D11DeviceChild<ID3D11Texture3D1> {
+
+ public:
+
+ D3D11Texture3D(
+ D3D11Device* pDevice,
+ const D3D11_COMMON_TEXTURE_DESC* pDesc);
+
+ ~D3D11Texture3D();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetType(
+ D3D11_RESOURCE_DIMENSION *pResourceDimension) final;
+
+ UINT STDMETHODCALLTYPE GetEvictionPriority() final;
+
+ void STDMETHODCALLTYPE SetEvictionPriority(UINT EvictionPriority) final;
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_TEXTURE3D_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(
+ D3D11_TEXTURE3D_DESC1* pDesc) final;
+
+ D3D11CommonTexture* GetCommonTexture() {
+ return &m_texture;
+ }
+
+ D3D10Texture3D* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ private:
+
+ D3D11CommonTexture m_texture;
+ D3D11VkInteropSurface m_interop;
+ D3D11DXGIResource m_resource;
+ D3D10Texture3D m_d3d10;
+
+ };
+
+
+ /**
+ * \brief Retrieves texture from resource pointer
+ *
+ * \param [in] pResource The resource to query
+ * \returns Pointer to texture info, or \c nullptr
+ */
+ D3D11CommonTexture* GetCommonTexture(
+ ID3D11Resource* pResource);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp
new file mode 100644
index 00000000..d4448c54
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.cpp
@@ -0,0 +1,141 @@
+#include "d3d11_util.h"
+
+namespace dxvk {
+
+ HRESULT DecodeSampleCount(UINT Count, VkSampleCountFlagBits* pCount) {
+ VkSampleCountFlagBits flag;
+
+ switch (Count) {
+ case 1: flag = VK_SAMPLE_COUNT_1_BIT; break;
+ case 2: flag = VK_SAMPLE_COUNT_2_BIT; break;
+ case 4: flag = VK_SAMPLE_COUNT_4_BIT; break;
+ case 8: flag = VK_SAMPLE_COUNT_8_BIT; break;
+ case 16: flag = VK_SAMPLE_COUNT_16_BIT; break;
+ default: return E_INVALIDARG;
+ }
+
+ if (pCount != nullptr) {
+ *pCount = flag;
+ return S_OK;
+ } return S_FALSE;
+ }
+
+
+ VkSamplerAddressMode DecodeAddressMode(
+ D3D11_TEXTURE_ADDRESS_MODE mode) {
+ switch (mode) {
+ case D3D11_TEXTURE_ADDRESS_WRAP:
+ return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+
+ case D3D11_TEXTURE_ADDRESS_MIRROR:
+ return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
+
+ case D3D11_TEXTURE_ADDRESS_CLAMP:
+ return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+
+ case D3D11_TEXTURE_ADDRESS_BORDER:
+ return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+
+ case D3D11_TEXTURE_ADDRESS_MIRROR_ONCE:
+ return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
+
+ default:
+ Logger::err(str::format("D3D11: Unsupported address mode: ", mode));
+ return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ }
+ }
+
+
+ VkCompareOp DecodeCompareOp(D3D11_COMPARISON_FUNC Mode) {
+ switch (Mode) {
+ case D3D11_COMPARISON_NEVER: return VK_COMPARE_OP_NEVER;
+ case D3D11_COMPARISON_LESS: return VK_COMPARE_OP_LESS;
+ case D3D11_COMPARISON_EQUAL: return VK_COMPARE_OP_EQUAL;
+ case D3D11_COMPARISON_LESS_EQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL;
+ case D3D11_COMPARISON_GREATER: return VK_COMPARE_OP_GREATER;
+ case D3D11_COMPARISON_NOT_EQUAL: return VK_COMPARE_OP_NOT_EQUAL;
+ case D3D11_COMPARISON_GREATER_EQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL;
+ case D3D11_COMPARISON_ALWAYS: return VK_COMPARE_OP_ALWAYS;
+ }
+
+ if (Mode != 0) // prevent log spamming when apps use ZeroMemory
+ Logger::err(str::format("D3D11: Unsupported compare op: ", Mode));
+ return VK_COMPARE_OP_NEVER;
+ }
+
+
+ VkConservativeRasterizationModeEXT DecodeConservativeRasterizationMode(
+ D3D11_CONSERVATIVE_RASTERIZATION_MODE Mode) {
+ switch (Mode) {
+ case D3D11_CONSERVATIVE_RASTERIZATION_MODE_OFF:
+ return VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ case D3D11_CONSERVATIVE_RASTERIZATION_MODE_ON:
+ return VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
+ }
+
+ Logger::err(str::format("D3D11: Unsupported conservative raster mode: ", Mode));
+ return VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ }
+
+
+ VkShaderStageFlagBits GetShaderStage(DxbcProgramType ProgramType) {
+ switch (ProgramType) {
+ case DxbcProgramType::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
+ case DxbcProgramType::HullShader: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+ case DxbcProgramType::DomainShader: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+ case DxbcProgramType::GeometryShader: return VK_SHADER_STAGE_GEOMETRY_BIT;
+ case DxbcProgramType::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
+ case DxbcProgramType::ComputeShader: return VK_SHADER_STAGE_COMPUTE_BIT;
+ default: return VkShaderStageFlagBits(0);
+ }
+ }
+
+
+ VkFormatFeatureFlags GetBufferFormatFeatures(UINT BindFlags) {
+ VkFormatFeatureFlags features = 0;
+
+ if (BindFlags & D3D11_BIND_SHADER_RESOURCE)
+ features |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
+ if (BindFlags & D3D11_BIND_UNORDERED_ACCESS)
+ features |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT;
+
+ return features;
+ }
+
+
+ VkFormatFeatureFlags GetImageFormatFeatures(UINT BindFlags) {
+ VkFormatFeatureFlags features = 0;
+
+ if (BindFlags & D3D11_BIND_DEPTH_STENCIL)
+ features |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ if (BindFlags & D3D11_BIND_RENDER_TARGET)
+ features |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+ if (BindFlags & D3D11_BIND_SHADER_RESOURCE)
+ features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+ if (BindFlags & D3D11_BIND_UNORDERED_ACCESS)
+ features |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
+
+ return features;
+ }
+
+
+ VkFormat GetPackedDepthStencilFormat(DXGI_FORMAT Format) {
+ switch (Format) {
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ return VK_FORMAT_D24_UNORM_S8_UINT;
+
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ return VK_FORMAT_D32_SFLOAT_S8_UINT;
+
+ default:
+ return VK_FORMAT_UNDEFINED;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h
new file mode 100644
index 00000000..749dc8be
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_util.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../dxbc/dxbc_util.h"
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ template<typename T>
+ UINT CompactSparseList(T* pData, UINT Mask) {
+ uint32_t count = 0;
+
+ for (uint32_t id : bit::BitMask(Mask))
+ pData[count++] = pData[id];
+
+ return count;
+ }
+
+ HRESULT DecodeSampleCount(
+ UINT Count,
+ VkSampleCountFlagBits* pCount);
+
+ VkSamplerAddressMode DecodeAddressMode(
+ D3D11_TEXTURE_ADDRESS_MODE mode);
+
+ VkCompareOp DecodeCompareOp(
+ D3D11_COMPARISON_FUNC Mode);
+
+ VkConservativeRasterizationModeEXT DecodeConservativeRasterizationMode(
+ D3D11_CONSERVATIVE_RASTERIZATION_MODE Mode);
+
+ VkShaderStageFlagBits GetShaderStage(
+ DxbcProgramType ProgramType);
+
+ VkFormatFeatureFlags GetBufferFormatFeatures(
+ UINT BindFlags);
+
+ VkFormatFeatureFlags GetImageFormatFeatures(
+ UINT BindFlags);
+
+ VkFormat GetPackedDepthStencilFormat(
+ DXGI_FORMAT Format);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp
new file mode 100644
index 00000000..db534659
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.cpp
@@ -0,0 +1,1303 @@
+#include <algorithm>
+
+#include "d3d11_context.h"
+#include "d3d11_context_imm.h"
+#include "d3d11_video.h"
+
+#include <d3d11_video_blit_frag.h>
+#include <d3d11_video_blit_vert.h>
+
+namespace dxvk {
+
+ D3D11VideoProcessorEnumerator::D3D11VideoProcessorEnumerator(
+ D3D11Device* pDevice,
+ const D3D11_VIDEO_PROCESSOR_CONTENT_DESC& Desc)
+ : D3D11DeviceChild<ID3D11VideoProcessorEnumerator>(pDevice),
+ m_desc(Desc) {
+
+ }
+
+
+ D3D11VideoProcessorEnumerator::~D3D11VideoProcessorEnumerator() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11VideoProcessorEnumerator)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11VideoProcessorEnumerator::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorContentDesc(
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pContentDesc) {
+ *pContentDesc = m_desc;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat(
+ DXGI_FORMAT Format,
+ UINT* pFlags) {
+ Logger::err("D3D11VideoProcessorEnumerator::CheckVideoProcessorFormat: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorCaps(
+ D3D11_VIDEO_PROCESSOR_CAPS* pCaps) {
+ Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCaps: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps(
+ UINT TypeIndex,
+ D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS* pCaps) {
+ Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorRateConversionCaps: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorCustomRate(
+ UINT TypeIndex,
+ UINT CustomRateIndex,
+ D3D11_VIDEO_PROCESSOR_CUSTOM_RATE* pRate) {
+ Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorCustomRate: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorEnumerator::GetVideoProcessorFilterRange(
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ D3D11_VIDEO_PROCESSOR_FILTER_RANGE* pRange) {
+ Logger::err("D3D11VideoProcessorEnumerator::GetVideoProcessorFilterRange: Stub");
+ return E_NOTIMPL;
+ }
+
+
+
+
+ D3D11VideoProcessor::D3D11VideoProcessor(
+ D3D11Device* pDevice,
+ D3D11VideoProcessorEnumerator* pEnumerator,
+ UINT RateConversionIndex)
+ : D3D11DeviceChild<ID3D11VideoProcessor>(pDevice),
+ m_enumerator(pEnumerator), m_rateConversionIndex(RateConversionIndex) {
+
+ }
+
+
+ D3D11VideoProcessor::~D3D11VideoProcessor() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessor::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11VideoProcessor)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11VideoProcessor::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessor::GetContentDesc(
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC *pDesc) {
+ m_enumerator->GetVideoProcessorContentDesc(pDesc);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessor::GetRateConversionCaps(
+ D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS *pCaps) {
+ m_enumerator->GetVideoProcessorRateConversionCaps(m_rateConversionIndex, pCaps);
+ }
+
+
+
+
+ D3D11VideoProcessorInputView::D3D11VideoProcessorInputView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC& Desc)
+ : D3D11DeviceChild<ID3D11VideoProcessorInputView>(pDevice),
+ m_resource(pResource), m_desc(Desc) {
+ D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ Rc<DxvkImage> dxvkImage = GetCommonTexture(pResource)->GetImage();
+
+ if (!(dxvkImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
+ DxvkImageCreateInfo info = dxvkImage->info();
+ info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
+ info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ info.shared = VK_FALSE;
+ dxvkImage = m_copy = pDevice->GetDXVKDevice()->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+ DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
+ DXGI_VK_FORMAT_FAMILY formatFamily = pDevice->LookupFamily(resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
+
+ VkImageAspectFlags aspectMask = imageFormatInfo(formatInfo.Format)->aspectMask;
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = formatInfo.Format;
+ viewInfo.swizzle = formatInfo.Swizzle;
+ viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ switch (m_desc.ViewDimension) {
+ case D3D11_VPIV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = m_desc.Texture2D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_RTV_DIMENSION_UNKNOWN:
+ throw DxvkError("Invalid view dimension");
+ }
+
+ m_subresources.aspectMask = aspectMask;
+ m_subresources.baseArrayLayer = viewInfo.minLayer;
+ m_subresources.layerCount = viewInfo.numLayers;
+ m_subresources.mipLevel = viewInfo.minLevel;
+
+ for (uint32_t i = 0; aspectMask && i < m_views.size(); i++) {
+ viewInfo.aspect = vk::getNextAspect(aspectMask);
+
+ if (viewInfo.aspect != VK_IMAGE_ASPECT_COLOR_BIT)
+ viewInfo.format = formatFamily.Formats[i];
+
+ m_views[i] = pDevice->GetDXVKDevice()->createImageView(dxvkImage, viewInfo);
+ }
+
+ m_isYCbCr = IsYCbCrFormat(resourceDesc.Format);
+ }
+
+
+ D3D11VideoProcessorInputView::~D3D11VideoProcessorInputView() {
+
+ }
+
+
+ bool D3D11VideoProcessorInputView::IsYCbCrFormat(DXGI_FORMAT Format) {
+ static const std::array<DXGI_FORMAT, 3> s_formats = {{
+ DXGI_FORMAT_NV12,
+ DXGI_FORMAT_YUY2,
+ DXGI_FORMAT_AYUV,
+ }};
+
+ return std::find(s_formats.begin(), s_formats.end(), Format) != s_formats.end();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorInputView::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11VideoProcessorInputView)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11VideoProcessorInputView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessorInputView::GetResource(
+ ID3D11Resource** ppResource) {
+ *ppResource = m_resource.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessorInputView::GetDesc(
+ D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+
+ D3D11VideoProcessorOutputView::D3D11VideoProcessorOutputView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC& Desc)
+ : D3D11DeviceChild<ID3D11VideoProcessorOutputView>(pDevice),
+ m_resource(pResource), m_desc(Desc) {
+ D3D11_COMMON_RESOURCE_DESC resourceDesc = { };
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
+ resourceDesc.Format, DXGI_VK_FORMAT_MODE_COLOR);
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = formatInfo.Format;
+ viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
+ viewInfo.swizzle = formatInfo.Swizzle;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ switch (m_desc.ViewDimension) {
+ case D3D11_VPOV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = m_desc.Texture2D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_VPOV_DIMENSION_TEXTURE2DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = m_desc.Texture2DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = m_desc.Texture2DArray.FirstArraySlice;
+ viewInfo.numLayers = m_desc.Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_RTV_DIMENSION_UNKNOWN:
+ throw DxvkError("Invalid view dimension");
+ }
+
+ m_view = pDevice->GetDXVKDevice()->createImageView(
+ GetCommonTexture(pResource)->GetImage(), viewInfo);
+ }
+
+
+ D3D11VideoProcessorOutputView::~D3D11VideoProcessorOutputView() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoProcessorOutputView::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11VideoProcessorOutputView)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11VideoProcessorOutputView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessorOutputView::GetResource(
+ ID3D11Resource** ppResource) {
+ *ppResource = m_resource.ref();
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoProcessorOutputView::GetDesc(
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+
+ D3D11VideoContext::D3D11VideoContext(
+ D3D11ImmediateContext* pContext,
+ const Rc<DxvkDevice>& Device)
+ : m_ctx(pContext) {
+ const SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
+ const SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
+
+ const std::array<DxvkResourceSlot, 4> fsResourceSlots = {{
+ { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC },
+ { 1, VK_DESCRIPTOR_TYPE_SAMPLER },
+ { 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
+ { 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
+ }};
+
+ m_vs = Device->createShader(
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0, nullptr, { 0u, 1u },
+ vsCode);
+
+ m_fs = Device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fsResourceSlots.size(),
+ fsResourceSlots.data(),
+ { 1u, 1u, 0u, 0u },
+ fsCode);
+
+ DxvkSamplerCreateInfo samplerInfo;
+ samplerInfo.magFilter = VK_FILTER_LINEAR;
+ samplerInfo.minFilter = VK_FILTER_LINEAR;
+ samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ samplerInfo.mipmapLodBias = 0.0f;
+ samplerInfo.mipmapLodMin = 0.0f;
+ samplerInfo.mipmapLodMax = 0.0f;
+ samplerInfo.useAnisotropy = VK_FALSE;
+ samplerInfo.maxAnisotropy = 1.0f;
+ samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.compareToDepth = VK_FALSE;
+ samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
+ samplerInfo.borderColor = VkClearColorValue();
+ samplerInfo.usePixelCoord = VK_FALSE;
+ m_sampler = Device->createSampler(samplerInfo);
+
+ DxvkBufferCreateInfo bufferInfo;
+ bufferInfo.size = sizeof(UboData);
+ bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_ubo = Device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ D3D11VideoContext::~D3D11VideoContext() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VideoContext::AddRef() {
+ return m_ctx->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE D3D11VideoContext::Release() {
+ return m_ctx->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_ctx->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData) {
+ return m_ctx->GetPrivateData(Name, pDataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) {
+ return m_ctx->SetPrivateData(Name, DataSize, pData);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown) {
+ return m_ctx->SetPrivateDataInterface(Name, pUnknown);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::GetDevice(
+ ID3D11Device** ppDevice) {
+ return m_ctx->GetDevice(ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetDecoderBuffer(
+ ID3D11VideoDecoder* pDecoder,
+ D3D11_VIDEO_DECODER_BUFFER_TYPE Type,
+ UINT* BufferSize,
+ void** ppBuffer) {
+ Logger::err("D3D11VideoContext::GetDecoderBuffer: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::ReleaseDecoderBuffer(
+ ID3D11VideoDecoder* pDecoder,
+ D3D11_VIDEO_DECODER_BUFFER_TYPE Type) {
+ Logger::err("D3D11VideoContext::ReleaseDecoderBuffer: Stub");
+ return E_NOTIMPL;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderBeginFrame(
+ ID3D11VideoDecoder* pDecoder,
+ ID3D11VideoDecoderOutputView* pView,
+ UINT KeySize,
+ const void* pKey) {
+ Logger::err("D3D11VideoContext::DecoderBeginFrame: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderEndFrame(
+ ID3D11VideoDecoder* pDecoder) {
+ Logger::err("D3D11VideoContext::DecoderEndFrame: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::SubmitDecoderBuffers(
+ ID3D11VideoDecoder* pDecoder,
+ UINT BufferCount,
+ const D3D11_VIDEO_DECODER_BUFFER_DESC* pBufferDescs) {
+ Logger::err("D3D11VideoContext::SubmitDecoderBuffers: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::DecoderExtension(
+ ID3D11VideoDecoder* pDecoder,
+ const D3D11_VIDEO_DECODER_EXTENSION* pExtension) {
+ Logger::err("D3D11VideoContext::DecoderExtension: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputTargetRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable,
+ const RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+ state->outputTargetRectEnabled = Enable;
+
+ if (Enable)
+ state->outputTargetRect = *pRect;
+
+ static bool errorShown = false;
+
+ if (!std::exchange(errorShown, true))
+ Logger::err("D3D11VideoContext::VideoProcessorSetOutputTargetRect: Stub.");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputBackgroundColor(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL YCbCr,
+ const D3D11_VIDEO_COLOR* pColor) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+ state->outputBackgroundColorIsYCbCr = YCbCr;
+ state->outputBackgroundColor = *pColor;
+
+ static bool errorShown = false;
+
+ if (!std::exchange(errorShown, true))
+ Logger::err("D3D11VideoContext::VideoProcessorSetOutputBackgroundColor: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+ state->outputColorSpace = *pColorSpace;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputAlphaFillMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE AlphaFillMode,
+ UINT StreamIndex) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetOutputAlphaFillMode: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputConstriction(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable,
+ SIZE Size) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetOutputConstriction: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputStereoMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+ state->outputStereoModeEnabled = Enable;
+
+ if (Enable)
+ Logger::err("D3D11VideoContext: Stereo output not supported");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetOutputExtension: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamFrameFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_FRAME_FORMAT Format) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->frameFormat = Format;
+
+ if (Format != D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE)
+ Logger::err(str::format("D3D11VideoContext: Unsupported frame format: ", Format));
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->colorSpace = *pColorSpace;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamOutputRate(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_OUTPUT_RATE Rate,
+ BOOL Repeat,
+ const DXGI_RATIONAL* CustomRate) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamOutputRate: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamSourceRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->srcRectEnabled = Enable;
+
+ if (Enable)
+ state->srcRect = *pRect;
+
+ static bool errorShown = false;
+
+ if (!std::exchange(errorShown, true))
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamSourceRect: Stub.");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamDestRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->dstRectEnabled = Enable;
+
+ if (Enable)
+ state->dstRect = *pRect;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamAlpha(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ FLOAT Alpha) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamAlpha: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamPalette(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ UINT EntryCount,
+ const UINT* pEntries) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamPalette: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamPixelAspectRatio(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const DXGI_RATIONAL* pSrcAspectRatio,
+ const DXGI_RATIONAL* pDstAspectRatio) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamPixelAspectRatio: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamLumaKey(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ FLOAT Lower,
+ FLOAT Upper) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamLumaKey: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamStereoFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ D3D11_VIDEO_PROCESSOR_STEREO_FORMAT Format,
+ BOOL LeftViewFrame0,
+ BOOL BaseViewFrame0,
+ D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE FlipMode,
+ int MonoOffset) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamStereoFormat: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamAutoProcessingMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->autoProcessingEnabled = Enable;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamFilter(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ BOOL Enable,
+ int Level) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamFilter: Stub");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::VideoProcessorSetStreamExtension: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetStreamRotation(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ D3D11_VIDEO_PROCESSOR_ROTATION Rotation) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ state->rotationEnabled = Enable;
+ state->rotation = Rotation;
+
+ if (Enable && Rotation != D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY)
+ Logger::err(str::format("D3D11VideoContext: Unsupported rotation: ", Rotation));
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputTargetRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled,
+ RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+
+ if (pEnabled)
+ *pEnabled = state->outputTargetRectEnabled;
+
+ if (pRect)
+ *pRect = state->outputTargetRect;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputBackgroundColor(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pYCbCr,
+ D3D11_VIDEO_COLOR* pColor) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+
+ if (pYCbCr)
+ *pYCbCr = state->outputBackgroundColorIsYCbCr;
+
+ if (pColor)
+ *pColor = state->outputBackgroundColor;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+
+ if (pColorSpace)
+ *pColorSpace = state->outputColorSpace;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputAlphaFillMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE* pAlphaFillMode,
+ UINT* pStreamIndex) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetOutputAlphaFillMode: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputConstriction(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled,
+ SIZE* pSize) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetOutputConstriction: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputStereoMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetState();
+
+ if (pEnabled)
+ *pEnabled = state->outputStereoModeEnabled;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetOutputExtension: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamFrameFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_FRAME_FORMAT* pFormat) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ if (pFormat)
+ *pFormat = state->frameFormat;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ if (pColorSpace)
+ *pColorSpace = state->colorSpace;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamOutputRate(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_OUTPUT_RATE* pRate,
+ BOOL* pRepeat,
+ DXGI_RATIONAL* pCustomRate) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamOutputRate: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamSourceRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ if (pEnabled)
+ *pEnabled = state->srcRectEnabled;
+
+ if (pRect)
+ *pRect = state->srcRect;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamDestRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ RECT* pRect) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ if (pEnabled)
+ *pEnabled = state->dstRectEnabled;
+
+ if (pRect)
+ *pRect = state->dstRect;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamAlpha(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ FLOAT* pAlpha) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamAlpha: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamPalette(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ UINT EntryCount,
+ UINT* pEntries) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamPalette: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamPixelAspectRatio(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ DXGI_RATIONAL* pSrcAspectRatio,
+ DXGI_RATIONAL* pDstAspectRatio) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamPixelAspectRatio: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamLumaKey(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ FLOAT* pLower,
+ FLOAT* pUpper) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamLumaKey: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamStereoFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ D3D11_VIDEO_PROCESSOR_STEREO_FORMAT* pFormat,
+ BOOL* pLeftViewFrame0,
+ BOOL* pBaseViewFrame0,
+ D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE* pFlipMode,
+ int* pMonoOffset) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamStereoFormat: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamAutoProcessingMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ *pEnabled = state->autoProcessingEnabled;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamFilter(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ BOOL* pEnabled,
+ int* pLevel) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamFilter: Stub");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::VideoProcessorGetStreamExtension: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetStreamRotation(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnable,
+ D3D11_VIDEO_PROCESSOR_ROTATION* pRotation) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto state = static_cast<D3D11VideoProcessor*>(pVideoProcessor)->GetStreamState(StreamIndex);
+
+ if (!state)
+ return;
+
+ if (pEnable)
+ *pEnable = state->rotationEnabled;
+
+ if (pRotation)
+ *pRotation = state->rotation;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorBlt(
+ ID3D11VideoProcessor* pVideoProcessor,
+ ID3D11VideoProcessorOutputView* pOutputView,
+ UINT FrameIdx,
+ UINT StreamCount,
+ const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) {
+ D3D10DeviceLock lock = m_ctx->LockContext();
+
+ auto videoProcessor = static_cast<D3D11VideoProcessor*>(pVideoProcessor);
+ bool hasStreamsEnabled = false;
+
+ // Resetting and restoring all context state incurs
+ // a lot of overhead, so only do it as necessary
+ for (uint32_t i = 0; i < StreamCount; i++) {
+ auto streamState = videoProcessor->GetStreamState(i);
+
+ if (!pStreams[i].Enable || !streamState)
+ continue;
+
+ if (!hasStreamsEnabled) {
+ m_ctx->ResetState();
+ BindOutputView(pOutputView);
+ hasStreamsEnabled = true;
+ }
+
+ BlitStream(streamState, &pStreams[i]);
+ }
+
+ if (hasStreamsEnabled)
+ m_ctx->RestoreState();
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::NegotiateCryptoSessionKeyExchange(
+ ID3D11CryptoSession* pSession,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::NegotiateCryptoSessionKeyExchange: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::EncryptionBlt(
+ ID3D11CryptoSession* pSession,
+ ID3D11Texture2D* pSrcSurface,
+ ID3D11Texture2D* pDstSurface,
+ UINT IVSize,
+ void* pIV) {
+ Logger::err("D3D11VideoContext::EncryptionBlt: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::DecryptionBlt(
+ ID3D11CryptoSession* pSession,
+ ID3D11Texture2D* pSrcSurface,
+ ID3D11Texture2D* pDstSurface,
+ D3D11_ENCRYPTED_BLOCK_INFO* pBlockInfo,
+ UINT KeySize,
+ const void* pKey,
+ UINT IVSize,
+ void* pIV) {
+ Logger::err("D3D11VideoContext::DecryptionBlt: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::StartSessionKeyRefresh(
+ ID3D11CryptoSession* pSession,
+ UINT RandomNumberSize,
+ void* pRandomNumber) {
+ Logger::err("D3D11VideoContext::StartSessionKeyRefresh: Stub");
+ }
+
+
+ void STDMETHODCALLTYPE D3D11VideoContext::FinishSessionKeyRefresh(
+ ID3D11CryptoSession* pSession) {
+ Logger::err("D3D11VideoContext::FinishSessionKeyRefresh: Stub");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::GetEncryptionBltKey(
+ ID3D11CryptoSession* pSession,
+ UINT KeySize,
+ void* pKey) {
+ Logger::err("D3D11VideoContext::GetEncryptionBltKey: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::NegotiateAuthenticatedChannelKeyExchange(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT DataSize,
+ void* pData) {
+ Logger::err("D3D11VideoContext::NegotiateAuthenticatedChannelKeyExchange: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::QueryAuthenticatedChannel(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT InputSize,
+ const void* pInput,
+ UINT OutputSize,
+ void* pOutput) {
+ Logger::err("D3D11VideoContext::QueryAuthenticatedChannel: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11VideoContext::ConfigureAuthenticatedChannel(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT InputSize,
+ const void* pInput,
+ D3D11_AUTHENTICATED_CONFIGURE_OUTPUT* pOutput) {
+ Logger::err("D3D11VideoContext::ConfigureAuthenticatedChannel: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ void D3D11VideoContext::ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]) {
+ float result[3][4];
+
+ for (uint32_t i = 0; i < 3; i++) {
+ for (uint32_t j = 0; j < 4; j++) {
+ result[i][j] = pSrc[i][0] * pDst[0][j]
+ + pSrc[i][1] * pDst[1][j]
+ + pSrc[i][2] * pDst[2][j]
+ + pSrc[i][3] * float(j == 3);
+ }
+ }
+
+ memcpy(pDst, &result[0][0], sizeof(result));
+ }
+
+
+ void D3D11VideoContext::ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709) {
+ static const float pretransform[3][4] = {
+ { 0.0f, 1.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1.0f, -0.5f },
+ { 1.0f, 0.0f, 0.0f, -0.5f },
+ };
+
+ static const float bt601[3][4] = {
+ { 1.0f, 0.000000f, 1.402000f, 0.0f },
+ { 1.0f, -0.344136f, -0.714136f, 0.0f },
+ { 1.0f, 1.772000f, 0.000000f, 0.0f },
+ };
+
+ static const float bt709[3][4] = {
+ { 1.0f, 0.000000f, 1.574800f, 0.0f },
+ { 1.0f, -0.187324f, -0.468124f, 0.0f },
+ { 1.0f, 1.855600f, 0.000000f, 0.0f },
+ };
+
+ ApplyColorMatrix(pColorMatrix, pretransform);
+ ApplyColorMatrix(pColorMatrix, UseBt709 ? bt709 : bt601);
+ }
+
+
+ void D3D11VideoContext::BindOutputView(
+ ID3D11VideoProcessorOutputView* pOutputView) {
+ auto dxvkView = static_cast<D3D11VideoProcessorOutputView*>(pOutputView)->GetView();
+
+ m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) {
+ DxvkRenderTargets rt;
+ rt.color[0].view = cView;
+ rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ ctx->bindRenderTargets(rt);
+ ctx->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vs);
+ ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_fs);
+ ctx->bindResourceBuffer(0, DxvkBufferSlice(m_ubo));
+
+ DxvkInputAssemblyState iaState;
+ iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ iaState.primitiveRestart = VK_FALSE;
+ iaState.patchVertexCount = 0;
+ ctx->setInputAssemblyState(iaState);
+ });
+
+ VkExtent3D viewExtent = dxvkView->mipLevelExtent(0);
+ m_dstExtent = { viewExtent.width, viewExtent.height };
+ }
+
+
+ void D3D11VideoContext::BlitStream(
+ const D3D11VideoProcessorStreamState* pStreamState,
+ const D3D11_VIDEO_PROCESSOR_STREAM* pStream) {
+ if (pStream->PastFrames || pStream->FutureFrames)
+ Logger::err("D3D11VideoContext: Ignoring non-zero PastFrames and FutureFrames");
+
+ if (pStream->OutputIndex)
+ Logger::err("D3D11VideoContext: Ignoring non-zero OutputIndex");
+
+ if (pStream->InputFrameOrField)
+ Logger::err("D3D11VideoContext: Ignoring non-zero InputFrameOrField");
+
+ auto view = static_cast<D3D11VideoProcessorInputView*>(pStream->pInputSurface);
+
+ if (view->NeedsCopy()) {
+ m_ctx->EmitCs([
+ cDstImage = view->GetShadowCopy(),
+ cSrcImage = view->GetImage(),
+ cSrcLayers = view->GetImageSubresources()
+ ] (DxvkContext* ctx) {
+ VkImageSubresourceLayers cDstLayers;
+ cDstLayers.aspectMask = cSrcLayers.aspectMask;
+ cDstLayers.baseArrayLayer = 0;
+ cDstLayers.layerCount = cSrcLayers.layerCount;
+ cDstLayers.mipLevel = cSrcLayers.mipLevel;
+
+ ctx->copyImage(
+ cDstImage, cDstLayers, VkOffset3D(),
+ cSrcImage, cSrcLayers, VkOffset3D(),
+ cDstImage->info().extent);
+ });
+ }
+
+ m_ctx->EmitCs([this,
+ cStreamState = *pStreamState,
+ cViews = view->GetViews(),
+ cIsYCbCr = view->IsYCbCr()
+ ] (DxvkContext* ctx) {
+ VkViewport viewport;
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = float(m_dstExtent.width);
+ viewport.height = float(m_dstExtent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { 0, 0 };
+ scissor.extent = m_dstExtent;
+
+ if (cStreamState.dstRectEnabled) {
+ viewport.x = float(cStreamState.dstRect.left);
+ viewport.y = float(cStreamState.dstRect.top);
+ viewport.width = float(cStreamState.dstRect.right) - viewport.x;
+ viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
+ }
+
+ UboData uboData = { };
+ uboData.colorMatrix[0][0] = 1.0f;
+ uboData.colorMatrix[1][1] = 1.0f;
+ uboData.colorMatrix[2][2] = 1.0f;
+ uboData.coordMatrix[0][0] = 1.0f;
+ uboData.coordMatrix[1][1] = 1.0f;
+ uboData.yMin = 0.0f;
+ uboData.yMax = 1.0f;
+
+ if (cIsYCbCr)
+ ApplyYCbCrMatrix(uboData.colorMatrix, cStreamState.colorSpace.YCbCr_Matrix);
+
+ if (cStreamState.colorSpace.Nominal_Range) {
+ uboData.yMin = 0.0627451f;
+ uboData.yMax = 0.9215686f;
+ }
+
+ DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice();
+ memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData));
+
+ ctx->invalidateBuffer(m_ubo, uboSlice);
+ ctx->setViewports(1, &viewport, &scissor);
+ ctx->bindResourceSampler(1, m_sampler);
+
+ for (uint32_t i = 0; i < cViews.size(); i++)
+ ctx->bindResourceView(2 + i, cViews[i], nullptr);
+
+ ctx->draw(3, 1, 0, 0);
+ });
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h
new file mode 100644
index 00000000..85979eb8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_video.h
@@ -0,0 +1,612 @@
+#pragma once
+
+#include "d3d11_device.h"
+
+namespace dxvk {
+
+ static constexpr uint32_t D3D11_VK_VIDEO_STREAM_COUNT = 8;
+
+ class D3D11VideoProcessorEnumerator : public D3D11DeviceChild<ID3D11VideoProcessorEnumerator> {
+
+ public:
+
+ D3D11VideoProcessorEnumerator(
+ D3D11Device* pDevice,
+ const D3D11_VIDEO_PROCESSOR_CONTENT_DESC& Desc);
+
+ ~D3D11VideoProcessorEnumerator();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetVideoProcessorContentDesc(
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC* pContentDesc);
+
+ HRESULT STDMETHODCALLTYPE CheckVideoProcessorFormat(
+ DXGI_FORMAT Format,
+ UINT* pFlags);
+
+ HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps(
+ D3D11_VIDEO_PROCESSOR_CAPS* pCaps);
+
+ HRESULT STDMETHODCALLTYPE GetVideoProcessorRateConversionCaps(
+ UINT TypeIndex,
+ D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS* pCaps);
+
+ HRESULT STDMETHODCALLTYPE GetVideoProcessorCustomRate(
+ UINT TypeIndex,
+ UINT CustomRateIndex,
+ D3D11_VIDEO_PROCESSOR_CUSTOM_RATE* pRate);
+
+ HRESULT STDMETHODCALLTYPE GetVideoProcessorFilterRange(
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ D3D11_VIDEO_PROCESSOR_FILTER_RANGE* pRange);
+
+ private:
+
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC m_desc;
+
+ };
+
+
+ struct D3D11VideoProcessorStreamState {
+ BOOL autoProcessingEnabled = TRUE;
+ BOOL dstRectEnabled = FALSE;
+ BOOL srcRectEnabled = FALSE;
+ BOOL rotationEnabled = FALSE;
+ RECT dstRect = RECT();
+ RECT srcRect = RECT();
+ D3D11_VIDEO_FRAME_FORMAT frameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
+ D3D11_VIDEO_PROCESSOR_ROTATION rotation = D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY;
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE();
+ };
+
+ struct D3D11VideoProcessorState {
+ BOOL outputStereoModeEnabled = FALSE;
+ BOOL outputBackgroundColorIsYCbCr = FALSE;
+ BOOL outputTargetRectEnabled = FALSE;
+ RECT outputTargetRect = RECT();
+ D3D11_VIDEO_COLOR outputBackgroundColor = D3D11_VIDEO_COLOR();
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE();
+ };
+
+ class D3D11VideoProcessor : public D3D11DeviceChild<ID3D11VideoProcessor> {
+
+ public:
+
+ D3D11VideoProcessor(
+ D3D11Device* pDevice,
+ D3D11VideoProcessorEnumerator* pEnumerator,
+ UINT RateConversionIndex);
+
+ ~D3D11VideoProcessor();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE GetContentDesc(
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC *pDesc);
+
+ void STDMETHODCALLTYPE GetRateConversionCaps(
+ D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS *pCaps);
+
+ D3D11VideoProcessorState* GetState() {
+ return &m_state;
+ }
+
+ D3D11VideoProcessorStreamState* GetStreamState(UINT StreamIndex) {
+ return StreamIndex < D3D11_VK_VIDEO_STREAM_COUNT
+ ? &m_streams[StreamIndex]
+ : nullptr;
+ }
+
+ private:
+
+ D3D11VideoProcessorEnumerator* m_enumerator;
+ uint32_t m_rateConversionIndex;
+ D3D11VideoProcessorState m_state;
+ D3D11VideoProcessorStreamState m_streams[D3D11_VK_VIDEO_STREAM_COUNT];
+
+ };
+
+
+
+ class D3D11VideoProcessorInputView : public D3D11DeviceChild<ID3D11VideoProcessorInputView> {
+
+ public:
+
+ D3D11VideoProcessorInputView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC& Desc);
+
+ ~D3D11VideoProcessorInputView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE GetResource(
+ ID3D11Resource** ppResource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC* pDesc);
+
+ const bool IsYCbCr() const {
+ return m_isYCbCr;
+ }
+
+ const bool NeedsCopy() const {
+ return m_copy != nullptr;
+ }
+
+ Rc<DxvkImage> GetImage() const {
+ return GetCommonTexture(m_resource.ptr())->GetImage();
+ }
+
+ VkImageSubresourceLayers GetImageSubresources() const {
+ return m_subresources;
+ }
+
+ Rc<DxvkImage> GetShadowCopy() const {
+ return m_copy;
+ }
+
+ std::array<Rc<DxvkImageView>, 2> GetViews() const {
+ return m_views;
+ }
+
+ private:
+
+ Com<ID3D11Resource> m_resource;
+ D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC m_desc;
+ VkImageSubresourceLayers m_subresources;
+ Rc<DxvkImage> m_copy;
+ std::array<Rc<DxvkImageView>, 2> m_views;
+ bool m_isYCbCr = false;
+
+ static bool IsYCbCrFormat(DXGI_FORMAT Format);
+
+ };
+
+
+
+ class D3D11VideoProcessorOutputView : public D3D11DeviceChild<ID3D11VideoProcessorOutputView> {
+
+ public:
+
+ D3D11VideoProcessorOutputView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC& Desc);
+
+ ~D3D11VideoProcessorOutputView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE GetResource(
+ ID3D11Resource** ppResource);
+
+ void STDMETHODCALLTYPE GetDesc(
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc);
+
+ Rc<DxvkImageView> GetView() const {
+ return m_view;
+ }
+
+ private:
+
+ Com<ID3D11Resource> m_resource;
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC m_desc;
+ Rc<DxvkImageView> m_view;
+
+ };
+
+
+
+ class D3D11VideoContext : public ID3D11VideoContext {
+
+ public:
+
+ D3D11VideoContext(
+ D3D11ImmediateContext* pContext,
+ const Rc<DxvkDevice>& Device);
+
+ ~D3D11VideoContext();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData);
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown);
+
+ void STDMETHODCALLTYPE GetDevice(
+ ID3D11Device** ppDevice);
+
+ HRESULT STDMETHODCALLTYPE GetDecoderBuffer(
+ ID3D11VideoDecoder* pDecoder,
+ D3D11_VIDEO_DECODER_BUFFER_TYPE Type,
+ UINT* BufferSize,
+ void** ppBuffer);
+
+ HRESULT STDMETHODCALLTYPE ReleaseDecoderBuffer(
+ ID3D11VideoDecoder* pDecoder,
+ D3D11_VIDEO_DECODER_BUFFER_TYPE Type);
+
+ HRESULT STDMETHODCALLTYPE DecoderBeginFrame(
+ ID3D11VideoDecoder* pDecoder,
+ ID3D11VideoDecoderOutputView* pView,
+ UINT KeySize,
+ const void* pKey);
+
+ HRESULT STDMETHODCALLTYPE DecoderEndFrame(
+ ID3D11VideoDecoder* pDecoder);
+
+ HRESULT STDMETHODCALLTYPE SubmitDecoderBuffers(
+ ID3D11VideoDecoder* pDecoder,
+ UINT BufferCount,
+ const D3D11_VIDEO_DECODER_BUFFER_DESC* pBufferDescs);
+
+ HRESULT STDMETHODCALLTYPE DecoderExtension(
+ ID3D11VideoDecoder* pDecoder,
+ const D3D11_VIDEO_DECODER_EXTENSION* pExtension);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputTargetRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable,
+ const RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputBackgroundColor(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL YCbCr,
+ const D3D11_VIDEO_COLOR* pColor);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputAlphaFillMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE AlphaFillMode,
+ UINT StreamIndex);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputConstriction(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable,
+ SIZE Size);
+
+ void STDMETHODCALLTYPE VideoProcessorSetOutputStereoMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL Enable);
+
+ HRESULT STDMETHODCALLTYPE VideoProcessorSetOutputExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamFrameFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_FRAME_FORMAT Format);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamOutputRate(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_OUTPUT_RATE Rate,
+ BOOL Repeat,
+ const DXGI_RATIONAL* CustomRate);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamSourceRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamDestRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamAlpha(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ FLOAT Alpha);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamPalette(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ UINT EntryCount,
+ const UINT* pEntries);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamPixelAspectRatio(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ const DXGI_RATIONAL* pSrcAspectRatio,
+ const DXGI_RATIONAL* pDstAspectRatio);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamLumaKey(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ FLOAT Lower,
+ FLOAT Upper);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamStereoFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ D3D11_VIDEO_PROCESSOR_STEREO_FORMAT Format,
+ BOOL LeftViewFrame0,
+ BOOL BaseViewFrame0,
+ D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE FlipMode,
+ int MonoOffset);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamAutoProcessingMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamFilter(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ BOOL Enable,
+ int Level);
+
+ HRESULT STDMETHODCALLTYPE VideoProcessorSetStreamExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData);
+
+ void STDMETHODCALLTYPE VideoProcessorSetStreamRotation(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL Enable,
+ D3D11_VIDEO_PROCESSOR_ROTATION Rotation);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputTargetRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled,
+ RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputBackgroundColor(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pYCbCr,
+ D3D11_VIDEO_COLOR* pColor);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputAlphaFillMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE* pAlphaFillMode,
+ UINT* pStreamIndex);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputConstriction(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled,
+ SIZE* pSize);
+
+ void STDMETHODCALLTYPE VideoProcessorGetOutputStereoMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ BOOL* pEnabled);
+
+ HRESULT STDMETHODCALLTYPE VideoProcessorGetOutputExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamFrameFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_FRAME_FORMAT* pFormat);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamColorSpace(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamOutputRate(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_OUTPUT_RATE* pRate,
+ BOOL* pRepeat,
+ DXGI_RATIONAL* pCustomRate);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamSourceRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamDestRect(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ RECT* pRect);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamAlpha(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ FLOAT* pAlpha);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamPalette(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ UINT EntryCount,
+ UINT* pEntries);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamPixelAspectRatio(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ DXGI_RATIONAL* pSrcAspectRatio,
+ DXGI_RATIONAL* pDstAspectRatio);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamLumaKey(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ FLOAT* pLower,
+ FLOAT* pUpper);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamStereoFormat(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled,
+ D3D11_VIDEO_PROCESSOR_STEREO_FORMAT* pFormat,
+ BOOL* pLeftViewFrame0,
+ BOOL* pBaseViewFrame0,
+ D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE* pFlipMode,
+ int* pMonoOffset);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamAutoProcessingMode(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnabled);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamFilter(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ D3D11_VIDEO_PROCESSOR_FILTER Filter,
+ BOOL* pEnabled,
+ int* pLevel);
+
+ HRESULT STDMETHODCALLTYPE VideoProcessorGetStreamExtension(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ const GUID* pExtensionGuid,
+ UINT DataSize,
+ void* pData);
+
+ void STDMETHODCALLTYPE VideoProcessorGetStreamRotation(
+ ID3D11VideoProcessor* pVideoProcessor,
+ UINT StreamIndex,
+ BOOL* pEnable,
+ D3D11_VIDEO_PROCESSOR_ROTATION* pRotation);
+
+ HRESULT STDMETHODCALLTYPE VideoProcessorBlt(
+ ID3D11VideoProcessor* pVideoProcessor,
+ ID3D11VideoProcessorOutputView* pOutputView,
+ UINT FrameIdx,
+ UINT StreamCount,
+ const D3D11_VIDEO_PROCESSOR_STREAM* pStreams);
+
+ HRESULT STDMETHODCALLTYPE NegotiateCryptoSessionKeyExchange(
+ ID3D11CryptoSession* pSession,
+ UINT DataSize,
+ void* pData);
+
+ void STDMETHODCALLTYPE EncryptionBlt(
+ ID3D11CryptoSession* pSession,
+ ID3D11Texture2D* pSrcSurface,
+ ID3D11Texture2D* pDstSurface,
+ UINT IVSize,
+ void* pIV);
+
+ void STDMETHODCALLTYPE DecryptionBlt(
+ ID3D11CryptoSession* pSession,
+ ID3D11Texture2D* pSrcSurface,
+ ID3D11Texture2D* pDstSurface,
+ D3D11_ENCRYPTED_BLOCK_INFO* pBlockInfo,
+ UINT KeySize,
+ const void* pKey,
+ UINT IVSize,
+ void* pIV);
+
+ void STDMETHODCALLTYPE StartSessionKeyRefresh(
+ ID3D11CryptoSession* pSession,
+ UINT RandomNumberSize,
+ void* pRandomNumber);
+
+ void STDMETHODCALLTYPE FinishSessionKeyRefresh(
+ ID3D11CryptoSession* pSession);
+
+ HRESULT STDMETHODCALLTYPE GetEncryptionBltKey(
+ ID3D11CryptoSession* pSession,
+ UINT KeySize,
+ void* pKey);
+
+ HRESULT STDMETHODCALLTYPE NegotiateAuthenticatedChannelKeyExchange(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT DataSize,
+ void* pData);
+
+ HRESULT STDMETHODCALLTYPE QueryAuthenticatedChannel(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT InputSize,
+ const void* pInput,
+ UINT OutputSize,
+ void* pOutput);
+
+ HRESULT STDMETHODCALLTYPE ConfigureAuthenticatedChannel(
+ ID3D11AuthenticatedChannel* pChannel,
+ UINT InputSize,
+ const void* pInput,
+ D3D11_AUTHENTICATED_CONFIGURE_OUTPUT* pOutput);
+
+ private:
+
+ struct alignas(16) UboData {
+ float colorMatrix[3][4];
+ float coordMatrix[3][2];
+ float yMin, yMax;
+ };
+
+ D3D11ImmediateContext* m_ctx;
+
+ Rc<DxvkSampler> m_sampler;
+ Rc<DxvkShader> m_vs;
+ Rc<DxvkShader> m_fs;
+ Rc<DxvkBuffer> m_ubo;
+
+ VkExtent2D m_dstExtent = { 0u, 0u };
+
+ void ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]);
+
+ void ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709);
+
+ void BindOutputView(
+ ID3D11VideoProcessorOutputView* pOutputView);
+
+ void BlitStream(
+ const D3D11VideoProcessorStreamState* pStreamState,
+ const D3D11_VIDEO_PROCESSOR_STREAM* pStream);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h
new file mode 100644
index 00000000..50fcef10
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "d3d11_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Buffer view info
+ *
+ * Stores the byte range covered
+ * by a buffer view.
+ */
+ struct D3D11_VK_BUFFER_VIEW_INFO {
+ VkDeviceSize Offset;
+ VkDeviceSize Length;
+ };
+
+ /**
+ * \brief Image view info
+ *
+ * Stores the subresource range
+ * covered by an image view.
+ */
+ struct D3D11_VK_IMAGE_VIEW_INFO {
+ VkImageAspectFlags Aspects;
+ uint32_t MinLevel;
+ uint32_t MinLayer;
+ uint32_t NumLevels;
+ uint32_t NumLayers;
+ };
+
+ /**
+ * \brief Common view info
+ *
+ * Stores a pointer to the resource as
+ * well as the type-specific range that
+ * is affected by the view.
+ */
+ struct D3D11_VK_VIEW_INFO {
+ ID3D11Resource* pResource;
+ D3D11_RESOURCE_DIMENSION Dimension;
+ UINT BindFlags;
+ union {
+ D3D11_VK_BUFFER_VIEW_INFO Buffer;
+ D3D11_VK_IMAGE_VIEW_INFO Image;
+ };
+ };
+
+ /**
+ * \brief Checks whether two views overlap
+ *
+ * Overlapping views may conflict in case
+ * one or both views are used for writing.
+ * \param [in] a First view to check
+ * \param [in] b Second view to check
+ * \returns \c true if the views overlap
+ */
+ inline bool CheckViewOverlap(const D3D11_VK_VIEW_INFO& a, const D3D11_VK_VIEW_INFO b) {
+ if (likely(a.pResource != b.pResource))
+ return false;
+
+ if (a.Dimension == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ // Just check whether the buffer ranges overlap
+ return (a.Buffer.Offset < b.Buffer.Offset + b.Buffer.Length)
+ && (a.Buffer.Offset + a.Buffer.Length > b.Buffer.Offset);
+ } else {
+ // Check whether the subresource ranges overlap
+ return (a.Image.Aspects & b.Image.Aspects)
+ && (a.Image.MinLevel < b.Image.MinLevel + b.Image.NumLevels)
+ && (a.Image.MinLayer < b.Image.MinLayer + b.Image.NumLayers)
+ && (a.Image.MinLevel + a.Image.NumLevels > b.Image.MinLevel)
+ && (a.Image.MinLayer + a.Image.NumLayers > b.Image.MinLayer);
+ }
+ }
+
+ template<typename T1, typename T2>
+ bool CheckViewOverlap(const T1* a, const T2* b) {
+ return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo());
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp
new file mode 100644
index 00000000..f0520c64
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.cpp
@@ -0,0 +1,280 @@
+#include "d3d11_device.h"
+#include "d3d11_buffer.h"
+#include "d3d11_resource.h"
+#include "d3d11_texture.h"
+#include "d3d11_view_dsv.h"
+
+namespace dxvk {
+
+ D3D11DepthStencilView::D3D11DepthStencilView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc)
+ : D3D11DeviceChild<ID3D11DepthStencilView>(pDevice),
+ m_resource(pResource), m_desc(*pDesc), m_d3d10(this) {
+ ResourceAddRefPrivate(m_resource);
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_DEPTH).Format;
+ viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
+ viewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_DSV_DIMENSION_TEXTURE1D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ viewInfo.minLevel = pDesc->Texture1D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = pDesc->Texture2D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DMS:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
+ break;
+
+ default:
+ throw DxvkError("D3D11: Invalid view dimension for DSV");
+ }
+
+ // Normalize view type so that we won't accidentally
+ // bind 2D array views and 2D views at the same time
+ if (viewInfo.numLayers == 1) {
+ if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ }
+
+ // Populate view info struct
+ m_info.pResource = pResource;
+ m_info.Dimension = resourceDesc.Dim;
+ m_info.BindFlags = resourceDesc.BindFlags;
+ m_info.Image.Aspects = viewInfo.aspect;
+ m_info.Image.MinLevel = viewInfo.minLevel;
+ m_info.Image.MinLayer = viewInfo.minLayer;
+ m_info.Image.NumLevels = viewInfo.numLevels;
+ m_info.Image.NumLayers = viewInfo.numLayers;
+
+ if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH)
+ m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ if (m_desc.Flags & D3D11_DSV_READ_ONLY_STENCIL)
+ m_info.Image.Aspects &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ // Create the underlying image view object
+ m_view = pDevice->GetDXVKDevice()->createImageView(
+ GetCommonTexture(pResource)->GetImage(), viewInfo);
+ }
+
+
+ D3D11DepthStencilView::~D3D11DepthStencilView() {
+ ResourceReleasePrivate(m_resource);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11DepthStencilView::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11DepthStencilView)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10View)
+ || riid == __uuidof(ID3D10DepthStencilView)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11DepthStencilView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DepthStencilView::GetResource(ID3D11Resource** ppResource) {
+ *ppResource = ref(m_resource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11DepthStencilView::GetDesc(D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ HRESULT D3D11DepthStencilView::GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+ pDesc->Flags = 0;
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D;
+ pDesc->Texture1D.MipSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY;
+ pDesc->Texture1DArray.MipSlice = 0;
+ pDesc->Texture1DArray.FirstArraySlice = 0;
+ pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize;
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.SampleDesc.Count == 1) {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+ pDesc->Texture2D.MipSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
+ pDesc->Texture2DArray.MipSlice = 0;
+ pDesc->Texture2DArray.FirstArraySlice = 0;
+ pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize;
+ }
+ } else {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
+ } else {
+ pDesc->ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
+ pDesc->Texture2DMSArray.FirstArraySlice = 0;
+ pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize;
+ }
+ }
+ } return S_OK;
+
+ default:
+ Logger::err(str::format(
+ "D3D11: Unsupported dimension for depth stencil view: ",
+ resourceDim));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT D3D11DepthStencilView::NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ uint32_t numLayers = 0;
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE1D
+ && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE1DARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture1D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2D
+ && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DARRAY
+ && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DMS
+ && pDesc->ViewDimension != D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture2D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ default:
+ return E_INVALIDARG;
+ }
+
+ if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
+ pDesc->Format = format;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
+ if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
+ pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
+ if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
+ pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
+ break;
+
+ case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
+ if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice)
+ pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice;
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h
new file mode 100644
index 00000000..41b6fcb1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_dsv.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_view_dsv.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_view.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Depth-stencil view
+ *
+ * Unordered access views are special in that they can
+ * have counters, which can be used inside shaders to
+ * atomically append or consume structures.
+ */
+ class D3D11DepthStencilView : public D3D11DeviceChild<ID3D11DepthStencilView> {
+
+ public:
+
+ D3D11DepthStencilView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc);
+
+ ~D3D11DepthStencilView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;
+
+ void STDMETHODCALLTYPE GetDesc(D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc) final;
+
+ const D3D11_VK_VIEW_INFO& GetViewInfo() const {
+ return m_info;
+ }
+
+ D3D11_RESOURCE_DIMENSION GetResourceType() const {
+ D3D11_RESOURCE_DIMENSION type;
+ m_resource->GetType(&type);
+ return type;
+ }
+
+ Rc<DxvkImageView> GetImageView() const {
+ return m_view;
+ }
+
+ VkImageLayout GetRenderLayout() const {
+ if (m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL) {
+ switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) {
+ default: // case 0
+ return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ case D3D11_DSV_READ_ONLY_DEPTH:
+ return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR;
+ case D3D11_DSV_READ_ONLY_STENCIL:
+ return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR;
+ case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL:
+ return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
+ }
+ } else {
+ return VK_IMAGE_LAYOUT_GENERAL;
+ }
+ }
+
+ VkImageAspectFlags GetWritableAspectMask() const {
+ VkImageAspectFlags mask = m_view->formatInfo()->aspectMask;
+ if (m_desc.Flags & D3D11_DSV_READ_ONLY_DEPTH) mask &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
+ if (m_desc.Flags & D3D11_DSV_READ_ONLY_STENCIL) mask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
+ return mask;
+ }
+
+ D3D10DepthStencilView* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc);
+
+ static HRESULT NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11_DEPTH_STENCIL_VIEW_DESC m_desc;
+ D3D11_VK_VIEW_INFO m_info;
+ Rc<DxvkImageView> m_view;
+ D3D10DepthStencilView m_d3d10;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp
new file mode 100644
index 00000000..86460502
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.cpp
@@ -0,0 +1,440 @@
+#include "d3d11_device.h"
+#include "d3d11_buffer.h"
+#include "d3d11_resource.h"
+#include "d3d11_texture.h"
+#include "d3d11_view_rtv.h"
+
+namespace dxvk {
+
+ D3D11RenderTargetView::D3D11RenderTargetView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc)
+ : D3D11DeviceChild<ID3D11RenderTargetView1>(pDevice),
+ m_resource(pResource), m_desc(*pDesc), m_d3d10(this) {
+ ResourceAddRefPrivate(m_resource);
+
+ auto texture = GetCommonTexture(pResource);
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ DXGI_VK_FORMAT_INFO formatInfo = pDevice->LookupFormat(
+ pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR);
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = formatInfo.Format;
+ viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
+ viewInfo.swizzle = formatInfo.Swizzle;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_RTV_DIMENSION_TEXTURE1D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ viewInfo.minLevel = pDesc->Texture1D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = pDesc->Texture2D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMS:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE3D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture3D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture3D.FirstWSlice;
+ viewInfo.numLayers = pDesc->Texture3D.WSize;
+ break;
+
+ default:
+ throw DxvkError("D3D11: Invalid view dimension for RTV");
+ }
+
+ if (texture->GetPlaneCount() > 1)
+ viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
+
+ // Normalize view type so that we won't accidentally
+ // bind 2D array views and 2D views at the same time
+ if (viewInfo.numLayers == 1) {
+ if (viewInfo.type == VK_IMAGE_VIEW_TYPE_1D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ if (viewInfo.type == VK_IMAGE_VIEW_TYPE_2D_ARRAY) viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ }
+
+ // Populate view info struct
+ m_info.pResource = pResource;
+ m_info.Dimension = resourceDesc.Dim;
+ m_info.BindFlags = resourceDesc.BindFlags;
+ m_info.Image.Aspects = viewInfo.aspect;
+ m_info.Image.MinLevel = viewInfo.minLevel;
+ m_info.Image.MinLayer = viewInfo.minLayer;
+ m_info.Image.NumLevels = viewInfo.numLevels;
+ m_info.Image.NumLayers = viewInfo.numLayers;
+
+ // Create the underlying image view object
+ m_view = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
+ }
+
+
+ D3D11RenderTargetView::~D3D11RenderTargetView() {
+ ResourceReleasePrivate(m_resource);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11RenderTargetView::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11RenderTargetView)
+ || riid == __uuidof(ID3D11RenderTargetView1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10View)
+ || riid == __uuidof(ID3D10RenderTargetView)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11RenderTargetView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RenderTargetView::GetResource(ID3D11Resource** ppResource) {
+ *ppResource = ref(m_resource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RenderTargetView::GetDesc(D3D11_RENDER_TARGET_VIEW_DESC* pDesc) {
+ pDesc->Format = m_desc.Format;
+ pDesc->ViewDimension = m_desc.ViewDimension;
+
+ switch (m_desc.ViewDimension) {
+ case D3D11_RTV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_RTV_DIMENSION_BUFFER:
+ pDesc->Buffer = m_desc.Buffer;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE1D:
+ pDesc->Texture1D = m_desc.Texture1D;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
+ pDesc->Texture1DArray = m_desc.Texture1DArray;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2D:
+ pDesc->Texture2D.MipSlice = m_desc.Texture2D.MipSlice;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
+ pDesc->Texture2DArray.MipSlice = m_desc.Texture2DArray.MipSlice;
+ pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice;
+ pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMS:
+ pDesc->Texture2DMS = m_desc.Texture2DMS;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
+ pDesc->Texture2DMSArray = m_desc.Texture2DMSArray;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE3D:
+ pDesc->Texture3D = m_desc.Texture3D;
+ break;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11RenderTargetView::GetDesc1(D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ HRESULT D3D11RenderTargetView::GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
+ pDesc->Texture1D.MipSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
+ pDesc->Texture1DArray.MipSlice = 0;
+ pDesc->Texture1DArray.FirstArraySlice = 0;
+ pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize;
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.SampleDesc.Count == 1) {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ pDesc->Texture2D.MipSlice = 0;
+ pDesc->Texture2D.PlaneSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ pDesc->Texture2DArray.MipSlice = 0;
+ pDesc->Texture2DArray.FirstArraySlice = 0;
+ pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize;
+ pDesc->Texture2DArray.PlaneSlice = 0;
+ }
+ } else {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
+ } else {
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
+ pDesc->Texture2DMSArray.FirstArraySlice = 0;
+ pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize;
+ }
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+ pDesc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
+ pDesc->Texture3D.MipSlice = 0;
+ pDesc->Texture3D.FirstWSlice = 0;
+ pDesc->Texture3D.WSize = resourceDesc.Depth;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format(
+ "D3D11: Unsupported dimension for render target view: ",
+ resourceDim));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ D3D11_RENDER_TARGET_VIEW_DESC1 D3D11RenderTargetView::PromoteDesc(
+ const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
+ UINT Plane) {
+ D3D11_RENDER_TARGET_VIEW_DESC1 dstDesc;
+ dstDesc.Format = pDesc->Format;
+ dstDesc.ViewDimension = pDesc->ViewDimension;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_RTV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_RTV_DIMENSION_BUFFER:
+ dstDesc.Buffer = pDesc->Buffer;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE1D:
+ dstDesc.Texture1D = pDesc->Texture1D;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
+ dstDesc.Texture1DArray = pDesc->Texture1DArray;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2D:
+ dstDesc.Texture2D.MipSlice = pDesc->Texture2D.MipSlice;
+ dstDesc.Texture2D.PlaneSlice = Plane;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
+ dstDesc.Texture2DArray.MipSlice = pDesc->Texture2DArray.MipSlice;
+ dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
+ dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize;
+ dstDesc.Texture2DArray.PlaneSlice = Plane;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMS:
+ dstDesc.Texture2DMS = pDesc->Texture2DMS;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
+ dstDesc.Texture2DMSArray = pDesc->Texture2DMSArray;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE3D:
+ dstDesc.Texture3D = pDesc->Texture3D;
+ break;
+ }
+
+ return dstDesc;
+ }
+
+
+ HRESULT D3D11RenderTargetView::NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ uint32_t numLayers = 0;
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: {
+ if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_BUFFER) {
+ Logger::err("D3D11: Incompatible view dimension for Buffer");
+ return E_INVALIDARG;
+ }
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE1D
+ && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE1DARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture1D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2D
+ && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DARRAY
+ && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DMS
+ && pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture2D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_RTV_DIMENSION_TEXTURE3D) {
+ Logger::err("D3D11: Incompatible view dimension for Texture3D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = std::max(resourceDesc.Depth >> pDesc->Texture3D.MipSlice, 1u);
+ } break;
+
+ default:
+ return E_INVALIDARG;
+ }
+
+ if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
+ pDesc->Format = format;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
+ if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
+ pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2D:
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
+ if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
+ pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
+ if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice)
+ pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice;
+ break;
+
+ case D3D11_RTV_DIMENSION_TEXTURE3D:
+ if (pDesc->Texture3D.WSize > numLayers - pDesc->Texture3D.FirstWSlice)
+ pDesc->Texture3D.WSize = numLayers - pDesc->Texture3D.FirstWSlice;
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+ }
+
+
+ UINT D3D11RenderTargetView::GetPlaneSlice(const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) {
+ switch (pDesc->ViewDimension) {
+ case D3D11_RTV_DIMENSION_TEXTURE2D:
+ return pDesc->Texture2D.PlaneSlice;
+ case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
+ return pDesc->Texture2DArray.PlaneSlice;
+ default:
+ return 0;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h
new file mode 100644
index 00000000..080146ec
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_rtv.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_view_rtv.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_view.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Render target view
+ */
+ class D3D11RenderTargetView : public D3D11DeviceChild<ID3D11RenderTargetView1> {
+
+ public:
+
+ D3D11RenderTargetView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc);
+
+ ~D3D11RenderTargetView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;
+
+ void STDMETHODCALLTYPE GetDesc(D3D11_RENDER_TARGET_VIEW_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(D3D11_RENDER_TARGET_VIEW_DESC1* pDesc) final;
+
+ const D3D11_VK_VIEW_INFO& GetViewInfo() const {
+ return m_info;
+ }
+
+ BOOL HasBindFlag(UINT Flags) const {
+ return m_info.BindFlags & Flags;
+ }
+
+ D3D11_RESOURCE_DIMENSION GetResourceType() const {
+ D3D11_RESOURCE_DIMENSION type;
+ m_resource->GetType(&type);
+ return type;
+ }
+
+ Rc<DxvkImageView> GetImageView() const {
+ return m_view;
+ }
+
+ VkImageLayout GetRenderLayout() const {
+ return m_view->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
+ ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ : VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+ D3D10RenderTargetView* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_RENDER_TARGET_VIEW_DESC1* pDesc);
+
+ static D3D11_RENDER_TARGET_VIEW_DESC1 PromoteDesc(
+ const D3D11_RENDER_TARGET_VIEW_DESC* pDesc,
+ UINT Plane);
+
+ static HRESULT NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_RENDER_TARGET_VIEW_DESC1* pDesc);
+
+ static UINT GetPlaneSlice(
+ const D3D11_RENDER_TARGET_VIEW_DESC1* pDesc);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11_RENDER_TARGET_VIEW_DESC1 m_desc;
+ D3D11_VK_VIEW_INFO m_info;
+ Rc<DxvkImageView> m_view;
+ D3D10RenderTargetView m_d3d10;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp
new file mode 100644
index 00000000..1c3d4d8d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.cpp
@@ -0,0 +1,592 @@
+#include "d3d11_device.h"
+#include "d3d11_buffer.h"
+#include "d3d11_resource.h"
+#include "d3d11_texture.h"
+#include "d3d11_view_srv.h"
+
+namespace dxvk {
+
+ D3D11ShaderResourceView::D3D11ShaderResourceView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc)
+ : D3D11DeviceChild<ID3D11ShaderResourceView1>(pDevice),
+ m_resource(pResource), m_desc(*pDesc), m_d3d10(this) {
+ ResourceAddRefPrivate(m_resource);
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ // Basic view resource info
+ m_info.pResource = pResource;
+ m_info.Dimension = resourceDesc.Dim;
+ m_info.BindFlags = resourceDesc.BindFlags;
+
+ if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto buffer = static_cast<D3D11Buffer*>(pResource);
+
+ // Move buffer description to a common struct to
+ // avoid having to handle the two cases separately
+ D3D11_BUFFEREX_SRV bufInfo;
+
+ if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) {
+ bufInfo.FirstElement = pDesc->BufferEx.FirstElement;
+ bufInfo.NumElements = pDesc->BufferEx.NumElements;
+ bufInfo.Flags = pDesc->BufferEx.Flags;
+ } else if (pDesc->ViewDimension == D3D11_SRV_DIMENSION_BUFFER) {
+ bufInfo.FirstElement = pDesc->Buffer.FirstElement;
+ bufInfo.NumElements = pDesc->Buffer.NumElements;
+ bufInfo.Flags = 0;
+ } else {
+ throw DxvkError("D3D11: Invalid view dimension for buffer SRV");
+ }
+
+ // Fill in buffer view info
+ DxvkBufferViewCreateInfo viewInfo;
+
+ if (bufInfo.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
+ // Raw buffer view. We'll represent this as a
+ // uniform texel buffer with UINT32 elements.
+ viewInfo.format = VK_FORMAT_R32_UINT;
+ viewInfo.rangeOffset = sizeof(uint32_t) * bufInfo.FirstElement;
+ viewInfo.rangeLength = sizeof(uint32_t) * bufInfo.NumElements;
+ } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
+ // Structured buffer view
+ viewInfo.format = VK_FORMAT_R32_UINT;
+ viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * bufInfo.FirstElement;
+ viewInfo.rangeLength = buffer->Desc()->StructureByteStride * bufInfo.NumElements;
+ } else {
+ viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
+
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format);
+ viewInfo.rangeOffset = formatInfo->elementSize * bufInfo.FirstElement;
+ viewInfo.rangeLength = formatInfo->elementSize * bufInfo.NumElements;
+ }
+
+ // Populate view info struct
+ m_info.Buffer.Offset = viewInfo.rangeOffset;
+ m_info.Buffer.Length = viewInfo.rangeLength;
+
+ // Create underlying buffer view object
+ m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
+ buffer->GetBuffer(), viewInfo);
+ } else {
+ auto texture = GetCommonTexture(pResource);
+ auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = formatInfo.Format;
+ viewInfo.aspect = formatInfo.Aspect;
+ viewInfo.swizzle = formatInfo.Swizzle;
+ viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ // Shaders expect the stencil value in the G component
+ if (viewInfo.aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
+ viewInfo.swizzle = VkComponentMapping {
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
+ }
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_SRV_DIMENSION_TEXTURE1D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ viewInfo.minLevel = pDesc->Texture1D.MostDetailedMip;
+ viewInfo.numLevels = pDesc->Texture1D.MipLevels;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture1DArray.MostDetailedMip;
+ viewInfo.numLevels = pDesc->Texture1DArray.MipLevels;
+ viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = pDesc->Texture2D.MostDetailedMip;
+ viewInfo.numLevels = pDesc->Texture2D.MipLevels;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture2DArray.MostDetailedMip;
+ viewInfo.numLevels = pDesc->Texture2DArray.MipLevels;
+ viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMS:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DMSArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DMSArray.ArraySize;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
+ viewInfo.minLevel = pDesc->Texture3D.MostDetailedMip;
+ viewInfo.numLevels = pDesc->Texture3D.MipLevels;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE: {
+ const bool cubeArraysEnabled = pDevice->GetDXVKDevice()->features().core.features.imageCubeArray;
+ viewInfo.type = cubeArraysEnabled ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
+ viewInfo.minLevel = pDesc->TextureCube.MostDetailedMip;
+ viewInfo.numLevels = pDesc->TextureCube.MipLevels;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 6;
+ } break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
+ viewInfo.minLevel = pDesc->TextureCubeArray.MostDetailedMip;
+ viewInfo.numLevels = pDesc->TextureCubeArray.MipLevels;
+ viewInfo.minLayer = pDesc->TextureCubeArray.First2DArrayFace;
+ viewInfo.numLayers = pDesc->TextureCubeArray.NumCubes * 6;
+ break;
+
+ default:
+ throw DxvkError("D3D11: Invalid view dimension for image SRV");
+ }
+
+ if (texture->GetPlaneCount() > 1)
+ viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
+
+ // Populate view info struct
+ m_info.Image.Aspects = viewInfo.aspect;
+ m_info.Image.MinLevel = viewInfo.minLevel;
+ m_info.Image.MinLayer = viewInfo.minLayer;
+ m_info.Image.NumLevels = viewInfo.numLevels;
+ m_info.Image.NumLayers = viewInfo.numLayers;
+
+ // Create the underlying image view object
+ m_imageView = pDevice->GetDXVKDevice()->createImageView(texture->GetImage(), viewInfo);
+ }
+ }
+
+
+ D3D11ShaderResourceView::~D3D11ShaderResourceView() {
+ ResourceReleasePrivate(m_resource);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11ShaderResourceView::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11ShaderResourceView)
+ || riid == __uuidof(ID3D11ShaderResourceView1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(ID3D10DeviceChild)
+ || riid == __uuidof(ID3D10View)
+ || riid == __uuidof(ID3D10ShaderResourceView)
+ || riid == __uuidof(ID3D10ShaderResourceView1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11ShaderResourceView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ShaderResourceView::GetResource(ID3D11Resource** ppResource) {
+ *ppResource = ref(m_resource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) {
+ pDesc->Format = m_desc.Format;
+ pDesc->ViewDimension = m_desc.ViewDimension;
+
+ switch (m_desc.ViewDimension) {
+ case D3D11_SRV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_SRV_DIMENSION_BUFFER:
+ pDesc->Buffer = m_desc.Buffer;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1D:
+ pDesc->Texture1D = m_desc.Texture1D;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
+ pDesc->Texture1DArray = m_desc.Texture1DArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ pDesc->Texture2D.MostDetailedMip = m_desc.Texture2D.MostDetailedMip;
+ pDesc->Texture2D.MipLevels = m_desc.Texture2D.MipLevels;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ pDesc->Texture2DArray.MostDetailedMip = m_desc.Texture2DArray.MostDetailedMip;
+ pDesc->Texture2DArray.MipLevels = m_desc.Texture2DArray.MipLevels;
+ pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice;
+ pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMS:
+ pDesc->Texture2DMS = m_desc.Texture2DMS;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
+ pDesc->Texture2DMSArray = m_desc.Texture2DMSArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ pDesc->Texture3D = m_desc.Texture3D;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ pDesc->TextureCube = m_desc.TextureCube;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
+ pDesc->TextureCubeArray = m_desc.TextureCubeArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_BUFFEREX:
+ pDesc->BufferEx = m_desc.BufferEx;
+ break;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11ShaderResourceView::GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ HRESULT D3D11ShaderResourceView::GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: {
+ D3D11_BUFFER_DESC bufferDesc;
+ static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
+
+ if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
+ pDesc->Format = DXGI_FORMAT_UNKNOWN;
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ pDesc->Buffer.FirstElement = 0;
+ pDesc->Buffer.NumElements = bufferDesc.ByteWidth / bufferDesc.StructureByteStride;
+ return S_OK;
+ }
+ } return E_INVALIDARG;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
+ pDesc->Texture1D.MostDetailedMip = 0;
+ pDesc->Texture1D.MipLevels = resourceDesc.MipLevels;
+ } else {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
+ pDesc->Texture1DArray.MostDetailedMip = 0;
+ pDesc->Texture1DArray.MipLevels = resourceDesc.MipLevels;
+ pDesc->Texture1DArray.FirstArraySlice = 0;
+ pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize;
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.SampleDesc.Count == 1) {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ pDesc->Texture2D.MostDetailedMip = 0;
+ pDesc->Texture2D.MipLevels = resourceDesc.MipLevels;
+ pDesc->Texture2D.PlaneSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
+ pDesc->Texture2DArray.MostDetailedMip = 0;
+ pDesc->Texture2DArray.MipLevels = resourceDesc.MipLevels;
+ pDesc->Texture2DArray.FirstArraySlice = 0;
+ pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize;
+ pDesc->Texture2DArray.PlaneSlice = 0;
+ }
+ } else {
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
+ } else {
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
+ pDesc->Texture2DMSArray.FirstArraySlice = 0;
+ pDesc->Texture2DMSArray.ArraySize = resourceDesc.ArraySize;
+ }
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+ pDesc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
+ pDesc->Texture3D.MostDetailedMip = 0;
+ pDesc->Texture3D.MipLevels = resourceDesc.MipLevels;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format(
+ "D3D11: Unsupported dimension for shader resource view: ",
+ resourceDim));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC1 D3D11ShaderResourceView::PromoteDesc(
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ UINT Plane) {
+ D3D11_SHADER_RESOURCE_VIEW_DESC1 dstDesc;
+ dstDesc.Format = pDesc->Format;
+ dstDesc.ViewDimension = pDesc->ViewDimension;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_SRV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_SRV_DIMENSION_BUFFER:
+ dstDesc.Buffer = pDesc->Buffer;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1D:
+ dstDesc.Texture1D = pDesc->Texture1D;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
+ dstDesc.Texture1DArray = pDesc->Texture1DArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ dstDesc.Texture2D.MostDetailedMip = pDesc->Texture2D.MostDetailedMip;
+ dstDesc.Texture2D.MipLevels = pDesc->Texture2D.MipLevels;
+ dstDesc.Texture2D.PlaneSlice = Plane;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ dstDesc.Texture2DArray.MostDetailedMip = pDesc->Texture2DArray.MostDetailedMip;
+ dstDesc.Texture2DArray.MipLevels = pDesc->Texture2DArray.MipLevels;
+ dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
+ dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize;
+ dstDesc.Texture2DArray.PlaneSlice = Plane;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMS:
+ dstDesc.Texture2DMS = pDesc->Texture2DMS;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
+ dstDesc.Texture2DMSArray = pDesc->Texture2DMSArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ dstDesc.Texture3D = pDesc->Texture3D;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ dstDesc.TextureCube = pDesc->TextureCube;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
+ dstDesc.TextureCubeArray = pDesc->TextureCubeArray;
+ break;
+
+ case D3D11_SRV_DIMENSION_BUFFEREX:
+ dstDesc.BufferEx = pDesc->BufferEx;
+ break;
+ }
+
+ return dstDesc;
+ }
+
+
+ HRESULT D3D11ShaderResourceView::NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ uint32_t mipLevels = 0;
+ uint32_t numLayers = 0;
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: {
+ if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFER
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_BUFFEREX) {
+ Logger::err("D3D11: Incompatible view dimension for Buffer");
+ return E_INVALIDARG;
+ }
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1D
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE1DARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture1D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ mipLevels = resourceDesc.MipLevels;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2D
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DARRAY
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMS
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBE
+ && pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture2D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ mipLevels = resourceDesc.MipLevels;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_SRV_DIMENSION_TEXTURE3D) {
+ Logger::err("D3D11: Incompatible view dimension for Texture3D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ mipLevels = resourceDesc.MipLevels;
+ numLayers = 1;
+ } break;
+
+ default:
+ return E_INVALIDARG;
+ }
+
+ if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
+ pDesc->Format = format;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_SRV_DIMENSION_BUFFER:
+ if (pDesc->Buffer.NumElements == 0)
+ return E_INVALIDARG;
+ break;
+
+ case D3D11_SRV_DIMENSION_BUFFEREX:
+ if (pDesc->BufferEx.NumElements == 0)
+ return E_INVALIDARG;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1D:
+ if (pDesc->Texture1D.MipLevels > mipLevels - pDesc->Texture1D.MostDetailedMip)
+ pDesc->Texture1D.MipLevels = mipLevels - pDesc->Texture1D.MostDetailedMip;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
+ if (pDesc->Texture1DArray.MipLevels > mipLevels - pDesc->Texture1DArray.MostDetailedMip)
+ pDesc->Texture1DArray.MipLevels = mipLevels - pDesc->Texture1DArray.MostDetailedMip;
+ if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
+ pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ if (pDesc->Texture2D.MipLevels > mipLevels - pDesc->Texture2D.MostDetailedMip)
+ pDesc->Texture2D.MipLevels = mipLevels - pDesc->Texture2D.MostDetailedMip;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ if (pDesc->Texture2DArray.MipLevels > mipLevels - pDesc->Texture2DArray.MostDetailedMip)
+ pDesc->Texture2DArray.MipLevels = mipLevels - pDesc->Texture2DArray.MostDetailedMip;
+ if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
+ pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
+ if (pDesc->Texture2DMSArray.ArraySize > numLayers - pDesc->Texture2DMSArray.FirstArraySlice)
+ pDesc->Texture2DMSArray.ArraySize = numLayers - pDesc->Texture2DMSArray.FirstArraySlice;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ if (pDesc->TextureCube.MipLevels > mipLevels - pDesc->TextureCube.MostDetailedMip)
+ pDesc->TextureCube.MipLevels = mipLevels - pDesc->TextureCube.MostDetailedMip;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
+ if (pDesc->TextureCubeArray.MipLevels > mipLevels - pDesc->TextureCubeArray.MostDetailedMip)
+ pDesc->TextureCubeArray.MipLevels = mipLevels - pDesc->TextureCubeArray.MostDetailedMip;
+ if (pDesc->TextureCubeArray.NumCubes > (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6)
+ pDesc->TextureCubeArray.NumCubes = (numLayers - pDesc->TextureCubeArray.First2DArrayFace) / 6;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURE3D:
+ if (pDesc->Texture3D.MipLevels > mipLevels - pDesc->Texture3D.MostDetailedMip)
+ pDesc->Texture3D.MipLevels = mipLevels - pDesc->Texture3D.MostDetailedMip;
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+ }
+
+
+ UINT D3D11ShaderResourceView::GetPlaneSlice(const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) {
+ switch (pDesc->ViewDimension) {
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ return pDesc->Texture2D.PlaneSlice;
+ case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
+ return pDesc->Texture2DArray.PlaneSlice;
+ default:
+ return 0;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h
new file mode 100644
index 00000000..e7c5872e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_srv.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../d3d10/d3d10_view_srv.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_view.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Shader resource view
+ */
+ class D3D11ShaderResourceView : public D3D11DeviceChild<ID3D11ShaderResourceView1> {
+
+ public:
+
+ D3D11ShaderResourceView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);
+
+ ~D3D11ShaderResourceView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;
+
+ void STDMETHODCALLTYPE GetDesc(D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc) final;
+
+ const D3D11_VK_VIEW_INFO& GetViewInfo() const {
+ return m_info;
+ }
+
+ BOOL TestHazards() const {
+ return m_info.BindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_UNORDERED_ACCESS);
+ }
+
+ D3D11_RESOURCE_DIMENSION GetResourceType() const {
+ D3D11_RESOURCE_DIMENSION type;
+ m_resource->GetType(&type);
+ return type;
+ }
+
+ D3D11_COMMON_RESOURCE_DESC GetResourceDesc() const {
+ D3D11_COMMON_RESOURCE_DESC desc;
+ GetCommonResourceDesc(m_resource, &desc);
+ return desc;
+ }
+
+ Rc<DxvkBufferView> GetBufferView() const {
+ return m_bufferView;
+ }
+
+ Rc<DxvkImageView> GetImageView() const {
+ return m_imageView;
+ }
+
+ D3D10ShaderResourceView* GetD3D10Iface() {
+ return &m_d3d10;
+ }
+
+ static HRESULT GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);
+
+ static D3D11_SHADER_RESOURCE_VIEW_DESC1 PromoteDesc(
+ const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
+ UINT Plane);
+
+ static HRESULT NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);
+
+ static UINT GetPlaneSlice(
+ const D3D11_SHADER_RESOURCE_VIEW_DESC1* pDesc);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11_SHADER_RESOURCE_VIEW_DESC1 m_desc;
+ D3D11_VK_VIEW_INFO m_info;
+ Rc<DxvkBufferView> m_bufferView;
+ Rc<DxvkImageView> m_imageView;
+ D3D10ShaderResourceView m_d3d10;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp
new file mode 100644
index 00000000..54f826e7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.cpp
@@ -0,0 +1,447 @@
+#include "d3d11_device.h"
+#include "d3d11_buffer.h"
+#include "d3d11_resource.h"
+#include "d3d11_texture.h"
+#include "d3d11_view_uav.h"
+
+namespace dxvk {
+
+ D3D11UnorderedAccessView::D3D11UnorderedAccessView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc)
+ : D3D11DeviceChild<ID3D11UnorderedAccessView1>(pDevice),
+ m_resource(pResource), m_desc(*pDesc) {
+ ResourceAddRefPrivate(m_resource);
+
+ D3D11_COMMON_RESOURCE_DESC resourceDesc;
+ GetCommonResourceDesc(pResource, &resourceDesc);
+
+ // Basic view resource info
+ m_info.pResource = pResource;
+ m_info.Dimension = resourceDesc.Dim;
+ m_info.BindFlags = resourceDesc.BindFlags;
+
+ if (resourceDesc.Dim == D3D11_RESOURCE_DIMENSION_BUFFER) {
+ auto buffer = static_cast<D3D11Buffer*>(pResource);
+
+ DxvkBufferViewCreateInfo viewInfo;
+
+ if (pDesc->Buffer.Flags & D3D11_BUFFEREX_SRV_FLAG_RAW) {
+ viewInfo.format = VK_FORMAT_R32_UINT;
+ viewInfo.rangeOffset = sizeof(uint32_t) * pDesc->Buffer.FirstElement;
+ viewInfo.rangeLength = sizeof(uint32_t) * pDesc->Buffer.NumElements;
+ } else if (pDesc->Format == DXGI_FORMAT_UNKNOWN) {
+ viewInfo.format = VK_FORMAT_R32_UINT;
+ viewInfo.rangeOffset = buffer->Desc()->StructureByteStride * pDesc->Buffer.FirstElement;
+ viewInfo.rangeLength = buffer->Desc()->StructureByteStride * pDesc->Buffer.NumElements;
+ } else {
+ viewInfo.format = pDevice->LookupFormat(pDesc->Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
+
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(viewInfo.format);
+ viewInfo.rangeOffset = formatInfo->elementSize * pDesc->Buffer.FirstElement;
+ viewInfo.rangeLength = formatInfo->elementSize * pDesc->Buffer.NumElements;
+ }
+
+ if (pDesc->Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER))
+ m_counterBuffer = CreateCounterBuffer();
+
+ // Populate view info struct
+ m_info.Buffer.Offset = viewInfo.rangeOffset;
+ m_info.Buffer.Length = viewInfo.rangeLength;
+
+ m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
+ buffer->GetBuffer(), viewInfo);
+ } else {
+ auto texture = GetCommonTexture(pResource);
+ auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = formatInfo.Format;
+ viewInfo.aspect = formatInfo.Aspect;
+ viewInfo.swizzle = formatInfo.Swizzle;
+ viewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_UAV_DIMENSION_TEXTURE1D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ viewInfo.minLevel = pDesc->Texture1D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture1DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture1DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture1DArray.ArraySize;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2D:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.minLevel = pDesc->Texture2D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = pDesc->Texture2DArray.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = pDesc->Texture2DArray.FirstArraySlice;
+ viewInfo.numLayers = pDesc->Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE3D:
+ // FIXME we actually have to map this to a
+ // 2D array view in order to support W slices
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_3D;
+ viewInfo.minLevel = pDesc->Texture3D.MipSlice;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ break;
+
+ default:
+ throw DxvkError("D3D11: Invalid view dimension for image UAV");
+ }
+
+ if (texture->GetPlaneCount() > 1)
+ viewInfo.aspect = vk::getPlaneAspect(GetPlaneSlice(pDesc));
+
+ // Populate view info struct
+ m_info.Image.Aspects = viewInfo.aspect;
+ m_info.Image.MinLevel = viewInfo.minLevel;
+ m_info.Image.MinLayer = viewInfo.minLayer;
+ m_info.Image.NumLevels = viewInfo.numLevels;
+ m_info.Image.NumLayers = viewInfo.numLayers;
+
+ m_imageView = pDevice->GetDXVKDevice()->createImageView(
+ GetCommonTexture(pResource)->GetImage(), viewInfo);
+ }
+ }
+
+
+ D3D11UnorderedAccessView::~D3D11UnorderedAccessView() {
+ ResourceReleasePrivate(m_resource);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D11UnorderedAccessView::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(ID3D11DeviceChild)
+ || riid == __uuidof(ID3D11View)
+ || riid == __uuidof(ID3D11UnorderedAccessView)
+ || riid == __uuidof(ID3D11UnorderedAccessView1)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D11UnorderedAccessView::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetResource(ID3D11Resource** ppResource) {
+ *ppResource = ref(m_resource);
+ }
+
+
+ void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) {
+ pDesc->Format = m_desc.Format;
+ pDesc->ViewDimension = m_desc.ViewDimension;
+
+ switch (m_desc.ViewDimension) {
+ case D3D11_UAV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_UAV_DIMENSION_BUFFER:
+ pDesc->Buffer = m_desc.Buffer;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1D:
+ pDesc->Texture1D = m_desc.Texture1D;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
+ pDesc->Texture1DArray = m_desc.Texture1DArray;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2D:
+ pDesc->Texture2D.MipSlice = m_desc.Texture2D.MipSlice;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+ pDesc->Texture2DArray.MipSlice = m_desc.Texture2DArray.MipSlice;
+ pDesc->Texture2DArray.FirstArraySlice = m_desc.Texture2DArray.FirstArraySlice;
+ pDesc->Texture2DArray.ArraySize = m_desc.Texture2DArray.ArraySize;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE3D:
+ pDesc->Texture3D = m_desc.Texture3D;
+ break;
+ }
+ }
+
+
+ void STDMETHODCALLTYPE D3D11UnorderedAccessView::GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
+ *pDesc = m_desc;
+ }
+
+
+ HRESULT D3D11UnorderedAccessView::GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: {
+ D3D11_BUFFER_DESC bufferDesc;
+ static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
+
+ if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
+ pDesc->Format = DXGI_FORMAT_UNKNOWN;
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ pDesc->Buffer.FirstElement = 0;
+ pDesc->Buffer.NumElements = bufferDesc.ByteWidth / bufferDesc.StructureByteStride;
+ pDesc->Buffer.Flags = 0;
+ return S_OK;
+ }
+ } return E_INVALIDARG;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1D;
+ pDesc->Texture1D.MipSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE1DARRAY;
+ pDesc->Texture1DArray.MipSlice = 0;
+ pDesc->Texture1DArray.FirstArraySlice = 0;
+ pDesc->Texture1DArray.ArraySize = resourceDesc.ArraySize;
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+
+ if (resourceDesc.ArraySize == 1) {
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
+ pDesc->Texture2D.MipSlice = 0;
+ pDesc->Texture2D.PlaneSlice = 0;
+ } else {
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
+ pDesc->Texture2DArray.MipSlice = 0;
+ pDesc->Texture2DArray.FirstArraySlice = 0;
+ pDesc->Texture2DArray.ArraySize = resourceDesc.ArraySize;
+ pDesc->Texture2DArray.PlaneSlice = 0;
+ }
+ } return S_OK;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ pDesc->Format = resourceDesc.Format;
+ pDesc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
+ pDesc->Texture3D.MipSlice = 0;
+ pDesc->Texture3D.WSize = resourceDesc.Depth;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format(
+ "D3D11: Unsupported dimension for unordered access view: ",
+ resourceDim));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1 D3D11UnorderedAccessView::PromoteDesc(
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ UINT Plane) {
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1 dstDesc;
+ dstDesc.Format = pDesc->Format;
+ dstDesc.ViewDimension = pDesc->ViewDimension;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_UAV_DIMENSION_UNKNOWN:
+ break;
+
+ case D3D11_UAV_DIMENSION_BUFFER:
+ dstDesc.Buffer = pDesc->Buffer;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1D:
+ dstDesc.Texture1D = pDesc->Texture1D;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
+ dstDesc.Texture1DArray = pDesc->Texture1DArray;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2D:
+ dstDesc.Texture2D.MipSlice = pDesc->Texture2D.MipSlice;
+ dstDesc.Texture2D.PlaneSlice = Plane;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+ dstDesc.Texture2DArray.MipSlice = pDesc->Texture2DArray.MipSlice;
+ dstDesc.Texture2DArray.FirstArraySlice = pDesc->Texture2DArray.FirstArraySlice;
+ dstDesc.Texture2DArray.ArraySize = pDesc->Texture2DArray.ArraySize;
+ dstDesc.Texture2DArray.PlaneSlice = Plane;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE3D:
+ dstDesc.Texture3D = pDesc->Texture3D;
+ break;
+ }
+
+ return dstDesc;
+ }
+
+
+ HRESULT D3D11UnorderedAccessView::NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
+ D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ pResource->GetType(&resourceDim);
+
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ uint32_t numLayers = 0;
+
+ switch (resourceDim) {
+ case D3D11_RESOURCE_DIMENSION_BUFFER: {
+ if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_BUFFER) {
+ Logger::err("D3D11: Incompatible view dimension for Buffer");
+ return E_INVALIDARG;
+ }
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
+ D3D11_TEXTURE1D_DESC resourceDesc;
+ static_cast<D3D11Texture1D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1D
+ && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE1DARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture1D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
+ D3D11_TEXTURE2D_DESC resourceDesc;
+ static_cast<D3D11Texture2D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2D
+ && pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE2DARRAY) {
+ Logger::err("D3D11: Incompatible view dimension for Texture2D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = resourceDesc.ArraySize;
+ } break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
+ D3D11_TEXTURE3D_DESC resourceDesc;
+ static_cast<D3D11Texture3D*>(pResource)->GetDesc(&resourceDesc);
+
+ if (pDesc->ViewDimension != D3D11_UAV_DIMENSION_TEXTURE3D) {
+ Logger::err("D3D11: Incompatible view dimension for Texture3D");
+ return E_INVALIDARG;
+ }
+
+ format = resourceDesc.Format;
+ numLayers = std::max(resourceDesc.Depth >> pDesc->Texture3D.MipSlice, 1u);
+ } break;
+
+ default:
+ return E_INVALIDARG;
+ }
+
+ if (pDesc->Format == DXGI_FORMAT_UNKNOWN)
+ pDesc->Format = format;
+
+ switch (pDesc->ViewDimension) {
+ case D3D11_UAV_DIMENSION_BUFFER:
+ if (pDesc->Buffer.NumElements == 0)
+ return E_INVALIDARG;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE1DARRAY:
+ if (pDesc->Texture1DArray.ArraySize > numLayers - pDesc->Texture1DArray.FirstArraySlice)
+ pDesc->Texture1DArray.ArraySize = numLayers - pDesc->Texture1DArray.FirstArraySlice;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2D:
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+ if (pDesc->Texture2DArray.ArraySize > numLayers - pDesc->Texture2DArray.FirstArraySlice)
+ pDesc->Texture2DArray.ArraySize = numLayers - pDesc->Texture2DArray.FirstArraySlice;
+ break;
+
+ case D3D11_UAV_DIMENSION_TEXTURE3D:
+ if (pDesc->Texture3D.WSize > numLayers - pDesc->Texture3D.FirstWSlice)
+ pDesc->Texture3D.WSize = numLayers - pDesc->Texture3D.FirstWSlice;
+ break;
+
+ default:
+ break;
+ }
+
+ return S_OK;
+ }
+
+
+ UINT D3D11UnorderedAccessView::GetPlaneSlice(const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) {
+ switch (pDesc->ViewDimension) {
+ case D3D11_UAV_DIMENSION_TEXTURE2D:
+ return pDesc->Texture2D.PlaneSlice;
+ case D3D11_UAV_DIMENSION_TEXTURE2DARRAY:
+ return pDesc->Texture2DArray.PlaneSlice;
+ default:
+ return 0;
+ }
+ }
+
+
+ Rc<DxvkBuffer> D3D11UnorderedAccessView::CreateCounterBuffer() {
+ Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
+
+ DxvkBufferCreateInfo info;
+ info.size = sizeof(uint32_t);
+ info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
+ | VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | device->getShaderPipelineStages();
+ info.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ return device->createBuffer(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h
new file mode 100644
index 00000000..3076fe09
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/d3d11_view_uav.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "d3d11_device_child.h"
+#include "d3d11_view.h"
+
+namespace dxvk {
+
+ class D3D11Device;
+
+ /**
+ * \brief Unordered access view
+ *
+ * Unordered access views are special in that they can
+ * have counters, which can be used inside shaders to
+ * atomically append or consume structures.
+ */
+ class D3D11UnorderedAccessView : public D3D11DeviceChild<ID3D11UnorderedAccessView1> {
+
+ public:
+
+ D3D11UnorderedAccessView(
+ D3D11Device* pDevice,
+ ID3D11Resource* pResource,
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);
+
+ ~D3D11UnorderedAccessView();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) final;
+
+ void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) final;
+
+ void STDMETHODCALLTYPE GetDesc(D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc) final;
+
+ void STDMETHODCALLTYPE GetDesc1(D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc) final;
+
+ const D3D11_VK_VIEW_INFO& GetViewInfo() const {
+ return m_info;
+ }
+
+ BOOL HasBindFlag(UINT Flags) const {
+ return m_info.BindFlags & Flags;
+ }
+
+ D3D11_RESOURCE_DIMENSION GetResourceType() const {
+ D3D11_RESOURCE_DIMENSION type;
+ m_resource->GetType(&type);
+ return type;
+ }
+
+ Rc<DxvkBufferView> GetBufferView() const {
+ return m_bufferView;
+ }
+
+ Rc<DxvkImageView> GetImageView() const {
+ return m_imageView;
+ }
+
+ DxvkBufferSlice GetCounterSlice() const {
+ return m_counterBuffer != nullptr
+ ? DxvkBufferSlice(m_counterBuffer)
+ : DxvkBufferSlice();
+ }
+
+ static HRESULT GetDescFromResource(
+ ID3D11Resource* pResource,
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);
+
+ static D3D11_UNORDERED_ACCESS_VIEW_DESC1 PromoteDesc(
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
+ UINT Plane);
+
+ static HRESULT NormalizeDesc(
+ ID3D11Resource* pResource,
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);
+
+ static UINT GetPlaneSlice(
+ const D3D11_UNORDERED_ACCESS_VIEW_DESC1* pDesc);
+
+ private:
+
+ ID3D11Resource* m_resource;
+ D3D11_UNORDERED_ACCESS_VIEW_DESC1 m_desc;
+ D3D11_VK_VIEW_INFO m_info;
+ Rc<DxvkBufferView> m_bufferView;
+ Rc<DxvkImageView> m_imageView;
+ Rc<DxvkBuffer> m_counterBuffer;
+
+ Rc<DxvkBuffer> CreateCounterBuffer();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build b/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build
new file mode 100644
index 00000000..ded034c9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/meson.build
@@ -0,0 +1,88 @@
+d3d11_res = wrc_generator.process('version.rc')
+
+dxgi_common_src = [
+ '../dxgi/dxgi_format.cpp',
+ '../dxgi/dxgi_monitor.cpp',
+ '../dxgi/dxgi_swapchain.cpp',
+]
+
+d3d10_src = [
+ '../d3d10/d3d10_blend.cpp',
+ '../d3d10/d3d10_buffer.cpp',
+ '../d3d10/d3d10_depth_stencil.cpp',
+ '../d3d10/d3d10_device.cpp',
+ '../d3d10/d3d10_input_layout.cpp',
+ '../d3d10/d3d10_multithread.cpp',
+ '../d3d10/d3d10_query.cpp',
+ '../d3d10/d3d10_rasterizer.cpp',
+ '../d3d10/d3d10_sampler.cpp',
+ '../d3d10/d3d10_texture.cpp',
+ '../d3d10/d3d10_util.cpp',
+ '../d3d10/d3d10_view_dsv.cpp',
+ '../d3d10/d3d10_view_rtv.cpp',
+ '../d3d10/d3d10_view_srv.cpp',
+]
+
+d3d11_src = [
+ 'd3d11_annotation.cpp',
+ 'd3d11_blend.cpp',
+ 'd3d11_buffer.cpp',
+ 'd3d11_class_linkage.cpp',
+ 'd3d11_cmdlist.cpp',
+ 'd3d11_context.cpp',
+ 'd3d11_context_def.cpp',
+ 'd3d11_context_ext.cpp',
+ 'd3d11_context_imm.cpp',
+ 'd3d11_cuda.cpp',
+ 'd3d11_depth_stencil.cpp',
+ 'd3d11_device.cpp',
+ 'd3d11_enums.cpp',
+ 'd3d11_initializer.cpp',
+ 'd3d11_input_layout.cpp',
+ 'd3d11_interop.cpp',
+ 'd3d11_main.cpp',
+ 'd3d11_options.cpp',
+ 'd3d11_query.cpp',
+ 'd3d11_rasterizer.cpp',
+ 'd3d11_resource.cpp',
+ 'd3d11_sampler.cpp',
+ 'd3d11_shader.cpp',
+ 'd3d11_state.cpp',
+ 'd3d11_state_object.cpp',
+ 'd3d11_swapchain.cpp',
+ 'd3d11_texture.cpp',
+ 'd3d11_util.cpp',
+ 'd3d11_video.cpp',
+ 'd3d11_view_dsv.cpp',
+ 'd3d11_view_rtv.cpp',
+ 'd3d11_view_srv.cpp',
+ 'd3d11_view_uav.cpp',
+]
+
+d3d11_shaders = files([
+ 'shaders/d3d11_video_blit_frag.frag',
+ 'shaders/d3d11_video_blit_vert.vert',
+])
+
+if not dxvk_native
+ # We don't want to allow GDI interop on *any* native builds
+ # because the idea is for you to write once and run anywhere.
+ d3d11_src += 'd3d11_gdi.cpp'
+endif
+
+if dxvk_native
+ lib_dxgi = dxgi_dep
+endif
+
+d3d11_dll = shared_library(so_prefix+'d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src,
+ glsl_generator.process(d3d11_shaders), d3d11_res,
+ name_prefix : '',
+ dependencies : [ lib_dxgi, dxbc_dep, dxvk_dep, wsi_dep ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'd3d11'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+d3d11_dep = declare_dependency(
+ link_with : [ d3d11_dll ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag
new file mode 100644
index 00000000..d659176c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_frag.frag
@@ -0,0 +1,56 @@
+#version 450
+
+layout(constant_id = 3) const bool c_planar = true;
+
+// Can't use matrix types here since even a two-row
+// matrix will be padded to 16 bytes per column for
+// absolutely no reason
+layout(std140, set = 0, binding = 0)
+uniform ubo_t {
+ vec4 color_matrix_r1;
+ vec4 color_matrix_r2;
+ vec4 color_matrix_r3;
+ vec2 coord_matrix_c1;
+ vec2 coord_matrix_c2;
+ vec2 coord_matrix_c3;
+ float y_min;
+ float y_max;
+};
+
+layout(location = 0) in vec2 i_texcoord;
+layout(location = 0) out vec4 o_color;
+
+layout(set = 0, binding = 1) uniform sampler s_sampler;
+layout(set = 0, binding = 2) uniform texture2D s_inputY;
+layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;
+
+void main() {
+ // Transform input texture coordinates to
+ // account for rotation and source rectangle
+ mat3x2 coord_matrix = mat3x2(
+ coord_matrix_c1,
+ coord_matrix_c2,
+ coord_matrix_c3);
+
+ vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
+
+ // Fetch source image color
+ vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
+
+ if (c_planar) {
+ color.g = texture(sampler2D(s_inputY, s_sampler), coord).r;
+ color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr;
+ color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
+ } else {
+ color = texture(sampler2D(s_inputY, s_sampler), coord);
+ }
+
+ // Color space transformation
+ mat3x4 color_matrix = mat3x4(
+ color_matrix_r1,
+ color_matrix_r2,
+ color_matrix_r3);
+
+ o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
+ o_color.a = color.a;
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert
new file mode 100644
index 00000000..1980b3c9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/shaders/d3d11_video_blit_vert.vert
@@ -0,0 +1,12 @@
+#version 450
+
+layout(location = 0) out vec2 o_texcoord;
+
+void main() {
+ vec2 coord = vec2(
+ float(gl_VertexIndex & 1) * 2.0f,
+ float(gl_VertexIndex & 2));
+
+ o_texcoord = coord;
+ gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc b/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc
new file mode 100644
index 00000000..060ef7bc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d11/version.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "Direct3D 11 Runtime"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "D3D11.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "D3D11.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9.def b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9.def
new file mode 100644
index 00000000..6829b194
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9.def
@@ -0,0 +1,22 @@
+LIBRARY D3D9.DLL
+EXPORTS
+ Direct3DShaderValidatorCreate9 @24
+
+ PSGPError @25
+ PSGPSampleTexture @26
+
+ D3DPERF_BeginEvent @27
+ D3DPERF_EndEvent @28
+ D3DPERF_GetStatus @29
+ D3DPERF_QueryRepeatFrame @30
+ D3DPERF_SetMarker @31
+ D3DPERF_SetOptions @32
+ D3DPERF_SetRegion @33
+
+ DebugSetLevel @34
+ DebugSetMute @35
+
+ Direct3D9EnableMaximizedWindowedModeShim @36
+
+ Direct3DCreate9 @37
+ Direct3DCreate9Ex @38
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.cpp
new file mode 100644
index 00000000..7f67839f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.cpp
@@ -0,0 +1,834 @@
+#include "d3d9_adapter.h"
+
+#include "d3d9_interface.h"
+#include "d3d9_monitor.h"
+#include "d3d9_caps.h"
+#include "d3d9_util.h"
+
+#include "../wsi/wsi_mode.h"
+#include "../wsi/wsi_monitor.h"
+
+#include "../util/util_bit.h"
+#include "../util/util_luid.h"
+#include "../util/util_ratio.h"
+#include "../util/util_string.h"
+
+#include <cfloat>
+
+namespace dxvk {
+
+ const char* GetDriverDLL(DxvkGpuVendor vendor) {
+ switch (vendor) {
+ default:
+ case DxvkGpuVendor::Nvidia: return "nvd3dum.dll";
+
+#if defined(__x86_64__) || defined(_M_X64)
+ case DxvkGpuVendor::Amd: return "aticfx64.dll";
+ case DxvkGpuVendor::Intel: return "igdumd64.dll";
+#else
+ case DxvkGpuVendor::Amd: return "aticfx32.dll";
+ case DxvkGpuVendor::Intel: return "igdumd32.dll";
+#endif
+ }
+ }
+
+
+ D3D9Adapter::D3D9Adapter(
+ D3D9InterfaceEx* pParent,
+ Rc<DxvkAdapter> Adapter,
+ UINT Ordinal,
+ UINT DisplayIndex)
+ : m_parent (pParent),
+ m_adapter (Adapter),
+ m_ordinal (Ordinal),
+ m_displayIndex (DisplayIndex),
+ m_modeCacheFormat (D3D9Format::Unknown),
+ m_d3d9Formats (Adapter, m_parent->GetOptions()) {
+ m_adapter->logAdapterInfo();
+ }
+
+ template <size_t N>
+ static void copyToStringArray(char (&dst)[N], const char* src) {
+ std::strncpy(dst, src, N);
+ dst[N - 1] = '\0';
+ }
+
+
+ HRESULT D3D9Adapter::GetAdapterIdentifier(
+ DWORD Flags,
+ D3DADAPTER_IDENTIFIER9* pIdentifier) {
+ if (unlikely(pIdentifier == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ auto& options = m_parent->GetOptions();
+
+ const auto& props = m_adapter->deviceProperties();
+
+ // TODO: Consolidate this!
+#ifndef DXVK_NATIVE
+ DISPLAY_DEVICEA device = { };
+ device.cb = sizeof(device);
+
+ if (!::EnumDisplayDevicesA(nullptr, m_displayIndex, &device, 0)) {
+ Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query display info");
+ return D3DERR_INVALIDCALL;
+ }
+
+ const char* displayName = device.DeviceName;
+#else
+ WCHAR wideDisplayName[32] = { };
+ if (!wsi::getDisplayName(GetDefaultMonitor(), wideDisplayName)) {
+ Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query monitor info");
+ return D3DERR_INVALIDCALL;
+ }
+
+ std::string displayNameStr = str::fromws(wideDisplayName);
+ const char* displayName = displayNameStr.c_str();
+#endif
+
+
+ GUID guid = bit::cast<GUID>(m_adapter->devicePropertiesExt().coreDeviceId.deviceUUID);
+
+ uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId);
+ uint32_t deviceId = options.customDeviceId == -1 ? props.deviceID : uint32_t(options.customDeviceId);
+ const char* desc = options.customDeviceDesc.empty() ? props.deviceName : options.customDeviceDesc.c_str();
+ const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId));
+
+ copyToStringArray(pIdentifier->Description, desc);
+ copyToStringArray(pIdentifier->DeviceName, displayName); // The GDI device name. Not the actual device name.
+ copyToStringArray(pIdentifier->Driver, driver); // This is the driver's dll.
+
+ pIdentifier->DeviceIdentifier = guid;
+ pIdentifier->DeviceId = deviceId;
+ pIdentifier->VendorId = vendorId;
+ pIdentifier->Revision = 0;
+ pIdentifier->SubSysId = 0;
+ pIdentifier->WHQLLevel = m_parent->IsExtended() ? 1 : 0; // This doesn't check with the driver on Direct3D9Ex and is always 1.
+ pIdentifier->DriverVersion.QuadPart = INT64_MAX;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::CheckDeviceType(
+ D3DDEVTYPE DevType,
+ D3D9Format AdapterFormat,
+ D3D9Format BackBufferFormat,
+ BOOL bWindowed) {
+ if (!IsSupportedAdapterFormat(AdapterFormat))
+ return D3DERR_NOTAVAILABLE;
+
+ if (!IsSupportedBackBufferFormat(AdapterFormat, BackBufferFormat, bWindowed))
+ return D3DERR_NOTAVAILABLE;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::CheckDeviceFormat(
+ D3DDEVTYPE DeviceType,
+ D3D9Format AdapterFormat,
+ DWORD Usage,
+ D3DRESOURCETYPE RType,
+ D3D9Format CheckFormat) {
+ if (!IsSupportedAdapterFormat(AdapterFormat))
+ return D3DERR_NOTAVAILABLE;
+
+ const bool dmap = Usage & D3DUSAGE_DMAP;
+ const bool rt = Usage & D3DUSAGE_RENDERTARGET;
+ const bool ds = Usage & D3DUSAGE_DEPTHSTENCIL;
+
+ const bool surface = RType == D3DRTYPE_SURFACE;
+ const bool texture = RType == D3DRTYPE_TEXTURE;
+
+ const bool twoDimensional = surface || texture;
+
+ const bool srgb = (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) != 0;
+
+ if (CheckFormat == D3D9Format::INST)
+ return D3D_OK;
+
+ if (rt && CheckFormat == D3D9Format::A8 && m_parent->GetOptions().disableA8RT)
+ return D3DERR_NOTAVAILABLE;
+
+ if (ds && !IsDepthFormat(CheckFormat))
+ return D3DERR_NOTAVAILABLE;
+
+ if (rt && CheckFormat == D3D9Format::NULL_FORMAT && twoDimensional)
+ return D3D_OK;
+
+ if (rt && CheckFormat == D3D9Format::RESZ && surface)
+ return D3D_OK;
+
+ if (CheckFormat == D3D9Format::ATOC && surface)
+ return D3D_OK;
+
+ if (CheckFormat == D3D9Format::NVDB && surface)
+ return m_adapter->features().core.features.depthBounds
+ ? D3D_OK
+ : D3DERR_NOTAVAILABLE;
+
+ // I really don't want to support this...
+ if (dmap)
+ return D3DERR_NOTAVAILABLE;
+
+ auto mapping = m_d3d9Formats.GetFormatMapping(CheckFormat);
+ if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
+ return D3DERR_NOTAVAILABLE;
+
+ if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
+ return D3DERR_NOTAVAILABLE;
+
+ if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
+ return D3D_OK;
+
+ // Let's actually ask Vulkan now that we got some quirks out the way!
+ return CheckDeviceVkFormat(mapping.FormatColor, Usage, RType);
+ }
+
+
+ HRESULT D3D9Adapter::CheckDeviceMultiSampleType(
+ D3DDEVTYPE DeviceType,
+ D3D9Format SurfaceFormat,
+ BOOL Windowed,
+ D3DMULTISAMPLE_TYPE MultiSampleType,
+ DWORD* pQualityLevels) {
+ if (pQualityLevels != nullptr)
+ *pQualityLevels = 1;
+
+ auto dst = ConvertFormatUnfixed(SurfaceFormat);
+ if (dst.FormatColor == VK_FORMAT_UNDEFINED)
+ return D3DERR_NOTAVAILABLE;
+
+ if (MultiSampleType != D3DMULTISAMPLE_NONE
+ && (SurfaceFormat == D3D9Format::D32_LOCKABLE
+ || SurfaceFormat == D3D9Format::D32F_LOCKABLE
+ || SurfaceFormat == D3D9Format::D16_LOCKABLE))
+ return D3DERR_NOTAVAILABLE;
+
+ uint32_t sampleCount = std::max<uint32_t>(MultiSampleType, 1u);
+
+ // Check if this is a power of two...
+ if (sampleCount & (sampleCount - 1))
+ return D3DERR_NOTAVAILABLE;
+
+ // Therefore...
+ VkSampleCountFlags sampleFlags = VkSampleCountFlags(sampleCount);
+
+ auto availableFlags = !IsDepthFormat(SurfaceFormat)
+ ? m_adapter->deviceProperties().limits.framebufferColorSampleCounts
+ : m_adapter->deviceProperties().limits.framebufferDepthSampleCounts;
+
+ if (!(availableFlags & sampleFlags))
+ return D3DERR_NOTAVAILABLE;
+
+ if (pQualityLevels != nullptr) {
+ if (MultiSampleType == D3DMULTISAMPLE_NONMASKABLE)
+ *pQualityLevels = 32 - bit::lzcnt(availableFlags);
+ else
+ *pQualityLevels = 1;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::CheckDepthStencilMatch(
+ D3DDEVTYPE DeviceType,
+ D3D9Format AdapterFormat,
+ D3D9Format RenderTargetFormat,
+ D3D9Format DepthStencilFormat) {
+ if (!IsDepthFormat(DepthStencilFormat))
+ return D3DERR_NOTAVAILABLE;
+
+ if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
+ return D3D_OK;
+
+ auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
+ if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
+ return D3DERR_NOTAVAILABLE;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::CheckDeviceFormatConversion(
+ D3DDEVTYPE DeviceType,
+ D3D9Format SourceFormat,
+ D3D9Format TargetFormat) {
+ bool sourceSupported = IsSupportedBackBufferFormat(D3D9Format::Unknown, SourceFormat, TRUE);
+ bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
+ || TargetFormat == D3D9Format::A1R5G5B5
+ || TargetFormat == D3D9Format::R5G6B5
+ // || TargetFormat == D3D9Format::R8G8B8 <-- We don't support R8G8B8
+ || TargetFormat == D3D9Format::X8R8G8B8
+ || TargetFormat == D3D9Format::A8R8G8B8
+ || TargetFormat == D3D9Format::A2R10G10B10
+ || TargetFormat == D3D9Format::A16B16G16R16
+ || TargetFormat == D3D9Format::A2B10G10R10
+ || TargetFormat == D3D9Format::A8B8G8R8
+ || TargetFormat == D3D9Format::X8B8G8R8
+ || TargetFormat == D3D9Format::A16B16G16R16F
+ || TargetFormat == D3D9Format::A32B32G32R32F;
+
+ return (sourceSupported && targetSupported)
+ ? D3D_OK
+ : D3DERR_NOTAVAILABLE;
+ }
+
+
+ HRESULT D3D9Adapter::GetDeviceCaps(
+ D3DDEVTYPE DeviceType,
+ D3DCAPS9* pCaps) {
+ using namespace dxvk::caps;
+
+ if (pCaps == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto& options = m_parent->GetOptions();
+
+ // TODO: Actually care about what the adapter supports here.
+ // ^ For Intel and older cards most likely here.
+
+ // Device Type
+ pCaps->DeviceType = DeviceType;
+ // Adapter Id
+ pCaps->AdapterOrdinal = m_ordinal;
+ // Caps 1
+ pCaps->Caps = D3DCAPS_READ_SCANLINE;
+ // Caps 2
+ pCaps->Caps2 = D3DCAPS2_FULLSCREENGAMMA
+ /* | D3DCAPS2_CANCALIBRATEGAMMA */
+ /* | D3DCAPS2_RESERVED */
+ /* | D3DCAPS2_CANMANAGERESOURCE */
+ | D3DCAPS2_DYNAMICTEXTURES
+ | D3DCAPS2_CANAUTOGENMIPMAP
+ /* | D3DCAPS2_CANSHARERESOURCE */;
+ // Caps 3
+ pCaps->Caps3 = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD
+ | D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
+ | D3DCAPS3_COPY_TO_VIDMEM
+ | D3DCAPS3_COPY_TO_SYSTEMMEM
+ /* | D3DCAPS3_DXVAHD */
+ /* | D3DCAPS3_DXVAHD_LIMITED */;
+ // Presentation Intervals
+ pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_DEFAULT
+ | D3DPRESENT_INTERVAL_ONE
+ | D3DPRESENT_INTERVAL_TWO
+ | D3DPRESENT_INTERVAL_THREE
+ | D3DPRESENT_INTERVAL_FOUR
+ | D3DPRESENT_INTERVAL_IMMEDIATE;
+ // Cursor
+ pCaps->CursorCaps = D3DCURSORCAPS_COLOR; // I do not support Cursor yet, but I don't want to say I don't support it for compatibility reasons.
+ // Dev Caps
+ pCaps->DevCaps = D3DDEVCAPS_EXECUTESYSTEMMEMORY
+ | D3DDEVCAPS_EXECUTEVIDEOMEMORY
+ | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY
+ | D3DDEVCAPS_TLVERTEXVIDEOMEMORY
+ /* | D3DDEVCAPS_TEXTURESYSTEMMEMORY */
+ | D3DDEVCAPS_TEXTUREVIDEOMEMORY
+ | D3DDEVCAPS_DRAWPRIMTLVERTEX
+ | D3DDEVCAPS_CANRENDERAFTERFLIP
+ | D3DDEVCAPS_TEXTURENONLOCALVIDMEM
+ | D3DDEVCAPS_DRAWPRIMITIVES2
+ /* | D3DDEVCAPS_SEPARATETEXTUREMEMORIES */
+ | D3DDEVCAPS_DRAWPRIMITIVES2EX
+ | D3DDEVCAPS_HWTRANSFORMANDLIGHT
+ | D3DDEVCAPS_CANBLTSYSTONONLOCAL
+ | D3DDEVCAPS_HWRASTERIZATION
+ | D3DDEVCAPS_PUREDEVICE
+ /* | D3DDEVCAPS_QUINTICRTPATCHES */
+ /* | D3DDEVCAPS_RTPATCHES */
+ /* | D3DDEVCAPS_RTPATCHHANDLEZERO */
+ /* | D3DDEVCAPS_NPATCHES */;
+ // Primitive Misc. Caps
+ pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_MASKZ
+ | D3DPMISCCAPS_CULLNONE
+ | D3DPMISCCAPS_CULLCW
+ | D3DPMISCCAPS_CULLCCW
+ | D3DPMISCCAPS_COLORWRITEENABLE
+ | D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
+ | D3DPMISCCAPS_CLIPTLVERTS
+ | D3DPMISCCAPS_TSSARGTEMP
+ | D3DPMISCCAPS_BLENDOP
+ /* | D3DPMISCCAPS_NULLREFERENCE */
+ | D3DPMISCCAPS_INDEPENDENTWRITEMASKS
+ | D3DPMISCCAPS_PERSTAGECONSTANT
+ | D3DPMISCCAPS_FOGANDSPECULARALPHA
+ | D3DPMISCCAPS_SEPARATEALPHABLEND
+ | D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
+ | D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
+ | D3DPMISCCAPS_FOGVERTEXCLAMPED
+ | D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
+ // Raster Caps
+ pCaps->RasterCaps = D3DPRASTERCAPS_DITHER
+ | D3DPRASTERCAPS_ZTEST
+ | D3DPRASTERCAPS_FOGVERTEX
+ | D3DPRASTERCAPS_FOGTABLE
+ | D3DPRASTERCAPS_MIPMAPLODBIAS
+ /* | D3DPRASTERCAPS_ZBUFFERLESSHSR */
+ | D3DPRASTERCAPS_FOGRANGE
+ | D3DPRASTERCAPS_ANISOTROPY
+ /* | D3DPRASTERCAPS_WBUFFER */
+ | D3DPRASTERCAPS_WFOG
+ | D3DPRASTERCAPS_ZFOG
+ | D3DPRASTERCAPS_COLORPERSPECTIVE
+ | D3DPRASTERCAPS_SCISSORTEST
+ | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
+ | D3DPRASTERCAPS_DEPTHBIAS
+ | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; // <-- TODO! (but difficult in Vk)
+ // Z Comparison Caps
+ pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER
+ | D3DPCMPCAPS_LESS
+ | D3DPCMPCAPS_EQUAL
+ | D3DPCMPCAPS_LESSEQUAL
+ | D3DPCMPCAPS_GREATER
+ | D3DPCMPCAPS_NOTEQUAL
+ | D3DPCMPCAPS_GREATEREQUAL
+ | D3DPCMPCAPS_ALWAYS;
+ // Source Blend Caps
+ pCaps->SrcBlendCaps = D3DPBLENDCAPS_ZERO
+ | D3DPBLENDCAPS_ONE
+ | D3DPBLENDCAPS_SRCCOLOR
+ | D3DPBLENDCAPS_INVSRCCOLOR
+ | D3DPBLENDCAPS_SRCALPHA
+ | D3DPBLENDCAPS_INVSRCALPHA
+ | D3DPBLENDCAPS_DESTALPHA
+ | D3DPBLENDCAPS_INVDESTALPHA
+ | D3DPBLENDCAPS_DESTCOLOR
+ | D3DPBLENDCAPS_INVDESTCOLOR
+ | D3DPBLENDCAPS_SRCALPHASAT
+ | D3DPBLENDCAPS_BOTHSRCALPHA
+ | D3DPBLENDCAPS_BOTHINVSRCALPHA
+ | D3DPBLENDCAPS_BLENDFACTOR
+ | D3DPBLENDCAPS_INVSRCCOLOR2
+ | D3DPBLENDCAPS_SRCCOLOR2;
+ // Destination Blend Caps
+ pCaps->DestBlendCaps = pCaps->SrcBlendCaps;
+ // Alpha Comparison Caps
+ pCaps->AlphaCmpCaps = pCaps->ZCmpCaps;
+ // Shade Caps
+ pCaps->ShadeCaps = D3DPSHADECAPS_COLORGOURAUDRGB
+ | D3DPSHADECAPS_SPECULARGOURAUDRGB
+ | D3DPSHADECAPS_ALPHAGOURAUDBLEND
+ | D3DPSHADECAPS_FOGGOURAUD;
+ // Texture Caps
+ pCaps->TextureCaps = D3DPTEXTURECAPS_PERSPECTIVE
+ /* | D3DPTEXTURECAPS_POW2 */
+ | D3DPTEXTURECAPS_ALPHA
+ /* | D3DPTEXTURECAPS_SQUAREONLY */
+ | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE
+ | D3DPTEXTURECAPS_ALPHAPALETTE
+ /* | D3DPTEXTURECAPS_NONPOW2CONDITIONAL */
+ | D3DPTEXTURECAPS_PROJECTED
+ | D3DPTEXTURECAPS_CUBEMAP
+ | D3DPTEXTURECAPS_VOLUMEMAP
+ | D3DPTEXTURECAPS_MIPMAP
+ | D3DPTEXTURECAPS_MIPVOLUMEMAP
+ | D3DPTEXTURECAPS_MIPCUBEMAP
+ /* | D3DPTEXTURECAPS_CUBEMAP_POW2 */
+ /* | D3DPTEXTURECAPS_VOLUMEMAP_POW2 */
+ /* | D3DPTEXTURECAPS_NOPROJECTEDBUMPENV */;
+ // Texture Filter Caps
+ pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MINFPOINT
+ | D3DPTFILTERCAPS_MINFLINEAR
+ | D3DPTFILTERCAPS_MINFANISOTROPIC
+ /* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
+ /* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
+ | D3DPTFILTERCAPS_MIPFPOINT
+ | D3DPTFILTERCAPS_MIPFLINEAR
+ /* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
+ | D3DPTFILTERCAPS_MAGFPOINT
+ | D3DPTFILTERCAPS_MAGFLINEAR
+ | D3DPTFILTERCAPS_MAGFANISOTROPIC
+ /* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
+ /* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
+ // Cube Texture Filter Caps
+ pCaps->CubeTextureFilterCaps = pCaps->TextureFilterCaps;
+ // Volume Texture Filter Caps
+ pCaps->VolumeTextureFilterCaps = pCaps->TextureFilterCaps;
+ // Texture Address Caps
+ pCaps->TextureAddressCaps = D3DPTADDRESSCAPS_WRAP
+ | D3DPTADDRESSCAPS_MIRROR
+ | D3DPTADDRESSCAPS_CLAMP
+ | D3DPTADDRESSCAPS_BORDER
+ | D3DPTADDRESSCAPS_INDEPENDENTUV
+ | D3DPTADDRESSCAPS_MIRRORONCE;
+ // Volume Texture Address Caps
+ pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps;
+ // Line Caps
+ pCaps->LineCaps = D3DLINECAPS_TEXTURE
+ | D3DLINECAPS_ZTEST
+ | D3DLINECAPS_BLEND
+ | D3DLINECAPS_ALPHACMP
+ | D3DLINECAPS_FOG
+ | D3DLINECAPS_ANTIALIAS; //<-- Lying about doing AA lines here, we don't *fully* support that.
+ // Max Texture Width
+ pCaps->MaxTextureWidth = MaxTextureDimension;
+ // Max Texture Height
+ pCaps->MaxTextureHeight = MaxTextureDimension;
+ // Max Volume Extent
+ pCaps->MaxVolumeExtent = 8192;
+ // Max Texture Repeat
+ pCaps->MaxTextureRepeat = 8192;
+ // Max Texture Aspect Ratio
+ pCaps->MaxTextureAspectRatio = 8192;
+ // Max Anisotropy
+ pCaps->MaxAnisotropy = 16;
+ // Max Vertex W
+ pCaps->MaxVertexW = 1e10f;
+ // Guard Bands
+ pCaps->GuardBandLeft = -32768.0f;
+ pCaps->GuardBandTop = -32768.0f;
+ pCaps->GuardBandRight = 32768.0f;
+ pCaps->GuardBandBottom = 32768.0f;
+ // Extents Adjust
+ pCaps->ExtentsAdjust = 0.0f;
+ // Stencil Caps
+ pCaps->StencilCaps = D3DSTENCILCAPS_KEEP
+ | D3DSTENCILCAPS_ZERO
+ | D3DSTENCILCAPS_REPLACE
+ | D3DSTENCILCAPS_INCRSAT
+ | D3DSTENCILCAPS_DECRSAT
+ | D3DSTENCILCAPS_INVERT
+ | D3DSTENCILCAPS_INCR
+ | D3DSTENCILCAPS_DECR
+ | D3DSTENCILCAPS_TWOSIDED;
+ // FVF Caps
+ pCaps->FVFCaps = (MaxSimultaneousTextures & D3DFVFCAPS_TEXCOORDCOUNTMASK)
+ /* | D3DFVFCAPS_DONOTSTRIPELEMENTS */
+ | D3DFVFCAPS_PSIZE;
+ // Texture Op Caps
+ pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE
+ | D3DTEXOPCAPS_SELECTARG1
+ | D3DTEXOPCAPS_SELECTARG2
+ | D3DTEXOPCAPS_MODULATE
+ | D3DTEXOPCAPS_MODULATE2X
+ | D3DTEXOPCAPS_MODULATE4X
+ | D3DTEXOPCAPS_ADD
+ | D3DTEXOPCAPS_ADDSIGNED
+ | D3DTEXOPCAPS_ADDSIGNED2X
+ | D3DTEXOPCAPS_SUBTRACT
+ | D3DTEXOPCAPS_ADDSMOOTH
+ | D3DTEXOPCAPS_BLENDDIFFUSEALPHA
+ | D3DTEXOPCAPS_BLENDTEXTUREALPHA
+ | D3DTEXOPCAPS_BLENDFACTORALPHA
+ | D3DTEXOPCAPS_BLENDTEXTUREALPHAPM
+ | D3DTEXOPCAPS_BLENDCURRENTALPHA
+ | D3DTEXOPCAPS_PREMODULATE
+ | D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
+ | D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
+ | D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
+ | D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
+ | D3DTEXOPCAPS_BUMPENVMAP
+ | D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
+ | D3DTEXOPCAPS_DOTPRODUCT3
+ | D3DTEXOPCAPS_MULTIPLYADD
+ | D3DTEXOPCAPS_LERP;
+ // Max Texture Blend Stages
+ pCaps->MaxTextureBlendStages = MaxTextureBlendStages;
+ // Max Simultaneous Textures
+ pCaps->MaxSimultaneousTextures = MaxSimultaneousTextures;
+ // Vertex Processing Caps
+ pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN
+ | D3DVTXPCAPS_MATERIALSOURCE7
+ | D3DVTXPCAPS_DIRECTIONALLIGHTS
+ | D3DVTXPCAPS_POSITIONALLIGHTS
+ | D3DVTXPCAPS_LOCALVIEWER
+ | D3DVTXPCAPS_TWEENING
+ | D3DVTXPCAPS_TEXGEN_SPHEREMAP
+ /* | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/;
+ // Max Active Lights
+ pCaps->MaxActiveLights = caps::MaxEnabledLights;
+ // Max User Clip Planes
+ pCaps->MaxUserClipPlanes = MaxClipPlanes;
+ // Max Vertex Blend Matrices
+ pCaps->MaxVertexBlendMatrices = 4;
+ // Max Vertex Blend Matrix Index
+ pCaps->MaxVertexBlendMatrixIndex = 8;
+ // Max Point Size
+ pCaps->MaxPointSize = 256.0f;
+ // Max Primitive Count
+ pCaps->MaxPrimitiveCount = 0x00555555;
+ // Max Vertex Index
+ pCaps->MaxVertexIndex = 0x00ffffff;
+ // Max Streams
+ pCaps->MaxStreams = MaxStreams;
+ // Max Stream Stride
+ pCaps->MaxStreamStride = 508; // bytes
+
+ const uint32_t majorVersion = options.shaderModel;
+ const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
+
+ // Shader Versions
+ pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
+ pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersion, minorVersion);
+
+ // Max Vertex Shader Const
+ pCaps->MaxVertexShaderConst = MaxFloatConstantsVS;
+ // Max PS1 Value
+ pCaps->PixelShader1xMaxValue = FLT_MAX;
+ // Dev Caps 2
+ pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET
+ /* | D3DDEVCAPS2_DMAPNPATCH */
+ /* | D3DDEVCAPS2_ADAPTIVETESSRTPATCH */
+ /* | D3DDEVCAPS2_ADAPTIVETESSNPATCH */
+ | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
+ /* | D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH */
+ | D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
+ // Max N Patch Tesselation Level
+ pCaps->MaxNpatchTessellationLevel = 0.0f;
+ // Reserved for... something
+ pCaps->Reserved5 = 0;
+ // Master adapter for us is adapter 0, atm...
+ pCaps->MasterAdapterOrdinal = 0;
+ // The group of adapters this one is in
+ pCaps->AdapterOrdinalInGroup = 0;
+ // Number of adapters in current group
+ pCaps->NumberOfAdaptersInGroup = 1;
+ // Decl Type Caps
+ pCaps->DeclTypes = D3DDTCAPS_UBYTE4
+ | D3DDTCAPS_UBYTE4N
+ | D3DDTCAPS_SHORT2N
+ | D3DDTCAPS_SHORT4N
+ | D3DDTCAPS_USHORT2N
+ | D3DDTCAPS_USHORT4N
+ | D3DDTCAPS_UDEC3
+ | D3DDTCAPS_DEC3N
+ | D3DDTCAPS_FLOAT16_2
+ | D3DDTCAPS_FLOAT16_4;
+ // Number of simultaneous RTs
+ pCaps->NumSimultaneousRTs = MaxSimultaneousRenderTargets;
+ // Possible StretchRect filters
+ pCaps->StretchRectFilterCaps = D3DPTFILTERCAPS_MINFPOINT
+ | D3DPTFILTERCAPS_MINFLINEAR
+ /* | D3DPTFILTERCAPS_MINFANISOTROPIC */
+ /* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
+ /* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
+ /* | D3DPTFILTERCAPS_MIPFPOINT */
+ /* | D3DPTFILTERCAPS_MIPFLINEAR */
+ /* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
+ | D3DPTFILTERCAPS_MAGFPOINT
+ | D3DPTFILTERCAPS_MAGFLINEAR
+ /* | D3DPTFILTERCAPS_MAGFANISOTROPIC */
+ /* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
+ /* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
+
+ // Not too bothered about doing these longhand
+ // We should match whatever my AMD hardware reports here
+ // methinks for the best chance of stuff working.
+ pCaps->VS20Caps.Caps = 1;
+ pCaps->VS20Caps.DynamicFlowControlDepth = 24;
+ pCaps->VS20Caps.NumTemps = 32;
+ pCaps->VS20Caps.StaticFlowControlDepth = 4;
+
+ pCaps->PS20Caps.Caps = 31;
+ pCaps->PS20Caps.DynamicFlowControlDepth = 24;
+ pCaps->PS20Caps.NumTemps = 32;
+ pCaps->PS20Caps.StaticFlowControlDepth = 4;
+
+ pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;
+
+ pCaps->VertexTextureFilterCaps = 50332416;
+ pCaps->MaxVShaderInstructionsExecuted = 4294967295;
+ pCaps->MaxPShaderInstructionsExecuted = 4294967295;
+
+ pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
+ pCaps->MaxPixelShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
+
+ return D3D_OK;
+ }
+
+
+ HMONITOR D3D9Adapter::GetMonitor() {
+ return GetDefaultMonitor();
+ }
+
+
+ UINT D3D9Adapter::GetAdapterModeCountEx(const D3DDISPLAYMODEFILTER* pFilter) {
+ if (pFilter == nullptr)
+ return 0;
+
+ // We don't offer any interlaced formats here so early out and avoid destroying mode cache.
+ if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
+ return 0;
+
+ CacheModes(EnumerateFormat(pFilter->Format));
+ return m_modes.size();
+ }
+
+
+ HRESULT D3D9Adapter::EnumAdapterModesEx(
+ const D3DDISPLAYMODEFILTER* pFilter,
+ UINT Mode,
+ D3DDISPLAYMODEEX* pMode) {
+ if (pMode == nullptr || pFilter == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ const D3D9Format format =
+ EnumerateFormat(pFilter->Format);
+
+ if (FAILED(CheckDeviceFormat(
+ D3DDEVTYPE_HAL, EnumerateFormat(pFilter->Format),
+ D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
+ EnumerateFormat(pFilter->Format))))
+ return D3DERR_INVALIDCALL;
+
+ CacheModes(format);
+
+ // We don't return any scanline orderings that aren't progressive,
+ // The format filtering is already handled for us by cache modes
+ // So we can early out here and then just index.
+ if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
+ return D3DERR_INVALIDCALL;
+
+ if (Mode >= m_modes.size())
+ return D3DERR_INVALIDCALL;
+
+ *pMode = m_modes[Mode];
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::GetAdapterDisplayModeEx(
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation) {
+ if (pMode == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ if (pRotation != nullptr)
+ *pRotation = D3DDISPLAYROTATION_IDENTITY;
+
+ wsi::WsiMode mode = { };
+
+ if (!wsi::getCurrentDisplayMode(GetDefaultMonitor(), &mode)) {
+ Logger::err("D3D9Adapter::GetAdapterDisplayModeEx: Failed to enum display settings");
+ return D3DERR_INVALIDCALL;
+ }
+
+ pMode->Size = sizeof(D3DDISPLAYMODEEX);
+ pMode->Width = mode.width;
+ pMode->Height = mode.height;
+ pMode->RefreshRate = mode.refreshRate.numerator / mode.refreshRate.denominator;
+ pMode->Format = D3DFMT_X8R8G8B8;
+ pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::GetAdapterLUID(LUID* pLUID) {
+ if (pLUID == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto& deviceId = m_adapter->devicePropertiesExt().coreDeviceId;
+
+ if (deviceId.deviceLUIDValid)
+ *pLUID = bit::cast<LUID>(deviceId.deviceLUID);
+ else
+ *pLUID = dxvk::GetAdapterLUID(m_ordinal);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9Adapter::CheckDeviceVkFormat(
+ VkFormat Format,
+ DWORD Usage,
+ D3DRESOURCETYPE RType) {
+ VkFormatFeatureFlags checkFlags = 0;
+
+ if (RType != D3DRTYPE_SURFACE)
+ checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+
+ if (Usage & D3DUSAGE_RENDERTARGET) {
+ checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+
+ if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING)
+ checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
+ }
+
+ if (Usage & D3DUSAGE_DEPTHSTENCIL)
+ checkFlags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ else
+ checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+
+ VkFormatFeatureFlags checkFlagsMipGen = checkFlags;
+
+ if (Usage & D3DUSAGE_AUTOGENMIPMAP) {
+ checkFlagsMipGen |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+ checkFlagsMipGen |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+ }
+
+ VkFormatProperties fmtSupport = m_adapter->formatProperties(Format);
+ VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures;
+
+ if ((imgFeatures & checkFlags) != checkFlags)
+ return D3DERR_NOTAVAILABLE;
+
+ return ((imgFeatures & checkFlagsMipGen) != checkFlagsMipGen)
+ ? D3DOK_NOAUTOGEN
+ : D3D_OK;
+ }
+
+
+ void D3D9Adapter::CacheModes(D3D9Format Format) {
+ if (!m_modes.empty() && m_modeCacheFormat == Format)
+ return; // We already cached the modes for this format. No need to do it again.
+
+ m_modes.clear();
+ m_modeCacheFormat = Format;
+
+ // Skip unsupported formats
+ if (!IsSupportedAdapterFormat(Format))
+ return;
+
+ auto& options = m_parent->GetOptions();
+
+ // Walk over all modes that the display supports and
+ // return those that match the requested format etc.
+ wsi::WsiMode devMode = { };
+
+ uint32_t modeIndex = 0;
+
+ const auto forcedRatio = Ratio<DWORD>(options.forceAspectRatio);
+
+ while (wsi::getDisplayMode(GetDefaultMonitor(), modeIndex++, &devMode)) {
+ // Skip interlaced modes altogether
+ if (devMode.interlaced)
+ continue;
+
+ // Skip modes with incompatible formats
+ if (devMode.bitsPerPixel != GetMonitorFormatBpp(Format))
+ continue;
+
+ if (!forcedRatio.undefined() && Ratio<DWORD>(devMode.width, devMode.height) != forcedRatio)
+ continue;
+
+ D3DDISPLAYMODEEX mode;
+ mode.Size = sizeof(D3DDISPLAYMODEEX);
+ mode.Width = devMode.width;
+ mode.Height = devMode.height;
+ mode.RefreshRate = devMode.refreshRate.numerator / devMode.refreshRate.denominator;
+ mode.Format = static_cast<D3DFORMAT>(Format);
+ mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+
+ m_modes.push_back(mode);
+ }
+
+ // Sort display modes by width, height and refresh rate,
+ // in that order. Some games rely on correct ordering.
+ std::sort(m_modes.begin(), m_modes.end(),
+ [](const D3DDISPLAYMODEEX& a, const D3DDISPLAYMODEEX& b) {
+ if (a.Width < b.Width) return true;
+ if (a.Width > b.Width) return false;
+
+ if (a.Height < b.Height) return true;
+ if (a.Height > b.Height) return false;
+
+ return a.RefreshRate < b.RefreshRate;
+ });
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.h
new file mode 100644
index 00000000..0cf74981
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_adapter.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+#include "d3d9_options.h"
+#include "d3d9_format.h"
+
+#include "../dxvk/dxvk_adapter.h"
+
+namespace dxvk {
+
+ class D3D9InterfaceEx;
+
+ class D3D9Adapter {
+
+ public:
+
+ D3D9Adapter(
+ D3D9InterfaceEx* pParent,
+ Rc<DxvkAdapter> Adapter,
+ UINT Ordinal,
+ UINT DisplayIndex);
+
+ HRESULT GetAdapterIdentifier(
+ DWORD Flags,
+ D3DADAPTER_IDENTIFIER9* pIdentifier);
+
+ HRESULT CheckDeviceType(
+ D3DDEVTYPE DevType,
+ D3D9Format AdapterFormat,
+ D3D9Format BackBufferFormat,
+ BOOL bWindowed);
+
+ HRESULT CheckDeviceFormat(
+ D3DDEVTYPE DeviceType,
+ D3D9Format AdapterFormat,
+ DWORD Usage,
+ D3DRESOURCETYPE RType,
+ D3D9Format CheckFormat);
+
+ HRESULT CheckDeviceMultiSampleType(
+ D3DDEVTYPE DeviceType,
+ D3D9Format SurfaceFormat,
+ BOOL Windowed,
+ D3DMULTISAMPLE_TYPE MultiSampleType,
+ DWORD* pQualityLevels);
+
+ HRESULT CheckDepthStencilMatch(
+ D3DDEVTYPE DeviceType,
+ D3D9Format AdapterFormat,
+ D3D9Format RenderTargetFormat,
+ D3D9Format DepthStencilFormat);
+
+ HRESULT CheckDeviceFormatConversion(
+ D3DDEVTYPE DeviceType,
+ D3D9Format SourceFormat,
+ D3D9Format TargetFormat);
+
+ HRESULT GetDeviceCaps(
+ D3DDEVTYPE DeviceType,
+ D3DCAPS9* pCaps);
+
+ HMONITOR GetMonitor();
+
+ UINT GetAdapterModeCountEx(const D3DDISPLAYMODEFILTER* pFilter);
+
+ HRESULT EnumAdapterModesEx(
+ const D3DDISPLAYMODEFILTER* pFilter,
+ UINT Mode,
+ D3DDISPLAYMODEEX* pMode);
+
+ HRESULT GetAdapterDisplayModeEx(
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation);
+
+ HRESULT GetAdapterLUID(LUID* pLUID);
+
+ UINT GetOrdinal() { return m_ordinal; }
+
+ Rc<DxvkAdapter> GetDXVKAdapter() { return m_adapter; }
+
+ D3D9_VK_FORMAT_MAPPING GetFormatMapping(D3D9Format Format) const {
+ return m_d3d9Formats.GetFormatMapping(Format);
+ }
+
+ const DxvkFormatInfo* GetUnsupportedFormatInfo(D3D9Format Format) const {
+ return m_d3d9Formats.GetUnsupportedFormatInfo(Format);
+ }
+
+ private:
+
+ HRESULT CheckDeviceVkFormat(
+ VkFormat Format,
+ DWORD Usage,
+ D3DRESOURCETYPE RType);
+
+ void CacheModes(D3D9Format Format);
+
+ D3D9InterfaceEx* m_parent;
+
+ Rc<DxvkAdapter> m_adapter;
+ UINT m_ordinal;
+ UINT m_displayIndex;
+
+ std::vector<D3DDISPLAYMODEEX> m_modes;
+ D3D9Format m_modeCacheFormat;
+
+ const D3D9VkFormatTable m_d3d9Formats;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.cpp
new file mode 100644
index 00000000..c0b72c46
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.cpp
@@ -0,0 +1,116 @@
+#include "d3d9_buffer.h"
+
+namespace dxvk {
+
+ ////////////////////////
+ // D3D9VertexBuffer
+ ////////////////////////
+
+ D3D9VertexBuffer::D3D9VertexBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc)
+ : D3D9VertexBufferBase(pDevice, pDesc) {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9VertexBuffer::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DVertexBuffer9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9VertexBuffer::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9VertexBuffer::GetType() {
+ return D3DRTYPE_VERTEXBUFFER;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9VertexBuffer::GetDesc(
+ D3DVERTEXBUFFER_DESC* pDesc) {
+ if (pDesc == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ const D3D9_BUFFER_DESC* desc = m_buffer.Desc();
+
+ pDesc->Format = static_cast<D3DFORMAT>(desc->Format);
+ pDesc->Type = desc->Type;
+ pDesc->Usage = desc->Usage;
+ pDesc->Pool = desc->Pool;
+ pDesc->Size = desc->Size;
+ pDesc->FVF = desc->FVF;
+
+ return D3D_OK;
+ }
+
+
+ //////////////////////
+ // D3D9IndexBuffer
+ //////////////////////
+
+
+ D3D9IndexBuffer::D3D9IndexBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc)
+ : D3D9IndexBufferBase(pDevice, pDesc) {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9IndexBuffer::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DIndexBuffer9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9IndexBuffer::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9IndexBuffer::GetType() {
+ return D3DRTYPE_INDEXBUFFER;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9IndexBuffer::GetDesc(
+ D3DINDEXBUFFER_DESC* pDesc) {
+ if (pDesc == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ const D3D9_BUFFER_DESC* desc = m_buffer.Desc();
+
+ pDesc->Format = static_cast<D3DFORMAT>(desc->Format);
+ pDesc->Type = desc->Type;
+ pDesc->Usage = desc->Usage;
+ pDesc->Pool = desc->Pool;
+ pDesc->Size = desc->Size;
+
+ return D3D_OK;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.h
new file mode 100644
index 00000000..0600334c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_buffer.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "d3d9_resource.h"
+
+#include "d3d9_common_buffer.h"
+
+namespace dxvk {
+
+ template <typename... Type>
+ class D3D9Buffer : public D3D9Resource<Type...> {
+
+ public:
+
+ D3D9Buffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc)
+ : D3D9Resource<Type...> (pDevice),
+ m_buffer (pDevice, pDesc) {
+
+ }
+
+ HRESULT STDMETHODCALLTYPE Lock(
+ UINT OffsetToLock,
+ UINT SizeToLock,
+ void** ppbData,
+ DWORD Flags) final {
+ return m_buffer.Lock(
+ OffsetToLock,
+ SizeToLock,
+ ppbData,
+ Flags);
+ }
+
+ HRESULT STDMETHODCALLTYPE Unlock() final {
+ return m_buffer.Unlock();
+ }
+
+ void STDMETHODCALLTYPE PreLoad() final {
+ m_buffer.PreLoad();
+ }
+
+ D3D9CommonBuffer* GetCommonBuffer() {
+ return &m_buffer;
+ }
+
+ protected:
+
+ D3D9CommonBuffer m_buffer;
+
+ };
+
+
+ using D3D9VertexBufferBase = D3D9Buffer<IDirect3DVertexBuffer9>;
+ class D3D9VertexBuffer final : public D3D9VertexBufferBase {
+
+ public:
+
+ D3D9VertexBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
+
+ HRESULT STDMETHODCALLTYPE GetDesc(D3DVERTEXBUFFER_DESC* pDesc);
+
+ };
+
+ using D3D9IndexBufferBase = D3D9Buffer<IDirect3DIndexBuffer9>;
+ class D3D9IndexBuffer final : public D3D9IndexBufferBase {
+
+ public:
+
+ D3D9IndexBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
+
+ HRESULT STDMETHODCALLTYPE GetDesc(D3DINDEXBUFFER_DESC* pDesc);
+
+ };
+
+ template <typename T>
+ inline D3D9CommonBuffer* GetCommonBuffer(const T& pResource) {
+ return pResource != nullptr ? pResource->GetCommonBuffer() : nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_caps.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_caps.h
new file mode 100644
index 00000000..0b008757
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_caps.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk::caps {
+
+ constexpr uint32_t MaxClipPlanes = 6;
+ constexpr uint32_t MaxSamplers = 16;
+ constexpr uint32_t MaxStreams = 16;
+ constexpr uint32_t MaxSimultaneousTextures = 8;
+ constexpr uint32_t MaxTextureBlendStages = MaxSimultaneousTextures;
+ constexpr uint32_t MaxSimultaneousRenderTargets = D3D_MAX_SIMULTANEOUS_RENDERTARGETS;
+
+ constexpr uint32_t MaxFloatConstantsVS = 256;
+ constexpr uint32_t MaxFloatConstantsPS = 224;
+ constexpr uint32_t MaxOtherConstants = 16;
+ constexpr uint32_t MaxFloatConstantsSoftware = 8192;
+ constexpr uint32_t MaxOtherConstantsSoftware = 2048;
+
+ constexpr uint32_t InputRegisterCount = 16;
+
+ constexpr uint32_t MaxTextureDimension = 16384;
+ constexpr uint32_t MaxMipLevels = 15;
+ constexpr uint32_t MaxSubresources = 15 * 6;
+
+ constexpr uint32_t MaxTransforms = 10 + 256;
+
+ constexpr uint32_t TextureStageCount = MaxSimultaneousTextures;
+
+ constexpr uint32_t MaxEnabledLights = 8;
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.cpp
new file mode 100644
index 00000000..509f0cbf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.cpp
@@ -0,0 +1,136 @@
+#include "d3d9_common_buffer.h"
+
+#include "d3d9_device.h"
+#include "d3d9_util.h"
+
+namespace dxvk {
+
+ D3D9CommonBuffer::D3D9CommonBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc)
+ : m_parent ( pDevice ), m_desc ( *pDesc ) {
+ m_buffer = CreateBuffer();
+ if (GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
+ m_stagingBuffer = CreateStagingBuffer();
+
+ m_sliceHandle = GetMapBuffer()->getSliceHandle();
+
+ if (m_desc.Pool != D3DPOOL_DEFAULT)
+ m_dirtyRange = D3D9Range(0, m_desc.Size);
+ }
+
+
+ HRESULT D3D9CommonBuffer::Lock(
+ UINT OffsetToLock,
+ UINT SizeToLock,
+ void** ppbData,
+ DWORD Flags) {
+ return m_parent->LockBuffer(
+ this,
+ OffsetToLock,
+ SizeToLock,
+ ppbData,
+ Flags);
+ }
+
+
+ HRESULT D3D9CommonBuffer::Unlock() {
+ return m_parent->UnlockBuffer(this);
+ }
+
+
+ HRESULT D3D9CommonBuffer::ValidateBufferProperties(const D3D9_BUFFER_DESC* pDesc) {
+ if (pDesc->Size == 0)
+ return D3DERR_INVALIDCALL;
+
+ return D3D_OK;
+ }
+
+
+ void D3D9CommonBuffer::PreLoad() {
+ if (IsPoolManaged(m_desc.Pool)) {
+ auto lock = m_parent->LockDevice();
+
+ if (NeedsUpload())
+ m_parent->FlushBuffer(this);
+ }
+ }
+
+
+ Rc<DxvkBuffer> D3D9CommonBuffer::CreateBuffer() const {
+ DxvkBufferCreateInfo info;
+ info.size = m_desc.Size;
+ info.usage = 0;
+ info.stages = 0;
+ info.access = 0;
+
+ VkMemoryPropertyFlags memoryFlags = 0;
+
+ if (m_desc.Type == D3DRTYPE_VERTEXBUFFER) {
+ info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+
+ if (m_parent->SupportsSWVP()) {
+ info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
+ info.access |= VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ }
+ else if (m_desc.Type == D3DRTYPE_INDEXBUFFER) {
+ info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ info.access |= VK_ACCESS_INDEX_READ_BIT;
+ }
+
+ if (GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT) {
+ info.stages |= VK_PIPELINE_STAGE_HOST_BIT;
+ info.access |= VK_ACCESS_HOST_WRITE_BIT;
+
+ if (!(m_desc.Usage & D3DUSAGE_WRITEONLY))
+ info.access |= VK_ACCESS_HOST_READ_BIT;
+
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ }
+ else {
+ info.stages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ info.access |= VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ }
+
+ if (memoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT && m_parent->GetOptions()->apitraceMode) {
+ memoryFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ }
+
+ return m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
+ }
+
+
+ Rc<DxvkBuffer> D3D9CommonBuffer::CreateStagingBuffer() const {
+ DxvkBufferCreateInfo info;
+ info.size = m_desc.Size;
+ info.stages = VK_PIPELINE_STAGE_HOST_BIT
+ | VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+
+ info.access = VK_ACCESS_HOST_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT;
+
+ if (!(m_desc.Usage & D3DUSAGE_WRITEONLY))
+ info.access |= VK_ACCESS_HOST_READ_BIT;
+
+ VkMemoryPropertyFlags memoryFlags =
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+
+ return m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.h
new file mode 100644
index 00000000..8f24d9c8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_buffer.h
@@ -0,0 +1,225 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+#include "d3d9_device_child.h"
+#include "d3d9_format.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Buffer map mode
+ */
+ enum D3D9_COMMON_BUFFER_MAP_MODE {
+ D3D9_COMMON_BUFFER_MAP_MODE_BUFFER,
+ D3D9_COMMON_BUFFER_MAP_MODE_DIRECT
+ };
+
+ /**
+ * \brief Common buffer descriptor
+ */
+ struct D3D9_BUFFER_DESC {
+ D3DRESOURCETYPE Type;
+ UINT Size;
+ DWORD Usage;
+ D3D9Format Format;
+ D3DPOOL Pool;
+ DWORD FVF;
+ };
+
+ /**
+ * \brief The type of buffer you want to use
+ */
+ enum D3D9_COMMON_BUFFER_TYPE {
+ D3D9_COMMON_BUFFER_TYPE_MAPPING,
+ D3D9_COMMON_BUFFER_TYPE_STAGING,
+ D3D9_COMMON_BUFFER_TYPE_REAL
+ };
+
+ struct D3D9Range {
+ D3D9Range() { Clear(); }
+
+ D3D9Range(uint32_t min, uint32_t max)
+ : min(min),
+ max(max) {
+
+ }
+
+ inline bool IsDegenerate() { return min == max; }
+
+ inline void Conjoin(D3D9Range range) {
+ if (IsDegenerate())
+ *this = range;
+ else {
+ min = std::min(range.min, min);
+ max = std::max(range.max, max);
+ }
+ }
+
+ inline bool Overlaps(D3D9Range range) {
+ if (IsDegenerate())
+ return false;
+
+ return range.max > min && range.min < max;
+ }
+
+ inline void Clear() { min = 0; max = 0; }
+
+ uint32_t min = 0;
+ uint32_t max = 0;
+ };
+
+ class D3D9CommonBuffer {
+ static constexpr VkDeviceSize BufferSliceAlignment = 64;
+ public:
+
+ D3D9CommonBuffer(
+ D3D9DeviceEx* pDevice,
+ const D3D9_BUFFER_DESC* pDesc);
+
+ HRESULT Lock(
+ UINT OffsetToLock,
+ UINT SizeToLock,
+ void** ppbData,
+ DWORD Flags);
+
+ HRESULT Unlock();
+
+ /**
+ * \brief Determine the mapping mode of the buffer, (ie. direct mapping or backed)
+ */
+ inline D3D9_COMMON_BUFFER_MAP_MODE GetMapMode() const {
+ return (m_desc.Pool == D3DPOOL_DEFAULT && (m_desc.Usage & (D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)))
+ ? D3D9_COMMON_BUFFER_MAP_MODE_DIRECT
+ : D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
+ }
+
+ /**
+ * \brief Abstraction for getting a type of buffer (mapping/staging/the real buffer) across mapping modes.
+ */
+ template <D3D9_COMMON_BUFFER_TYPE Type>
+ inline const Rc<DxvkBuffer>& GetBuffer() const {
+ if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_MAPPING)
+ return GetMapBuffer();
+ else if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_STAGING)
+ return GetStagingBuffer();
+ else //if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_REAL)
+ return GetRealBuffer();
+ }
+
+ template <D3D9_COMMON_BUFFER_TYPE Type>
+ inline DxvkBufferSlice GetBufferSlice() const {
+ return GetBufferSlice<Type>(0, m_desc.Size);
+ }
+
+ template <D3D9_COMMON_BUFFER_TYPE Type>
+ inline DxvkBufferSlice GetBufferSlice(VkDeviceSize offset) const {
+ return GetBufferSlice<Type>(offset, m_desc.Size - offset);
+ }
+
+ template <D3D9_COMMON_BUFFER_TYPE Type>
+ inline DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const {
+ return DxvkBufferSlice(GetBuffer<Type>(), offset, length);
+ }
+
+ inline DxvkBufferSliceHandle AllocMapSlice() {
+ return GetMapBuffer()->allocSlice();
+ }
+
+ inline DxvkBufferSliceHandle DiscardMapSlice() {
+ m_sliceHandle = GetMapBuffer()->allocSlice();
+ return m_sliceHandle;
+ }
+
+ inline DxvkBufferSliceHandle GetMappedSlice() const {
+ return m_sliceHandle;
+ }
+
+ inline DWORD GetMapFlags() const { return m_mapFlags; }
+ inline void SetMapFlags(DWORD Flags) { m_mapFlags = Flags; }
+
+ inline const D3D9_BUFFER_DESC* Desc() const { return &m_desc; }
+
+ static HRESULT ValidateBufferProperties(const D3D9_BUFFER_DESC* pDesc);
+
+ /**
+ * \brief The range of the buffer that was changed using Lock calls
+ */
+ inline D3D9Range& DirtyRange() { return m_dirtyRange; }
+
+ /**
+ * \brief The range of the buffer that might currently be read by the GPU
+ */
+ inline D3D9Range& GPUReadingRange() { return m_gpuReadingRange; }
+
+ /**
+ * \brief Whether or not the buffer was written to by the GPU (in IDirect3DDevice9::ProcessVertices)
+ */
+ inline bool WasWrittenByGPU() const { return m_wasWrittenByGPU; }
+
+ /**
+ * \brief Sets whether or not the buffer was written to by the GPU
+ */
+ inline void SetWrittenByGPU(bool state) { m_wasWrittenByGPU = state; }
+
+ inline uint32_t IncrementLockCount() { return ++m_lockCount; }
+ inline uint32_t DecrementLockCount() {
+ if (m_lockCount == 0)
+ return 0;
+
+ return --m_lockCount;
+ }
+ inline uint32_t GetLockCount() const { return m_lockCount; }
+
+ /**
+ * \brief Whether or not the staging buffer needs to be copied to the actual buffer
+ */
+ inline bool NeedsUpload() { return m_desc.Pool != D3DPOOL_DEFAULT && !m_dirtyRange.IsDegenerate(); }
+
+ inline bool DoesStagingBufferUploads() const { return m_uploadUsingStaging; }
+
+ inline void EnableStagingBufferUploads() {
+ if (GetMapMode() != D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
+ return;
+
+ m_uploadUsingStaging = true;
+ }
+
+ void PreLoad();
+
+ private:
+
+ Rc<DxvkBuffer> CreateBuffer() const;
+ Rc<DxvkBuffer> CreateStagingBuffer() const;
+
+ inline const Rc<DxvkBuffer>& GetMapBuffer() const {
+ return m_stagingBuffer != nullptr ? m_stagingBuffer : m_buffer;
+ }
+
+ inline const Rc<DxvkBuffer>& GetStagingBuffer() const {
+ return m_stagingBuffer;
+ }
+
+ inline const Rc<DxvkBuffer>& GetRealBuffer() const {
+ return m_buffer;
+ }
+
+ D3D9DeviceEx* m_parent;
+ const D3D9_BUFFER_DESC m_desc;
+ DWORD m_mapFlags;
+ bool m_wasWrittenByGPU = false;
+ bool m_uploadUsingStaging = false;
+
+ Rc<DxvkBuffer> m_buffer;
+ Rc<DxvkBuffer> m_stagingBuffer;
+
+ DxvkBufferSliceHandle m_sliceHandle;
+
+ D3D9Range m_dirtyRange;
+ D3D9Range m_gpuReadingRange;
+
+ uint32_t m_lockCount = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.cpp
new file mode 100644
index 00000000..a44bb459
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.cpp
@@ -0,0 +1,522 @@
+#include "d3d9_common_texture.h"
+
+#include "d3d9_util.h"
+#include "d3d9_device.h"
+
+#include <algorithm>
+
+namespace dxvk {
+
+ D3D9CommonTexture::D3D9CommonTexture(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc,
+ D3DRESOURCETYPE ResourceType)
+ : m_device(pDevice), m_desc(*pDesc), m_type(ResourceType) {
+ if (m_desc.Format == D3D9Format::Unknown)
+ m_desc.Format = (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL)
+ ? D3D9Format::D32
+ : D3D9Format::X8R8G8B8;
+
+ for (uint32_t i = 0; i < m_dirtyBoxes.size(); i++) {
+ AddDirtyBox(nullptr, i);
+ }
+
+ if (m_desc.Pool != D3DPOOL_DEFAULT) {
+ const uint32_t subresources = CountSubresources();
+ for (uint32_t i = 0; i < subresources; i++) {
+ SetNeedsUpload(i, true);
+ }
+ }
+
+ m_mapping = pDevice->LookupFormat(m_desc.Format);
+
+ m_mapMode = DetermineMapMode();
+ m_shadow = DetermineShadowState();
+
+ if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED) {
+ bool plainSurface = m_type == D3DRTYPE_SURFACE &&
+ !(m_desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL));
+
+ try {
+ m_image = CreatePrimaryImage(ResourceType, plainSurface);
+ }
+ catch (const DxvkError& e) {
+ // D3DUSAGE_AUTOGENMIPMAP and offscreen plain is mutually exclusive
+ // so we can combine their retry this way.
+ if (m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP || plainSurface) {
+ m_desc.Usage &= ~D3DUSAGE_AUTOGENMIPMAP;
+ m_desc.MipLevels = 1;
+ m_image = CreatePrimaryImage(ResourceType, false);
+ }
+ else
+ throw e;
+ }
+
+ CreateSampleView(0);
+
+ if (!IsManaged()) {
+ m_size = m_image->memSize();
+ if (!m_device->ChangeReportedMemory(-m_size))
+ throw DxvkError("D3D9: Reporting out of memory from tracking.");
+ }
+ }
+
+ if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM)
+ CreateBuffers();
+
+ m_exposedMipLevels = m_desc.MipLevels;
+
+ if (m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP)
+ m_exposedMipLevels = 1;
+ }
+
+
+ D3D9CommonTexture::~D3D9CommonTexture() {
+ if (m_size != 0)
+ m_device->ChangeReportedMemory(m_size);
+ }
+
+
+ VkImageSubresource D3D9CommonTexture::GetSubresourceFromIndex(
+ VkImageAspectFlags Aspect,
+ UINT Subresource) const {
+ VkImageSubresource result;
+ result.aspectMask = Aspect;
+ result.mipLevel = Subresource % m_desc.MipLevels;
+ result.arrayLayer = Subresource / m_desc.MipLevels;
+ return result;
+ }
+
+
+ HRESULT D3D9CommonTexture::NormalizeTextureProperties(
+ D3D9DeviceEx* pDevice,
+ D3D9_COMMON_TEXTURE_DESC* pDesc) {
+ auto* options = pDevice->GetOptions();
+
+ //////////////////////
+ // Mapping Validation
+ auto mapping = pDevice->LookupFormat(pDesc->Format);
+
+ // Handle DisableA8RT hack for The Sims 2
+ if (pDesc->Format == D3D9Format::A8 &&
+ (pDesc->Usage & D3DUSAGE_RENDERTARGET) &&
+ options->disableA8RT)
+ return D3DERR_INVALIDCALL;
+
+ // If the mapping is invalid then lets return invalid
+ // Some edge cases:
+ // NULL format does not map to anything, but should succeed
+ // SCRATCH textures can still be made if the device does not support
+ // the format at all.
+
+ if (!mapping.IsValid() && pDesc->Format != D3D9Format::NULL_FORMAT) {
+ auto info = pDevice->UnsupportedFormatInfo(pDesc->Format);
+
+ if (pDesc->Pool != D3DPOOL_SCRATCH || info->elementSize == 0)
+ return D3DERR_INVALIDCALL;
+ }
+
+ ///////////////////
+ // Desc Validation
+
+ if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0)
+ return D3DERR_INVALIDCALL;
+
+ if (FAILED(DecodeMultiSampleType(pDesc->MultiSample, pDesc->MultisampleQuality, nullptr)))
+ return D3DERR_INVALIDCALL;
+
+ // Using MANAGED pool with DYNAMIC usage is illegal
+ if (IsPoolManaged(pDesc->Pool) && (pDesc->Usage & D3DUSAGE_DYNAMIC))
+ return D3DERR_INVALIDCALL;
+
+ // D3DUSAGE_WRITEONLY doesn't apply to textures.
+ if (pDesc->Usage & D3DUSAGE_WRITEONLY)
+ return D3DERR_INVALIDCALL;
+
+ // RENDERTARGET and DEPTHSTENCIL must be default pool
+ constexpr DWORD incompatibleUsages = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
+ if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & incompatibleUsages))
+ return D3DERR_INVALIDCALL;
+
+ // Use the maximum possible mip level count if the supplied
+ // mip level count is either unspecified (0) or invalid
+ const uint32_t maxMipLevelCount = pDesc->MultiSample <= D3DMULTISAMPLE_NONMASKABLE
+ ? util::computeMipLevelCount({ pDesc->Width, pDesc->Height, pDesc->Depth })
+ : 1u;
+
+ if (pDesc->Usage & D3DUSAGE_AUTOGENMIPMAP)
+ pDesc->MipLevels = 0;
+
+ if (pDesc->MipLevels == 0 || pDesc->MipLevels > maxMipLevelCount)
+ pDesc->MipLevels = maxMipLevelCount;
+
+ return D3D_OK;
+ }
+
+
+ bool D3D9CommonTexture::CreateBufferSubresource(UINT Subresource) {
+ if (m_buffers[Subresource] != nullptr)
+ return false;
+
+ DxvkBufferCreateInfo info;
+ info.size = GetMipSize(Subresource);
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
+ | VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ if (m_mapping.ConversionFormatInfo.FormatType != D3D9ConversionFormat_None) {
+ info.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ }
+
+ VkMemoryPropertyFlags memType = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+
+ m_buffers[Subresource] = m_device->GetDXVKDevice()->createBuffer(info, memType);
+ m_mappedSlices[Subresource] = m_buffers[Subresource]->getSliceHandle();
+
+ return true;
+ }
+
+
+ VkDeviceSize D3D9CommonTexture::GetMipSize(UINT Subresource) const {
+ const UINT MipLevel = Subresource % m_desc.MipLevels;
+
+ const DxvkFormatInfo* formatInfo = m_mapping.FormatColor != VK_FORMAT_UNDEFINED
+ ? imageFormatInfo(m_mapping.FormatColor)
+ : m_device->UnsupportedFormatInfo(m_desc.Format);
+
+ const VkExtent3D mipExtent = util::computeMipLevelExtent(
+ GetExtent(), MipLevel);
+
+ const VkExtent3D blockCount = util::computeBlockCount(
+ mipExtent, formatInfo->blockSize);
+
+ const uint32_t planeCount = m_mapping.ConversionFormatInfo.PlaneCount;
+
+ return std::min(planeCount, 2u)
+ * align(formatInfo->elementSize * blockCount.width, 4)
+ * blockCount.height
+ * blockCount.depth;
+ }
+
+
+ Rc<DxvkImage> D3D9CommonTexture::CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT) const {
+ DxvkImageCreateInfo imageInfo;
+ imageInfo.type = GetImageTypeFromResourceType(ResourceType);
+ imageInfo.format = m_mapping.ConversionFormatInfo.FormatColor != VK_FORMAT_UNDEFINED
+ ? m_mapping.ConversionFormatInfo.FormatColor
+ : m_mapping.FormatColor;
+ imageInfo.flags = 0;
+ imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.extent.width = m_desc.Width;
+ imageInfo.extent.height = m_desc.Height;
+ imageInfo.extent.depth = m_desc.Depth;
+ imageInfo.numLayers = m_desc.ArraySize;
+ imageInfo.mipLevels = m_desc.MipLevels;
+ imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT;
+ imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | m_device->GetEnabledShaderStages();
+ imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_GENERAL;
+ imageInfo.shared = m_desc.IsBackBuffer;
+
+ if (m_mapping.ConversionFormatInfo.FormatType != D3D9ConversionFormat_None) {
+ imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ }
+
+ DecodeMultiSampleType(m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount);
+
+ // The image must be marked as mutable if it can be reinterpreted
+ // by a view with a different format. Depth-stencil formats cannot
+ // be reinterpreted in Vulkan, so we'll ignore those.
+ auto formatProperties = imageFormatInfo(m_mapping.FormatColor);
+
+ bool isMutable = m_mapping.FormatSrgb != VK_FORMAT_UNDEFINED;
+ bool isColorFormat = (formatProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
+
+ if (isMutable && isColorFormat) {
+ imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+ imageInfo.viewFormatCount = 2;
+ imageInfo.viewFormats = m_mapping.Formats;
+ }
+
+ // Are we an RT, need to gen mips or an offscreen plain surface?
+ if (m_desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_AUTOGENMIPMAP) || TryOffscreenRT) {
+ imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ }
+
+ if (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) {
+ imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
+ | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+ }
+
+ if (ResourceType == D3DRTYPE_CUBETEXTURE)
+ imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+
+ // Some image formats (i.e. the R32G32B32 ones) are
+ // only supported with linear tiling on most GPUs
+ if (!CheckImageSupport(&imageInfo, VK_IMAGE_TILING_OPTIMAL))
+ imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
+
+ // We must keep LINEAR images in GENERAL layout, but we
+ // can choose a better layout for the image based on how
+ // it is going to be used by the game.
+ if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL)
+ imageInfo.layout = OptimizeLayout(imageInfo.usage);
+
+ // For some formats, we need to enable render target
+ // capabilities if available, but these should
+ // in no way affect the default image layout
+ imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
+
+ // Check if we can actually create the image
+ if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
+ throw DxvkError(str::format(
+ "D3D9: Cannot create texture:",
+ "\n Type: ", std::hex, ResourceType,
+ "\n Format: ", m_desc.Format,
+ "\n Extent: ", m_desc.Width,
+ "x", m_desc.Height,
+ "x", m_desc.Depth,
+ "\n Samples: ", m_desc.MultiSample,
+ "\n Layers: ", m_desc.ArraySize,
+ "\n Levels: ", m_desc.MipLevels,
+ "\n Usage: ", std::hex, m_desc.Usage,
+ "\n Pool: ", std::hex, m_desc.Pool));
+ }
+
+ return m_device->GetDXVKDevice()->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ Rc<DxvkImage> D3D9CommonTexture::CreateResolveImage() const {
+ DxvkImageCreateInfo imageInfo = m_image->info();
+ imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+
+ return m_device->GetDXVKDevice()->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ BOOL D3D9CommonTexture::DetermineShadowState() const {
+ static std::array<D3D9Format, 3> blacklist = {
+ D3D9Format::INTZ, D3D9Format::DF16, D3D9Format::DF24
+ };
+
+ return IsDepthFormat(m_desc.Format)
+ && std::find(blacklist.begin(), blacklist.end(), m_desc.Format) == blacklist.end();
+ }
+
+
+ BOOL D3D9CommonTexture::CheckImageSupport(
+ const DxvkImageCreateInfo* pImageInfo,
+ VkImageTiling Tiling) const {
+ const Rc<DxvkAdapter> adapter = m_device->GetDXVKDevice()->adapter();
+
+ VkImageFormatProperties formatProps = { };
+
+ VkResult status = adapter->imageFormatProperties(
+ pImageInfo->format, pImageInfo->type, Tiling,
+ pImageInfo->usage, pImageInfo->flags, formatProps);
+
+ if (status != VK_SUCCESS)
+ return FALSE;
+
+ return (pImageInfo->extent.width <= formatProps.maxExtent.width)
+ && (pImageInfo->extent.height <= formatProps.maxExtent.height)
+ && (pImageInfo->extent.depth <= formatProps.maxExtent.depth)
+ && (pImageInfo->numLayers <= formatProps.maxArrayLayers)
+ && (pImageInfo->mipLevels <= formatProps.maxMipLevels)
+ && (pImageInfo->sampleCount & formatProps.sampleCounts);
+ }
+
+
+ VkImageUsageFlags D3D9CommonTexture::EnableMetaCopyUsage(
+ VkFormat Format,
+ VkImageTiling Tiling) const {
+ VkFormatFeatureFlags requestedFeatures = 0;
+
+ if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT)
+ requestedFeatures |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT)
+ requestedFeatures |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+
+ if (requestedFeatures == 0)
+ return 0;
+
+ // Enable usage flags for all supported and requested features
+ VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format);
+
+ requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
+ ? properties.optimalTilingFeatures
+ : properties.linearTilingFeatures;
+
+ VkImageUsageFlags requestedUsage = 0;
+
+ if (requestedFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (requestedFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
+ requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ return requestedUsage;
+ }
+
+
+ VkImageType D3D9CommonTexture::GetImageTypeFromResourceType(D3DRESOURCETYPE Type) {
+ switch (Type) {
+ case D3DRTYPE_SURFACE:
+ case D3DRTYPE_TEXTURE: return VK_IMAGE_TYPE_2D;
+ case D3DRTYPE_VOLUMETEXTURE: return VK_IMAGE_TYPE_3D;
+ case D3DRTYPE_CUBETEXTURE: return VK_IMAGE_TYPE_2D;
+ default: throw DxvkError("D3D9CommonTexture: Unhandled resource type");
+ }
+ }
+
+
+ VkImageViewType D3D9CommonTexture::GetImageViewTypeFromResourceType(
+ D3DRESOURCETYPE Dimension,
+ UINT Layer) {
+ switch (Dimension) {
+ case D3DRTYPE_SURFACE:
+ case D3DRTYPE_TEXTURE: return VK_IMAGE_VIEW_TYPE_2D;
+ case D3DRTYPE_VOLUMETEXTURE: return VK_IMAGE_VIEW_TYPE_3D;
+ case D3DRTYPE_CUBETEXTURE: return Layer == AllLayers
+ ? VK_IMAGE_VIEW_TYPE_CUBE
+ : VK_IMAGE_VIEW_TYPE_2D;
+ default: throw DxvkError("D3D9CommonTexture: Unhandled resource type");
+ }
+ }
+
+
+ VkImageLayout D3D9CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) const {
+ const VkImageUsageFlags usageFlags = Usage;
+
+ // Filter out unnecessary flags. Transfer operations
+ // are handled by the backend in a transparent manner.
+ Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+
+ // Ignore sampled bit in case the image was created with
+ // an image flag that only allows attachment usage
+ if (m_desc.IsAttachmentOnly)
+ Usage &= ~VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ // If the image is used only as an attachment, we never
+ // have to transform the image back to a different layout
+ if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+
+ // If the image is used for reading but not as a storage
+ // image, we can optimize the image for texture access
+ if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
+ return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
+ ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+
+ // Otherwise, we have to stick with the default layout
+ return VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+
+ Rc<DxvkImageView> D3D9CommonTexture::CreateView(
+ UINT Layer,
+ UINT Lod,
+ VkImageUsageFlags UsageFlags,
+ bool Srgb) {
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.format = m_mapping.ConversionFormatInfo.FormatColor != VK_FORMAT_UNDEFINED
+ ? PickSRGB(m_mapping.ConversionFormatInfo.FormatColor, m_mapping.ConversionFormatInfo.FormatSrgb, Srgb)
+ : PickSRGB(m_mapping.FormatColor, m_mapping.FormatSrgb, Srgb);
+ viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
+ viewInfo.swizzle = m_mapping.Swizzle;
+ viewInfo.usage = UsageFlags;
+ viewInfo.type = GetImageViewTypeFromResourceType(m_type, Layer);
+ viewInfo.minLevel = Lod;
+ viewInfo.numLevels = m_desc.MipLevels - Lod;
+ viewInfo.minLayer = Layer == AllLayers ? 0 : Layer;
+ viewInfo.numLayers = Layer == AllLayers ? m_desc.ArraySize : 1;
+
+ // Remove the stencil aspect if we are trying to create a regular image
+ // view of a depth stencil format
+ if (UsageFlags != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ viewInfo.aspect &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ if (UsageFlags == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
+ UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ viewInfo.numLevels = 1;
+
+ // Remove swizzle on depth views.
+ if (UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ viewInfo.swizzle = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+
+ // Create the underlying image view object
+ return m_device->GetDXVKDevice()->createImageView(GetImage(), viewInfo);
+ }
+
+
+ void D3D9CommonTexture::PreLoadAll() {
+ if (!IsManaged())
+ return;
+
+ auto lock = m_device->LockDevice();
+ m_device->UploadManagedTexture(this);
+ m_device->MarkTextureUploaded(this);
+ }
+
+
+ void D3D9CommonTexture::PreLoadSubresource(UINT Subresource) {
+ if (IsManaged()) {
+ auto lock = m_device->LockDevice();
+
+ if (NeedsUpload(Subresource)) {
+ m_device->FlushImage(this, Subresource);
+ SetNeedsUpload(Subresource, false);
+
+ if (!NeedsAnyUpload())
+ m_device->MarkTextureUploaded(this);
+ }
+ }
+ }
+
+
+ void D3D9CommonTexture::CreateSampleView(UINT Lod) {
+ // This will be a no-op for SYSTEMMEM types given we
+ // don't expose the cap to allow texturing with them.
+ if (unlikely(m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM))
+ return;
+
+ m_sampleView.Color = CreateView(AllLayers, Lod, VK_IMAGE_USAGE_SAMPLED_BIT, false);
+
+ if (IsSrgbCompatible())
+ m_sampleView.Srgb = CreateView(AllLayers, Lod, VK_IMAGE_USAGE_SAMPLED_BIT, true);
+ }
+
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.h
new file mode 100644
index 00000000..3a6ac45e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_common_texture.h
@@ -0,0 +1,512 @@
+#pragma once
+
+#include "d3d9_format.h"
+#include "d3d9_util.h"
+#include "d3d9_caps.h"
+
+#include "../dxvk/dxvk_device.h"
+
+#include "../util/util_bit.h"
+
+namespace dxvk {
+
+ class D3D9DeviceEx;
+
+ /**
+ * \brief Image memory mapping mode
+ *
+ * Determines how exactly \c LockBox will
+ * behave when mapping an image.
+ */
+ enum D3D9_COMMON_TEXTURE_MAP_MODE {
+ D3D9_COMMON_TEXTURE_MAP_MODE_NONE, ///< No mapping available
+ D3D9_COMMON_TEXTURE_MAP_MODE_BACKED, ///< Mapped image through buffer
+ D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM, ///< Only a buffer - no image
+ };
+
+ /**
+ * \brief Common texture description
+ *
+ * Contains all members that can be
+ * defined for 2D, Cube and 3D textures.
+ */
+ struct D3D9_COMMON_TEXTURE_DESC {
+ UINT Width;
+ UINT Height;
+ UINT Depth;
+ UINT ArraySize;
+ UINT MipLevels;
+ DWORD Usage;
+ D3D9Format Format;
+ D3DPOOL Pool;
+ D3DMULTISAMPLE_TYPE MultiSample;
+ DWORD MultisampleQuality;
+ bool Discard;
+ bool IsBackBuffer;
+ bool IsAttachmentOnly;
+ };
+
+ struct D3D9ColorView {
+ inline Rc<DxvkImageView>& Pick(bool Srgb) {
+ return Srgb ? this->Srgb : this->Color;
+ }
+
+ inline const Rc<DxvkImageView>& Pick(bool Srgb) const {
+ return Srgb ? this->Srgb : this->Color;
+ }
+
+ Rc<DxvkImageView> Color;
+ Rc<DxvkImageView> Srgb;
+ };
+
+ template <typename T>
+ using D3D9SubresourceArray = std::array<T, caps::MaxSubresources>;
+
+ using D3D9SubresourceBitset = bit::bitset<caps::MaxSubresources>;
+
+ class D3D9CommonTexture {
+
+ public:
+
+ D3D9CommonTexture(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc,
+ D3DRESOURCETYPE ResourceType);
+
+ ~D3D9CommonTexture();
+
+ /**
+ * \brief Device
+ * \returns The parent device
+ */
+ D3D9DeviceEx* Device() const {
+ return m_device;
+ }
+
+ /**
+ * \brief Texture properties
+ *
+ * The returned data can be used to fill in
+ * \c D3D11_TEXTURE2D_DESC and similar structs.
+ * \returns Pointer to texture description
+ */
+ const D3D9_COMMON_TEXTURE_DESC* Desc() const {
+ return &m_desc;
+ }
+
+ /**
+ * \brief Vulkan Format
+ * \returns The Vulkan format of the resource
+ */
+ const D3D9_VK_FORMAT_MAPPING& GetFormatMapping() const {
+ return m_mapping;
+ }
+
+ /**
+ * \brief Counts number of subresources
+ * \returns Number of subresources
+ */
+ UINT CountSubresources() const {
+ return m_desc.ArraySize * m_desc.MipLevels;
+ }
+
+ /**
+ * \brief Map mode
+ * \returns Map mode
+ */
+ D3D9_COMMON_TEXTURE_MAP_MODE GetMapMode() const {
+ return m_mapMode;
+ }
+
+ /**
+ * \brief The DXVK image
+ * Note, this will be nullptr if the map mode is D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM
+ * \returns The DXVK image
+ */
+ const Rc<DxvkImage>& GetImage() const {
+ return m_image;
+ }
+
+ /**
+ * \brief Get a copy of the main image, but with a single sample
+ * This function will allocate/reuse an image with the same info
+ * as the main image
+ * \returns An image with identical info, but 1 sample
+ */
+ const Rc<DxvkImage>& GetResolveImage() {
+ if (unlikely(m_resolveImage == nullptr))
+ m_resolveImage = CreateResolveImage();
+
+ return m_resolveImage;
+ }
+
+ const Rc<DxvkBuffer>& GetBuffer(UINT Subresource) {
+ return m_buffers[Subresource];
+ }
+
+
+ DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) {
+ return m_mappedSlices[Subresource];
+ }
+
+
+ DxvkBufferSliceHandle DiscardMapSlice(UINT Subresource) {
+ DxvkBufferSliceHandle handle = m_buffers[Subresource]->allocSlice();
+ m_mappedSlices[Subresource] = handle;
+ return handle;
+ }
+
+ /**
+ * \brief Computes subresource from the subresource index
+ *
+ * Used by some functions that operate on only
+ * one subresource, such as \c UpdateSurface.
+ * \param [in] Aspect The image aspect
+ * \param [in] Subresource Subresource index
+ * \returns The Vulkan image subresource
+ */
+ VkImageSubresource GetSubresourceFromIndex(
+ VkImageAspectFlags Aspect,
+ UINT Subresource) const;
+
+ /**
+ * \brief Normalizes and validates texture description
+ *
+ * Fills in undefined values and validates the texture
+ * parameters. Any error returned by this method should
+ * be forwarded to the application.
+ * \param [in,out] pDesc Texture description
+ * \returns \c S_OK if the parameters are valid
+ */
+ static HRESULT NormalizeTextureProperties(
+ D3D9DeviceEx* pDevice,
+ D3D9_COMMON_TEXTURE_DESC* pDesc);
+
+ /**
+ * \brief Shadow
+ * \returns Whether the texture is to be depth compared
+ */
+ bool IsShadow() const {
+ return m_shadow;
+ }
+
+ /**
+ * \brief Null
+ * \returns Whether the texture is D3DFMT_NULL or not
+ */
+ bool IsNull() const {
+ return m_desc.Format == D3D9Format::NULL_FORMAT;
+ }
+
+ /**
+ * \brief Subresource
+ * \returns The subresource idx of a given face and mip level
+ */
+ UINT CalcSubresource(UINT Face, UINT MipLevel) const {
+ return Face * m_desc.MipLevels + MipLevel;
+ }
+
+ /**
+ * \brief Creates buffers
+ * Creates mapping and staging buffers for all subresources
+ * allocates new buffers if necessary
+ */
+ void CreateBuffers() {
+ const uint32_t count = CountSubresources();
+ for (uint32_t i = 0; i < count; i++)
+ CreateBufferSubresource(i);
+ }
+
+ /**
+ * \brief Creates a buffer
+ * Creates mapping and staging buffers for a given subresource
+ * allocates new buffers if necessary
+ * \returns Whether an allocation happened
+ */
+ bool CreateBufferSubresource(UINT Subresource);
+
+ /**
+ * \brief Destroys a buffer
+ * Destroys mapping and staging buffers for a given subresource
+ */
+ void DestroyBufferSubresource(UINT Subresource) {
+ m_buffers[Subresource] = nullptr;
+ SetWrittenByGPU(Subresource, true);
+ }
+
+ bool IsDynamic() const {
+ return m_desc.Usage & D3DUSAGE_DYNAMIC;
+ }
+
+ /**
+ * \brief Managed
+ * \returns Whether a resource is managed (pool) or not
+ */
+ bool IsManaged() const {
+ return IsPoolManaged(m_desc.Pool);
+ }
+
+ /**
+ * \brief Render Target
+ * \returns Whether a resource is a render target or not
+ */
+ bool IsRenderTarget() const {
+ return m_desc.Usage & D3DUSAGE_RENDERTARGET;
+ }
+
+ /**
+ * \brief Depth stencil
+ * \returns Whether a resource is a depth stencil or not
+ */
+ bool IsDepthStencil() const {
+ return m_desc.Usage & D3DUSAGE_DEPTHSTENCIL;
+ }
+
+ /**
+ * \brief Autogen Mipmap
+ * \returns Whether the texture is to have automatic mip generation
+ */
+ bool IsAutomaticMip() const {
+ return m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP;
+ }
+
+ /**
+ * \brief Checks whether sRGB views can be created
+ * \returns Whether the format is sRGB compatible.
+ */
+ bool IsSrgbCompatible() const {
+ return m_mapping.FormatSrgb;
+ }
+
+ /**
+ * \brief Recreate main image view
+ * Recreates the main view of the sampler w/ a specific LOD.
+ * SetLOD only works on MANAGED textures so this is A-okay.
+ */
+ void CreateSampleView(UINT Lod);
+
+ /**
+ * \brief Extent
+ * \returns The extent of the top-level mip
+ */
+ VkExtent3D GetExtent() const {
+ return VkExtent3D{ m_desc.Width, m_desc.Height, m_desc.Depth };
+ }
+
+ /**
+ * \brief Mip Extent
+ * \returns The extent of a mip or subresource
+ */
+ VkExtent3D GetExtentMip(UINT Subresource) const {
+ UINT MipLevel = Subresource % m_desc.MipLevels;
+ return util::computeMipLevelExtent(GetExtent(), MipLevel);
+ }
+
+ bool MarkHazardous() {
+ return std::exchange(m_hazardous, true);
+ }
+
+ D3DRESOURCETYPE GetType() {
+ return m_type;
+ }
+
+ const D3D9_VK_FORMAT_MAPPING& GetMapping() { return m_mapping; }
+
+ void SetLocked(UINT Subresource, bool value) { m_locked.set(Subresource, value); }
+
+ bool GetLocked(UINT Subresource) const { return m_locked.get(Subresource); }
+
+ bool IsAnySubresourceLocked() const { return m_locked.any(); }
+
+ void SetWrittenByGPU(UINT Subresource, bool value) { m_wasWrittenByGPU.set(Subresource, value); }
+
+ bool WasWrittenByGPU(UINT Subresource) const { return m_wasWrittenByGPU.get(Subresource); }
+
+ void MarkAllWrittenByGPU() { m_wasWrittenByGPU.setAll(); }
+
+ void SetReadOnlyLocked(UINT Subresource, bool readOnly) { return m_readOnly.set(Subresource, readOnly); }
+
+ bool GetReadOnlyLocked(UINT Subresource) const { return m_readOnly.get(Subresource); }
+
+ const Rc<DxvkImageView>& GetSampleView(bool srgb) const {
+ return m_sampleView.Pick(srgb && IsSrgbCompatible());
+ }
+
+ VkImageLayout DetermineRenderTargetLayout() const {
+ return m_image != nullptr &&
+ m_image->info().tiling == VK_IMAGE_TILING_OPTIMAL &&
+ !m_hazardous
+ ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ : VK_IMAGE_LAYOUT_GENERAL;
+ }
+
+ VkImageLayout DetermineDepthStencilLayout(bool write, bool hazardous) const {
+ VkImageLayout layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ if (unlikely(hazardous)) {
+ layout = write
+ ? VK_IMAGE_LAYOUT_GENERAL
+ : VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
+ }
+
+ if (unlikely(m_image->info().tiling != VK_IMAGE_TILING_OPTIMAL))
+ layout = VK_IMAGE_LAYOUT_GENERAL;
+
+ return layout;
+ }
+
+ Rc<DxvkImageView> CreateView(
+ UINT Layer,
+ UINT Lod,
+ VkImageUsageFlags UsageFlags,
+ bool Srgb);
+ D3D9SubresourceBitset& GetUploadBitmask() { return m_needsUpload; }
+
+ void SetNeedsUpload(UINT Subresource, bool upload) { m_needsUpload.set(Subresource, upload); }
+ bool NeedsUpload(UINT Subresource) const { return m_needsUpload.get(Subresource); }
+ bool NeedsAnyUpload() { return m_needsUpload.any(); }
+ void ClearNeedsUpload() { return m_needsUpload.clearAll(); }
+ bool DoesStagingBufferUploads(UINT Subresource) const { return m_uploadUsingStaging.get(Subresource); }
+
+ void EnableStagingBufferUploads(UINT Subresource) {
+ m_uploadUsingStaging.set(Subresource, true);
+ }
+
+ void SetNeedsMipGen(bool value) { m_needsMipGen = value; }
+ bool NeedsMipGen() const { return m_needsMipGen; }
+
+ DWORD ExposedMipLevels() { return m_exposedMipLevels; }
+
+ void SetMipFilter(D3DTEXTUREFILTERTYPE filter) { m_mipFilter = filter; }
+ D3DTEXTUREFILTERTYPE GetMipFilter() const { return m_mipFilter; }
+
+ void PreLoadAll();
+ void PreLoadSubresource(UINT Subresource);
+
+ void AddDirtyBox(CONST D3DBOX* pDirtyBox, uint32_t layer) {
+ if (pDirtyBox) {
+ D3DBOX box = *pDirtyBox;
+ if (box.Right <= box.Left
+ || box.Bottom <= box.Top
+ || box.Back <= box.Front)
+ return;
+
+ box.Right = std::min(box.Right, m_desc.Width);
+ box.Bottom = std::min(box.Bottom, m_desc.Height);
+ box.Back = std::min(box.Back, m_desc.Depth);
+
+ D3DBOX& dirtyBox = m_dirtyBoxes[layer];
+ if (dirtyBox.Left == dirtyBox.Right) {
+ dirtyBox = box;
+ } else {
+ dirtyBox.Left = std::min(dirtyBox.Left, box.Left);
+ dirtyBox.Right = std::max(dirtyBox.Right, box.Right);
+ dirtyBox.Top = std::min(dirtyBox.Top, box.Top);
+ dirtyBox.Bottom = std::max(dirtyBox.Bottom, box.Bottom);
+ dirtyBox.Front = std::min(dirtyBox.Front, box.Front);
+ dirtyBox.Back = std::max(dirtyBox.Back, box.Back);
+ }
+ } else {
+ m_dirtyBoxes[layer] = { 0, 0, m_desc.Width, m_desc.Height, 0, m_desc.Depth };
+ }
+ }
+
+ void ClearDirtyBoxes() {
+ for (uint32_t i = 0; i < m_dirtyBoxes.size(); i++) {
+ m_dirtyBoxes[i] = { 0, 0, 0, 0, 0, 0 };
+ }
+ }
+
+ const D3DBOX& GetDirtyBox(uint32_t layer) const {
+ return m_dirtyBoxes[layer];
+ }
+
+ static VkImageType GetImageTypeFromResourceType(
+ D3DRESOURCETYPE Dimension);
+
+ private:
+
+ D3D9DeviceEx* m_device;
+ D3D9_COMMON_TEXTURE_DESC m_desc;
+ D3DRESOURCETYPE m_type;
+ D3D9_COMMON_TEXTURE_MAP_MODE m_mapMode;
+
+ Rc<DxvkImage> m_image;
+ Rc<DxvkImage> m_resolveImage;
+ D3D9SubresourceArray<
+ Rc<DxvkBuffer>> m_buffers;
+ D3D9SubresourceArray<
+ DxvkBufferSliceHandle> m_mappedSlices;
+
+ D3D9_VK_FORMAT_MAPPING m_mapping;
+
+ bool m_shadow; //< Depth Compare-ness
+
+ int64_t m_size = 0;
+
+ bool m_systemmemModified = false;
+
+ bool m_hazardous = false;
+
+ D3D9ColorView m_sampleView;
+
+ D3D9SubresourceBitset m_locked = { };
+
+ D3D9SubresourceBitset m_readOnly = { };
+
+ D3D9SubresourceBitset m_wasWrittenByGPU = { };
+
+ D3D9SubresourceBitset m_needsUpload = { };
+
+ D3D9SubresourceBitset m_uploadUsingStaging = { };
+
+ DWORD m_exposedMipLevels = 0;
+
+ bool m_needsMipGen = false;
+
+ D3DTEXTUREFILTERTYPE m_mipFilter = D3DTEXF_LINEAR;
+
+ std::array<D3DBOX, 6> m_dirtyBoxes;
+
+ /**
+ * \brief Mip level
+ * \returns Size of packed mip level in bytes
+ */
+ VkDeviceSize GetMipSize(UINT Subresource) const;
+
+ Rc<DxvkImage> CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT) const;
+
+ Rc<DxvkImage> CreateResolveImage() const;
+
+ BOOL DetermineShadowState() const;
+
+ BOOL CheckImageSupport(
+ const DxvkImageCreateInfo* pImageInfo,
+ VkImageTiling Tiling) const;
+
+ VkImageUsageFlags EnableMetaCopyUsage(
+ VkFormat Format,
+ VkImageTiling Tiling) const;
+
+ D3D9_COMMON_TEXTURE_MAP_MODE DetermineMapMode() const {
+ if (m_desc.Format == D3D9Format::NULL_FORMAT)
+ return D3D9_COMMON_TEXTURE_MAP_MODE_NONE;
+
+ if (m_desc.Pool == D3DPOOL_SYSTEMMEM || m_desc.Pool == D3DPOOL_SCRATCH)
+ return D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM;
+
+ return D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
+ }
+
+ VkImageLayout OptimizeLayout(
+ VkImageUsageFlags Usage) const;
+
+ static VkImageViewType GetImageViewTypeFromResourceType(
+ D3DRESOURCETYPE Dimension,
+ UINT Layer);
+
+ static constexpr UINT AllLayers = UINT32_MAX;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_config.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_config.h
new file mode 100644
index 00000000..4a882e9c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_config.h
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace dxvk::config {
+
+ constexpr bool FullValidation = false;
+ constexpr bool FloatEmulationByDefault = false;
+ constexpr bool FixedFunctionEnabled = true;
+ constexpr bool HazardTrackingEnabled = false;
+ constexpr bool ManagedUploadTrackingEnabled = true;
+ constexpr bool MipGenTrackingEnabled = false;
+ constexpr bool SWVPEnabled = false;
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_layout.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_layout.h
new file mode 100644
index 00000000..df4120bc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_layout.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <cstdint>
+
+#include "d3d9_caps.h"
+
+namespace dxvk {
+
+ struct D3D9ConstantLayout {
+ uint32_t floatCount;
+ uint32_t intCount;
+ uint32_t boolCount;
+ uint32_t bitmaskCount;
+
+ uint32_t floatSize() const { return floatCount * 4 * sizeof(float); }
+ uint32_t intSize() const { return intCount * 4 * sizeof(int); }
+ uint32_t bitmaskSize() const {
+ // Account for SWVP (non SWVP uses a spec constant)
+ return bitmaskCount != 1
+ ? bitmaskCount * 1 * sizeof(uint32_t)
+ : 0;
+ }
+
+ uint32_t floatOffset() const { return 0; }
+ uint32_t intOffset() const { return floatOffset() + floatSize(); }
+ uint32_t bitmaskOffset() const { return intOffset() + intSize(); }
+
+ uint32_t totalSize() const { return floatSize() + intSize() + bitmaskSize(); }
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_set.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_set.h
new file mode 100644
index 00000000..16b4e7e9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_constant_set.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "d3d9_caps.h"
+
+#include "../dxvk/dxvk_buffer.h"
+
+#include "../dxso/dxso_isgn.h"
+
+#include "../util/util_math.h"
+#include "../util/util_vector.h"
+
+#include <cstdint>
+
+namespace dxvk {
+
+ enum class D3D9ConstantType {
+ Float,
+ Int,
+ Bool
+ };
+
+ // We make an assumption later based on the packing of this struct for copying.
+ struct D3D9ShaderConstantsVSSoftware {
+ Vector4 fConsts[caps::MaxFloatConstantsSoftware];
+ Vector4i iConsts[caps::MaxOtherConstantsSoftware];
+ uint32_t bConsts[caps::MaxOtherConstantsSoftware / 32];
+ };
+
+ struct D3D9ShaderConstantsVSHardware {
+ Vector4 fConsts[caps::MaxFloatConstantsVS];
+ Vector4i iConsts[caps::MaxOtherConstants];
+ uint32_t bConsts[1];
+ };
+
+ struct D3D9ShaderConstantsPS {
+ Vector4 fConsts[caps::MaxFloatConstantsPS];
+ Vector4i iConsts[caps::MaxOtherConstants];
+ uint32_t bConsts[1];
+ };
+
+ struct D3D9ConstantSets {
+ Rc<DxvkBuffer> buffer;
+ DxsoShaderMetaInfo meta = {};
+ bool dirty = true;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.cpp
new file mode 100644
index 00000000..510bbbc9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.cpp
@@ -0,0 +1,67 @@
+#include "d3d9_cursor.h"
+#include "d3d9_util.h"
+
+#include <utility>
+
+namespace dxvk {
+
+#ifndef DXVK_NATIVE
+ void D3D9Cursor::UpdateCursor(int X, int Y) {
+ POINT currentPos = { };
+ if (::GetCursorPos(&currentPos) && currentPos == POINT{ X, Y })
+ return;
+
+ ::SetCursorPos(X, Y);
+ }
+
+
+ BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
+ ::SetCursor(bShow ? m_hCursor : nullptr);
+ return std::exchange(m_visible, bShow);
+ }
+
+
+ HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
+ DWORD mask[32];
+ std::memset(mask, ~0, sizeof(mask));
+
+ ICONINFO info;
+ info.fIcon = FALSE;
+ info.xHotspot = XHotSpot;
+ info.yHotspot = YHotSpot;
+ info.hbmMask = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 1, mask);
+ info.hbmColor = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 32, &bitmap[0]);
+
+ if (m_hCursor != nullptr)
+ ::DestroyCursor(m_hCursor);
+
+ m_hCursor = ::CreateIconIndirect(&info);
+
+ ::DeleteObject(info.hbmMask);
+ ::DeleteObject(info.hbmColor);
+
+ ShowCursor(m_visible);
+
+ return D3D_OK;
+ }
+#else
+ void D3D9Cursor::UpdateCursor(int X, int Y) {
+ Logger::warn("D3D9Cursor::UpdateCursor: Not supported on native");
+ }
+
+
+ BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
+ Logger::warn("D3D9Cursor::ShowCursor: Not supported on native");
+
+ return std::exchange(m_visible, bShow);
+ }
+
+
+ HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
+ Logger::warn("D3D9Cursor::SetHardwareCursor: Not supported on native");
+
+ return D3DERR_INVALIDCALL;
+ }
+#endif
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.h
new file mode 100644
index 00000000..1b541d14
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_cursor.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ constexpr uint32_t HardwareCursorWidth = 32u;
+ constexpr uint32_t HardwareCursorHeight = 32u;
+ constexpr uint32_t HardwareCursorFormatSize = 4u;
+ constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
+
+ // Format Size of 4 bytes (ARGB)
+ using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
+
+ class D3D9Cursor {
+
+ public:
+
+ void UpdateCursor(int X, int Y);
+
+ BOOL ShowCursor(BOOL bShow);
+
+ HRESULT SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap);
+
+ private:
+
+ BOOL m_visible = FALSE;
+
+#ifndef DXVK_NATIVE
+ HCURSOR m_hCursor = nullptr;
+#endif
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.cpp
new file mode 100644
index 00000000..7af7f511
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.cpp
@@ -0,0 +1,7219 @@
+#include "d3d9_device.h"
+
+#include "d3d9_interface.h"
+#include "d3d9_swapchain.h"
+#include "d3d9_caps.h"
+#include "d3d9_util.h"
+#include "d3d9_texture.h"
+#include "d3d9_buffer.h"
+#include "d3d9_vertex_declaration.h"
+#include "d3d9_shader.h"
+#include "d3d9_query.h"
+#include "d3d9_stateblock.h"
+#include "d3d9_monitor.h"
+#include "d3d9_spec_constants.h"
+#include "d3d9_names.h"
+#include "d3d9_format_helpers.h"
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_instance.h"
+
+#include "../util/util_bit.h"
+#include "../util/util_math.h"
+
+#include "d3d9_initializer.h"
+
+#include <algorithm>
+#include <cfloat>
+#ifdef MSC_VER
+#pragma fenv_access (on)
+#endif
+
+namespace dxvk {
+
+ D3D9DeviceEx::D3D9DeviceEx(
+ D3D9InterfaceEx* pParent,
+ D3D9Adapter* pAdapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ Rc<DxvkDevice> dxvkDevice)
+ : m_parent ( pParent )
+ , m_deviceType ( DeviceType )
+ , m_window ( hFocusWindow )
+ , m_behaviorFlags ( BehaviorFlags )
+ , m_adapter ( pAdapter )
+ , m_dxvkDevice ( dxvkDevice )
+ , m_shaderModules ( new D3D9ShaderModuleSet )
+ , m_d3d9Options ( dxvkDevice, pParent->GetInstance()->config() )
+ , m_multithread ( BehaviorFlags & D3DCREATE_MULTITHREADED )
+ , m_isSWVP ( (BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) ? true : false )
+ , m_csThread ( dxvkDevice->createContext() )
+ , m_csChunk ( AllocCsChunk() ) {
+ // If we can SWVP, then we use an extended constant set
+ // as SWVP has many more slots available than HWVP.
+ bool canSWVP = CanSWVP();
+ DetermineConstantLayouts(canSWVP);
+
+ if (canSWVP)
+ Logger::info("D3D9DeviceEx: Using extended constant set for software vertex processing.");
+
+ m_initializer = new D3D9Initializer(m_dxvkDevice);
+ m_converter = new D3D9FormatHelper(m_dxvkDevice);
+
+ EmitCs([
+ cDevice = m_dxvkDevice
+ ] (DxvkContext* ctx) {
+ ctx->beginRecording(cDevice->createCommandList());
+
+ DxvkLogicOpState loState;
+ loState.enableLogicOp = VK_FALSE;
+ loState.logicOp = VK_LOGIC_OP_CLEAR;
+ ctx->setLogicOpState(loState);
+ });
+
+ if (!(BehaviorFlags & D3DCREATE_FPU_PRESERVE))
+ SetupFPU();
+
+ m_dxsoOptions = DxsoOptions(this, m_d3d9Options);
+
+ CreateConstantBuffers();
+
+ m_availableMemory = DetermineInitialTextureMemory();
+ }
+
+
+ D3D9DeviceEx::~D3D9DeviceEx() {
+ Flush();
+ SynchronizeCsThread();
+
+ delete m_initializer;
+ delete m_converter;
+
+ m_dxvkDevice->waitForIdle(); // Sync Device
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ bool extended = m_parent->IsExtended()
+ && riid == __uuidof(IDirect3DDevice9Ex);
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DDevice9)
+ || extended) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ // We want to ignore this if the extended device is queried and we weren't made extended.
+ if (riid == __uuidof(IDirect3DDevice9Ex))
+ return E_NOINTERFACE;
+
+ Logger::warn("D3D9DeviceEx::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::TestCooperativeLevel() {
+ // Equivelant of D3D11/DXGI present tests. We can always present.
+ return D3D_OK;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D9DeviceEx::GetAvailableTextureMem() {
+ // This is not meant to be accurate.
+ // The values are also wildly incorrect in d3d9... But some games rely
+ // on this inaccurate value...
+
+ // Clamp to megabyte range, as per spec.
+ constexpr UINT range = 0xfff00000;
+
+ // Can't have negative memory!
+ int64_t memory = std::max<int64_t>(m_availableMemory.load(), 0);
+
+ return UINT(memory) & range;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::EvictManagedResources() {
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetDirect3D(IDirect3D9** ppD3D9) {
+ if (ppD3D9 == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *ppD3D9 = m_parent.ref();
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetDeviceCaps(D3DCAPS9* pCaps) {
+ return m_adapter->GetDeviceCaps(m_deviceType, pCaps);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode) {
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->GetDisplayMode(pMode);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters) {
+ if (pParameters == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ pParameters->AdapterOrdinal = m_adapter->GetOrdinal();
+ pParameters->BehaviorFlags = m_behaviorFlags;
+ pParameters->DeviceType = m_deviceType;
+ pParameters->hFocusWindow = m_window;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetCursorProperties(
+ UINT XHotSpot,
+ UINT YHotSpot,
+ IDirect3DSurface9* pCursorBitmap) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pCursorBitmap == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ auto* cursorTex = GetCommonTexture(pCursorBitmap);
+ if (unlikely(cursorTex->Desc()->Format != D3D9Format::A8R8G8B8))
+ return D3DERR_INVALIDCALL;
+
+ uint32_t inputWidth = cursorTex->Desc()->Width;
+ uint32_t inputHeight = cursorTex->Desc()->Height;
+
+ // Always use a hardware cursor when windowed.
+ bool hwCursor = m_presentParams.Windowed;
+
+ // Always use a hardware cursor w/h <= 32 px
+ hwCursor |= inputWidth <= HardwareCursorWidth
+ || inputHeight <= HardwareCursorHeight;
+
+ if (hwCursor) {
+ D3DLOCKED_BOX lockedBox;
+ HRESULT hr = LockImage(cursorTex, 0, 0, &lockedBox, nullptr, D3DLOCK_READONLY);
+ if (FAILED(hr))
+ return hr;
+
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(lockedBox.pBits);
+
+ // Windows works with a stride of 128, lets respect that.
+ // Copy data to the bitmap...
+ CursorBitmap bitmap = { 0 };
+ size_t copyPitch = std::min<size_t>(
+ HardwareCursorPitch,
+ inputWidth * inputHeight * HardwareCursorFormatSize);
+
+ for (uint32_t h = 0; h < HardwareCursorHeight; h++)
+ std::memcpy(&bitmap[h * HardwareCursorPitch], &data[h * lockedBox.RowPitch], copyPitch);
+
+ UnlockImage(cursorTex, 0, 0);
+
+ // Set this as our cursor.
+ return m_cursor.SetHardwareCursor(XHotSpot, YHotSpot, bitmap);
+ }
+
+ // Software Cursor...
+ Logger::warn("D3D9DeviceEx::SetCursorProperties: Software cursor not implemented.");
+ return D3D_OK;
+ }
+
+
+ void STDMETHODCALLTYPE D3D9DeviceEx::SetCursorPosition(int X, int Y, DWORD Flags) {
+ D3D9DeviceLock lock = LockDevice();
+
+ // I was not able to find an instance
+ // where the cursor update was not immediate.
+
+ // Fullscreen + Windowed seem to have the same
+ // behaviour here.
+
+ // Hence we ignore the flag D3DCURSOR_IMMEDIATE_UPDATE.
+
+ m_cursor.UpdateCursor(X, Y);
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D9DeviceEx::ShowCursor(BOOL bShow) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return m_cursor.ShowCursor(bShow);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateAdditionalSwapChain(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ IDirect3DSwapChain9** ppSwapChain) {
+ return CreateAdditionalSwapChainEx(pPresentationParameters, nullptr, ppSwapChain);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(pSwapChain);
+
+ if (unlikely(pSwapChain == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ // This only returns the implicit swapchain...
+
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ *pSwapChain = static_cast<IDirect3DSwapChain9*>(m_implicitSwapchain.ref());
+
+ return D3D_OK;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D9DeviceEx::GetNumberOfSwapChains() {
+ // This only counts the implicit swapchain...
+
+ return 1;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) {
+ D3D9DeviceLock lock = LockDevice();
+
+ HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
+ if (FAILED(hr))
+ return hr;
+
+ hr = ResetState(pPresentationParameters);
+ if (FAILED(hr))
+ return hr;
+
+ Flush();
+ SynchronizeCsThread();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Present(
+ const RECT* pSourceRect,
+ const RECT* pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion) {
+ return PresentEx(
+ pSourceRect,
+ pDestRect,
+ hDestWindowOverride,
+ pDirtyRegion,
+ 0);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetBackBuffer(
+ UINT iSwapChain,
+ UINT iBackBuffer,
+ D3DBACKBUFFER_TYPE Type,
+ IDirect3DSurface9** ppBackBuffer) {
+ InitReturnPtr(ppBackBuffer);
+
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->GetBackBuffer(iBackBuffer, Type, ppBackBuffer);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) {
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->GetRasterStatus(pRasterStatus);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetDialogBoxMode(BOOL bEnableDialogs) {
+ return m_implicitSwapchain->SetDialogBoxMode(bEnableDialogs);
+ }
+
+
+ void STDMETHODCALLTYPE D3D9DeviceEx::SetGammaRamp(
+ UINT iSwapChain,
+ DWORD Flags,
+ const D3DGAMMARAMP* pRamp) {
+ if (unlikely(iSwapChain != 0))
+ return;
+
+ m_implicitSwapchain->SetGammaRamp(Flags, pRamp);
+ }
+
+
+ void STDMETHODCALLTYPE D3D9DeviceEx::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp) {
+ if (unlikely(iSwapChain != 0))
+ return;
+
+ m_implicitSwapchain->GetGammaRamp(pRamp);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateTexture(
+ UINT Width,
+ UINT Height,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DTexture9** ppTexture,
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(ppTexture);
+
+ if (unlikely(ppTexture == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = Width;
+ desc.Height = Height;
+ desc.Depth = 1;
+ desc.ArraySize = 1;
+ desc.MipLevels = Levels;
+ desc.Usage = Usage;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = Pool;
+ desc.Discard = FALSE;
+ desc.MultiSample = D3DMULTISAMPLE_NONE;
+ desc.MultisampleQuality = 0;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = FALSE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9Texture2D> texture = new D3D9Texture2D(this, &desc);
+
+ void* initialData = nullptr;
+
+ if (Pool == D3DPOOL_SYSTEMMEM && Levels == 1 && pSharedHandle != nullptr)
+ initialData = *(reinterpret_cast<void**>(pSharedHandle));
+
+ m_initializer->InitTexture(texture->GetCommonTexture(), initialData);
+ *ppTexture = texture.ref();
+
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateVolumeTexture(
+ UINT Width,
+ UINT Height,
+ UINT Depth,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DVolumeTexture9** ppVolumeTexture,
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(ppVolumeTexture);
+
+ if (unlikely(ppVolumeTexture == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = Width;
+ desc.Height = Height;
+ desc.Depth = Depth;
+ desc.ArraySize = 1;
+ desc.MipLevels = Levels;
+ desc.Usage = Usage;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = Pool;
+ desc.Discard = FALSE;
+ desc.MultiSample = D3DMULTISAMPLE_NONE;
+ desc.MultisampleQuality = 0;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = FALSE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9Texture3D> texture = new D3D9Texture3D(this, &desc);
+ m_initializer->InitTexture(texture->GetCommonTexture());
+ *ppVolumeTexture = texture.ref();
+
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateCubeTexture(
+ UINT EdgeLength,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DCubeTexture9** ppCubeTexture,
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(ppCubeTexture);
+
+ if (unlikely(ppCubeTexture == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = EdgeLength;
+ desc.Height = EdgeLength;
+ desc.Depth = 1;
+ desc.ArraySize = 6; // A cube has 6 faces, wowwie!
+ desc.MipLevels = Levels;
+ desc.Usage = Usage;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = Pool;
+ desc.Discard = FALSE;
+ desc.MultiSample = D3DMULTISAMPLE_NONE;
+ desc.MultisampleQuality = 0;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = FALSE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9TextureCube> texture = new D3D9TextureCube(this, &desc);
+ m_initializer->InitTexture(texture->GetCommonTexture());
+ *ppCubeTexture = texture.ref();
+
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateVertexBuffer(
+ UINT Length,
+ DWORD Usage,
+ DWORD FVF,
+ D3DPOOL Pool,
+ IDirect3DVertexBuffer9** ppVertexBuffer,
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(ppVertexBuffer);
+
+ if (unlikely(ppVertexBuffer == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_BUFFER_DESC desc;
+ desc.Format = D3D9Format::VERTEXDATA;
+ desc.FVF = FVF;
+ desc.Pool = Pool;
+ desc.Size = Length;
+ desc.Type = D3DRTYPE_VERTEXBUFFER;
+ desc.Usage = Usage;
+
+ if (FAILED(D3D9CommonBuffer::ValidateBufferProperties(&desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9VertexBuffer> buffer = new D3D9VertexBuffer(this, &desc);
+ m_initializer->InitBuffer(buffer->GetCommonBuffer());
+ *ppVertexBuffer = buffer.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateIndexBuffer(
+ UINT Length,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DIndexBuffer9** ppIndexBuffer,
+ HANDLE* pSharedHandle) {
+ InitReturnPtr(ppIndexBuffer);
+
+ if (unlikely(ppIndexBuffer == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_BUFFER_DESC desc;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = Pool;
+ desc.Size = Length;
+ desc.Type = D3DRTYPE_INDEXBUFFER;
+ desc.Usage = Usage;
+
+ if (FAILED(D3D9CommonBuffer::ValidateBufferProperties(&desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9IndexBuffer> buffer = new D3D9IndexBuffer(this, &desc);
+ m_initializer->InitBuffer(buffer->GetCommonBuffer());
+ *ppIndexBuffer = buffer.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateRenderTarget(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Lockable,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle) {
+ return CreateRenderTargetEx(
+ Width,
+ Height,
+ Format,
+ MultiSample,
+ MultisampleQuality,
+ Lockable,
+ ppSurface,
+ pSharedHandle,
+ 0);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateDepthStencilSurface(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Discard,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle) {
+ return CreateDepthStencilSurfaceEx(
+ Width,
+ Height,
+ Format,
+ MultiSample,
+ MultisampleQuality,
+ Discard,
+ ppSurface,
+ pSharedHandle,
+ 0);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::UpdateSurface(
+ IDirect3DSurface9* pSourceSurface,
+ const RECT* pSourceRect,
+ IDirect3DSurface9* pDestinationSurface,
+ const POINT* pDestPoint) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9Surface* src = static_cast<D3D9Surface*>(pSourceSurface);
+ D3D9Surface* dst = static_cast<D3D9Surface*>(pDestinationSurface);
+
+ if (unlikely(src == nullptr || dst == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture();
+ D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture();
+
+ if (unlikely(srcTextureInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM || dstTextureInfo->Desc()->Pool != D3DPOOL_DEFAULT))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(srcTextureInfo->Desc()->Format != dstTextureInfo->Desc()->Format))
+ return D3DERR_INVALIDCALL;
+
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTextureInfo->GetFormatMapping().FormatColor);
+
+ VkOffset3D srcBlockOffset = { 0u, 0u, 0u };
+ VkOffset3D dstOffset = { 0u, 0u, 0u };
+ VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource());
+ VkExtent3D texLevelBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize);
+
+ VkExtent3D copyExtent = texLevelExtent;
+
+ if (pSourceRect != nullptr) {
+ const VkExtent3D extent = { uint32_t(pSourceRect->right - pSourceRect->left), uint32_t(pSourceRect->bottom - pSourceRect->top), 1 };
+
+ const bool extentAligned = extent.width % formatInfo->blockSize.width == 0
+ && extent.height % formatInfo->blockSize.height == 0;
+
+ if (pSourceRect->left < 0
+ || pSourceRect->top < 0
+ || pSourceRect->right <= pSourceRect->left
+ || pSourceRect->bottom <= pSourceRect->top
+ || pSourceRect->left % formatInfo->blockSize.width != 0
+ || pSourceRect->top % formatInfo->blockSize.height != 0
+ || (extent != texLevelExtent && !extentAligned))
+ return D3DERR_INVALIDCALL;
+
+ srcBlockOffset = { pSourceRect->left / int32_t(formatInfo->blockSize.width),
+ pSourceRect->top / int32_t(formatInfo->blockSize.height),
+ 0u };
+
+ copyExtent = { extent.width,
+ extent.height,
+ 1u };
+ }
+
+ if (pDestPoint != nullptr) {
+ if (pDestPoint->x % formatInfo->blockSize.width != 0
+ || pDestPoint->y % formatInfo->blockSize.height != 0
+ || pDestPoint->x < 0
+ || pDestPoint->y < 0)
+ return D3DERR_INVALIDCALL;
+
+ dstOffset = { pDestPoint->x,
+ pDestPoint->y,
+ 0u };
+ }
+
+ VkExtent3D copyBlockCount = util::computeBlockCount(copyExtent, formatInfo->blockSize);
+
+ const auto dstSubresource = vk::makeSubresourceLayers(
+ dstTextureInfo->GetSubresourceFromIndex(VK_IMAGE_ASPECT_COLOR_BIT, dst->GetSubresource()));
+
+ DxvkBufferSliceHandle srcSlice = srcTextureInfo->GetMappedSlice(src->GetSubresource());
+ VkDeviceSize dirtySize = copyBlockCount.width * copyBlockCount.height * formatInfo->elementSize;
+ D3D9BufferSlice slice = AllocTempBuffer<false>(dirtySize);
+ VkDeviceSize pitch = align(texLevelBlockCount.width * formatInfo->elementSize, 4);
+ VkDeviceSize copySrcOffset = srcBlockOffset.z * texLevelBlockCount.height * pitch
+ + srcBlockOffset.y * pitch
+ + srcBlockOffset.x * formatInfo->elementSize;
+
+ void* srcData = reinterpret_cast<uint8_t*>(srcSlice.mapPtr) + copySrcOffset;
+ util::packImageData(
+ slice.mapPtr, srcData, copyBlockCount, formatInfo->elementSize,
+ pitch, pitch * texLevelBlockCount.height);
+
+ Rc<DxvkImage> dstImage = dstTextureInfo->GetImage();
+
+ EmitCs([
+ cDstImage = std::move(dstImage),
+ cSrcSlice = slice.slice,
+ cDstLayers = dstSubresource,
+ cDstOffset = dstOffset,
+ cCopyExtent = copyExtent
+ ] (DxvkContext* ctx) {
+ ctx->copyBufferToImage(
+ cDstImage, cDstLayers, cDstOffset, cCopyExtent,
+ cSrcSlice.buffer(), cSrcSlice.offset(), 0, 0);
+ });
+
+ dstTextureInfo->SetWrittenByGPU(dst->GetSubresource(), true);
+
+ if (dstTextureInfo->IsAutomaticMip())
+ MarkTextureMipsDirty(dstTextureInfo);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::UpdateTexture(
+ IDirect3DBaseTexture9* pSourceTexture,
+ IDirect3DBaseTexture9* pDestinationTexture) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (!pDestinationTexture || !pSourceTexture)
+ return D3DERR_INVALIDCALL;
+
+ D3D9CommonTexture* dstTexInfo = GetCommonTexture(pDestinationTexture);
+ D3D9CommonTexture* srcTexInfo = GetCommonTexture(pSourceTexture);
+
+ if (unlikely(srcTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM || dstTexInfo->Desc()->Pool != D3DPOOL_DEFAULT))
+ return D3DERR_INVALIDCALL;
+
+ const Rc<DxvkImage> dstImage = dstTexInfo->GetImage();
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTexInfo->GetFormatMapping().FormatColor);
+ uint32_t mipLevels = std::min(srcTexInfo->Desc()->MipLevels, dstTexInfo->Desc()->MipLevels);
+ uint32_t arraySlices = std::min(srcTexInfo->Desc()->ArraySize, dstTexInfo->Desc()->ArraySize);
+
+ if (unlikely(srcTexInfo->IsAutomaticMip() && !dstTexInfo->IsAutomaticMip()))
+ return D3DERR_INVALIDCALL;
+
+ if (dstTexInfo->IsAutomaticMip())
+ mipLevels = 1;
+
+ for (uint32_t a = 0; a < arraySlices; a++) {
+ const D3DBOX& box = srcTexInfo->GetDirtyBox(a);
+ if (box.Left >= box.Right || box.Top >= box.Bottom || box.Front >= box.Back)
+ continue;
+
+ for (uint32_t m = 0; m < mipLevels; m++) {
+ VkImageSubresourceLayers dstLayers = { VK_IMAGE_ASPECT_COLOR_BIT, m, a, 1 };
+
+ VkOffset3D scaledBoxOffset = {
+ int32_t(alignDown(box.Left >> m, formatInfo->blockSize.width)),
+ int32_t(alignDown(box.Top >> m, formatInfo->blockSize.height)),
+ int32_t(alignDown(box.Front >> m, formatInfo->blockSize.depth))
+ };
+ VkExtent3D scaledBoxExtent = util::computeMipLevelExtent({
+ uint32_t(box.Right - int32_t(alignDown(box.Left, formatInfo->blockSize.width))),
+ uint32_t(box.Bottom - int32_t(alignDown(box.Top, formatInfo->blockSize.height))),
+ uint32_t(box.Back - int32_t(alignDown(box.Front, formatInfo->blockSize.depth)))
+ }, m);
+ VkExtent3D scaledBoxExtentBlockCount = util::computeBlockCount(scaledBoxExtent, formatInfo->blockSize);
+ VkExtent3D scaledAlignedBoxExtent = util::computeBlockExtent(scaledBoxExtentBlockCount, formatInfo->blockSize);
+
+ VkExtent3D texLevelExtent = dstImage->mipLevelExtent(m);
+ VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize);
+
+ scaledAlignedBoxExtent.width = std::min<uint32_t>(texLevelExtent.width - scaledBoxOffset.x, scaledAlignedBoxExtent.width);
+ scaledAlignedBoxExtent.height = std::min<uint32_t>(texLevelExtent.height - scaledBoxOffset.y, scaledAlignedBoxExtent.height);
+ scaledAlignedBoxExtent.depth = std::min<uint32_t>(texLevelExtent.depth - scaledBoxOffset.z, scaledAlignedBoxExtent.depth);
+
+ VkDeviceSize dirtySize = scaledBoxExtentBlockCount.width * scaledBoxExtentBlockCount.height * scaledBoxExtentBlockCount.depth * formatInfo->elementSize;
+ D3D9BufferSlice slice = AllocTempBuffer<false>(dirtySize);
+ VkOffset3D boxOffsetBlockCount = util::computeBlockOffset(scaledBoxOffset, formatInfo->blockSize);
+ VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4);
+ VkDeviceSize copySrcOffset = boxOffsetBlockCount.z * texLevelExtentBlockCount.height * pitch
+ + boxOffsetBlockCount.y * pitch
+ + boxOffsetBlockCount.x * formatInfo->elementSize;
+
+ void* srcData = reinterpret_cast<uint8_t*>(srcTexInfo->GetMappedSlice(srcTexInfo->CalcSubresource(a, m)).mapPtr) + copySrcOffset;
+ util::packImageData(
+ slice.mapPtr, srcData, scaledBoxExtentBlockCount, formatInfo->elementSize,
+ pitch, pitch * texLevelExtentBlockCount.height);
+
+ scaledAlignedBoxExtent.width = std::min<uint32_t>(texLevelExtent.width, scaledAlignedBoxExtent.width);
+ scaledAlignedBoxExtent.height = std::min<uint32_t>(texLevelExtent.height, scaledAlignedBoxExtent.height);
+ scaledAlignedBoxExtent.depth = std::min<uint32_t>(texLevelExtent.depth, scaledAlignedBoxExtent.depth);
+
+ EmitCs([
+ cDstImage = dstImage,
+ cSrcSlice = slice.slice,
+ cDstLayers = dstLayers,
+ cExtent = scaledAlignedBoxExtent,
+ cOffset = scaledBoxOffset
+ ] (DxvkContext* ctx) {
+ ctx->copyBufferToImage(
+ cDstImage, cDstLayers,
+ cOffset, cExtent,
+ cSrcSlice.buffer(), cSrcSlice.offset(), 0, 0);
+ });
+
+ dstTexInfo->SetWrittenByGPU(dstTexInfo->CalcSubresource(a, m), true);
+ }
+ }
+
+ srcTexInfo->ClearDirtyBoxes();
+ if (dstTexInfo->IsAutomaticMip() && mipLevels != dstTexInfo->Desc()->MipLevels)
+ MarkTextureMipsDirty(dstTexInfo);
+
+ FlushImplicit(false);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetRenderTargetData(
+ IDirect3DSurface9* pRenderTarget,
+ IDirect3DSurface9* pDestSurface) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9Surface* src = static_cast<D3D9Surface*>(pRenderTarget);
+ D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
+
+ if (unlikely(src == nullptr || dst == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (pRenderTarget == pDestSurface)
+ return D3D_OK;
+
+ D3D9CommonTexture* dstTexInfo = GetCommonTexture(dst);
+ D3D9CommonTexture* srcTexInfo = GetCommonTexture(src);
+
+ if (srcTexInfo->Desc()->Format != dstTexInfo->Desc()->Format)
+ return D3DERR_INVALIDCALL;
+
+ if (dstTexInfo->Desc()->Pool == D3DPOOL_DEFAULT)
+ return this->StretchRect(pRenderTarget, nullptr, pDestSurface, nullptr, D3DTEXF_NONE);
+
+ Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
+
+ Rc<DxvkImage> srcImage = srcTexInfo->GetImage();
+ const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
+
+ const VkImageSubresource srcSubresource = srcTexInfo->GetSubresourceFromIndex(srcFormatInfo->aspectMask, src->GetSubresource());
+ VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ VkExtent3D srcExtent = srcTexInfo->GetExtentMip(src->GetMipLevel());
+
+ VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(srcExtent, srcFormatInfo->blockSize);
+ VkDeviceSize pitch = align(texLevelExtentBlockCount.width * uint32_t(srcFormatInfo->elementSize), 4);
+ uint32_t pitchBlocks = uint32_t(pitch / srcFormatInfo->elementSize);
+ VkExtent2D dstExtent = VkExtent2D{ pitchBlocks,
+ texLevelExtentBlockCount.height * pitchBlocks };
+
+ EmitCs([
+ cBuffer = dstBuffer,
+ cImage = srcImage,
+ cSubresources = srcSubresourceLayers,
+ cLevelExtent = srcExtent,
+ cDstExtent = dstExtent
+ ] (DxvkContext* ctx) {
+ ctx->copyImageToBuffer(cBuffer, 0, 4, 0,
+ cImage, cSubresources, VkOffset3D { 0, 0, 0 },
+ cLevelExtent);
+ });
+
+ dstTexInfo->SetWrittenByGPU(dst->GetSubresource(), true);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface) {
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->GetFrontBufferData(pDestSurface);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::StretchRect(
+ IDirect3DSurface9* pSourceSurface,
+ const RECT* pSourceRect,
+ IDirect3DSurface9* pDestSurface,
+ const RECT* pDestRect,
+ D3DTEXTUREFILTERTYPE Filter) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
+ D3D9Surface* src = static_cast<D3D9Surface*>(pSourceSurface);
+
+ if (unlikely(src == nullptr || dst == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(src == dst))
+ return D3DERR_INVALIDCALL;
+
+ bool fastPath = true;
+
+ D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture();
+ D3D9CommonTexture* srcTextureInfo = src->GetCommonTexture();
+
+ if (unlikely(dstTextureInfo->Desc()->Pool != D3DPOOL_DEFAULT ||
+ srcTextureInfo->Desc()->Pool != D3DPOOL_DEFAULT))
+ return D3DERR_INVALIDCALL;
+
+ Rc<DxvkImage> dstImage = dstTextureInfo->GetImage();
+ Rc<DxvkImage> srcImage = srcTextureInfo->GetImage();
+
+ const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(dstImage->info().format);
+ const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
+
+ const VkImageSubresource dstSubresource = dstTextureInfo->GetSubresourceFromIndex(dstFormatInfo->aspectMask, dst->GetSubresource());
+ const VkImageSubresource srcSubresource = srcTextureInfo->GetSubresourceFromIndex(srcFormatInfo->aspectMask, src->GetSubresource());
+
+ if (unlikely((srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) && m_flags.test(D3D9DeviceFlag::InScene)))
+ return D3DERR_INVALIDCALL;
+
+ VkExtent3D srcExtent = srcImage->mipLevelExtent(srcSubresource.mipLevel);
+ VkExtent3D dstExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
+
+ D3D9Format srcFormat = srcTextureInfo->Desc()->Format;
+ D3D9Format dstFormat = dstTextureInfo->Desc()->Format;
+
+ // We may only fast path copy non identicals one way!
+ // We don't know what garbage could be in the X8 data.
+ bool similar = AreFormatsSimilar(srcFormat, dstFormat);
+
+ // Copies are only supported on similar formats.
+ fastPath &= similar;
+
+ // Copies are only supported if the sample count matches,
+ // otherwise we need to resolve.
+ bool needsResolve = srcImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT;
+ bool fbBlit = dstImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT;
+ fastPath &= !fbBlit;
+
+ // Copies would only work if we are block aligned.
+ if (pSourceRect != nullptr) {
+ fastPath &= (pSourceRect->left % srcFormatInfo->blockSize.width == 0);
+ fastPath &= (pSourceRect->right % srcFormatInfo->blockSize.width == 0);
+ fastPath &= (pSourceRect->top % srcFormatInfo->blockSize.height == 0);
+ fastPath &= (pSourceRect->bottom % srcFormatInfo->blockSize.height == 0);
+ }
+
+ if (pDestRect != nullptr) {
+ fastPath &= (pDestRect->left % dstFormatInfo->blockSize.width == 0);
+ fastPath &= (pDestRect->top % dstFormatInfo->blockSize.height == 0);
+ }
+
+ VkImageSubresourceLayers dstSubresourceLayers = {
+ dstSubresource.aspectMask,
+ dstSubresource.mipLevel,
+ dstSubresource.arrayLayer, 1 };
+
+ VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ VkImageBlit blitInfo;
+ blitInfo.dstSubresource = dstSubresourceLayers;
+ blitInfo.srcSubresource = srcSubresourceLayers;
+
+ blitInfo.dstOffsets[0] = pDestRect != nullptr
+ ? VkOffset3D{ int32_t(pDestRect->left), int32_t(pDestRect->top), 0 }
+ : VkOffset3D{ 0, 0, 0 };
+
+ blitInfo.dstOffsets[1] = pDestRect != nullptr
+ ? VkOffset3D{ int32_t(pDestRect->right), int32_t(pDestRect->bottom), 1 }
+ : VkOffset3D{ int32_t(dstExtent.width), int32_t(dstExtent.height), 1 };
+
+ blitInfo.srcOffsets[0] = pSourceRect != nullptr
+ ? VkOffset3D{ int32_t(pSourceRect->left), int32_t(pSourceRect->top), 0 }
+ : VkOffset3D{ 0, 0, 0 };
+
+ blitInfo.srcOffsets[1] = pSourceRect != nullptr
+ ? VkOffset3D{ int32_t(pSourceRect->right), int32_t(pSourceRect->bottom), 1 }
+ : VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
+
+ if (unlikely(IsBlitRegionInvalid(blitInfo.srcOffsets, srcExtent)))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(IsBlitRegionInvalid(blitInfo.dstOffsets, dstExtent)))
+ return D3DERR_INVALIDCALL;
+
+ VkExtent3D srcCopyExtent =
+ { uint32_t(blitInfo.srcOffsets[1].x - blitInfo.srcOffsets[0].x),
+ uint32_t(blitInfo.srcOffsets[1].y - blitInfo.srcOffsets[0].y),
+ uint32_t(blitInfo.srcOffsets[1].z - blitInfo.srcOffsets[0].z) };
+
+ VkExtent3D dstCopyExtent =
+ { uint32_t(blitInfo.dstOffsets[1].x - blitInfo.dstOffsets[0].x),
+ uint32_t(blitInfo.dstOffsets[1].y - blitInfo.dstOffsets[0].y),
+ uint32_t(blitInfo.dstOffsets[1].z - blitInfo.dstOffsets[0].z) };
+
+ // Copies would only work if the extents match. (ie. no stretching)
+ bool stretch = srcCopyExtent != dstCopyExtent;
+ fastPath &= !stretch;
+
+ if (!fastPath || needsResolve) {
+ // Compressed destination formats are forbidden for blits.
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::BlockCompressed))
+ return D3DERR_INVALIDCALL;
+ }
+
+ auto EmitResolveCS = [&](const Rc<DxvkImage>& resolveDst, bool intermediate) {
+ VkImageResolve region;
+ region.srcSubresource = blitInfo.srcSubresource;
+ region.srcOffset = blitInfo.srcOffsets[0];
+ region.dstSubresource = intermediate ? blitInfo.srcSubresource : blitInfo.dstSubresource;
+ region.dstOffset = intermediate ? blitInfo.srcOffsets[0] : blitInfo.dstOffsets[0];
+ region.extent = srcCopyExtent;
+
+ EmitCs([
+ cDstImage = resolveDst,
+ cSrcImage = srcImage,
+ cRegion = region
+ ] (DxvkContext* ctx) {
+ if (cRegion.srcSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->resolveImage(
+ cDstImage, cSrcImage, cRegion,
+ VK_FORMAT_UNDEFINED);
+ }
+ else {
+ ctx->resolveDepthStencilImage(
+ cDstImage, cSrcImage, cRegion,
+ VK_RESOLVE_MODE_AVERAGE_BIT_KHR,
+ VK_RESOLVE_MODE_AVERAGE_BIT_KHR);
+ }
+ });
+ };
+
+ if (fastPath) {
+ if (needsResolve) {
+ EmitResolveCS(dstImage, false);
+ } else {
+ EmitCs([
+ cDstImage = dstImage,
+ cSrcImage = srcImage,
+ cDstLayers = blitInfo.dstSubresource,
+ cSrcLayers = blitInfo.srcSubresource,
+ cDstOffset = blitInfo.dstOffsets[0],
+ cSrcOffset = blitInfo.srcOffsets[0],
+ cExtent = srcCopyExtent
+ ] (DxvkContext* ctx) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, cDstOffset,
+ cSrcImage, cSrcLayers, cSrcOffset,
+ cExtent);
+ });
+ }
+ }
+ else {
+ if (needsResolve) {
+ auto resolveSrc = srcTextureInfo->GetResolveImage();
+
+ EmitResolveCS(resolveSrc, true);
+ srcImage = resolveSrc;
+ }
+
+ EmitCs([
+ cDstImage = dstImage,
+ cDstMap = dstTextureInfo->GetMapping().Swizzle,
+ cSrcImage = srcImage,
+ cSrcMap = srcTextureInfo->GetMapping().Swizzle,
+ cBlitInfo = blitInfo,
+ cFilter = stretch ? DecodeFilter(Filter) : VK_FILTER_NEAREST
+ ] (DxvkContext* ctx) {
+ ctx->blitImage(
+ cDstImage,
+ cDstMap,
+ cSrcImage,
+ cSrcMap,
+ cBlitInfo,
+ cFilter);
+ });
+ }
+
+ dstTextureInfo->SetWrittenByGPU(dst->GetSubresource(), true);
+
+ if (dstTextureInfo->IsAutomaticMip())
+ MarkTextureMipsDirty(dstTextureInfo);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ColorFill(
+ IDirect3DSurface9* pSurface,
+ const RECT* pRect,
+ D3DCOLOR Color) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9Surface* dst = static_cast<D3D9Surface*>(pSurface);
+
+ if (unlikely(dst == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9CommonTexture* dstTextureInfo = dst->GetCommonTexture();
+
+ if (unlikely(dstTextureInfo->Desc()->Pool != D3DPOOL_DEFAULT))
+ return D3DERR_INVALIDCALL;
+
+ VkExtent3D mipExtent = dstTextureInfo->GetExtentMip(dst->GetSubresource());
+
+ VkOffset3D offset = VkOffset3D{ 0u, 0u, 0u };
+ VkExtent3D extent = mipExtent;
+
+ bool isFullExtent = true;
+ if (pRect != nullptr) {
+ ConvertRect(*pRect, offset, extent);
+
+ isFullExtent = offset == VkOffset3D{ 0u, 0u, 0u }
+ && extent == mipExtent;
+ }
+
+ Rc<DxvkImageView> rtView = dst->GetRenderTargetView(false);
+
+ VkClearValue clearValue;
+ DecodeD3DCOLOR(Color, clearValue.color.float32);
+
+ // Fast path for games that may use this as an
+ // alternative to Clear on render targets.
+ if (isFullExtent && rtView != nullptr) {
+ EmitCs([
+ cImageView = rtView,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ } else {
+ if (unlikely(rtView == nullptr)) {
+ const D3D9Format format = dstTextureInfo->Desc()->Format;
+ if (format != D3D9Format::NULL_FORMAT)
+ Logger::err(str::format("D3D9DeviceEx::ColorFill: Unsupported format ", format));
+
+ return D3D_OK;
+ }
+
+ EmitCs([
+ cImageView = rtView,
+ cOffset = offset,
+ cExtent = extent,
+ cClearValue = clearValue
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(
+ cImageView,
+ cOffset, cExtent,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ cClearValue);
+ });
+ }
+
+ dstTextureInfo->SetWrittenByGPU(dst->GetSubresource(), true);
+
+ if (dstTextureInfo->IsAutomaticMip())
+ MarkTextureMipsDirty(dstTextureInfo);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateOffscreenPlainSurface(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle) {
+ return CreateOffscreenPlainSurfaceEx(
+ Width, Height,
+ Format, Pool,
+ ppSurface, pSharedHandle,
+ 0);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetRenderTarget(
+ DWORD RenderTargetIndex,
+ IDirect3DSurface9* pRenderTarget) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(RenderTargetIndex >= caps::MaxSimultaneousRenderTargets
+ || (pRenderTarget == nullptr && RenderTargetIndex == 0)))
+ return D3DERR_INVALIDCALL;
+
+ D3D9Surface* rt = static_cast<D3D9Surface*>(pRenderTarget);
+ D3D9CommonTexture* texInfo = rt != nullptr
+ ? rt->GetCommonTexture()
+ : nullptr;
+
+ if (unlikely(rt != nullptr && !(texInfo->Desc()->Usage & D3DUSAGE_RENDERTARGET)))
+ return D3DERR_INVALIDCALL;
+
+ if (RenderTargetIndex == 0) {
+ auto rtSize = rt->GetSurfaceExtent();
+
+ D3DVIEWPORT9 viewport;
+ viewport.X = 0;
+ viewport.Y = 0;
+ viewport.Width = rtSize.width;
+ viewport.Height = rtSize.height;
+ viewport.MinZ = 0.0f;
+ viewport.MaxZ = 1.0f;
+
+ RECT scissorRect;
+ scissorRect.left = 0;
+ scissorRect.top = 0;
+ scissorRect.right = rtSize.width;
+ scissorRect.bottom = rtSize.height;
+
+ if (m_state.viewport != viewport) {
+ m_flags.set(D3D9DeviceFlag::DirtyFFViewport);
+ m_flags.set(D3D9DeviceFlag::DirtyPointScale);
+ m_flags.set(D3D9DeviceFlag::DirtyViewportScissor);
+ m_state.viewport = viewport;
+ }
+
+ if (m_state.scissorRect != scissorRect) {
+ m_flags.set(D3D9DeviceFlag::DirtyViewportScissor);
+ m_state.scissorRect = scissorRect;
+ }
+ }
+
+ if (m_state.renderTargets[RenderTargetIndex] == rt)
+ return D3D_OK;
+
+ // Do a strong flush if the first render target is changed.
+ FlushImplicit(RenderTargetIndex == 0 ? TRUE : FALSE);
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+
+ m_state.renderTargets[RenderTargetIndex] = rt;
+
+ UpdateBoundRTs(RenderTargetIndex);
+ UpdateActiveRTs(RenderTargetIndex);
+
+ uint32_t originalAlphaSwizzleRTs = m_alphaSwizzleRTs;
+
+ m_alphaSwizzleRTs &= ~(1 << RenderTargetIndex);
+
+ if (rt != nullptr) {
+ if (texInfo->GetMapping().Swizzle.a == VK_COMPONENT_SWIZZLE_ONE)
+ m_alphaSwizzleRTs |= 1 << RenderTargetIndex;
+
+ if (texInfo->IsAutomaticMip())
+ texInfo->SetNeedsMipGen(true);
+
+ texInfo->SetWrittenByGPU(rt->GetSubresource(), true);
+ }
+
+ if (originalAlphaSwizzleRTs != m_alphaSwizzleRTs)
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+
+ if (RenderTargetIndex == 0) {
+ bool validSampleMask = texInfo->Desc()->MultiSample > D3DMULTISAMPLE_NONMASKABLE;
+
+ if (validSampleMask != m_flags.test(D3D9DeviceFlag::ValidSampleMask)) {
+ m_flags.clr(D3D9DeviceFlag::ValidSampleMask);
+ if (validSampleMask)
+ m_flags.set(D3D9DeviceFlag::ValidSampleMask);
+
+ m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
+ }
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetRenderTarget(
+ DWORD RenderTargetIndex,
+ IDirect3DSurface9** ppRenderTarget) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppRenderTarget);
+
+ if (unlikely(ppRenderTarget == nullptr || RenderTargetIndex > caps::MaxSimultaneousRenderTargets))
+ return D3DERR_INVALIDCALL;
+
+ if (m_state.renderTargets[RenderTargetIndex] == nullptr)
+ return D3DERR_NOTFOUND;
+
+ *ppRenderTarget = m_state.renderTargets[RenderTargetIndex].ref();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9Surface* ds = static_cast<D3D9Surface*>(pNewZStencil);
+
+ if (unlikely(ds && !(ds->GetCommonTexture()->Desc()->Usage & D3DUSAGE_DEPTHSTENCIL)))
+ return D3DERR_INVALIDCALL;
+
+ if (m_state.depthStencil == ds)
+ return D3D_OK;
+
+ FlushImplicit(FALSE);
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+
+ if (ds != nullptr) {
+ float rValue = GetDepthBufferRValue(ds->GetCommonTexture()->GetFormatMapping().FormatColor);
+ if (m_depthBiasScale != rValue) {
+ m_depthBiasScale = rValue;
+ m_flags.set(D3D9DeviceFlag::DirtyDepthBias);
+ }
+ }
+
+ m_state.depthStencil = ds;
+
+ UpdateActiveHazardsDS(UINT32_MAX);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppZStencilSurface);
+
+ if (unlikely(ppZStencilSurface == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (m_state.depthStencil == nullptr)
+ return D3DERR_NOTFOUND;
+
+ *ppZStencilSurface = m_state.depthStencil.ref();
+
+ return D3D_OK;
+ }
+
+ // The Begin/EndScene functions actually do nothing.
+ // Some games don't even call them.
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::BeginScene() {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(m_flags.test(D3D9DeviceFlag::InScene)))
+ return D3DERR_INVALIDCALL;
+
+ m_flags.set(D3D9DeviceFlag::InScene);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::EndScene() {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(!m_flags.test(D3D9DeviceFlag::InScene)))
+ return D3DERR_INVALIDCALL;
+
+ FlushImplicit(true);
+
+ m_flags.clr(D3D9DeviceFlag::InScene);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Clear(
+ DWORD Count,
+ const D3DRECT* pRects,
+ DWORD Flags,
+ D3DCOLOR Color,
+ float Z,
+ DWORD Stencil) {
+ if (unlikely(!Count && pRects))
+ return D3D_OK;
+
+ D3D9DeviceLock lock = LockDevice();
+
+ const auto& vp = m_state.viewport;
+ const auto& sc = m_state.scissorRect;
+
+ bool srgb = m_state.renderStates[D3DRS_SRGBWRITEENABLE];
+ bool scissor = m_state.renderStates[D3DRS_SCISSORTESTENABLE];
+
+ VkOffset3D offset = { int32_t(vp.X), int32_t(vp.Y), 0 };
+ VkExtent3D extent = { vp.Width, vp.Height, 1u };
+
+ if (scissor) {
+ offset.x = std::max<int32_t> (offset.x, sc.left);
+ offset.y = std::max<int32_t> (offset.y, sc.top);
+
+ extent.width = std::min<uint32_t>(extent.width, sc.right - offset.x);
+ extent.height = std::min<uint32_t>(extent.height, sc.bottom - offset.y);
+ }
+
+ // This becomes pretty unreadable in one singular if statement...
+ if (Count) {
+ // If pRects is null, or our first rect encompasses the viewport:
+ if (!pRects)
+ Count = 0;
+ else if (pRects[0].x1 <= offset.x && pRects[0].y1 <= offset.y
+ && pRects[0].x2 >= offset.x + int32_t(extent.width) && pRects[0].y2 >= offset.y + int32_t(extent.height))
+ Count = 0;
+ }
+
+ // Here, Count of 0 will denote whether or not to care about user rects.
+ VkClearValue clearValueDepth;
+ clearValueDepth.depthStencil.depth = Z;
+ clearValueDepth.depthStencil.stencil = Stencil;
+
+ VkClearValue clearValueColor;
+ DecodeD3DCOLOR(Color, clearValueColor.color.float32);
+
+ VkImageAspectFlags depthAspectMask = 0;
+ if (m_state.depthStencil != nullptr) {
+ if (Flags & D3DCLEAR_ZBUFFER)
+ depthAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ if (Flags & D3DCLEAR_STENCIL)
+ depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ depthAspectMask &= imageFormatInfo(m_state.depthStencil->GetCommonTexture()->GetFormatMapping().FormatColor)->aspectMask;
+ }
+
+ auto ClearImageView = [this](
+ uint32_t alignment,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags aspectMask,
+ VkClearValue clearValue) {
+
+ VkExtent3D imageExtent = imageView->mipLevelExtent(0);
+ extent.width = std::min(imageExtent.width, extent.width);
+ extent.height = std::min(imageExtent.height, extent.height);
+
+ if (unlikely(uint32_t(offset.x) >= imageExtent.width || uint32_t(offset.y) >= imageExtent.height))
+ return;
+
+ const bool fullClear = align(extent.width, alignment) == align(imageExtent.width, alignment)
+ && align(extent.height, alignment) == align(imageExtent.height, alignment)
+ && offset.x == 0
+ && offset.y == 0;
+
+ if (fullClear) {
+ EmitCs([
+ cClearValue = clearValue,
+ cAspectMask = aspectMask,
+ cImageView = imageView
+ ] (DxvkContext* ctx) {
+ ctx->clearRenderTarget(
+ cImageView,
+ cAspectMask,
+ cClearValue);
+ });
+ }
+ else {
+ EmitCs([
+ cClearValue = clearValue,
+ cAspectMask = aspectMask,
+ cImageView = imageView,
+ cOffset = offset,
+ cExtent = extent
+ ] (DxvkContext* ctx) {
+ ctx->clearImageView(
+ cImageView,
+ cOffset, cExtent,
+ cAspectMask,
+ cClearValue);
+ });
+ }
+ };
+
+ auto ClearViewRect = [&](
+ uint32_t alignment,
+ VkOffset3D offset,
+ VkExtent3D extent) {
+ // Clear depth if we need to.
+ if (depthAspectMask != 0)
+ ClearImageView(alignment, offset, extent, m_state.depthStencil->GetDepthStencilView(), depthAspectMask, clearValueDepth);
+
+ // Clear render targets if we need to.
+ if (Flags & D3DCLEAR_TARGET) {
+ for (uint32_t rt : bit::BitMask(m_boundRTs)) {
+ const auto& rts = m_state.renderTargets[rt];
+ const auto& rtv = rts->GetRenderTargetView(srgb);
+
+ if (likely(rtv != nullptr)) {
+ ClearImageView(alignment, offset, extent, rtv, VK_IMAGE_ASPECT_COLOR_BIT, clearValueColor);
+
+ D3D9CommonTexture* dstTexture = rts->GetCommonTexture();
+
+ if (dstTexture->IsAutomaticMip())
+ MarkTextureMipsDirty(dstTexture);
+ }
+ }
+ }
+ };
+
+ // A Hat in Time and other UE3 games only gets partial clears here
+ // because of an oversized rt height due to their weird alignment...
+ // This works around that.
+ uint32_t alignment = m_d3d9Options.lenientClear ? 8 : 1;
+
+ if (!Count) {
+ // Clear our viewport & scissor minified region in this rendertarget.
+ ClearViewRect(alignment, offset, extent);
+ }
+ else {
+ // Clear the application provided rects.
+ for (uint32_t i = 0; i < Count; i++) {
+ VkOffset3D rectOffset = {
+ std::max<int32_t>(pRects[i].x1, offset.x),
+ std::max<int32_t>(pRects[i].y1, offset.y),
+ 0
+ };
+
+ VkExtent3D rectExtent = {
+ std::min<uint32_t>(pRects[i].x2, offset.x + extent.width) - rectOffset.x,
+ std::min<uint32_t>(pRects[i].y2, offset.y + extent.height) - rectOffset.y,
+ 1u
+ };
+
+ ClearViewRect(alignment, rectOffset, rectExtent);
+ }
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix) {
+ return SetStateTransform(GetTransformIndex(State), pMatrix);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pMatrix == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pMatrix = bit::cast<D3DMATRIX>(m_state.transforms[GetTransformIndex(State)]);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::MultiplyTransform(D3DTRANSFORMSTATETYPE TransformState, const D3DMATRIX* pMatrix) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->MultiplyStateTransform(TransformState, pMatrix);
+
+ uint32_t idx = GetTransformIndex(TransformState);
+
+ m_state.transforms[idx] = m_state.transforms[idx] * ConvertMatrix(pMatrix);
+
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ if (idx == GetTransformIndex(D3DTS_VIEW) || idx >= GetTransformIndex(D3DTS_WORLD))
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexBlend);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetViewport(const D3DVIEWPORT9* pViewport) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetViewport(pViewport);
+
+ if (m_state.viewport == *pViewport)
+ return D3D_OK;
+
+ m_state.viewport = *pViewport;
+
+ m_flags.set(D3D9DeviceFlag::DirtyViewportScissor);
+ m_flags.set(D3D9DeviceFlag::DirtyFFViewport);
+ m_flags.set(D3D9DeviceFlag::DirtyPointScale);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetViewport(D3DVIEWPORT9* pViewport) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (pViewport == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *pViewport = m_state.viewport;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetMaterial(const D3DMATERIAL9* pMaterial) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pMaterial == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetMaterial(pMaterial);
+
+ m_state.material = *pMaterial;
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetMaterial(D3DMATERIAL9* pMaterial) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pMaterial == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pMaterial = m_state.material;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetLight(DWORD Index, const D3DLIGHT9* pLight) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pLight == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord())) {
+ Logger::warn("D3D9DeviceEx::SetLight: State block not implemented.");
+ return D3D_OK;
+ }
+
+ if (Index >= m_state.lights.size())
+ m_state.lights.resize(Index + 1);
+
+ m_state.lights[Index] = *pLight;
+
+ if (m_state.IsLightEnabled(Index))
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetLight(DWORD Index, D3DLIGHT9* pLight) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pLight == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(Index >= m_state.lights.size() || !m_state.lights[Index]))
+ return D3DERR_INVALIDCALL;
+
+ *pLight = m_state.lights[Index].value();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::LightEnable(DWORD Index, BOOL Enable) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(Index >= m_state.lights.size()))
+ m_state.lights.resize(Index + 1);
+
+ if (unlikely(!m_state.lights[Index]))
+ m_state.lights[Index] = DefaultLight;
+
+ if (m_state.IsLightEnabled(Index) == !!Enable)
+ return D3D_OK;
+
+ uint32_t searchIndex = UINT32_MAX;
+ uint32_t setIndex = Index;
+
+ if (!Enable)
+ std::swap(searchIndex, setIndex);
+
+ for (auto& idx : m_state.enabledLightIndices) {
+ if (idx == searchIndex) {
+ idx = setIndex;
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+ }
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetLightEnable(DWORD Index, BOOL* pEnable) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pEnable == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(Index >= m_state.lights.size() || !m_state.lights[Index]))
+ return D3DERR_INVALIDCALL;
+
+ *pEnable = m_state.IsLightEnabled(Index) ? 128 : 0; // Weird quirk but OK.
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetClipPlane(DWORD Index, const float* pPlane) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(Index >= caps::MaxClipPlanes || !pPlane))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetClipPlane(Index, pPlane);
+
+ bool dirty = false;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ dirty |= m_state.clipPlanes[Index].coeff[i] != pPlane[i];
+ m_state.clipPlanes[Index].coeff[i] = pPlane[i];
+ }
+
+ bool enabled = m_state.renderStates[D3DRS_CLIPPLANEENABLE] & (1u << Index);
+ dirty &= enabled;
+
+ if (dirty)
+ m_flags.set(D3D9DeviceFlag::DirtyClipPlanes);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetClipPlane(DWORD Index, float* pPlane) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(Index >= caps::MaxClipPlanes || !pPlane))
+ return D3DERR_INVALIDCALL;
+
+ for (uint32_t i = 0; i < 4; i++)
+ pPlane[i] = m_state.clipPlanes[Index].coeff[i];
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) {
+ D3D9DeviceLock lock = LockDevice();
+
+ // D3D9 only allows reading for values 0 and 7-255 so we don't need to do anything but return OK
+ if (unlikely(State > 255 || (State < D3DRS_ZENABLE && State != 0))) {
+ return D3D_OK;
+ }
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetRenderState(State, Value);
+
+ auto& states = m_state.renderStates;
+
+ bool changed = states[State] != Value;
+
+ if (likely(changed)) {
+ const bool oldClipPlaneEnabled = IsClipPlaneEnabled();
+
+ const bool oldDepthBiasEnabled = IsDepthBiasEnabled();
+
+ const bool oldATOC = IsAlphaToCoverageEnabled();
+ const bool oldNVDB = states[D3DRS_ADAPTIVETESS_X] == uint32_t(D3D9Format::NVDB);
+ const bool oldAlphaTest = IsAlphaTestEnabled();
+
+ states[State] = Value;
+
+ // AMD's driver hack for ATOC and RESZ
+ if (unlikely(State == D3DRS_POINTSIZE)) {
+ // ATOC
+ constexpr uint32_t AlphaToCoverageEnable = uint32_t(D3D9Format::A2M1);
+ constexpr uint32_t AlphaToCoverageDisable = uint32_t(D3D9Format::A2M0);
+
+ if (Value == AlphaToCoverageEnable
+ || Value == AlphaToCoverageDisable) {
+ m_amdATOC = Value == AlphaToCoverageEnable;
+
+ bool newATOC = IsAlphaToCoverageEnabled();
+ bool newAlphaTest = IsAlphaTestEnabled();
+
+ if (oldATOC != newATOC)
+ m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
+
+ if (oldAlphaTest != newAlphaTest)
+ m_flags.set(D3D9DeviceFlag::DirtyAlphaTestState);
+
+ return D3D_OK;
+ }
+
+ // RESZ
+ constexpr uint32_t RESZ = 0x7fa05000;
+ if (Value == RESZ) {
+ ResolveZ();
+ return D3D_OK;
+ }
+ }
+
+ // NV's driver hack for ATOC.
+ if (unlikely(State == D3DRS_ADAPTIVETESS_Y)) {
+ constexpr uint32_t AlphaToCoverageEnable = uint32_t(D3D9Format::ATOC);
+ constexpr uint32_t AlphaToCoverageDisable = 0;
+
+ if (Value == AlphaToCoverageEnable
+ || Value == AlphaToCoverageDisable) {
+ m_nvATOC = Value == AlphaToCoverageEnable;
+
+ bool newATOC = IsAlphaToCoverageEnabled();
+ bool newAlphaTest = IsAlphaTestEnabled();
+
+ if (oldATOC != newATOC)
+ m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
+
+ if (oldAlphaTest != newAlphaTest)
+ m_flags.set(D3D9DeviceFlag::DirtyAlphaTestState);
+
+ return D3D_OK;
+ }
+
+ if (unlikely(Value == uint32_t(D3D9Format::COPM))) {
+ // UE3 calls this MinimalNVIDIADriverShaderOptimization
+ Logger::info("D3D9DeviceEx::SetRenderState: MinimalNVIDIADriverShaderOptimization is unsupported");
+ return D3D_OK;
+ }
+ }
+
+ switch (State) {
+ case D3DRS_SEPARATEALPHABLENDENABLE:
+ case D3DRS_ALPHABLENDENABLE:
+ case D3DRS_BLENDOP:
+ case D3DRS_BLENDOPALPHA:
+ case D3DRS_DESTBLEND:
+ case D3DRS_DESTBLENDALPHA:
+ case D3DRS_SRCBLEND:
+ case D3DRS_SRCBLENDALPHA:
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+ break;
+
+ case D3DRS_COLORWRITEENABLE:
+ UpdateActiveRTs(0);
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+ break;
+ case D3DRS_COLORWRITEENABLE1:
+ UpdateActiveRTs(1);
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+ break;
+ case D3DRS_COLORWRITEENABLE2:
+ UpdateActiveRTs(2);
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+ break;
+ case D3DRS_COLORWRITEENABLE3:
+ UpdateActiveRTs(3);
+ m_flags.set(D3D9DeviceFlag::DirtyBlendState);
+ break;
+
+ case D3DRS_ALPHATESTENABLE: {
+ bool newATOC = IsAlphaToCoverageEnabled();
+ bool newAlphaTest = IsAlphaTestEnabled();
+
+ if (oldATOC != newATOC)
+ m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
+
+ if (oldAlphaTest != newAlphaTest)
+ m_flags.set(D3D9DeviceFlag::DirtyAlphaTestState);
+
+ break;
+ }
+
+ case D3DRS_ALPHAFUNC:
+ m_flags.set(D3D9DeviceFlag::DirtyAlphaTestState);
+ break;
+
+ case D3DRS_BLENDFACTOR:
+ BindBlendFactor();
+ break;
+
+ case D3DRS_MULTISAMPLEMASK:
+ if (m_flags.test(D3D9DeviceFlag::ValidSampleMask))
+ m_flags.set(D3D9DeviceFlag::DirtyMultiSampleState);
+ break;
+
+ case D3DRS_ZWRITEENABLE:
+ if (m_activeHazardsDS != 0)
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+
+ m_flags.set(D3D9DeviceFlag::DirtyDepthStencilState);
+ break;
+
+ case D3DRS_ZENABLE:
+ case D3DRS_ZFUNC:
+ case D3DRS_TWOSIDEDSTENCILMODE:
+ case D3DRS_STENCILENABLE:
+ case D3DRS_STENCILFAIL:
+ case D3DRS_STENCILZFAIL:
+ case D3DRS_STENCILPASS:
+ case D3DRS_STENCILFUNC:
+ case D3DRS_CCW_STENCILFAIL:
+ case D3DRS_CCW_STENCILZFAIL:
+ case D3DRS_CCW_STENCILPASS:
+ case D3DRS_CCW_STENCILFUNC:
+ case D3DRS_STENCILMASK:
+ case D3DRS_STENCILWRITEMASK:
+ m_flags.set(D3D9DeviceFlag::DirtyDepthStencilState);
+ break;
+
+ case D3DRS_STENCILREF:
+ BindDepthStencilRefrence();
+ break;
+
+ case D3DRS_SCISSORTESTENABLE:
+ m_flags.set(D3D9DeviceFlag::DirtyViewportScissor);
+ break;
+
+ case D3DRS_SRGBWRITEENABLE:
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+ break;
+
+ case D3DRS_DEPTHBIAS:
+ case D3DRS_SLOPESCALEDEPTHBIAS: {
+ const bool depthBiasEnabled = IsDepthBiasEnabled();
+
+ if (depthBiasEnabled != oldDepthBiasEnabled)
+ m_flags.set(D3D9DeviceFlag::DirtyRasterizerState);
+
+ if (depthBiasEnabled)
+ m_flags.set(D3D9DeviceFlag::DirtyDepthBias);
+
+ break;
+ }
+ case D3DRS_CULLMODE:
+ case D3DRS_FILLMODE:
+ m_flags.set(D3D9DeviceFlag::DirtyRasterizerState);
+ break;
+
+ case D3DRS_CLIPPLANEENABLE: {
+ const bool clipPlaneEnabled = IsClipPlaneEnabled();
+
+ if (clipPlaneEnabled != oldClipPlaneEnabled)
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+
+ m_flags.set(D3D9DeviceFlag::DirtyClipPlanes);
+ break;
+ }
+
+ case D3DRS_ALPHAREF:
+ UpdatePushConstant<D3D9RenderStateItem::AlphaRef>();
+ break;
+
+ case D3DRS_TEXTUREFACTOR:
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelData);
+ break;
+
+ case D3DRS_DIFFUSEMATERIALSOURCE:
+ case D3DRS_AMBIENTMATERIALSOURCE:
+ case D3DRS_SPECULARMATERIALSOURCE:
+ case D3DRS_EMISSIVEMATERIALSOURCE:
+ case D3DRS_COLORVERTEX:
+ case D3DRS_LIGHTING:
+ case D3DRS_NORMALIZENORMALS:
+ case D3DRS_LOCALVIEWER:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+
+ case D3DRS_AMBIENT:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+ break;
+
+ case D3DRS_SPECULARENABLE:
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+ break;
+
+ case D3DRS_FOGENABLE:
+ case D3DRS_FOGVERTEXMODE:
+ case D3DRS_FOGTABLEMODE:
+ m_flags.set(D3D9DeviceFlag::DirtyFogState);
+ break;
+
+ case D3DRS_RANGEFOGENABLE:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+
+ case D3DRS_FOGCOLOR:
+ m_flags.set(D3D9DeviceFlag::DirtyFogColor);
+ break;
+
+ case D3DRS_FOGSTART:
+ m_flags.set(D3D9DeviceFlag::DirtyFogScale);
+ break;
+
+ case D3DRS_FOGEND:
+ m_flags.set(D3D9DeviceFlag::DirtyFogScale);
+ m_flags.set(D3D9DeviceFlag::DirtyFogEnd);
+ break;
+
+ case D3DRS_FOGDENSITY:
+ m_flags.set(D3D9DeviceFlag::DirtyFogDensity);
+ break;
+
+ case D3DRS_POINTSIZE:
+ UpdatePushConstant<D3D9RenderStateItem::PointSize>();
+ break;
+
+ case D3DRS_POINTSIZE_MIN:
+ UpdatePushConstant<D3D9RenderStateItem::PointSizeMin>();
+ break;
+
+ case D3DRS_POINTSIZE_MAX:
+ UpdatePushConstant<D3D9RenderStateItem::PointSizeMax>();
+ break;
+
+ case D3DRS_POINTSCALE_A:
+ case D3DRS_POINTSCALE_B:
+ case D3DRS_POINTSCALE_C:
+ m_flags.set(D3D9DeviceFlag::DirtyPointScale);
+ break;
+
+ case D3DRS_POINTSCALEENABLE:
+ case D3DRS_POINTSPRITEENABLE:
+ // Nothing to do here!
+ // This is handled in UpdatePointMode.
+ break;
+
+ case D3DRS_SHADEMODE:
+ if (m_state.pixelShader != nullptr) {
+ BindShader<DxsoProgramType::PixelShader>(
+ GetCommonShader(m_state.pixelShader),
+ GetPixelShaderPermutation());
+ }
+
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+ break;
+
+ case D3DRS_TWEENFACTOR:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+ break;
+
+ case D3DRS_VERTEXBLEND:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+
+ case D3DRS_INDEXEDVERTEXBLENDENABLE:
+ if (CanSWVP() && Value)
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexBlend);
+
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+
+ case D3DRS_ADAPTIVETESS_X:
+ case D3DRS_ADAPTIVETESS_Z:
+ case D3DRS_ADAPTIVETESS_W:
+ if (states[D3DRS_ADAPTIVETESS_X] == uint32_t(D3D9Format::NVDB) || oldNVDB) {
+ m_flags.set(D3D9DeviceFlag::DirtyDepthBounds);
+ break;
+ }
+
+ default:
+ static bool s_errorShown[256];
+
+ if (!std::exchange(s_errorShown[State], true))
+ Logger::warn(str::format("D3D9DeviceEx::SetRenderState: Unhandled render state ", State));
+ break;
+ }
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pValue == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(State > 255 || (State < D3DRS_ZENABLE && State != 0))) {
+ return D3DERR_INVALIDCALL;
+ }
+
+ if (State < D3DRS_ZENABLE || State > D3DRS_BLENDOPALPHA)
+ *pValue = 0;
+ else
+ *pValue = m_state.renderStates[State];
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateStateBlock(
+ D3DSTATEBLOCKTYPE Type,
+ IDirect3DStateBlock9** ppSB) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppSB);
+
+ if (unlikely(ppSB == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9StateBlock> sb = new D3D9StateBlock(this, ConvertStateBlockType(Type));
+ *ppSB = sb.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::BeginStateBlock() {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(m_recorder != nullptr))
+ return D3DERR_INVALIDCALL;
+
+ m_recorder = new D3D9StateBlock(this, D3D9StateBlockType::None);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::EndStateBlock(IDirect3DStateBlock9** ppSB) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppSB);
+
+ if (unlikely(ppSB == nullptr || m_recorder == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppSB = m_recorder.ref();
+ m_recorder = nullptr;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetClipStatus(const D3DCLIPSTATUS9* pClipStatus) {
+ Logger::warn("D3D9DeviceEx::SetClipStatus: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetClipStatus(D3DCLIPSTATUS9* pClipStatus) {
+ Logger::warn("D3D9DeviceEx::GetClipStatus: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (ppTexture == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *ppTexture = nullptr;
+
+ if (unlikely(InvalidSampler(Stage)))
+ return D3D_OK;
+
+ DWORD stateSampler = RemapSamplerState(Stage);
+
+ *ppTexture = ref(m_state.textures[stateSampler]);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) {
+ if (unlikely(InvalidSampler(Stage)))
+ return D3D_OK;
+
+ DWORD stateSampler = RemapSamplerState(Stage);
+
+ return SetStateTexture(stateSampler, pTexture);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetTextureStageState(
+ DWORD Stage,
+ D3DTEXTURESTAGESTATETYPE Type,
+ DWORD* pValue) {
+ auto dxvkType = RemapTextureStageStateType(Type);
+
+ if (unlikely(pValue == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pValue = 0;
+
+ if (unlikely(Stage >= caps::TextureStageCount))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(dxvkType >= TextureStageStateCount))
+ return D3DERR_INVALIDCALL;
+
+ *pValue = m_state.textureStages[Stage][dxvkType];
+
+ return D3D_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetTextureStageState(
+ DWORD Stage,
+ D3DTEXTURESTAGESTATETYPE Type,
+ DWORD Value) {
+ return SetStateTextureStageState(Stage, RemapTextureStageStateType(Type), Value);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetSamplerState(
+ DWORD Sampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD* pValue) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pValue == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pValue = 0;
+
+ if (unlikely(InvalidSampler(Sampler)))
+ return D3D_OK;
+
+ Sampler = RemapSamplerState(Sampler);
+
+ *pValue = m_state.samplerStates[Sampler][Type];
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetSamplerState(
+ DWORD Sampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value) {
+ if (unlikely(InvalidSampler(Sampler)))
+ return D3D_OK;
+
+ uint32_t stateSampler = RemapSamplerState(Sampler);
+
+ return SetStateSamplerState(stateSampler, Type, Value);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ValidateDevice(DWORD* pNumPasses) {
+ if (pNumPasses != nullptr)
+ *pNumPasses = 1;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries) {
+ // This succeeds even though we don't advertise support.
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries) {
+ // Don't advertise support for this...
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetCurrentTexturePalette(UINT PaletteNumber) {
+ // This succeeds even though we don't advertise support.
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetCurrentTexturePalette(UINT *PaletteNumber) {
+ // Don't advertise support for this...
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetScissorRect(const RECT* pRect) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pRect == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetScissorRect(pRect);
+
+ if (m_state.scissorRect == *pRect)
+ return D3D_OK;
+
+ m_state.scissorRect = *pRect;
+
+ m_flags.set(D3D9DeviceFlag::DirtyViewportScissor);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetScissorRect(RECT* pRect) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pRect == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pRect = m_state.scissorRect;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetSoftwareVertexProcessing(BOOL bSoftware) {
+ auto lock = LockDevice();
+
+ if (bSoftware && !CanSWVP())
+ return D3DERR_INVALIDCALL;
+
+ m_isSWVP = bSoftware;
+
+ return D3D_OK;
+ }
+
+
+ BOOL STDMETHODCALLTYPE D3D9DeviceEx::GetSoftwareVertexProcessing() {
+ auto lock = LockDevice();
+
+ return m_isSWVP;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetNPatchMode(float nSegments) {
+ return D3D_OK;
+ }
+
+
+ float STDMETHODCALLTYPE D3D9DeviceEx::GetNPatchMode() {
+ return 0.0f;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawPrimitive(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT StartVertex,
+ UINT PrimitiveCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(config::FullValidation && m_state.vertexDecl == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(config::FullValidation && !PrimitiveCount))
+ return S_OK;
+
+ PrepareDraw(PrimitiveType);
+
+ EmitCs([this,
+ cPrimType = PrimitiveType,
+ cPrimCount = PrimitiveCount,
+ cStartVertex = StartVertex,
+ cInstanceCount = GetInstanceCount()
+ ](DxvkContext* ctx) {
+ auto drawInfo = GenerateDrawInfo(cPrimType, cPrimCount, cInstanceCount);
+
+ ApplyPrimitiveType(ctx, cPrimType);
+
+ ctx->draw(
+ drawInfo.vertexCount, drawInfo.instanceCount,
+ cStartVertex, 0);
+ });
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawIndexedPrimitive(
+ D3DPRIMITIVETYPE PrimitiveType,
+ INT BaseVertexIndex,
+ UINT MinVertexIndex,
+ UINT NumVertices,
+ UINT StartIndex,
+ UINT PrimitiveCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(config::FullValidation && m_state.vertexDecl == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(config::FullValidation && !PrimitiveCount))
+ return S_OK;
+
+ PrepareDraw(PrimitiveType);
+
+ EmitCs([this,
+ cPrimType = PrimitiveType,
+ cPrimCount = PrimitiveCount,
+ cStartIndex = StartIndex,
+ cBaseVertexIndex = BaseVertexIndex,
+ cInstanceCount = GetInstanceCount()
+ ](DxvkContext* ctx) {
+ auto drawInfo = GenerateDrawInfo(cPrimType, cPrimCount, cInstanceCount);
+
+ ApplyPrimitiveType(ctx, cPrimType);
+
+ ctx->drawIndexed(
+ drawInfo.vertexCount, drawInfo.instanceCount,
+ cStartIndex,
+ cBaseVertexIndex, 0);
+ });
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawPrimitiveUP(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT PrimitiveCount,
+ const void* pVertexStreamZeroData,
+ UINT VertexStreamZeroStride) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(config::FullValidation && m_state.vertexDecl == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(config::FullValidation && !PrimitiveCount))
+ return S_OK;
+
+ PrepareDraw(PrimitiveType);
+
+ auto drawInfo = GenerateDrawInfo(PrimitiveType, PrimitiveCount, 0);
+
+ const uint32_t dataSize = GetUPDataSize(drawInfo.vertexCount, VertexStreamZeroStride);
+ const uint32_t bufferSize = GetUPBufferSize(drawInfo.vertexCount, VertexStreamZeroStride);
+
+ auto upSlice = AllocTempBuffer<true>(bufferSize);
+ FillUPVertexBuffer(upSlice.mapPtr, pVertexStreamZeroData, dataSize, bufferSize);
+
+ EmitCs([this,
+ cBufferSlice = std::move(upSlice.slice),
+ cPrimType = PrimitiveType,
+ cPrimCount = PrimitiveCount,
+ cInstanceCount = GetInstanceCount(),
+ cStride = VertexStreamZeroStride
+ ](DxvkContext* ctx) {
+ auto drawInfo = GenerateDrawInfo(cPrimType, cPrimCount, cInstanceCount);
+
+ ApplyPrimitiveType(ctx, cPrimType);
+
+ ctx->bindVertexBuffer(0, cBufferSlice, cStride);
+ ctx->draw(
+ drawInfo.vertexCount, drawInfo.instanceCount,
+ 0, 0);
+ ctx->bindVertexBuffer(0, DxvkBufferSlice(), 0);
+ });
+
+ m_state.vertexBuffers[0].vertexBuffer = nullptr;
+ m_state.vertexBuffers[0].offset = 0;
+ m_state.vertexBuffers[0].stride = 0;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawIndexedPrimitiveUP(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT MinVertexIndex,
+ UINT NumVertices,
+ UINT PrimitiveCount,
+ const void* pIndexData,
+ D3DFORMAT IndexDataFormat,
+ const void* pVertexStreamZeroData,
+ UINT VertexStreamZeroStride) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(config::FullValidation && m_state.vertexDecl == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(config::FullValidation && !PrimitiveCount))
+ return S_OK;
+
+ PrepareDraw(PrimitiveType);
+
+ auto drawInfo = GenerateDrawInfo(PrimitiveType, PrimitiveCount, 0);
+
+ const uint32_t vertexDataSize = GetUPDataSize(MinVertexIndex + NumVertices, VertexStreamZeroStride);
+ const uint32_t vertexBufferSize = GetUPBufferSize(MinVertexIndex + NumVertices, VertexStreamZeroStride);
+
+ const uint32_t indexSize = IndexDataFormat == D3DFMT_INDEX16 ? 2 : 4;
+ const uint32_t indicesSize = drawInfo.vertexCount * indexSize;
+
+ const uint32_t upSize = vertexBufferSize + indicesSize;
+
+ auto upSlice = AllocTempBuffer<true>(upSize);
+ uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr);
+ FillUPVertexBuffer(data, pVertexStreamZeroData, vertexDataSize, vertexBufferSize);
+ std::memcpy(data + vertexBufferSize, pIndexData, indicesSize);
+
+ EmitCs([this,
+ cVertexSize = vertexBufferSize,
+ cBufferSlice = std::move(upSlice.slice),
+ cPrimType = PrimitiveType,
+ cPrimCount = PrimitiveCount,
+ cStride = VertexStreamZeroStride,
+ cInstanceCount = GetInstanceCount(),
+ cIndexType = DecodeIndexType(
+ static_cast<D3D9Format>(IndexDataFormat))
+ ](DxvkContext* ctx) {
+ auto drawInfo = GenerateDrawInfo(cPrimType, cPrimCount, cInstanceCount);
+
+ ApplyPrimitiveType(ctx, cPrimType);
+
+ ctx->bindVertexBuffer(0, cBufferSlice.subSlice(0, cVertexSize), cStride);
+ ctx->bindIndexBuffer(cBufferSlice.subSlice(cVertexSize, cBufferSlice.length() - cVertexSize), cIndexType);
+ ctx->drawIndexed(
+ drawInfo.vertexCount, drawInfo.instanceCount,
+ 0,
+ 0, 0);
+ ctx->bindVertexBuffer(0, DxvkBufferSlice(), 0);
+ ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
+ });
+
+ m_state.vertexBuffers[0].vertexBuffer = nullptr;
+ m_state.vertexBuffers[0].offset = 0;
+ m_state.vertexBuffers[0].stride = 0;
+
+ m_state.indices = nullptr;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ProcessVertices(
+ UINT SrcStartIndex,
+ UINT DestIndex,
+ UINT VertexCount,
+ IDirect3DVertexBuffer9* pDestBuffer,
+ IDirect3DVertexDeclaration9* pVertexDecl,
+ DWORD Flags) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pDestBuffer == nullptr || pVertexDecl == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (!SupportsSWVP()) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("D3D9DeviceEx::ProcessVertices: SWVP emu unsupported (vertexPipelineStoresAndAtomics)");
+
+ return D3D_OK;
+ }
+
+ D3D9CommonBuffer* dst = static_cast<D3D9VertexBuffer*>(pDestBuffer)->GetCommonBuffer();
+ D3D9VertexDecl* decl = static_cast<D3D9VertexDecl*> (pVertexDecl);
+
+ PrepareDraw(D3DPT_FORCE_DWORD);
+
+ if (decl == nullptr) {
+ DWORD FVF = dst->Desc()->FVF;
+
+ auto iter = m_fvfTable.find(FVF);
+
+ if (iter == m_fvfTable.end()) {
+ decl = new D3D9VertexDecl(this, FVF);
+ m_fvfTable.insert(std::make_pair(FVF, decl));
+ }
+ else
+ decl = iter->second.ptr();
+ }
+
+ uint32_t offset = DestIndex * decl->GetSize();
+
+ auto slice = dst->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
+ slice = slice.subSlice(offset, slice.length() - offset);
+
+ EmitCs([this,
+ cDecl = ref(decl),
+ cVertexCount = VertexCount,
+ cStartIndex = SrcStartIndex,
+ cInstanceCount = GetInstanceCount(),
+ cBufferSlice = slice,
+ cIndexed = m_state.indices != nullptr
+ ](DxvkContext* ctx) {
+ Rc<DxvkShader> shader = m_swvpEmulator.GetShaderModule(this, cDecl);
+
+ auto drawInfo = GenerateDrawInfo(D3DPT_POINTLIST, cVertexCount, cInstanceCount);
+
+ if (drawInfo.instanceCount != 1) {
+ drawInfo.instanceCount = 1;
+
+ Logger::warn("D3D9DeviceEx::ProcessVertices: instancing unsupported");
+ }
+
+ ApplyPrimitiveType(ctx, D3DPT_POINTLIST);
+
+ // Unbind the pixel shader, we aren't drawing
+ // to avoid val errors / UB.
+ ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, nullptr);
+
+ ctx->bindShader(VK_SHADER_STAGE_GEOMETRY_BIT, shader);
+ ctx->bindResourceBuffer(getSWVPBufferSlot(), cBufferSlice);
+ ctx->draw(
+ drawInfo.vertexCount, drawInfo.instanceCount,
+ cStartIndex, 0);
+ ctx->bindResourceBuffer(getSWVPBufferSlot(), DxvkBufferSlice());
+ ctx->bindShader(VK_SHADER_STAGE_GEOMETRY_BIT, nullptr);
+ });
+
+ // We unbound the pixel shader before,
+ // let's make sure that gets rebound.
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+
+ if (m_state.pixelShader != nullptr) {
+ BindShader<DxsoProgramTypes::PixelShader>(
+ GetCommonShader(m_state.pixelShader),
+ GetPixelShaderPermutation());
+ }
+
+ if (dst->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER) {
+ uint32_t copySize = VertexCount * decl->GetSize();
+
+ EmitCs([
+ cSrcBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>(),
+ cDstBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>(),
+ cOffset = offset,
+ cCopySize = copySize
+ ](DxvkContext* ctx) {
+ ctx->copyBuffer(cDstBuffer, cOffset, cSrcBuffer, cOffset, cCopySize);
+ });
+ }
+
+ dst->SetWrittenByGPU(true);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateVertexDeclaration(
+ const D3DVERTEXELEMENT9* pVertexElements,
+ IDirect3DVertexDeclaration9** ppDecl) {
+ InitReturnPtr(ppDecl);
+
+ if (unlikely(ppDecl == nullptr || pVertexElements == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ const D3DVERTEXELEMENT9* counter = pVertexElements;
+ while (counter->Stream != 0xFF)
+ counter++;
+
+ const uint32_t declCount = uint32_t(counter - pVertexElements);
+
+ try {
+ const Com<D3D9VertexDecl> decl = new D3D9VertexDecl(this, pVertexElements, declCount);
+ *ppDecl = decl.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9VertexDecl* decl = static_cast<D3D9VertexDecl*>(pDecl);
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetVertexDeclaration(decl);
+
+ if (decl == m_state.vertexDecl.ptr())
+ return D3D_OK;
+
+ bool dirtyFFShader = decl == nullptr || m_state.vertexDecl == nullptr;
+ if (!dirtyFFShader)
+ dirtyFFShader |= decl->TestFlag(D3D9VertexDeclFlag::HasPositionT) != m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasPositionT)
+ || decl->TestFlag(D3D9VertexDeclFlag::HasColor0) != m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasColor0)
+ || decl->TestFlag(D3D9VertexDeclFlag::HasColor1) != m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasColor1)
+ || decl->GetTexcoordMask() != m_state.vertexDecl->GetTexcoordMask();
+
+ if (dirtyFFShader)
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+
+ m_state.vertexDecl = decl;
+
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppDecl);
+
+ if (ppDecl == nullptr)
+ return D3D_OK;
+
+ if (m_state.vertexDecl == nullptr)
+ return D3D_OK;
+
+ *ppDecl = m_state.vertexDecl.ref();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetFVF(DWORD FVF) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (FVF == 0)
+ return D3D_OK;
+
+ D3D9VertexDecl* decl = nullptr;
+
+ auto iter = m_fvfTable.find(FVF);
+
+ if (iter == m_fvfTable.end()) {
+ decl = new D3D9VertexDecl(this, FVF);
+ m_fvfTable.insert(std::make_pair(FVF, decl));
+ }
+ else
+ decl = iter->second.ptr();
+
+ return this->SetVertexDeclaration(decl);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetFVF(DWORD* pFVF) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (pFVF == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *pFVF = m_state.vertexDecl != nullptr
+ ? m_state.vertexDecl->GetFVF()
+ : 0;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateVertexShader(
+ const DWORD* pFunction,
+ IDirect3DVertexShader9** ppShader) {
+ // CreateVertexShader does not init the
+ // return ptr unlike CreatePixelShader
+
+ if (unlikely(ppShader == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ DxsoModuleInfo moduleInfo;
+ moduleInfo.options = m_dxsoOptions;
+
+ D3D9CommonShader module;
+
+ if (FAILED(this->CreateShaderModule(&module,
+ VK_SHADER_STAGE_VERTEX_BIT,
+ pFunction,
+ &moduleInfo)))
+ return D3DERR_INVALIDCALL;
+
+ *ppShader = ref(new D3D9VertexShader(this, module));
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetVertexShader(IDirect3DVertexShader9* pShader) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9VertexShader* shader = static_cast<D3D9VertexShader*>(pShader);
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetVertexShader(shader);
+
+ if (shader == m_state.vertexShader.ptr())
+ return D3D_OK;
+
+ auto* oldShader = GetCommonShader(m_state.vertexShader);
+ auto* newShader = GetCommonShader(shader);
+
+ bool oldCopies = oldShader && oldShader->GetMeta().needsConstantCopies;
+ bool newCopies = newShader && newShader->GetMeta().needsConstantCopies;
+
+ m_consts[DxsoProgramTypes::VertexShader].dirty |= oldCopies || newCopies || !oldShader;
+ m_consts[DxsoProgramTypes::VertexShader].meta = newShader ? newShader->GetMeta() : DxsoShaderMetaInfo();
+
+ if (newShader && oldShader) {
+ m_consts[DxsoProgramTypes::VertexShader].dirty
+ |= newShader->GetMeta().maxConstIndexF > oldShader->GetMeta().maxConstIndexF
+ || newShader->GetMeta().maxConstIndexI > oldShader->GetMeta().maxConstIndexI
+ || newShader->GetMeta().maxConstIndexB > oldShader->GetMeta().maxConstIndexB;
+ }
+
+ m_state.vertexShader = shader;
+
+ if (shader != nullptr) {
+ m_flags.clr(D3D9DeviceFlag::DirtyProgVertexShader);
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+
+ BindShader<DxsoProgramTypes::VertexShader>(
+ GetCommonShader(shader),
+ GetVertexShaderPermutation());
+
+ m_vsShaderMasks = newShader->GetShaderMask();
+ }
+ else
+ m_vsShaderMasks = D3D9ShaderMasks();
+
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetVertexShader(IDirect3DVertexShader9** ppShader) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppShader);
+
+ if (unlikely(ppShader == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppShader = m_state.vertexShader.ref();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetVertexShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetVertexShaderConstantF(
+ UINT StartRegister,
+ float* pConstantData,
+ UINT Vector4fCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetVertexShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetVertexShaderConstantI(
+ UINT StartRegister,
+ int* pConstantData,
+ UINT Vector4iCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetVertexShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetVertexShaderConstantB(
+ UINT StartRegister,
+ BOOL* pConstantData,
+ UINT BoolCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetStreamSource(
+ UINT StreamNumber,
+ IDirect3DVertexBuffer9* pStreamData,
+ UINT OffsetInBytes,
+ UINT Stride) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(StreamNumber >= caps::MaxStreams))
+ return D3DERR_INVALIDCALL;
+
+ D3D9VertexBuffer* buffer = static_cast<D3D9VertexBuffer*>(pStreamData);
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStreamSource(
+ StreamNumber,
+ buffer,
+ OffsetInBytes,
+ Stride);
+
+ auto& vbo = m_state.vertexBuffers[StreamNumber];
+ bool needsUpdate = vbo.vertexBuffer != buffer;
+
+ if (needsUpdate)
+ vbo.vertexBuffer = buffer;
+
+ if (buffer != nullptr) {
+ needsUpdate |= vbo.offset != OffsetInBytes
+ || vbo.stride != Stride;
+
+ vbo.offset = OffsetInBytes;
+ vbo.stride = Stride;
+ }
+
+ if (needsUpdate)
+ BindVertexBuffer(StreamNumber, buffer, OffsetInBytes, Stride);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetStreamSource(
+ UINT StreamNumber,
+ IDirect3DVertexBuffer9** ppStreamData,
+ UINT* pOffsetInBytes,
+ UINT* pStride) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppStreamData);
+
+ if (likely(pOffsetInBytes != nullptr))
+ *pOffsetInBytes = 0;
+
+ if (likely(pStride != nullptr))
+ *pStride = 0;
+
+ if (unlikely(ppStreamData == nullptr || pOffsetInBytes == nullptr || pStride == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(StreamNumber >= caps::MaxStreams))
+ return D3DERR_INVALIDCALL;
+
+ const auto& vbo = m_state.vertexBuffers[StreamNumber];
+
+ *ppStreamData = vbo.vertexBuffer.ref();
+ *pOffsetInBytes = vbo.offset;
+ *pStride = vbo.stride;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetStreamSourceFreq(UINT StreamNumber, UINT Setting) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(StreamNumber >= caps::MaxStreams))
+ return D3DERR_INVALIDCALL;
+
+ const bool indexed = Setting & D3DSTREAMSOURCE_INDEXEDDATA;
+ const bool instanced = Setting & D3DSTREAMSOURCE_INSTANCEDATA;
+
+ if (unlikely(StreamNumber == 0 && instanced))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(instanced && indexed))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(Setting == 0))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStreamSourceFreq(StreamNumber, Setting);
+
+ if (m_state.streamFreq[StreamNumber] == Setting)
+ return D3D_OK;
+
+ m_state.streamFreq[StreamNumber] = Setting;
+
+ if (instanced)
+ m_instancedData |= 1u << StreamNumber;
+ else
+ m_instancedData &= ~(1u << StreamNumber);
+
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetStreamSourceFreq(UINT StreamNumber, UINT* pSetting) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(StreamNumber >= caps::MaxStreams))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(pSetting == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pSetting = m_state.streamFreq[StreamNumber];
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetIndices(IDirect3DIndexBuffer9* pIndexData) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9IndexBuffer* buffer = static_cast<D3D9IndexBuffer*>(pIndexData);
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetIndices(buffer);
+
+ if (buffer == m_state.indices.ptr())
+ return D3D_OK;
+
+ m_state.indices = buffer;
+
+ BindIndices();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetIndices(IDirect3DIndexBuffer9** ppIndexData) {
+ D3D9DeviceLock lock = LockDevice();
+ InitReturnPtr(ppIndexData);
+
+ if (unlikely(ppIndexData == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppIndexData = m_state.indices.ref();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreatePixelShader(
+ const DWORD* pFunction,
+ IDirect3DPixelShader9** ppShader) {
+ InitReturnPtr(ppShader);
+
+ if (unlikely(ppShader == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ DxsoModuleInfo moduleInfo;
+ moduleInfo.options = m_dxsoOptions;
+
+ D3D9CommonShader module;
+
+ if (FAILED(this->CreateShaderModule(&module,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ pFunction,
+ &moduleInfo)))
+ return D3DERR_INVALIDCALL;
+
+ *ppShader = ref(new D3D9PixelShader(this, module));
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetPixelShader(IDirect3DPixelShader9* pShader) {
+ D3D9DeviceLock lock = LockDevice();
+
+ D3D9PixelShader* shader = static_cast<D3D9PixelShader*>(pShader);
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetPixelShader(shader);
+
+ if (shader == m_state.pixelShader.ptr())
+ return D3D_OK;
+
+ auto* oldShader = GetCommonShader(m_state.pixelShader);
+ auto* newShader = GetCommonShader(shader);
+
+ bool oldCopies = oldShader && oldShader->GetMeta().needsConstantCopies;
+ bool newCopies = newShader && newShader->GetMeta().needsConstantCopies;
+
+ m_consts[DxsoProgramTypes::PixelShader].dirty |= oldCopies || newCopies || !oldShader;
+ m_consts[DxsoProgramTypes::PixelShader].meta = newShader ? newShader->GetMeta() : DxsoShaderMetaInfo();
+
+ if (newShader && oldShader) {
+ m_consts[DxsoProgramTypes::PixelShader].dirty
+ |= newShader->GetMeta().maxConstIndexF > oldShader->GetMeta().maxConstIndexF
+ || newShader->GetMeta().maxConstIndexI > oldShader->GetMeta().maxConstIndexI
+ || newShader->GetMeta().maxConstIndexB > oldShader->GetMeta().maxConstIndexB;
+ }
+
+ m_state.pixelShader = shader;
+
+ if (shader != nullptr) {
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+
+ BindShader<DxsoProgramTypes::PixelShader>(
+ GetCommonShader(shader),
+ GetPixelShaderPermutation());
+
+ m_psShaderMasks = newShader->GetShaderMask();
+ }
+ else {
+ // TODO: What fixed function textures are in use?
+ // Currently we are making all 8 of them as in use here.
+
+ // The RT output is always 0 for fixed function.
+ m_psShaderMasks = FixedFunctionMask;
+ }
+
+ UpdateActiveHazardsRT(UINT32_MAX);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetPixelShader(IDirect3DPixelShader9** ppShader) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppShader);
+
+ if (unlikely(ppShader == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppShader = m_state.pixelShader.ref();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetPixelShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants <
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetPixelShaderConstantF(
+ UINT StartRegister,
+ float* pConstantData,
+ UINT Vector4fCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetPixelShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetPixelShaderConstantI(
+ UINT StartRegister,
+ int* pConstantData,
+ UINT Vector4iCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetPixelShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return SetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetPixelShaderConstantB(
+ UINT StartRegister,
+ BOOL* pConstantData,
+ UINT BoolCount) {
+ D3D9DeviceLock lock = LockDevice();
+
+ return GetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawRectPatch(
+ UINT Handle,
+ const float* pNumSegs,
+ const D3DRECTPATCH_INFO* pRectPatchInfo) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D9DeviceEx::DrawRectPatch: Stub");
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DrawTriPatch(
+ UINT Handle,
+ const float* pNumSegs,
+ const D3DTRIPATCH_INFO* pTriPatchInfo) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D9DeviceEx::DrawTriPatch: Stub");
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::DeletePatch(UINT Handle) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D9DeviceEx::DeletePatch: Stub");
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) {
+ HRESULT hr = D3D9Query::QuerySupported(this, Type);
+
+ if (ppQuery == nullptr || hr != D3D_OK)
+ return hr;
+
+ try {
+ *ppQuery = ref(new D3D9Query(this, Type));
+ return D3D_OK;
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ // Ex Methods
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetConvolutionMonoKernel(
+ UINT width,
+ UINT height,
+ float* rows,
+ float* columns) {
+ // We don't advertise support for this.
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ComposeRects(
+ IDirect3DSurface9* pSrc,
+ IDirect3DSurface9* pDst,
+ IDirect3DVertexBuffer9* pSrcRectDescs,
+ UINT NumRects,
+ IDirect3DVertexBuffer9* pDstRectDescs,
+ D3DCOMPOSERECTSOP Operation,
+ int Xoffset,
+ int Yoffset) {
+ Logger::warn("D3D9DeviceEx::ComposeRects: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetGPUThreadPriority(INT* pPriority) {
+ Logger::warn("D3D9DeviceEx::GetGPUThreadPriority: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetGPUThreadPriority(INT Priority) {
+ Logger::warn("D3D9DeviceEx::SetGPUThreadPriority: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::WaitForVBlank(UINT iSwapChain) {
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->WaitForVBlank();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CheckResourceResidency(IDirect3DResource9** pResourceArray, UINT32 NumResources) {
+ Logger::warn("D3D9DeviceEx::CheckResourceResidency: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::SetMaximumFrameLatency(UINT MaxLatency) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (MaxLatency == 0)
+ MaxLatency = DefaultFrameLatency;
+
+ if (MaxLatency > MaxFrameLatency)
+ MaxLatency = MaxFrameLatency;
+
+ m_frameLatency = MaxLatency;
+
+ m_implicitSwapchain->SyncFrameLatency();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetMaximumFrameLatency(UINT* pMaxLatency) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(pMaxLatency == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *pMaxLatency = m_frameLatency;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CheckDeviceState(HWND hDestinationWindow) {
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::PresentEx(
+ const RECT* pSourceRect,
+ const RECT* pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion,
+ DWORD dwFlags) {
+ return m_implicitSwapchain->Present(
+ pSourceRect,
+ pDestRect,
+ hDestWindowOverride,
+ pDirtyRegion,
+ dwFlags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateRenderTargetEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Lockable,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage) {
+ InitReturnPtr(ppSurface);
+
+ if (unlikely(ppSurface == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = Width;
+ desc.Height = Height;
+ desc.Depth = 1;
+ desc.ArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Usage = Usage | D3DUSAGE_RENDERTARGET;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.Discard = FALSE;
+ desc.MultiSample = MultiSample;
+ desc.MultisampleQuality = MultisampleQuality;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = TRUE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr);
+ m_initializer->InitTexture(surface->GetCommonTexture());
+ *ppSurface = surface.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateOffscreenPlainSurfaceEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage) {
+ InitReturnPtr(ppSurface);
+
+ if (unlikely(ppSurface == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = Width;
+ desc.Height = Height;
+ desc.Depth = 1;
+ desc.ArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Usage = Usage;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = Pool;
+ desc.Discard = FALSE;
+ desc.MultiSample = D3DMULTISAMPLE_NONE;
+ desc.MultisampleQuality = 0;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = Pool == D3DPOOL_DEFAULT;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr);
+ m_initializer->InitTexture(surface->GetCommonTexture());
+ *ppSurface = surface.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateDepthStencilSurfaceEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Discard,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage) {
+ InitReturnPtr(ppSurface);
+
+ if (unlikely(ppSurface == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = Width;
+ desc.Height = Height;
+ desc.Depth = 1;
+ desc.ArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Usage = Usage | D3DUSAGE_DEPTHSTENCIL;
+ desc.Format = EnumerateFormat(Format);
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.Discard = Discard;
+ desc.MultiSample = MultiSample;
+ desc.MultisampleQuality = MultisampleQuality;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = TRUE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_INVALIDCALL;
+
+ try {
+ const Com<D3D9Surface> surface = new D3D9Surface(this, &desc, nullptr);
+ m_initializer->InitTexture(surface->GetCommonTexture());
+ *ppSurface = surface.ref();
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ResetEx(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ D3D9DeviceLock lock = LockDevice();
+
+ HRESULT hr = ResetSwapChain(pPresentationParameters, pFullscreenDisplayMode);
+ if (FAILED(hr))
+ return hr;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::GetDisplayModeEx(
+ UINT iSwapChain,
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation) {
+ if (unlikely(iSwapChain != 0))
+ return D3DERR_INVALIDCALL;
+
+ return m_implicitSwapchain->GetDisplayModeEx(pMode, pRotation);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9DeviceEx::CreateAdditionalSwapChainEx(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ IDirect3DSwapChain9** ppSwapChain) {
+ D3D9DeviceLock lock = LockDevice();
+
+ InitReturnPtr(ppSwapChain);
+
+ if (ppSwapChain == nullptr || pPresentationParameters == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ // Additional fullscreen swapchains are forbidden.
+ if (!pPresentationParameters->Windowed)
+ return D3DERR_INVALIDCALL;
+
+ // We can't make another swapchain if we are fullscreen.
+ if (!m_implicitSwapchain->GetPresentParams()->Windowed)
+ return D3DERR_INVALIDCALL;
+
+ m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
+
+ try {
+ auto* swapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
+ *ppSwapChain = ref(swapchain);
+ }
+ catch (const DxvkError & e) {
+ Logger::err(e.message());
+ return D3DERR_NOTAVAILABLE;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::SetStateSamplerState(
+ DWORD StateSampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStateSamplerState(StateSampler, Type, Value);
+
+ auto& state = m_state.samplerStates;
+
+ if (state[StateSampler][Type] == Value)
+ return D3D_OK;
+
+ state[StateSampler][Type] = Value;
+
+ if (Type == D3DSAMP_ADDRESSU
+ || Type == D3DSAMP_ADDRESSV
+ || Type == D3DSAMP_ADDRESSW
+ || Type == D3DSAMP_MAGFILTER
+ || Type == D3DSAMP_MINFILTER
+ || Type == D3DSAMP_MIPFILTER
+ || Type == D3DSAMP_MAXANISOTROPY
+ || Type == D3DSAMP_MIPMAPLODBIAS
+ || Type == D3DSAMP_MAXMIPLEVEL
+ || Type == D3DSAMP_BORDERCOLOR)
+ m_dirtySamplerStates |= 1u << StateSampler;
+ else if (Type == D3DSAMP_SRGBTEXTURE && (m_activeTextures & (1u << StateSampler)))
+ m_dirtyTextures |= 1u << StateSampler;
+
+ constexpr DWORD Fetch4Enabled = MAKEFOURCC('G', 'E', 'T', '4');
+ constexpr DWORD Fetch4Disabled = MAKEFOURCC('G', 'E', 'T', '1');
+
+ if (unlikely(Type == D3DSAMP_MIPMAPLODBIAS)) {
+ if (unlikely(Value == Fetch4Enabled)) {
+ m_fetch4Enabled |= 1u << StateSampler;
+ if (state[StateSampler][D3DSAMP_MAGFILTER] == D3DTEXF_POINT)
+ m_fetch4 |= 1u << StateSampler;
+ }
+ else if (unlikely(Value == Fetch4Disabled)) {
+ m_fetch4Enabled &= ~(1u << StateSampler);
+ m_fetch4 &= ~(1u << StateSampler);
+ }
+ }
+
+ if (unlikely(Type == D3DSAMP_MAGFILTER && (m_fetch4Enabled & (1u << StateSampler)))) {
+ if (Value == D3DTEXF_POINT)
+ m_fetch4 |= 1u << StateSampler;
+ else
+ m_fetch4 &= ~(1u << StateSampler);
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStateTexture(StateSampler, pTexture);
+
+ if (m_state.textures[StateSampler] == pTexture)
+ return D3D_OK;
+
+ auto oldTexture = GetCommonTexture(m_state.textures[StateSampler]);
+ auto newTexture = GetCommonTexture(pTexture);
+
+ // We need to check our ops and disable respective stages.
+ // Given we have transition from a null resource to
+ // a valid resource or vice versa.
+ if (StateSampler < 16) {
+ const uint32_t offset = StateSampler * 2;
+ const uint32_t textureType = newTexture != nullptr
+ ? uint32_t(newTexture->GetType() - D3DRTYPE_TEXTURE)
+ : 0;
+ const uint32_t textureBitMask = 0b11u << offset;
+ const uint32_t textureBits = textureType << offset;
+
+ m_textureTypes &= ~textureBitMask;
+ m_textureTypes |= textureBits;
+
+ if (newTexture == nullptr || oldTexture == nullptr)
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+ }
+
+ DWORD oldUsage = oldTexture != nullptr ? oldTexture->Desc()->Usage : 0;
+ DWORD newUsage = newTexture != nullptr ? newTexture->Desc()->Usage : 0;
+
+ if (newTexture != nullptr) {
+ const bool oldDepth = m_depthTextures & (1u << StateSampler);
+ const bool newDepth = newTexture->IsShadow();
+
+ if (oldDepth != newDepth) {
+ m_depthTextures &= ~(1u << StateSampler);
+ if (newDepth)
+ m_depthTextures |= 1u << StateSampler;
+
+ m_dirtySamplerStates |= 1u << StateSampler;
+ }
+ }
+
+ DWORD combinedUsage = oldUsage | newUsage;
+
+ TextureChangePrivate(m_state.textures[StateSampler], pTexture);
+
+ m_dirtyTextures |= 1u << StateSampler;
+
+ UpdateActiveTextures(StateSampler, combinedUsage);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStateTransform(idx, pMatrix);
+
+ m_state.transforms[idx] = ConvertMatrix(pMatrix);
+
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ if (idx == GetTransformIndex(D3DTS_VIEW) || idx >= GetTransformIndex(D3DTS_WORLD))
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexBlend);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::SetStateTextureStageState(
+ DWORD Stage,
+ D3D9TextureStageStateTypes Type,
+ DWORD Value) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(Stage >= caps::TextureStageCount))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(Type >= TextureStageStateCount))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetStateTextureStageState(Stage, Type, Value);
+
+ if (likely(m_state.textureStages[Stage][Type] != Value)) {
+ m_state.textureStages[Stage][Type] = Value;
+
+ switch (Type) {
+ case DXVK_TSS_COLOROP:
+ case DXVK_TSS_COLORARG0:
+ case DXVK_TSS_COLORARG1:
+ case DXVK_TSS_COLORARG2:
+ case DXVK_TSS_ALPHAOP:
+ case DXVK_TSS_ALPHAARG0:
+ case DXVK_TSS_ALPHAARG1:
+ case DXVK_TSS_ALPHAARG2:
+ case DXVK_TSS_RESULTARG:
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+ break;
+
+ case DXVK_TSS_TEXCOORDINDEX:
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ break;
+
+ case DXVK_TSS_TEXTURETRANSFORMFLAGS:
+ m_projectionBitfield &= ~(1 << Stage);
+ if (Value & D3DTTFF_PROJECTED)
+ m_projectionBitfield |= 1 << Stage;
+
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+ break;
+
+ case DXVK_TSS_BUMPENVMAT00:
+ case DXVK_TSS_BUMPENVMAT01:
+ case DXVK_TSS_BUMPENVMAT10:
+ case DXVK_TSS_BUMPENVMAT11:
+ case DXVK_TSS_BUMPENVLSCALE:
+ case DXVK_TSS_BUMPENVLOFFSET:
+ case DXVK_TSS_CONSTANT:
+ m_flags.set(D3D9DeviceFlag::DirtySharedPixelShaderData);
+ break;
+
+ default: break;
+ }
+ }
+
+ return D3D_OK;
+ }
+
+
+ bool D3D9DeviceEx::IsExtended() {
+ return m_parent->IsExtended();
+ }
+
+
+ bool D3D9DeviceEx::SupportsSWVP() {
+ return m_dxvkDevice->features().core.features.vertexPipelineStoresAndAtomics;
+ }
+
+
+ HWND D3D9DeviceEx::GetWindow() {
+ return m_window;
+ }
+
+
+ DxvkDeviceFeatures D3D9DeviceEx::GetDeviceFeatures(const Rc<DxvkAdapter>& adapter) {
+ DxvkDeviceFeatures supported = adapter->features();
+ DxvkDeviceFeatures enabled = {};
+
+ // Geometry shaders are used for some meta ops
+ enabled.core.features.geometryShader = VK_TRUE;
+ enabled.core.features.robustBufferAccess = VK_TRUE;
+ enabled.extRobustness2.robustBufferAccess2 = supported.extRobustness2.robustBufferAccess2;
+
+ enabled.extMemoryPriority.memoryPriority = supported.extMemoryPriority.memoryPriority;
+
+ enabled.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation = supported.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation;
+
+ enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor;
+ enabled.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor = supported.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor;
+
+ // Null Descriptors
+ enabled.extRobustness2.nullDescriptor = supported.extRobustness2.nullDescriptor;
+
+ // ProcessVertices
+ enabled.core.features.vertexPipelineStoresAndAtomics = supported.core.features.vertexPipelineStoresAndAtomics;
+
+ // DXVK Meta
+ enabled.core.features.shaderStorageImageWriteWithoutFormat = VK_TRUE;
+ enabled.core.features.imageCubeArray = VK_TRUE;
+
+ // SM1 level hardware
+ enabled.core.features.depthClamp = VK_TRUE;
+ enabled.core.features.depthBiasClamp = VK_TRUE;
+ enabled.core.features.fillModeNonSolid = VK_TRUE;
+ enabled.core.features.pipelineStatisticsQuery = supported.core.features.pipelineStatisticsQuery;
+ enabled.core.features.sampleRateShading = VK_TRUE;
+ enabled.core.features.samplerAnisotropy = supported.core.features.samplerAnisotropy;
+ enabled.core.features.shaderClipDistance = VK_TRUE;
+ enabled.core.features.shaderCullDistance = VK_TRUE;
+
+ // Ensure we support real BC formats and unofficial vendor ones.
+ enabled.core.features.textureCompressionBC = VK_TRUE;
+
+ enabled.extDepthClipEnable.depthClipEnable = supported.extDepthClipEnable.depthClipEnable;
+ enabled.extHostQueryReset.hostQueryReset = supported.extHostQueryReset.hostQueryReset;
+
+ // SM2 level hardware
+ enabled.core.features.occlusionQueryPrecise = VK_TRUE;
+
+ // SM3 level hardware
+ enabled.core.features.multiViewport = VK_TRUE;
+ enabled.core.features.independentBlend = VK_TRUE;
+
+ // D3D10 level hardware supports this in D3D9 native.
+ enabled.core.features.fullDrawIndexUint32 = VK_TRUE;
+
+ // Enable depth bounds test if we support it.
+ enabled.core.features.depthBounds = supported.core.features.depthBounds;
+
+ if (supported.extCustomBorderColor.customBorderColorWithoutFormat) {
+ enabled.extCustomBorderColor.customBorderColors = VK_TRUE;
+ enabled.extCustomBorderColor.customBorderColorWithoutFormat = VK_TRUE;
+ }
+
+ return enabled;
+ }
+
+
+ void D3D9DeviceEx::DetermineConstantLayouts(bool canSWVP) {
+ m_vsLayout.floatCount = canSWVP ? uint32_t(m_d3d9Options.swvpFloatCount) : caps::MaxFloatConstantsVS;
+ m_vsLayout.intCount = canSWVP ? uint32_t(m_d3d9Options.swvpIntCount) : caps::MaxOtherConstants;
+ m_vsLayout.boolCount = canSWVP ? uint32_t(m_d3d9Options.swvpBoolCount) : caps::MaxOtherConstants;
+ m_vsLayout.bitmaskCount = align(m_vsLayout.boolCount, 32) / 32;
+
+ m_psLayout.floatCount = caps::MaxFloatConstantsPS;
+ m_psLayout.intCount = caps::MaxOtherConstants;
+ m_psLayout.boolCount = caps::MaxOtherConstants;
+ m_psLayout.bitmaskCount = align(m_psLayout.boolCount, 32) / 32;
+ }
+
+
+ template<bool UpBuffer>
+ D3D9BufferSlice D3D9DeviceEx::AllocTempBuffer(VkDeviceSize size) {
+ constexpr VkDeviceSize DefaultSize = 1 << 20;
+
+ VkMemoryPropertyFlags memoryFlags
+ = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+ if constexpr (UpBuffer) {
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ }
+
+ D3D9BufferSlice& currentSlice = UpBuffer ? m_upBuffer : m_managedUploadBuffer;
+
+ if (size <= DefaultSize) {
+ if (unlikely(!currentSlice.slice.defined())) {
+ DxvkBufferCreateInfo info;
+ info.size = DefaultSize;
+ if constexpr (UpBuffer) {
+ info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
+ | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
+ | VK_ACCESS_INDEX_READ_BIT;
+ info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ } else {
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
+ }
+
+ currentSlice.slice = DxvkBufferSlice(m_dxvkDevice->createBuffer(info, memoryFlags));
+ currentSlice.mapPtr = currentSlice.slice.mapPtr(0);
+ } else if (unlikely(currentSlice.slice.length() < size)) {
+ auto physSlice = currentSlice.slice.buffer()->allocSlice();
+
+ currentSlice.slice = DxvkBufferSlice(currentSlice.slice.buffer());
+ currentSlice.mapPtr = physSlice.mapPtr;
+
+ EmitCs([
+ cBuffer = currentSlice.slice.buffer(),
+ cSlice = physSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+ }
+
+ D3D9BufferSlice result;
+ result.slice = currentSlice.slice.subSlice(0, size);
+ result.mapPtr = reinterpret_cast<char*>(currentSlice.mapPtr) + currentSlice.slice.offset();
+
+ VkDeviceSize adjust = align(size, CACHE_LINE_SIZE);
+ currentSlice.slice = currentSlice.slice.subSlice(adjust, currentSlice.slice.length() - adjust);
+ return result;
+ } else {
+ // Create a temporary buffer for very large allocations
+ DxvkBufferCreateInfo info;
+ info.size = size;
+ if constexpr (UpBuffer) {
+ info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
+ | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
+ | VK_ACCESS_INDEX_READ_BIT;
+ info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ } else {
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT;
+ }
+
+ D3D9BufferSlice result;
+ result.slice = DxvkBufferSlice(m_dxvkDevice->createBuffer(info, memoryFlags));
+ result.mapPtr = result.slice.mapPtr(0);
+ return result;
+ }
+ }
+
+ bool D3D9DeviceEx::ShouldRecord() {
+ return m_recorder != nullptr && !m_recorder->IsApplying();
+ }
+
+
+ D3D9_VK_FORMAT_MAPPING D3D9DeviceEx::LookupFormat(
+ D3D9Format Format) const {
+ return m_adapter->GetFormatMapping(Format);
+ }
+
+ const DxvkFormatInfo* D3D9DeviceEx::UnsupportedFormatInfo(
+ D3D9Format Format) const {
+ return m_adapter->GetUnsupportedFormatInfo(Format);
+ }
+
+ bool D3D9DeviceEx::WaitForResource(
+ const Rc<DxvkResource>& Resource,
+ DWORD MapFlags) {
+ // Wait for the any pending D3D9 command to be executed
+ // on the CS thread so that we can determine whether the
+ // resource is currently in use or not.
+
+ // Determine access type to wait for based on map mode
+ DxvkAccess access = (MapFlags & D3DLOCK_READONLY)
+ ? DxvkAccess::Write
+ : DxvkAccess::Read;
+
+ if (!Resource->isInUse(access))
+ SynchronizeCsThread();
+
+ if (Resource->isInUse(access)) {
+ if (MapFlags & D3DLOCK_DONOTWAIT) {
+ // We don't have to wait, but misbehaving games may
+ // still try to spin on `Map` until the resource is
+ // idle, so we should flush pending commands
+ FlushImplicit(FALSE);
+ return false;
+ }
+ else {
+ // Make sure pending commands using the resource get
+ // executed on the the GPU if we have to wait for it
+ Flush();
+ SynchronizeCsThread();
+
+ Resource->waitIdle(access);
+ }
+ }
+
+ return true;
+ }
+
+
+ uint32_t D3D9DeviceEx::CalcImageLockOffset(
+ uint32_t SlicePitch,
+ uint32_t RowPitch,
+ const DxvkFormatInfo* FormatInfo,
+ const D3DBOX* pBox) {
+ if (pBox == nullptr)
+ return 0;
+
+ std::array<uint32_t, 3> offsets = { pBox->Front, pBox->Top, pBox->Left };
+
+ uint32_t elementSize = 1;
+
+ if (FormatInfo != nullptr) {
+ elementSize = FormatInfo->elementSize;
+
+ offsets[0] = offsets[0] / FormatInfo->blockSize.depth;
+ offsets[1] = offsets[1] / FormatInfo->blockSize.height;
+ offsets[2] = offsets[2] / FormatInfo->blockSize.width;
+ }
+
+ return offsets[0] * SlicePitch +
+ offsets[1] * RowPitch +
+ offsets[2] * elementSize;
+ }
+
+
+ HRESULT D3D9DeviceEx::LockImage(
+ D3D9CommonTexture* pResource,
+ UINT Face,
+ UINT MipLevel,
+ D3DLOCKED_BOX* pLockedBox,
+ const D3DBOX* pBox,
+ DWORD Flags) {
+ D3D9DeviceLock lock = LockDevice();
+
+ UINT Subresource = pResource->CalcSubresource(Face, MipLevel);
+
+ // Don't allow multiple lockings.
+ if (unlikely(pResource->GetLocked(Subresource)))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely((Flags & (D3DLOCK_DISCARD | D3DLOCK_READONLY)) == (D3DLOCK_DISCARD | D3DLOCK_READONLY)))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(!m_d3d9Options.allowDoNotWait))
+ Flags &= ~D3DLOCK_DONOTWAIT;
+
+ if (unlikely((Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)))
+ Flags &= ~D3DLOCK_DISCARD;
+
+ auto& desc = *(pResource->Desc());
+
+ bool alloced = pResource->CreateBufferSubresource(Subresource);
+
+ const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource);
+
+ auto& formatMapping = pResource->GetFormatMapping();
+
+ const DxvkFormatInfo* formatInfo = formatMapping.IsValid()
+ ? imageFormatInfo(formatMapping.FormatColor) : UnsupportedFormatInfo(pResource->Desc()->Format);
+
+ auto subresource = pResource->GetSubresourceFromIndex(
+ formatInfo->aspectMask, Subresource);
+
+ VkExtent3D levelExtent = pResource->GetExtentMip(MipLevel);
+ VkExtent3D blockCount = util::computeBlockCount(levelExtent, formatInfo->blockSize);
+
+ const bool systemmem = desc.Pool == D3DPOOL_SYSTEMMEM;
+ const bool managed = IsPoolManaged(desc.Pool);
+ const bool scratch = desc.Pool == D3DPOOL_SCRATCH;
+
+ bool fullResource = pBox == nullptr;
+ if (unlikely(!fullResource)) {
+ VkOffset3D lockOffset;
+ VkExtent3D lockExtent;
+
+ ConvertBox(*pBox, lockOffset, lockExtent);
+
+ fullResource = lockOffset == VkOffset3D{ 0, 0, 0 }
+ && lockExtent.width >= levelExtent.width
+ && lockExtent.height >= levelExtent.height
+ && lockExtent.depth >= levelExtent.depth;
+ }
+
+ // If we are not locking the entire image
+ // a partial discard is meant to occur.
+ // We can't really implement that, so just ignore discard
+ // if we are not locking the full resource
+
+ // DISCARD is also ignored for MANAGED and SYSTEMEM.
+ // DISCARD is not ignored for non-DYNAMIC unlike what the docs say.
+
+ if (!fullResource || desc.Pool != D3DPOOL_DEFAULT)
+ Flags &= ~D3DLOCK_DISCARD;
+
+ if (desc.Usage & D3DUSAGE_WRITEONLY)
+ Flags &= ~D3DLOCK_READONLY;
+
+ const bool readOnly = Flags & D3DLOCK_READONLY;
+ pResource->SetReadOnlyLocked(Subresource, readOnly);
+
+ bool renderable = desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL);
+
+ // If we recently wrote to the texture on the gpu,
+ // then we need to copy -> buffer
+ // We are also always dirty if we are a render target,
+ // a depth stencil, or auto generate mipmaps.
+ bool wasWrittenByGPU = pResource->WasWrittenByGPU(Subresource) || renderable;
+ pResource->SetWrittenByGPU(Subresource, false);
+
+ DxvkBufferSliceHandle physSlice;
+
+ if (Flags & D3DLOCK_DISCARD) {
+ // We do not have to preserve the contents of the
+ // buffer if the entire image gets discarded.
+ physSlice = pResource->DiscardMapSlice(Subresource);
+
+ EmitCs([
+ cImageBuffer = std::move(mappedBuffer),
+ cBufferSlice = physSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
+ });
+ }
+ else if ((managed && !m_d3d9Options.evictManagedOnUnlock) || scratch || systemmem) {
+ // Managed and scratch resources
+ // are meant to be able to provide readback without waiting.
+ // We always keep a copy of them in system memory for this reason.
+ // No need to wait as its not in use.
+ physSlice = pResource->GetMappedSlice(Subresource);
+
+ // We do not need to wait for the resource in the event the
+ // calling app promises not to overwrite data that is in use
+ // or is reading. Remember! This will only trigger for MANAGED resources
+ // that cannot get affected by GPU, therefore readonly is A-OK for NOT waiting.
+ const bool usesStagingBuffer = pResource->DoesStagingBufferUploads(Subresource);
+ const bool skipWait = (scratch || managed || (systemmem && !wasWrittenByGPU))
+ && (usesStagingBuffer || readOnly);
+
+ if (alloced) {
+ std::memset(physSlice.mapPtr, 0, physSlice.length);
+ }
+ else if (!skipWait) {
+ if (!(Flags & D3DLOCK_DONOTWAIT) && !WaitForResource(mappedBuffer, D3DLOCK_DONOTWAIT))
+ pResource->EnableStagingBufferUploads(Subresource);
+
+ if (!WaitForResource(mappedBuffer, Flags))
+ return D3DERR_WASSTILLDRAWING;
+ }
+ }
+ else {
+ physSlice = pResource->GetMappedSlice(Subresource);
+
+ if (!alloced || wasWrittenByGPU) {
+ if (unlikely(wasWrittenByGPU)) {
+ Rc<DxvkImage> resourceImage = pResource->GetImage();
+
+ Rc<DxvkImage> mappedImage = resourceImage->info().sampleCount != 1
+ ? pResource->GetResolveImage()
+ : std::move(resourceImage);
+
+ // When using any map mode which requires the image contents
+ // to be preserved, and if the GPU has write access to the
+ // image, copy the current image contents into the buffer.
+ auto subresourceLayers = vk::makeSubresourceLayers(subresource);
+
+ // We need to resolve this, some games
+ // lock MSAA render targets even though
+ // that's entirely illegal and they explicitly
+ // tell us that they do NOT want to lock them...
+ if (resourceImage != nullptr) {
+ EmitCs([
+ cMainImage = resourceImage,
+ cResolveImage = mappedImage,
+ cSubresource = subresourceLayers
+ ] (DxvkContext* ctx) {
+ VkImageResolve region;
+ region.srcSubresource = cSubresource;
+ region.srcOffset = VkOffset3D { 0, 0, 0 };
+ region.dstSubresource = cSubresource;
+ region.dstOffset = VkOffset3D { 0, 0, 0 };
+ region.extent = cMainImage->mipLevelExtent(cSubresource.mipLevel);
+
+ if (cSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->resolveImage(
+ cResolveImage, cMainImage, region,
+ cMainImage->info().format);
+ }
+ else {
+ ctx->resolveDepthStencilImage(
+ cResolveImage, cMainImage, region,
+ VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR,
+ VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR);
+ }
+ });
+ }
+
+ VkFormat packedFormat = GetPackedDepthStencilFormat(desc.Format);
+
+ EmitCs([
+ cImageBuffer = mappedBuffer,
+ cImage = std::move(mappedImage),
+ cSubresources = subresourceLayers,
+ cLevelExtent = levelExtent,
+ cPackedFormat = packedFormat
+ ] (DxvkContext* ctx) {
+ if (cSubresources.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ ctx->copyImageToBuffer(cImageBuffer, 0, 4, 0,
+ cImage, cSubresources, VkOffset3D { 0, 0, 0 },
+ cLevelExtent);
+ } else {
+ // Copying DS to a packed buffer is only supported for D24S8 and D32S8
+ // right now so the 4 byte row alignment is guaranteed by the format size
+ ctx->copyDepthStencilImageToPackedBuffer(
+ cImageBuffer, 0,
+ VkOffset2D { 0, 0 },
+ VkExtent2D { cLevelExtent.width, cLevelExtent.height },
+ cImage, cSubresources,
+ VkOffset2D { 0, 0 },
+ VkExtent2D { cLevelExtent.width, cLevelExtent.height },
+ cPackedFormat);
+ }
+ });
+ }
+
+ if (!WaitForResource(mappedBuffer, Flags))
+ return D3DERR_WASSTILLDRAWING;
+ } else {
+ // If we are a new alloc, and we weren't written by the GPU
+ // that means that we are a newly initialized
+ // texture, and hence can just memset -> 0 and
+ // avoid a wait here.
+ std::memset(physSlice.mapPtr, 0, physSlice.length);
+ }
+ }
+
+ const bool atiHack = desc.Format == D3D9Format::ATI1 || desc.Format == D3D9Format::ATI2;
+ // Set up map pointer.
+ if (atiHack) {
+ // We need to lie here. The game is expected to use this info and do a workaround.
+ // It's stupid. I know.
+ pLockedBox->RowPitch = align(std::max(desc.Width >> MipLevel, 1u), 4);
+ pLockedBox->SlicePitch = pLockedBox->RowPitch * std::max(desc.Height >> MipLevel, 1u);
+ }
+ else {
+ // Data is tightly packed within the mapped buffer.
+ pLockedBox->RowPitch = align(formatInfo->elementSize * blockCount.width, 4);
+ pLockedBox->SlicePitch = pLockedBox->RowPitch * blockCount.height;
+ }
+
+ pResource->SetLocked(Subresource, true);
+
+ const bool noDirtyUpdate = Flags & D3DLOCK_NO_DIRTY_UPDATE;
+ if (likely((pResource->IsManaged() && m_d3d9Options.evictManagedOnUnlock)
+ || ((desc.Pool == D3DPOOL_DEFAULT || !noDirtyUpdate) && !readOnly))) {
+ if (pBox && MipLevel != 0) {
+ D3DBOX scaledBox = *pBox;
+ scaledBox.Left <<= MipLevel;
+ scaledBox.Right = std::min(scaledBox.Right << MipLevel, pResource->Desc()->Width);
+ scaledBox.Top <<= MipLevel;
+ scaledBox.Bottom = std::min(scaledBox.Bottom << MipLevel, pResource->Desc()->Height);
+ scaledBox.Back <<= MipLevel;
+ scaledBox.Front = std::min(scaledBox.Front << MipLevel, pResource->Desc()->Depth);
+ pResource->AddDirtyBox(&scaledBox, Face);
+ } else {
+ pResource->AddDirtyBox(pBox, Face);
+ }
+ }
+
+ if (managed && !m_d3d9Options.evictManagedOnUnlock && !readOnly) {
+ pResource->SetNeedsUpload(Subresource, true);
+
+ for (uint32_t i : bit::BitMask(m_activeTextures)) {
+ // Guaranteed to not be nullptr...
+ auto texInfo = GetCommonTexture(m_state.textures[i]);
+
+ if (texInfo == pResource) {
+ m_activeTexturesToUpload |= 1 << i;
+ // We can early out here, no need to add another index for this.
+ break;
+ }
+ }
+ }
+
+ const uint32_t offset = CalcImageLockOffset(
+ pLockedBox->SlicePitch,
+ pLockedBox->RowPitch,
+ (!atiHack) ? formatInfo : nullptr,
+ pBox);
+
+
+ uint8_t* data = reinterpret_cast<uint8_t*>(physSlice.mapPtr);
+ data += offset;
+ pLockedBox->pBits = data;
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::UnlockImage(
+ D3D9CommonTexture* pResource,
+ UINT Face,
+ UINT MipLevel) {
+ D3D9DeviceLock lock = LockDevice();
+
+ UINT Subresource = pResource->CalcSubresource(Face, MipLevel);
+
+ // We weren't locked anyway!
+ if (unlikely(!pResource->GetLocked(Subresource)))
+ return D3D_OK;
+
+ pResource->SetLocked(Subresource, false);
+
+ // Flush image contents from staging if we aren't read only
+ // and we aren't deferring for managed.
+ const D3DBOX& box = pResource->GetDirtyBox(Face);
+ bool shouldFlush = pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
+ shouldFlush &= box.Left < box.Right && box.Top < box.Bottom && box.Front < box.Back;
+ shouldFlush &= !pResource->IsManaged() || m_d3d9Options.evictManagedOnUnlock;
+
+ if (shouldFlush) {
+ this->FlushImage(pResource, Subresource);
+ if (!pResource->IsAnySubresourceLocked())
+ pResource->ClearDirtyBoxes();
+ }
+
+ // Toss our staging buffer if we're not dynamic
+ // and we aren't managed (for sysmem copy.)
+ bool shouldToss = pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
+ shouldToss &= !pResource->IsDynamic();
+ shouldToss &= !pResource->IsManaged() || m_d3d9Options.evictManagedOnUnlock;
+
+ if (shouldToss) {
+ pResource->DestroyBufferSubresource(Subresource);
+ pResource->SetWrittenByGPU(Subresource, true);
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::FlushImage(
+ D3D9CommonTexture* pResource,
+ UINT Subresource) {
+ const Rc<DxvkImage> image = pResource->GetImage();
+
+ // Now that data has been written into the buffer,
+ // we need to copy its contents into the image
+ const DxvkBufferSliceHandle srcSlice = pResource->GetMappedSlice(Subresource);
+
+ auto formatInfo = imageFormatInfo(image->info().format);
+ auto subresource = pResource->GetSubresourceFromIndex(
+ formatInfo->aspectMask, Subresource);
+
+ VkImageSubresourceLayers subresourceLayers = {
+ subresource.aspectMask,
+ subresource.mipLevel,
+ subresource.arrayLayer, 1 };
+
+ auto convertFormat = pResource->GetFormatMapping().ConversionFormatInfo;
+
+ if (likely(convertFormat.FormatType == D3D9ConversionFormat_None)) {
+ VkImageSubresourceLayers dstLayers = { VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel, subresource.arrayLayer, 1 };
+
+ const D3DBOX& box = pResource->GetDirtyBox(subresource.arrayLayer);
+ VkOffset3D scaledBoxOffset = {
+ int32_t(alignDown(box.Left >> subresource.mipLevel, formatInfo->blockSize.width)),
+ int32_t(alignDown(box.Top >> subresource.mipLevel, formatInfo->blockSize.height)),
+ int32_t(alignDown(box.Front >> subresource.mipLevel, formatInfo->blockSize.depth))
+ };
+ VkExtent3D scaledBoxExtent = util::computeMipLevelExtent({
+ uint32_t(box.Right - int32_t(alignDown(box.Left, formatInfo->blockSize.width))),
+ uint32_t(box.Bottom - int32_t(alignDown(box.Top, formatInfo->blockSize.height))),
+ uint32_t(box.Back - int32_t(alignDown(box.Front, formatInfo->blockSize.depth)))
+ }, subresource.mipLevel);
+ VkExtent3D scaledBoxExtentBlockCount = util::computeBlockCount(scaledBoxExtent, formatInfo->blockSize);
+ VkExtent3D scaledAlignedBoxExtent = util::computeBlockExtent(scaledBoxExtentBlockCount, formatInfo->blockSize);
+
+ VkExtent3D texLevelExtent = image->mipLevelExtent(subresource.mipLevel);
+ VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize);
+
+ scaledAlignedBoxExtent.width = std::min<uint32_t>(texLevelExtent.width - scaledBoxOffset.x, scaledAlignedBoxExtent.width);
+ scaledAlignedBoxExtent.height = std::min<uint32_t>(texLevelExtent.height - scaledBoxOffset.y, scaledAlignedBoxExtent.height);
+ scaledAlignedBoxExtent.depth = std::min<uint32_t>(texLevelExtent.depth - scaledBoxOffset.z, scaledAlignedBoxExtent.depth);
+
+ VkOffset3D boxOffsetBlockCount = util::computeBlockOffset(scaledBoxOffset, formatInfo->blockSize);
+ VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4);
+ VkDeviceSize copySrcOffset = boxOffsetBlockCount.z * texLevelExtentBlockCount.height * pitch
+ + boxOffsetBlockCount.y * pitch
+ + boxOffsetBlockCount.x * formatInfo->elementSize;
+
+ VkDeviceSize rowAlignment = 0;
+ DxvkBufferSlice copySrcSlice;
+ if (pResource->DoesStagingBufferUploads(Subresource)) {
+ VkDeviceSize dirtySize = scaledBoxExtentBlockCount.width * scaledBoxExtentBlockCount.height * scaledBoxExtentBlockCount.depth * formatInfo->elementSize;
+ D3D9BufferSlice slice = AllocTempBuffer<false>(dirtySize);
+ copySrcSlice = slice.slice;
+ void* srcData = reinterpret_cast<uint8_t*>(srcSlice.mapPtr) + copySrcOffset;
+ util::packImageData(
+ slice.mapPtr, srcData, scaledBoxExtentBlockCount, formatInfo->elementSize,
+ pitch, pitch * texLevelExtentBlockCount.height);
+ } else {
+ copySrcSlice = DxvkBufferSlice(pResource->GetBuffer(Subresource), copySrcOffset, srcSlice.length);
+ rowAlignment = pitch; // row alignment can act as the pitch parameter
+ }
+
+ EmitCs([
+ cSrcSlice = std::move(copySrcSlice),
+ cDstImage = image,
+ cDstLayers = dstLayers,
+ cDstLevelExtent = scaledAlignedBoxExtent,
+ cOffset = scaledBoxOffset,
+ cRowAlignment = rowAlignment
+ ] (DxvkContext* ctx) {
+ ctx->copyBufferToImage(
+ cDstImage, cDstLayers,
+ cOffset, cDstLevelExtent,
+ cSrcSlice.buffer(), cSrcSlice.offset(),
+ cRowAlignment, 0);
+ });
+ }
+ else {
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(pResource->GetFormatMapping().FormatColor);
+ VkExtent3D texLevelExtent = image->mipLevelExtent(subresource.mipLevel);
+ VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize);
+ // Add more blocks for the other planes that we might have.
+ // TODO: PLEASE CLEAN ME
+ texLevelExtentBlockCount.height *= std::min(convertFormat.PlaneCount, 2u);
+
+ // the converter can not handle the 4 aligned pitch so we always repack into a staging buffer
+ D3D9BufferSlice slice = AllocTempBuffer<false>(srcSlice.length);
+ VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4);
+
+ util::packImageData(
+ slice.mapPtr, srcSlice.mapPtr, texLevelExtentBlockCount, formatInfo->elementSize,
+ pitch, std::min(convertFormat.PlaneCount, 2u) * pitch * texLevelExtentBlockCount.height);
+
+ Flush();
+ SynchronizeCsThread();
+
+ m_converter->ConvertFormat(
+ convertFormat,
+ image, subresourceLayers,
+ slice.slice);
+ }
+
+ if (pResource->IsAutomaticMip())
+ MarkTextureMipsDirty(pResource);
+
+ return D3D_OK;
+ }
+
+
+ void D3D9DeviceEx::EmitGenerateMips(
+ D3D9CommonTexture* pResource) {
+ if (pResource->IsManaged())
+ UploadManagedTexture(pResource);
+
+ EmitCs([
+ cImageView = pResource->GetSampleView(false),
+ cFilter = pResource->GetMipFilter()
+ ] (DxvkContext* ctx) {
+ ctx->generateMipmaps(cImageView, DecodeFilter(cFilter));
+ });
+ }
+
+
+ HRESULT D3D9DeviceEx::LockBuffer(
+ D3D9CommonBuffer* pResource,
+ UINT OffsetToLock,
+ UINT SizeToLock,
+ void** ppbData,
+ DWORD Flags) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (unlikely(ppbData == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (!m_d3d9Options.allowDiscard)
+ Flags &= ~D3DLOCK_DISCARD;
+
+ auto& desc = *pResource->Desc();
+
+ // Ignore DISCARD if NOOVERWRITE is set
+ if (unlikely((Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)))
+ Flags &= ~D3DLOCK_DISCARD;
+
+ // Ignore DISCARD and NOOVERWRITE if the buffer is not DEFAULT pool (tests + Halo 2)
+ // The docs say DISCARD and NOOVERWRITE are ignored if the buffer is not DYNAMIC
+ // but tests say otherwise!
+ if (desc.Pool != D3DPOOL_DEFAULT)
+ Flags &= ~(D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE);
+
+ // Ignore DONOTWAIT if we are DYNAMIC
+ // Yes... D3D9 is a good API.
+ if (desc.Usage & D3DUSAGE_DYNAMIC)
+ Flags &= ~D3DLOCK_DONOTWAIT;
+
+ // We only bounds check for MANAGED.
+ // (TODO: Apparently this is meant to happen for DYNAMIC too but I am not sure
+ // how that works given it is meant to be a DIRECT access..?)
+ const bool respectUserBounds = !(Flags & D3DLOCK_DISCARD) &&
+ SizeToLock != 0;
+
+ // If we don't respect the bounds, encompass it all in our tests/checks
+ // These values may be out of range and don't get clamped.
+ uint32_t offset = respectUserBounds ? OffsetToLock : 0;
+ uint32_t size = respectUserBounds ? std::min(SizeToLock, desc.Size - offset) : desc.Size;
+ D3D9Range lockRange = D3D9Range(offset, offset + size);
+
+ if ((desc.Pool == D3DPOOL_DEFAULT || !(Flags & D3DLOCK_NO_DIRTY_UPDATE)) && !(Flags & D3DLOCK_READONLY))
+ pResource->DirtyRange().Conjoin(lockRange);
+
+ Rc<DxvkBuffer> mappingBuffer = pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>();
+
+ DxvkBufferSliceHandle physSlice;
+
+ if (Flags & D3DLOCK_DISCARD) {
+ // Allocate a new backing slice for the buffer and set
+ // it as the 'new' mapped slice. This assumes that the
+ // only way to invalidate a buffer is by mapping it.
+ physSlice = pResource->DiscardMapSlice();
+
+ EmitCs([
+ cBuffer = std::move(mappingBuffer),
+ cBufferSlice = physSlice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cBufferSlice);
+ });
+
+ pResource->SetWrittenByGPU(false);
+ pResource->GPUReadingRange().Clear();
+ }
+ else {
+ // Use map pointer from previous map operation. This
+ // way we don't have to synchronize with the CS thread
+ // if the map mode is D3DLOCK_NOOVERWRITE.
+ physSlice = pResource->GetMappedSlice();
+
+ // NOOVERWRITE promises that they will not write in a currently used area.
+ // Therefore we can skip waiting for these two cases.
+ // We can also skip waiting if there is not dirty range overlap, if we are one of those resources.
+
+ // If we are respecting the bounds ie. (MANAGED) we can test overlap
+ // of our bounds, otherwise we just ignore this and go for it all the time.
+ const bool wasWrittenByGPU = pResource->WasWrittenByGPU();
+ const bool readOnly = Flags & D3DLOCK_READONLY;
+ const bool noOverlap = !pResource->GPUReadingRange().Overlaps(lockRange);
+ const bool noOverwrite = Flags & D3DLOCK_NOOVERWRITE;
+ const bool usesStagingBuffer = pResource->DoesStagingBufferUploads();
+ const bool directMapping = pResource->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT;
+ const bool skipWait = (!wasWrittenByGPU && (usesStagingBuffer || readOnly || (noOverlap && !directMapping))) || noOverwrite;
+ if (!skipWait) {
+ if (!(Flags & D3DLOCK_DONOTWAIT) && !WaitForResource(mappingBuffer, D3DLOCK_DONOTWAIT))
+ pResource->EnableStagingBufferUploads();
+
+ if (!WaitForResource(mappingBuffer, Flags))
+ return D3DERR_WASSTILLDRAWING;
+
+ pResource->SetWrittenByGPU(false);
+ pResource->GPUReadingRange().Clear();
+ }
+ }
+
+ uint8_t* data = reinterpret_cast<uint8_t*>(physSlice.mapPtr);
+ // The offset/size is not clamped to or affected by the desc size.
+ data += OffsetToLock;
+
+ *ppbData = reinterpret_cast<void*>(data);
+
+ DWORD oldFlags = pResource->GetMapFlags();
+
+ // We need to remove the READONLY flags from the map flags
+ // if there was ever a non-readonly upload.
+ if (!(Flags & D3DLOCK_READONLY))
+ oldFlags &= ~D3DLOCK_READONLY;
+
+ pResource->SetMapFlags(Flags | oldFlags);
+ pResource->IncrementLockCount();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::FlushBuffer(
+ D3D9CommonBuffer* pResource) {
+ auto dstBuffer = pResource->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
+ auto srcSlice = pResource->GetMappedSlice();
+
+ D3D9Range& range = pResource->DirtyRange();
+
+ DxvkBufferSlice copySrcSlice;
+ if (pResource->DoesStagingBufferUploads()) {
+ D3D9BufferSlice slice = AllocTempBuffer<false>(range.max - range.min);
+ copySrcSlice = slice.slice;
+ void* srcData = reinterpret_cast<uint8_t*>(srcSlice.mapPtr) + range.min;
+ memcpy(slice.mapPtr, srcData, range.max - range.min);
+ } else {
+ copySrcSlice = DxvkBufferSlice(pResource->GetBuffer<D3D9_COMMON_BUFFER_TYPE_MAPPING>(), range.min, range.max - range.min);
+ }
+
+ EmitCs([
+ cDstSlice = dstBuffer,
+ cSrcSlice = copySrcSlice,
+ cDstOffset = range.min,
+ cLength = range.max - range.min
+ ] (DxvkContext* ctx) {
+ ctx->copyBuffer(
+ cDstSlice.buffer(),
+ cDstSlice.offset() + cDstOffset,
+ cSrcSlice.buffer(),
+ cSrcSlice.offset(),
+ cLength);
+ });
+
+ pResource->GPUReadingRange().Conjoin(pResource->DirtyRange());
+ pResource->DirtyRange().Clear();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::UnlockBuffer(
+ D3D9CommonBuffer* pResource) {
+ D3D9DeviceLock lock = LockDevice();
+
+ if (pResource->DecrementLockCount() != 0)
+ return D3D_OK;
+
+ if (pResource->GetMapMode() != D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
+ return D3D_OK;
+
+ if (pResource->DirtyRange().IsDegenerate())
+ return D3D_OK;
+
+ pResource->SetMapFlags(0);
+
+ if (pResource->Desc()->Pool != D3DPOOL_DEFAULT)
+ return D3D_OK;
+
+ FlushImplicit(FALSE);
+
+ FlushBuffer(pResource);
+
+ return D3D_OK;
+ }
+
+
+ void D3D9DeviceEx::EmitCsChunk(DxvkCsChunkRef&& chunk) {
+ m_csThread.dispatchChunk(std::move(chunk));
+ m_csIsBusy = true;
+ }
+
+
+ void D3D9DeviceEx::FlushImplicit(BOOL StrongHint) {
+ // Flush only if the GPU is about to go idle, in
+ // order to keep the number of submissions low.
+ uint32_t pending = m_dxvkDevice->pendingSubmissions();
+
+ if (StrongHint || pending <= MaxPendingSubmits) {
+ auto now = dxvk::high_resolution_clock::now();
+
+ uint32_t delay = MinFlushIntervalUs
+ + IncFlushIntervalUs * pending;
+
+ // Prevent flushing too often in short intervals.
+ if (now - m_lastFlush >= std::chrono::microseconds(delay))
+ Flush();
+ }
+ }
+
+
+ void D3D9DeviceEx::SynchronizeCsThread() {
+ D3D9DeviceLock lock = LockDevice();
+
+ // Dispatch current chunk so that all commands
+ // recorded prior to this function will be run
+ FlushCsChunk();
+
+ if (m_csThread.isBusy())
+ m_csThread.synchronize();
+ }
+
+
+ void D3D9DeviceEx::SetupFPU() {
+ // Should match d3d9 float behaviour.
+
+#if defined(_MSC_VER)
+ // For MSVC we can use these cross arch and platform funcs to set the FPU.
+ // This will work on any platform, x86, x64, ARM, etc.
+
+ // Clear exceptions.
+ _clearfp();
+
+ // Disable exceptions
+ _controlfp(_MCW_EM, _MCW_EM);
+
+#ifndef _WIN64
+ // Use 24 bit precision
+ _controlfp(_PC_24, _MCW_PC);
+#endif
+
+ // Round to nearest
+ _controlfp(_RC_NEAR, _MCW_RC);
+#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || defined(__x86_64__) || defined(__ia64))
+ // For GCC/MinGW we can use inline asm to set it.
+ // This only works for x86 and x64 processors however.
+
+ uint16_t control;
+
+ // Get current control word.
+ __asm__ __volatile__("fnstcw %0" : "=m" (*&control));
+
+ // Clear existing settings.
+ control &= 0xF0C0;
+
+ // Disable exceptions
+ // Use 24 bit precision
+ // Round to nearest
+ control |= 0x003F;
+
+ // Set new control word.
+ __asm__ __volatile__("fldcw %0" : : "m" (*&control));
+#else
+ Logger::warn("D3D9DeviceEx::SetupFPU: not supported on this arch.");
+#endif
+ }
+
+
+ int64_t D3D9DeviceEx::DetermineInitialTextureMemory() {
+ auto memoryProp = m_adapter->GetDXVKAdapter()->memoryProperties();
+
+ VkDeviceSize availableTextureMemory = 0;
+
+ for (uint32_t i = 0; i < memoryProp.memoryHeapCount; i++)
+ availableTextureMemory += memoryProp.memoryHeaps[i].size;
+
+ constexpr VkDeviceSize Megabytes = 1024 * 1024;
+
+ // The value returned is a 32-bit value, so we need to clamp it.
+ VkDeviceSize maxMemory = (VkDeviceSize(m_d3d9Options.maxAvailableMemory) * Megabytes) - 1;
+ availableTextureMemory = std::min(availableTextureMemory, maxMemory);
+
+ return int64_t(availableTextureMemory);
+ }
+
+
+ Rc<DxvkBuffer> D3D9DeviceEx::CreateConstantBuffer(
+ bool SSBO,
+ VkDeviceSize Size,
+ DxsoProgramType ShaderStage,
+ DxsoConstantBuffers BufferType) {
+ DxvkBufferCreateInfo info = { };
+ info.usage = SSBO ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ info.access = SSBO ? VK_ACCESS_SHADER_READ_BIT : VK_ACCESS_UNIFORM_READ_BIT;
+ info.size = Size;
+ info.stages = ShaderStage == DxsoProgramType::VertexShader
+ ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
+ : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+
+ VkMemoryPropertyFlags memoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
+ | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ if (m_d3d9Options.deviceLocalConstantBuffers)
+ memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ Rc<DxvkBuffer> buffer = m_dxvkDevice->createBuffer(info, memoryFlags);
+
+ const uint32_t slotId = computeResourceSlotId(
+ ShaderStage, DxsoBindingType::ConstantBuffer,
+ BufferType);
+
+ EmitCs([
+ cSlotId = slotId,
+ cBuffer = buffer
+ ] (DxvkContext* ctx) {
+ ctx->bindResourceBuffer(cSlotId,
+ DxvkBufferSlice(cBuffer, 0, cBuffer->info().size));
+ });
+
+ return buffer;
+ }
+
+
+ void D3D9DeviceEx::CreateConstantBuffers() {
+ m_consts[DxsoProgramTypes::VertexShader].buffer =
+ CreateConstantBuffer(m_dxsoOptions.vertexConstantBufferAsSSBO,
+ m_vsLayout.totalSize(),
+ DxsoProgramType::VertexShader,
+ DxsoConstantBuffers::VSConstantBuffer);
+
+ m_consts[DxsoProgramTypes::PixelShader].buffer =
+ CreateConstantBuffer(false,
+ m_psLayout.totalSize(),
+ DxsoProgramType::PixelShader,
+ DxsoConstantBuffers::PSConstantBuffer);
+
+ m_vsClipPlanes =
+ CreateConstantBuffer(false,
+ caps::MaxClipPlanes * sizeof(D3D9ClipPlane),
+ DxsoProgramType::VertexShader,
+ DxsoConstantBuffers::VSClipPlanes);
+
+ m_vsFixedFunction =
+ CreateConstantBuffer(false,
+ sizeof(D3D9FixedFunctionVS),
+ DxsoProgramType::VertexShader,
+ DxsoConstantBuffers::VSFixedFunction);
+
+ m_psFixedFunction =
+ CreateConstantBuffer(false,
+ sizeof(D3D9FixedFunctionPS),
+ DxsoProgramType::PixelShader,
+ DxsoConstantBuffers::PSFixedFunction);
+
+ m_psShared =
+ CreateConstantBuffer(false,
+ sizeof(D3D9SharedPS),
+ DxsoProgramType::PixelShader,
+ DxsoConstantBuffers::PSShared);
+
+ m_vsVertexBlend =
+ CreateConstantBuffer(true,
+ CanSWVP()
+ ? sizeof(D3D9FixedFunctionVertexBlendDataSW)
+ : sizeof(D3D9FixedFunctionVertexBlendDataHW),
+ DxsoProgramType::VertexShader,
+ DxsoConstantBuffers::VSVertexBlendData);
+ }
+
+
+ template <DxsoProgramType ShaderStage, typename HardwareLayoutType, typename SoftwareLayoutType, typename ShaderType>
+ inline void D3D9DeviceEx::UploadHardwareConstantSet(void* pData, const SoftwareLayoutType& Src, const ShaderType& Shader) {
+ const D3D9ConstantSets& constSet = m_consts[ShaderStage];
+
+ auto* dst = reinterpret_cast<HardwareLayoutType*>(pData);
+
+ if (constSet.meta.maxConstIndexF)
+ std::memcpy(dst->fConsts, Src.fConsts, constSet.meta.maxConstIndexF * sizeof(Vector4));
+ if (constSet.meta.maxConstIndexI)
+ std::memcpy(dst->iConsts, Src.iConsts, constSet.meta.maxConstIndexI * sizeof(Vector4i));
+ }
+
+
+ template <typename SoftwareLayoutType, typename ShaderType>
+ inline void D3D9DeviceEx::UploadSoftwareConstantSet(void* pData, const SoftwareLayoutType& Src, const D3D9ConstantLayout& Layout, const ShaderType& Shader) {
+ const D3D9ConstantSets& constSet = m_consts[DxsoProgramType::VertexShader];
+
+ auto dst = reinterpret_cast<uint8_t*>(pData);
+
+ if (constSet.meta.maxConstIndexF)
+ std::memcpy(dst + Layout.floatOffset(), Src.fConsts, constSet.meta.maxConstIndexF * sizeof(Vector4));
+ if (constSet.meta.maxConstIndexI)
+ std::memcpy(dst + Layout.intOffset(), Src.iConsts, constSet.meta.maxConstIndexI * sizeof(Vector4i));
+ if (constSet.meta.maxConstIndexB)
+ std::memcpy(dst + Layout.bitmaskOffset(), Src.bConsts, Layout.bitmaskSize());
+ }
+
+
+ template <DxsoProgramType ShaderStage, typename HardwareLayoutType, typename SoftwareLayoutType, typename ShaderType>
+ inline void D3D9DeviceEx::UploadConstantSet(const SoftwareLayoutType& Src, const D3D9ConstantLayout& Layout, const ShaderType& Shader) {
+ D3D9ConstantSets& constSet = m_consts[ShaderStage];
+
+ if (!constSet.dirty)
+ return;
+
+ constSet.dirty = false;
+
+ DxvkBufferSliceHandle slice = constSet.buffer->allocSlice();
+
+ EmitCs([
+ cBuffer = constSet.buffer,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+
+ if constexpr (ShaderStage == DxsoProgramType::PixelShader)
+ UploadHardwareConstantSet<ShaderStage, HardwareLayoutType>(slice.mapPtr, Src, Shader);
+ else if (likely(!CanSWVP()))
+ UploadHardwareConstantSet<ShaderStage, HardwareLayoutType>(slice.mapPtr, Src, Shader);
+ else
+ UploadSoftwareConstantSet(slice.mapPtr, Src, Layout, Shader);
+
+ if (constSet.meta.needsConstantCopies) {
+ Vector4* data = reinterpret_cast<Vector4*>(slice.mapPtr);
+
+ auto& shaderConsts = GetCommonShader(Shader)->GetConstants();
+
+ for (const auto& constant : shaderConsts)
+ data[constant.uboIdx] = *reinterpret_cast<const Vector4*>(constant.float32);
+ }
+ }
+
+
+ template <DxsoProgramType ShaderStage>
+ void D3D9DeviceEx::UploadConstants() {
+ if constexpr (ShaderStage == DxsoProgramTypes::VertexShader)
+ return UploadConstantSet<ShaderStage, D3D9ShaderConstantsVSHardware>(m_state.vsConsts, m_vsLayout, m_state.vertexShader);
+ else
+ return UploadConstantSet<ShaderStage, D3D9ShaderConstantsPS> (m_state.psConsts, m_psLayout, m_state.pixelShader);
+ }
+
+
+ void D3D9DeviceEx::UpdateClipPlanes() {
+ m_flags.clr(D3D9DeviceFlag::DirtyClipPlanes);
+
+ auto slice = m_vsClipPlanes->allocSlice();
+ auto dst = reinterpret_cast<D3D9ClipPlane*>(slice.mapPtr);
+
+ for (uint32_t i = 0; i < caps::MaxClipPlanes; i++) {
+ dst[i] = (m_state.renderStates[D3DRS_CLIPPLANEENABLE] & (1 << i))
+ ? m_state.clipPlanes[i]
+ : D3D9ClipPlane();
+ }
+
+ EmitCs([
+ cBuffer = m_vsClipPlanes,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+ }
+
+
+ template <uint32_t Offset, uint32_t Length>
+ void D3D9DeviceEx::UpdatePushConstant(const void* pData) {
+ struct ConstantData { uint8_t Data[Length]; };
+
+ auto* constData = reinterpret_cast<const ConstantData*>(pData);
+
+ EmitCs([
+ cData = *constData
+ ](DxvkContext* ctx) {
+ ctx->pushConstants(Offset, Length, &cData);
+ });
+ }
+
+
+ template <D3D9RenderStateItem Item>
+ void D3D9DeviceEx::UpdatePushConstant() {
+ auto& rs = m_state.renderStates;
+
+ if constexpr (Item == D3D9RenderStateItem::AlphaRef) {
+ float alpha = float(rs[D3DRS_ALPHAREF] & 0xFF) / 255.0f;
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, alphaRef), sizeof(float)>(&alpha);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::FogColor) {
+ Vector4 color;
+ DecodeD3DCOLOR(D3DCOLOR(rs[D3DRS_FOGCOLOR]), color.data);
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, fogColor), sizeof(D3D9RenderStateInfo::fogColor)>(&color);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::FogDensity) {
+ float density = bit::cast<float>(rs[D3DRS_FOGDENSITY]);
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, fogDensity), sizeof(float)>(&density);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::FogEnd) {
+ float end = bit::cast<float>(rs[D3DRS_FOGEND]);
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, fogEnd), sizeof(float)>(&end);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::FogScale) {
+ float end = bit::cast<float>(rs[D3DRS_FOGEND]);
+ float start = bit::cast<float>(rs[D3DRS_FOGSTART]);
+
+ float scale = 1.0f / (end - start);
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, fogScale), sizeof(float)>(&scale);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointSize) {
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointSize), sizeof(float)>(&rs[D3DRS_POINTSIZE]);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointSizeMin) {
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointSizeMin), sizeof(float)>(&rs[D3DRS_POINTSIZE_MIN]);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointSizeMax) {
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointSizeMax), sizeof(float)>(&rs[D3DRS_POINTSIZE_MAX]);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointScaleA) {
+ float scale = bit::cast<float>(rs[D3DRS_POINTSCALE_A]);
+ scale /= float(m_state.viewport.Height * m_state.viewport.Height);
+
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointScaleA), sizeof(float)>(&scale);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointScaleB) {
+ float scale = bit::cast<float>(rs[D3DRS_POINTSCALE_B]);
+ scale /= float(m_state.viewport.Height * m_state.viewport.Height);
+
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointScaleB), sizeof(float)>(&scale);
+ }
+ else if constexpr (Item == D3D9RenderStateItem::PointScaleC) {
+ float scale = bit::cast<float>(rs[D3DRS_POINTSCALE_C]);
+ scale /= float(m_state.viewport.Height * m_state.viewport.Height);
+
+ UpdatePushConstant<offsetof(D3D9RenderStateInfo, pointScaleC), sizeof(float)>(&scale);
+ }
+ else
+ Logger::warn("D3D9: Invalid push constant set to update.");
+ }
+
+
+
+ void D3D9DeviceEx::Flush() {
+ D3D9DeviceLock lock = LockDevice();
+
+ m_initializer->Flush();
+ m_converter->Flush();
+
+ if (m_csIsBusy || !m_csChunk->empty()) {
+ // Add commands to flush the threaded
+ // context, then flush the command list
+ EmitCs([](DxvkContext* ctx) {
+ ctx->flushCommandList();
+ });
+
+ FlushCsChunk();
+
+ // Reset flush timer used for implicit flushes
+ m_lastFlush = dxvk::high_resolution_clock::now();
+ m_csIsBusy = false;
+ }
+ }
+
+
+ inline void D3D9DeviceEx::UpdateBoundRTs(uint32_t index) {
+ const uint32_t bit = 1 << index;
+
+ m_boundRTs &= ~bit;
+
+ if (m_state.renderTargets[index] != nullptr &&
+ !m_state.renderTargets[index]->IsNull())
+ m_boundRTs |= bit;
+ }
+
+
+ inline void D3D9DeviceEx::UpdateActiveRTs(uint32_t index) {
+ if (!config::HazardTrackingEnabled)
+ return;
+
+ const uint32_t bit = 1 << index;
+
+ m_activeRTs &= ~bit;
+
+ if ((m_boundRTs & bit) != 0 &&
+ m_state.renderTargets[index]->GetBaseTexture() != nullptr &&
+ m_state.renderStates[ColorWriteIndex(index)])
+ m_activeRTs |= bit;
+
+ UpdateActiveHazardsRT(bit);
+ }
+
+
+ inline void D3D9DeviceEx::UpdateActiveTextures(uint32_t index, DWORD combinedUsage) {
+ if (!config::ManagedUploadTrackingEnabled && !config::HazardTrackingEnabled && !config::MipGenTrackingEnabled)
+ return;
+
+ const uint32_t bit = 1 << index;
+
+ if (config::HazardTrackingEnabled) {
+ m_activeRTTextures &= ~bit;
+ m_activeDSTextures &= ~bit;
+ }
+ m_activeTextures &= ~bit;
+ if (config::ManagedUploadTrackingEnabled)
+ m_activeTexturesToUpload &= ~bit;
+ if (config::MipGenTrackingEnabled)
+ m_activeTexturesToGen &= ~bit;
+
+ auto tex = GetCommonTexture(m_state.textures[index]);
+ if (tex != nullptr) {
+ m_activeTextures |= bit;
+
+ if (unlikely(config::HazardTrackingEnabled && tex->IsRenderTarget()))
+ m_activeRTTextures |= bit;
+
+ if (unlikely(config::HazardTrackingEnabled && tex->IsDepthStencil()))
+ m_activeDSTextures |= bit;
+
+ if (unlikely(config::ManagedUploadTrackingEnabled && tex->NeedsAnyUpload()))
+ m_activeTexturesToUpload |= bit;
+
+ if (unlikely(config::MipGenTrackingEnabled && tex->NeedsMipGen()))
+ m_activeTexturesToGen |= bit;
+ }
+
+ if (config::HazardTrackingEnabled) {
+ if (unlikely(combinedUsage & D3DUSAGE_RENDERTARGET))
+ UpdateActiveHazardsRT(UINT32_MAX);
+
+ if (unlikely(combinedUsage & D3DUSAGE_DEPTHSTENCIL))
+ UpdateActiveHazardsDS(bit);
+ }
+ }
+
+
+ inline void D3D9DeviceEx::UpdateActiveHazardsRT(uint32_t rtMask) {
+ if (!config::HazardTrackingEnabled)
+ return;
+
+ auto masks = m_psShaderMasks;
+ masks.rtMask &= m_activeRTs & rtMask;
+ masks.samplerMask &= m_activeRTTextures;
+
+ m_activeHazardsRT = m_activeHazardsRT & (~rtMask);
+ for (uint32_t rtIdx : bit::BitMask(masks.rtMask)) {
+ for (uint32_t samplerIdx : bit::BitMask(masks.samplerMask)) {
+ D3D9Surface* rtSurf = m_state.renderTargets[rtIdx].ptr();
+
+ IDirect3DBaseTexture9* rtBase = rtSurf->GetBaseTexture();
+ IDirect3DBaseTexture9* texBase = m_state.textures[samplerIdx];
+
+ // HACK: Don't mark for hazards if we aren't rendering to mip 0!
+ // Some games use screenspace passes like this for blurring
+ // Sampling from mip 0 (texture) -> mip 1 (rt)
+ // and we'd trigger the hazard path otherwise which is unnecessary,
+ // and would shove us into GENERAL and emitting readback barriers.
+ if (likely(rtSurf->GetMipLevel() != 0 || rtBase != texBase))
+ continue;
+
+ m_activeHazardsRT |= 1 << rtIdx;
+ }
+ }
+ }
+
+
+ inline void D3D9DeviceEx::UpdateActiveHazardsDS(uint32_t texMask) {
+ if (!config::HazardTrackingEnabled)
+ return;
+
+ m_activeHazardsDS = m_activeHazardsDS & (~texMask);
+ if (m_state.depthStencil != nullptr &&
+ m_state.depthStencil->GetBaseTexture() != nullptr) {
+ uint32_t samplerMask = m_activeDSTextures & texMask;
+ for (uint32_t samplerIdx : bit::BitMask(samplerMask)) {
+ IDirect3DBaseTexture9* dsBase = m_state.depthStencil->GetBaseTexture();
+ IDirect3DBaseTexture9* texBase = m_state.textures[samplerIdx];
+
+ if (likely(dsBase != texBase))
+ continue;
+
+ m_activeHazardsDS |= 1 << samplerIdx;
+ }
+ }
+ }
+
+
+ void D3D9DeviceEx::MarkRenderHazards() {
+ if (!config::HazardTrackingEnabled)
+ return;
+
+ for (uint32_t rtIdx : bit::BitMask(m_activeHazardsRT)) {
+ // Guaranteed to not be nullptr...
+ auto tex = m_state.renderTargets[rtIdx]->GetCommonTexture();
+ if (unlikely(!tex->MarkHazardous())) {
+ TransitionImage(tex, VK_IMAGE_LAYOUT_GENERAL);
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+ }
+ }
+ }
+
+
+ void D3D9DeviceEx::UploadManagedTexture(D3D9CommonTexture* pResource) {
+ for (uint32_t subresource = 0; subresource < pResource->CountSubresources(); subresource++) {
+ if (!pResource->NeedsUpload(subresource) || pResource->GetBuffer(subresource) == nullptr)
+ continue;
+
+ this->FlushImage(pResource, subresource);
+ }
+
+ pResource->ClearDirtyBoxes();
+ pResource->ClearNeedsUpload();
+ }
+
+
+ void D3D9DeviceEx::UploadManagedTextures(uint32_t mask) {
+ if (!config::ManagedUploadTrackingEnabled)
+ return;
+
+ // Guaranteed to not be nullptr...
+ for (uint32_t texIdx : bit::BitMask(mask))
+ UploadManagedTexture(GetCommonTexture(m_state.textures[texIdx]));
+
+ m_activeTexturesToUpload &= ~mask;
+ }
+
+
+ void D3D9DeviceEx::GenerateTextureMips(uint32_t mask) {
+ for (uint32_t texIdx : bit::BitMask(mask)) {
+ // Guaranteed to not be nullptr...
+ auto texInfo = GetCommonTexture(m_state.textures[texIdx]);
+
+ if (texInfo->NeedsMipGen()) {
+ this->EmitGenerateMips(texInfo);
+ texInfo->SetNeedsMipGen(false);
+ }
+ }
+
+ m_activeTexturesToGen &= ~mask;
+ }
+
+
+ void D3D9DeviceEx::MarkTextureMipsDirty(D3D9CommonTexture* pResource) {
+ if (!config::MipGenTrackingEnabled)
+ return;
+
+ pResource->SetNeedsMipGen(true);
+ pResource->MarkAllWrittenByGPU();
+
+ for (uint32_t i : bit::BitMask(m_activeTextures)) {
+ // Guaranteed to not be nullptr...
+ auto texInfo = GetCommonTexture(m_state.textures[i]);
+
+ if (texInfo == pResource) {
+ m_activeTexturesToGen |= 1 << i;
+ // We can early out here, no need to add another index for this.
+ break;
+ }
+ }
+ }
+
+
+ void D3D9DeviceEx::MarkTextureMipsUnDirty(D3D9CommonTexture* pResource) {
+ if (!config::MipGenTrackingEnabled)
+ return;
+
+ pResource->SetNeedsMipGen(false);
+
+ for (uint32_t i : bit::BitMask(m_activeTextures)) {
+ // Guaranteed to not be nullptr...
+ auto texInfo = GetCommonTexture(m_state.textures[i]);
+
+ if (texInfo == pResource)
+ m_activeTexturesToGen &= ~(1 << i);
+ }
+ }
+
+
+ void D3D9DeviceEx::MarkTextureUploaded(D3D9CommonTexture* pResource) {
+ if (!config::ManagedUploadTrackingEnabled)
+ return;
+
+ for (uint32_t i : bit::BitMask(m_activeTextures)) {
+ // Guaranteed to not be nullptr...
+ auto texInfo = GetCommonTexture(m_state.textures[i]);
+
+ if (texInfo == pResource)
+ m_activeTexturesToUpload &= ~(1 << i);
+ }
+ }
+
+
+ template <bool Points>
+ void D3D9DeviceEx::UpdatePointMode() {
+ if constexpr (!Points) {
+ m_lastPointMode = 0;
+
+ EmitCs([](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PointMode, 0);
+ });
+ }
+ else {
+ auto& rs = m_state.renderStates;
+
+ const bool scale = rs[D3DRS_POINTSCALEENABLE] && !UseProgrammableVS();
+ const bool sprite = rs[D3DRS_POINTSPRITEENABLE];
+
+ const uint32_t scaleBit = scale ? 1u : 0u;
+ const uint32_t spriteBit = sprite ? 2u : 0u;
+
+ uint32_t mode = scaleBit | spriteBit;
+
+ if (rs[D3DRS_POINTSCALEENABLE] && m_flags.test(D3D9DeviceFlag::DirtyPointScale)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyPointScale);
+
+ UpdatePushConstant<D3D9RenderStateItem::PointScaleA>();
+ UpdatePushConstant<D3D9RenderStateItem::PointScaleB>();
+ UpdatePushConstant<D3D9RenderStateItem::PointScaleC>();
+ }
+
+ if (unlikely(mode != m_lastPointMode)) {
+ EmitCs([cMode = mode] (DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PointMode, cMode);
+ });
+
+ m_lastPointMode = mode;
+ }
+ }
+ }
+
+
+ void D3D9DeviceEx::UpdateFog() {
+ auto& rs = m_state.renderStates;
+
+ bool fogEnabled = rs[D3DRS_FOGENABLE];
+
+ bool pixelFog = rs[D3DRS_FOGTABLEMODE] != D3DFOG_NONE && fogEnabled;
+ bool vertexFog = rs[D3DRS_FOGVERTEXMODE] != D3DFOG_NONE && fogEnabled && !pixelFog;
+
+ auto UpdateFogConstants = [&](D3DFOGMODE FogMode) {
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogColor)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogColor);
+ UpdatePushConstant<D3D9RenderStateItem::FogColor>();
+ }
+
+ if (FogMode == D3DFOG_LINEAR) {
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogScale)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogScale);
+ UpdatePushConstant<D3D9RenderStateItem::FogScale>();
+ }
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogEnd)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogEnd);
+ UpdatePushConstant<D3D9RenderStateItem::FogEnd>();
+ }
+ }
+ else if (FogMode == D3DFOG_EXP || FogMode == D3DFOG_EXP2) {
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogDensity)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogDensity);
+ UpdatePushConstant<D3D9RenderStateItem::FogDensity>();
+ }
+ }
+ };
+
+ if (vertexFog) {
+ D3DFOGMODE mode = D3DFOGMODE(rs[D3DRS_FOGVERTEXMODE]);
+
+ UpdateFogConstants(mode);
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogState);
+
+ EmitCs([cMode = mode] (DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, true);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, cMode);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, D3DFOG_NONE);
+ });
+ }
+ }
+ else if (pixelFog) {
+ D3DFOGMODE mode = D3DFOGMODE(rs[D3DRS_FOGTABLEMODE]);
+
+ UpdateFogConstants(mode);
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogState);
+
+ EmitCs([cMode = mode] (DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, true);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, D3DFOG_NONE);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, cMode);
+ });
+ }
+ }
+ else {
+ if (fogEnabled)
+ UpdateFogConstants(D3DFOG_NONE);
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFogState)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFogState);
+
+ EmitCs([cEnabled = fogEnabled] (DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::FogEnabled, cEnabled);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexFogMode, D3DFOG_NONE);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelFogMode, D3DFOG_NONE);
+ });
+ }
+ }
+ }
+
+
+ void D3D9DeviceEx::BindFramebuffer() {
+ m_flags.clr(D3D9DeviceFlag::DirtyFramebuffer);
+
+ DxvkRenderTargets attachments;
+
+ bool srgb = m_state.renderStates[D3DRS_SRGBWRITEENABLE];
+
+ // D3D9 doesn't have the concept of a framebuffer object,
+ // so we'll just create a new one every time the render
+ // target bindings are updated. Set up the attachments.
+ VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
+
+ for (uint32_t i : bit::BitMask(m_boundRTs)) {
+ const DxvkImageCreateInfo& rtImageInfo = m_state.renderTargets[i]->GetCommonTexture()->GetImage()->info();
+
+ if (likely(sampleCount == VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM))
+ sampleCount = rtImageInfo.sampleCount;
+ else if (unlikely(sampleCount != rtImageInfo.sampleCount))
+ continue;
+
+ attachments.color[i] = {
+ m_state.renderTargets[i]->GetRenderTargetView(srgb),
+ m_state.renderTargets[i]->GetRenderTargetLayout() };
+ }
+
+ if (m_state.depthStencil != nullptr) {
+ const DxvkImageCreateInfo& dsImageInfo = m_state.depthStencil->GetCommonTexture()->GetImage()->info();
+ const bool depthWrite = m_state.renderStates[D3DRS_ZWRITEENABLE];
+
+ if (likely(sampleCount == VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM || sampleCount == dsImageInfo.sampleCount)) {
+ attachments.depth = {
+ m_state.depthStencil->GetDepthStencilView(),
+ m_state.depthStencil->GetDepthStencilLayout(depthWrite, m_activeHazardsDS != 0) };
+ }
+ }
+
+ // Create and bind the framebuffer object to the context
+ EmitCs([
+ cAttachments = std::move(attachments)
+ ] (DxvkContext* ctx) {
+ ctx->bindRenderTargets(cAttachments);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindViewportAndScissor() {
+ m_flags.clr(D3D9DeviceFlag::DirtyViewportScissor);
+
+ VkViewport viewport;
+ VkRect2D scissor;
+
+ // D3D9's coordinate system has its origin in the bottom left,
+ // but the viewport coordinates are aligned to the top-left
+ // corner so we can get away with flipping the viewport.
+ const D3DVIEWPORT9& vp = m_state.viewport;
+
+ // Correctness Factor for 1/2 texel offset
+ // We need to bias this slightly to make
+ // imprecision in games happy.
+ // Originally we did this only for powers of two
+ // resolutions but since NEAREST filtering fixed to
+ // truncate, we need to do this all the time now.
+ float cf = 0.5f - (1.0f / 128.0f);
+
+ viewport = VkViewport{
+ float(vp.X) + cf, float(vp.Height + vp.Y) + cf,
+ float(vp.Width), -float(vp.Height),
+ vp.MinZ, vp.MaxZ,
+ };
+
+ // Scissor rectangles. Vulkan does not provide an easy way
+ // to disable the scissor test, so we'll have to set scissor
+ // rects that are at least as large as the framebuffer.
+ bool enableScissorTest = m_state.renderStates[D3DRS_SCISSORTESTENABLE];
+
+ if (enableScissorTest) {
+ RECT sr = m_state.scissorRect;
+
+ VkOffset2D srPosA;
+ srPosA.x = std::max<int32_t>(0, sr.left);
+ srPosA.x = std::max<int32_t>(vp.X, srPosA.x);
+ srPosA.y = std::max<int32_t>(0, sr.top);
+ srPosA.y = std::max<int32_t>(vp.Y, srPosA.y);
+
+ VkOffset2D srPosB;
+ srPosB.x = std::max<int32_t>(srPosA.x, sr.right);
+ srPosB.x = std::min<int32_t>(vp.X + vp.Width, srPosB.x);
+ srPosB.y = std::max<int32_t>(srPosA.y, sr.bottom);
+ srPosB.y = std::min<int32_t>(vp.Y + vp.Height, srPosB.y);
+
+ VkExtent2D srSize;
+ srSize.width = uint32_t(srPosB.x - srPosA.x);
+ srSize.height = uint32_t(srPosB.y - srPosA.y);
+
+ scissor = VkRect2D{ srPosA, srSize };
+ }
+ else {
+ scissor = VkRect2D{
+ VkOffset2D { int32_t(vp.X), int32_t(vp.Y) },
+ VkExtent2D { vp.Width, vp.Height }};
+ }
+
+ EmitCs([
+ cViewport = viewport,
+ cScissor = scissor
+ ] (DxvkContext* ctx) {
+ ctx->setViewports(
+ 1,
+ &cViewport,
+ &cScissor);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindMultiSampleState() {
+ m_flags.clr(D3D9DeviceFlag::DirtyMultiSampleState);
+
+ DxvkMultisampleState msState;
+ msState.sampleMask = m_flags.test(D3D9DeviceFlag::ValidSampleMask)
+ ? m_state.renderStates[D3DRS_MULTISAMPLEMASK]
+ : 0xffffffff;
+ msState.enableAlphaToCoverage = IsAlphaToCoverageEnabled();
+
+ EmitCs([
+ cState = msState
+ ] (DxvkContext* ctx) {
+ ctx->setMultisampleState(cState);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindBlendState() {
+ m_flags.clr(D3D9DeviceFlag::DirtyBlendState);
+
+ auto& state = m_state.renderStates;
+
+ bool separateAlpha = state[D3DRS_SEPARATEALPHABLENDENABLE];
+
+ DxvkBlendMode mode;
+ mode.enableBlending = state[D3DRS_ALPHABLENDENABLE] != FALSE;
+
+ D3D9BlendState color, alpha;
+
+ color.Src = D3DBLEND(state[D3DRS_SRCBLEND]);
+ color.Dst = D3DBLEND(state[D3DRS_DESTBLEND]);
+ color.Op = D3DBLENDOP(state[D3DRS_BLENDOP]);
+ FixupBlendState(color);
+
+ if (separateAlpha) {
+ alpha.Src = D3DBLEND(state[D3DRS_SRCBLENDALPHA]);
+ alpha.Dst = D3DBLEND(state[D3DRS_DESTBLENDALPHA]);
+ alpha.Op = D3DBLENDOP(state[D3DRS_BLENDOPALPHA]);
+ FixupBlendState(alpha);
+ }
+ else
+ alpha = color;
+
+ mode.colorSrcFactor = DecodeBlendFactor(color.Src, false);
+ mode.colorDstFactor = DecodeBlendFactor(color.Dst, false);
+ mode.colorBlendOp = DecodeBlendOp (color.Op);
+
+ mode.alphaSrcFactor = DecodeBlendFactor(alpha.Src, true);
+ mode.alphaDstFactor = DecodeBlendFactor(alpha.Dst, true);
+ mode.alphaBlendOp = DecodeBlendOp (alpha.Op);
+
+ mode.writeMask = state[ColorWriteIndex(0)];
+
+ std::array<VkColorComponentFlags, 3> extraWriteMasks;
+ for (uint32_t i = 0; i < 3; i++)
+ extraWriteMasks[i] = state[ColorWriteIndex(i + 1)];
+
+ EmitCs([
+ cMode = mode,
+ cWriteMasks = extraWriteMasks,
+ cAlphaMasks = m_alphaSwizzleRTs
+ ](DxvkContext* ctx) {
+ for (uint32_t i = 0; i < 4; i++) {
+ DxvkBlendMode mode = cMode;
+ if (i != 0)
+ mode.writeMask = cWriteMasks[i - 1];
+
+ const bool alphaSwizzle = cAlphaMasks & (1 << i);
+
+ auto NormalizeFactor = [alphaSwizzle](VkBlendFactor Factor) {
+ if (alphaSwizzle) {
+ if (Factor == VK_BLEND_FACTOR_DST_ALPHA)
+ return VK_BLEND_FACTOR_ONE;
+ else if (Factor == VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA)
+ return VK_BLEND_FACTOR_ZERO;
+ }
+
+ return Factor;
+ };
+
+ mode.colorSrcFactor = NormalizeFactor(mode.colorSrcFactor);
+ mode.colorDstFactor = NormalizeFactor(mode.colorDstFactor);
+ mode.alphaSrcFactor = NormalizeFactor(mode.alphaSrcFactor);
+ mode.alphaDstFactor = NormalizeFactor(mode.alphaDstFactor);
+
+ ctx->setBlendMode(i, mode);
+ }
+ });
+ }
+
+
+ void D3D9DeviceEx::BindBlendFactor() {
+ DxvkBlendConstants blendConstants;
+ DecodeD3DCOLOR(
+ D3DCOLOR(m_state.renderStates[D3DRS_BLENDFACTOR]),
+ reinterpret_cast<float*>(&blendConstants));
+
+ EmitCs([
+ cBlendConstants = blendConstants
+ ](DxvkContext* ctx) {
+ ctx->setBlendConstants(cBlendConstants);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindDepthStencilState() {
+ m_flags.clr(D3D9DeviceFlag::DirtyDepthStencilState);
+
+ auto& rs = m_state.renderStates;
+
+ bool stencil = rs[D3DRS_STENCILENABLE];
+ bool twoSidedStencil = stencil && rs[D3DRS_TWOSIDEDSTENCILMODE];
+
+ DxvkDepthStencilState state;
+ state.enableDepthTest = rs[D3DRS_ZENABLE] != FALSE;
+ state.enableDepthWrite = rs[D3DRS_ZWRITEENABLE] != FALSE;
+ state.enableStencilTest = stencil;
+ state.depthCompareOp = DecodeCompareOp(D3DCMPFUNC(rs[D3DRS_ZFUNC]));
+
+ if (stencil) {
+ state.stencilOpFront.failOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_STENCILFAIL]));
+ state.stencilOpFront.passOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_STENCILPASS]));
+ state.stencilOpFront.depthFailOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_STENCILZFAIL]));
+ state.stencilOpFront.compareOp = DecodeCompareOp(D3DCMPFUNC (rs[D3DRS_STENCILFUNC]));
+ state.stencilOpFront.compareMask = uint32_t(rs[D3DRS_STENCILMASK]);
+ state.stencilOpFront.writeMask = uint32_t(rs[D3DRS_STENCILWRITEMASK]);
+ state.stencilOpFront.reference = 0;
+ }
+ else
+ state.stencilOpFront = VkStencilOpState();
+
+ if (twoSidedStencil) {
+ state.stencilOpBack.failOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_CCW_STENCILFAIL]));
+ state.stencilOpBack.passOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_CCW_STENCILPASS]));
+ state.stencilOpBack.depthFailOp = DecodeStencilOp(D3DSTENCILOP(rs[D3DRS_CCW_STENCILZFAIL]));
+ state.stencilOpBack.compareOp = DecodeCompareOp(D3DCMPFUNC (rs[D3DRS_CCW_STENCILFUNC]));
+ state.stencilOpBack.compareMask = state.stencilOpFront.compareMask;
+ state.stencilOpBack.writeMask = state.stencilOpFront.writeMask;
+ state.stencilOpBack.reference = 0;
+ }
+ else
+ state.stencilOpBack = state.stencilOpFront;
+
+ EmitCs([
+ cState = state
+ ](DxvkContext* ctx) {
+ ctx->setDepthStencilState(cState);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindRasterizerState() {
+ m_flags.clr(D3D9DeviceFlag::DirtyRasterizerState);
+
+ auto& rs = m_state.renderStates;
+
+ DxvkRasterizerState state;
+ state.cullMode = DecodeCullMode(D3DCULL(rs[D3DRS_CULLMODE]));
+ state.depthBiasEnable = IsDepthBiasEnabled();
+ state.depthClipEnable = true;
+ state.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ state.polygonMode = DecodeFillMode(D3DFILLMODE(rs[D3DRS_FILLMODE]));
+ state.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ state.sampleCount = 0;
+
+ EmitCs([
+ cState = state
+ ](DxvkContext* ctx) {
+ ctx->setRasterizerState(cState);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindDepthBias() {
+ m_flags.clr(D3D9DeviceFlag::DirtyDepthBias);
+
+ auto& rs = m_state.renderStates;
+
+ float depthBias = bit::cast<float>(rs[D3DRS_DEPTHBIAS]) * m_depthBiasScale;
+ float slopeScaledDepthBias = bit::cast<float>(rs[D3DRS_SLOPESCALEDEPTHBIAS]);
+
+ DxvkDepthBias biases;
+ biases.depthBiasConstant = depthBias;
+ biases.depthBiasSlope = slopeScaledDepthBias;
+ biases.depthBiasClamp = 0.0f;
+
+ EmitCs([
+ cBiases = biases
+ ](DxvkContext* ctx) {
+ ctx->setDepthBias(cBiases);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindAlphaTestState() {
+ m_flags.clr(D3D9DeviceFlag::DirtyAlphaTestState);
+
+ auto& rs = m_state.renderStates;
+
+ VkCompareOp alphaOp = IsAlphaTestEnabled()
+ ? DecodeCompareOp(D3DCMPFUNC(rs[D3DRS_ALPHAFUNC]))
+ : VK_COMPARE_OP_ALWAYS;
+
+ EmitCs([cAlphaOp = alphaOp] (DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::AlphaCompareOp, cAlphaOp);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindDepthStencilRefrence() {
+ auto& rs = m_state.renderStates;
+
+ uint32_t ref = uint32_t(rs[D3DRS_STENCILREF]) & 0xff;
+
+ EmitCs([cRef = ref] (DxvkContext* ctx) {
+ ctx->setStencilReference(cRef);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindSampler(DWORD Sampler) {
+ auto& state = m_state.samplerStates[Sampler];
+
+ D3D9SamplerKey key;
+ key.AddressU = D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSU]);
+ key.AddressV = D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSV]);
+ key.AddressW = D3DTEXTUREADDRESS(state[D3DSAMP_ADDRESSW]);
+ key.MagFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MAGFILTER]);
+ key.MinFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MINFILTER]);
+ key.MipFilter = D3DTEXTUREFILTERTYPE(state[D3DSAMP_MIPFILTER]);
+ key.MaxAnisotropy = state[D3DSAMP_MAXANISOTROPY];
+ key.MipmapLodBias = bit::cast<float>(state[D3DSAMP_MIPMAPLODBIAS]);
+ key.MaxMipLevel = state[D3DSAMP_MAXMIPLEVEL];
+ key.BorderColor = D3DCOLOR(state[D3DSAMP_BORDERCOLOR]);
+ key.Depth = m_depthTextures & (1u << Sampler);
+
+ if (m_d3d9Options.samplerAnisotropy != -1) {
+ if (key.MagFilter == D3DTEXF_LINEAR)
+ key.MagFilter = D3DTEXF_ANISOTROPIC;
+
+ if (key.MinFilter == D3DTEXF_LINEAR)
+ key.MinFilter = D3DTEXF_ANISOTROPIC;
+
+ key.MaxAnisotropy = m_d3d9Options.samplerAnisotropy;
+ }
+
+ NormalizeSamplerKey(key);
+
+ auto samplerInfo = RemapStateSamplerShader(Sampler);
+
+ const uint32_t slot = computeResourceSlotId(
+ samplerInfo.first, DxsoBindingType::Image,
+ samplerInfo.second);
+
+ EmitCs([this,
+ cSlot = slot,
+ cKey = key
+ ] (DxvkContext* ctx) {
+ auto pair = m_samplers.find(cKey);
+ if (pair != m_samplers.end()) {
+ ctx->bindResourceSampler(cSlot, pair->second);
+ return;
+ }
+
+ auto mipFilter = DecodeMipFilter(cKey.MipFilter);
+
+ DxvkSamplerCreateInfo info;
+ info.addressModeU = DecodeAddressMode(cKey.AddressU);
+ info.addressModeV = DecodeAddressMode(cKey.AddressV);
+ info.addressModeW = DecodeAddressMode(cKey.AddressW);
+ info.compareToDepth = cKey.Depth;
+ info.compareOp = cKey.Depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_NEVER;
+ info.magFilter = DecodeFilter(cKey.MagFilter);
+ info.minFilter = DecodeFilter(cKey.MinFilter);
+ info.mipmapMode = mipFilter.MipFilter;
+ info.maxAnisotropy = float(cKey.MaxAnisotropy);
+ info.useAnisotropy = cKey.MaxAnisotropy > 1;
+ info.mipmapLodBias = cKey.MipmapLodBias;
+ info.mipmapLodMin = mipFilter.MipsEnabled ? float(cKey.MaxMipLevel) : 0;
+ info.mipmapLodMax = mipFilter.MipsEnabled ? FLT_MAX : 0;
+ info.usePixelCoord = VK_FALSE;
+
+ DecodeD3DCOLOR(cKey.BorderColor, info.borderColor.float32);
+
+ if (!m_dxvkDevice->features().extCustomBorderColor.customBorderColorWithoutFormat) {
+ // HACK: Let's get OPAQUE_WHITE border color over
+ // TRANSPARENT_BLACK if the border RGB is white.
+ if (info.borderColor.float32[0] == 1.0f
+ && info.borderColor.float32[1] == 1.0f
+ && info.borderColor.float32[2] == 1.0f
+ && !m_dxvkDevice->features().extCustomBorderColor.customBorderColors) {
+ // Then set the alpha to 1.
+ info.borderColor.float32[3] = 1.0f;
+ }
+ }
+
+ try {
+ auto sampler = m_dxvkDevice->createSampler(info);
+
+ m_samplers.insert(std::make_pair(cKey, sampler));
+ ctx->bindResourceSampler(cSlot, std::move(sampler));
+
+ m_samplerCount++;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ }
+ });
+ }
+
+
+ void D3D9DeviceEx::BindTexture(DWORD StateSampler) {
+ auto shaderSampler = RemapStateSamplerShader(StateSampler);
+
+ uint32_t slot = computeResourceSlotId(shaderSampler.first,
+ DxsoBindingType::Image, uint32_t(shaderSampler.second));
+
+ const bool srgb =
+ m_state.samplerStates[StateSampler][D3DSAMP_SRGBTEXTURE] & 0x1;
+
+ D3D9CommonTexture* commonTex =
+ GetCommonTexture(m_state.textures[StateSampler]);
+
+ EmitCs([
+ cSlot = slot,
+ cImageView = commonTex->GetSampleView(srgb)
+ ](DxvkContext* ctx) {
+ ctx->bindResourceView(cSlot, cImageView, nullptr);
+ });
+ }
+
+
+ void D3D9DeviceEx::UnbindTextures(uint32_t mask) {
+ EmitCs([
+ cMask = mask
+ ](DxvkContext* ctx) {
+ for (uint32_t i : bit::BitMask(cMask)) {
+ auto shaderSampler = RemapStateSamplerShader(i);
+
+ uint32_t slot = computeResourceSlotId(shaderSampler.first,
+ DxsoBindingType::Image, uint32_t(shaderSampler.second));
+
+ ctx->bindResourceView(slot, nullptr, nullptr);
+ }
+ });
+ }
+
+
+ void D3D9DeviceEx::UndirtySamplers(uint32_t mask) {
+ for (uint32_t i : bit::BitMask(mask))
+ BindSampler(i);
+
+ m_dirtySamplerStates &= ~mask;
+ }
+
+
+ void D3D9DeviceEx::UndirtyTextures(uint32_t usedMask) {
+ const uint32_t activeMask = usedMask & m_activeTextures;
+ const uint32_t inactiveMask = usedMask & ~m_activeTextures;
+
+ for (uint32_t i : bit::BitMask(activeMask))
+ BindTexture(i);
+
+ if (inactiveMask)
+ UnbindTextures(inactiveMask);
+
+ m_dirtyTextures &= ~usedMask;
+ }
+
+ void D3D9DeviceEx::MarkTextureBindingDirty(IDirect3DBaseTexture9* texture) {
+ D3D9DeviceLock lock = LockDevice();
+
+ for (uint32_t i : bit::BitMask(m_activeTextures)) {
+ if (m_state.textures[i] == texture)
+ m_dirtyTextures |= 1u << i;
+ }
+ }
+
+
+ D3D9DrawInfo D3D9DeviceEx::GenerateDrawInfo(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT PrimitiveCount,
+ UINT InstanceCount) {
+ D3D9DrawInfo drawInfo;
+ drawInfo.vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
+ drawInfo.instanceCount = m_iaState.streamsInstanced & m_iaState.streamsUsed
+ ? InstanceCount
+ : 1u;
+ return drawInfo;
+ }
+
+
+ uint32_t D3D9DeviceEx::GetInstanceCount() const {
+ return std::max(m_state.streamFreq[0] & 0x7FFFFFu, 1u);
+ }
+
+
+ void D3D9DeviceEx::PrepareDraw(D3DPRIMITIVETYPE PrimitiveType) {
+ if (config::HazardTrackingEnabled) {
+ if (unlikely(m_activeHazardsRT != 0)) {
+ EmitCs([](DxvkContext* ctx) {
+ ctx->emitRenderTargetReadbackBarrier();
+ });
+
+ if (m_d3d9Options.generalHazards)
+ MarkRenderHazards();
+ }
+
+ if (unlikely((m_lastHazardsDS == 0) != (m_activeHazardsDS == 0))) {
+ m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+ m_lastHazardsDS = m_activeHazardsDS;
+ }
+ }
+
+ for (uint32_t i = 0; i < caps::MaxStreams; i++) {
+ auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
+ if (vbo != nullptr && vbo->NeedsUpload())
+ FlushBuffer(vbo);
+ }
+
+ const uint32_t usedSamplerMask = m_psShaderMasks.samplerMask | m_vsShaderMasks.samplerMask;
+ const uint32_t usedTextureMask = m_activeTextures & usedSamplerMask;
+
+ if (config::ManagedUploadTrackingEnabled) {
+ const uint32_t texturesToUpload = m_activeTexturesToUpload & usedTextureMask;
+ if (unlikely(texturesToUpload != 0))
+ UploadManagedTextures(texturesToUpload);
+ }
+
+ if (config::MipGenTrackingEnabled) {
+ const uint32_t texturesToGen = m_activeTexturesToGen & usedTextureMask;
+ if (unlikely(texturesToGen != 0))
+ GenerateTextureMips(texturesToGen);
+ }
+
+ auto* ibo = GetCommonBuffer(m_state.indices);
+ if (ibo != nullptr && ibo->NeedsUpload())
+ FlushBuffer(ibo);
+
+ UpdateFog();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFramebuffer))
+ BindFramebuffer();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyViewportScissor))
+ BindViewportAndScissor();
+
+ const uint32_t activeDirtySamplers = m_dirtySamplerStates & usedTextureMask;
+ if (activeDirtySamplers)
+ UndirtySamplers(activeDirtySamplers);
+
+ const uint32_t usedDirtyTextures = m_dirtyTextures & usedSamplerMask;
+ if (usedDirtyTextures)
+ UndirtyTextures(usedDirtyTextures);
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyBlendState))
+ BindBlendState();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyDepthStencilState))
+ BindDepthStencilState();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyRasterizerState))
+ BindRasterizerState();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyDepthBias))
+ BindDepthBias();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyMultiSampleState))
+ BindMultiSampleState();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyAlphaTestState))
+ BindAlphaTestState();
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyClipPlanes))
+ UpdateClipPlanes();
+
+ if (PrimitiveType == D3DPT_POINTLIST)
+ UpdatePointMode<true>();
+ else if (m_lastPointMode != 0)
+ UpdatePointMode<false>();
+
+ if (likely(UseProgrammableVS())) {
+ if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyProgVertexShader))) {
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+
+ BindShader<DxsoProgramType::VertexShader>(
+ GetCommonShader(m_state.vertexShader),
+ GetVertexShaderPermutation());
+ }
+ UploadConstants<DxsoProgramTypes::VertexShader>();
+
+ if (likely(!CanSWVP())) {
+ UpdateBoolSpecConstantVertex(
+ m_state.vsConsts.bConsts[0] &
+ m_consts[DxsoProgramType::VertexShader].meta.boolConstantMask);
+ } else
+ UpdateBoolSpecConstantVertex(0);
+ }
+ else {
+ UpdateBoolSpecConstantVertex(0);
+ UpdateFixedFunctionVS();
+ }
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyInputLayout))
+ BindInputLayout();
+
+ auto UpdateSamplerTypes = [&](uint32_t types, uint32_t projections, uint32_t fetch4) {
+ if (m_lastSamplerTypes != types)
+ UpdateSamplerSpecConsant(types);
+
+ if (m_lastProjectionBitfield != projections)
+ UpdateProjectionSpecConstant(projections);
+
+ if (m_lastFetch4 != fetch4)
+ UpdateFetch4SpecConstant(fetch4);
+ };
+
+ if (likely(UseProgrammablePS())) {
+ UploadConstants<DxsoProgramTypes::PixelShader>();
+
+ const uint32_t psTextureMask = usedTextureMask & ((1u << 16u) - 1u);
+ const uint32_t fetch4 = m_fetch4 & psTextureMask;
+ const uint32_t projected = m_projectionBitfield & psTextureMask;
+
+ const auto& programInfo = GetCommonShader(m_state.pixelShader)->GetInfo();
+
+ if (programInfo.majorVersion() >= 2)
+ UpdateSamplerTypes(m_d3d9Options.forceSamplerTypeSpecConstants ? m_textureTypes : 0u, 0u, fetch4);
+ else
+ UpdateSamplerTypes(m_textureTypes, programInfo.minorVersion() >= 4 ? 0u : projected, fetch4); // For implicit samplers...
+
+ UpdateBoolSpecConstantPixel(
+ m_state.psConsts.bConsts[0] &
+ m_consts[DxsoProgramType::PixelShader].meta.boolConstantMask);
+ }
+ else {
+ UpdateBoolSpecConstantPixel(0);
+ UpdateSamplerTypes(0u, 0u, 0u);
+
+ UpdateFixedFunctionPS();
+ }
+
+ const uint32_t depthTextureMask = m_depthTextures & usedTextureMask;
+ if (depthTextureMask != m_lastSamplerDepthMode)
+ UpdateSamplerDepthModeSpecConstant(depthTextureMask);
+
+ if (m_flags.test(D3D9DeviceFlag::DirtySharedPixelShaderData) && config::FixedFunctionEnabled) {
+ m_flags.clr(D3D9DeviceFlag::DirtySharedPixelShaderData);
+
+ DxvkBufferSliceHandle slice = m_psShared->allocSlice();
+
+ EmitCs([
+ cBuffer = m_psShared,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+
+ D3D9SharedPS* data = reinterpret_cast<D3D9SharedPS*>(slice.mapPtr);
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ DecodeD3DCOLOR(D3DCOLOR(m_state.textureStages[i][DXVK_TSS_CONSTANT]), data->Stages[i].Constant);
+
+ // Flip major-ness so we can get away with a nice easy
+ // dot in the shader without complex access
+ data->Stages[i].BumpEnvMat[0][0] = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVMAT00]);
+ data->Stages[i].BumpEnvMat[1][0] = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVMAT01]);
+ data->Stages[i].BumpEnvMat[0][1] = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVMAT10]);
+ data->Stages[i].BumpEnvMat[1][1] = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVMAT11]);
+
+ data->Stages[i].BumpEnvLScale = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVLSCALE]);
+ data->Stages[i].BumpEnvLOffset = bit::cast<float>(m_state.textureStages[i][DXVK_TSS_BUMPENVLOFFSET]);
+ }
+ }
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyDepthBounds)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyDepthBounds);
+
+ DxvkDepthBounds db;
+ db.enableDepthBounds = (m_state.renderStates[D3DRS_ADAPTIVETESS_X] == uint32_t(D3D9Format::NVDB));
+ db.minDepthBounds = bit::cast<float>(m_state.renderStates[D3DRS_ADAPTIVETESS_Z]);
+ db.maxDepthBounds = bit::cast<float>(m_state.renderStates[D3DRS_ADAPTIVETESS_W]);
+
+ EmitCs([
+ cDepthBounds = db
+ ] (DxvkContext* ctx) {
+ ctx->setDepthBounds(cDepthBounds);
+ });
+ }
+ }
+
+
+ template <DxsoProgramType ShaderStage>
+ void D3D9DeviceEx::BindShader(
+ const D3D9CommonShader* pShaderModule,
+ D3D9ShaderPermutation Permutation) {
+ EmitCs([
+ cShader = pShaderModule->GetShader(Permutation)
+ ] (DxvkContext* ctx) {
+ ctx->bindShader(GetShaderStage(ShaderStage), cShader);
+ });
+ }
+
+
+ void D3D9DeviceEx::BindInputLayout() {
+ m_flags.clr(D3D9DeviceFlag::DirtyInputLayout);
+
+ if (m_state.vertexDecl == nullptr) {
+ EmitCs([&cIaState = m_iaState] (DxvkContext* ctx) {
+ cIaState.streamsUsed = 0;
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+ });
+ }
+ else {
+ std::array<uint32_t, caps::MaxStreams> streamFreq;
+
+ for (uint32_t i = 0; i < caps::MaxStreams; i++)
+ streamFreq[i] = m_state.streamFreq[i];
+
+ Com<D3D9VertexDecl, false> vertexDecl = m_state.vertexDecl;
+ Com<D3D9VertexShader, false> vertexShader;
+
+ if (UseProgrammableVS())
+ vertexShader = m_state.vertexShader;
+
+ EmitCs([
+ &cIaState = m_iaState,
+ cVertexDecl = std::move(vertexDecl),
+ cVertexShader = std::move(vertexShader),
+ cStreamsInstanced = m_instancedData,
+ cStreamFreq = streamFreq
+ ] (DxvkContext* ctx) {
+ cIaState.streamsInstanced = cStreamsInstanced;
+ cIaState.streamsUsed = 0;
+
+ const auto& elements = cVertexDecl->GetElements();
+
+ std::array<DxvkVertexAttribute, 2 * caps::InputRegisterCount> attrList;
+ std::array<DxvkVertexBinding, 2 * caps::InputRegisterCount> bindList;
+
+ uint32_t attrMask = 0;
+ uint32_t bindMask = 0;
+
+ const auto& isgn = cVertexShader != nullptr
+ ? GetCommonShader(cVertexShader)->GetIsgn()
+ : GetFixedFunctionIsgn();
+
+ for (uint32_t i = 0; i < isgn.elemCount; i++) {
+ const auto& decl = isgn.elems[i];
+
+ DxvkVertexAttribute attrib;
+ attrib.location = i;
+ attrib.binding = NullStreamIdx;
+ attrib.format = VK_FORMAT_R32G32B32A32_SFLOAT;
+ attrib.offset = 0;
+
+ for (const auto& element : elements) {
+ DxsoSemantic elementSemantic = { static_cast<DxsoUsage>(element.Usage), element.UsageIndex };
+ if (elementSemantic.usage == DxsoUsage::PositionT)
+ elementSemantic.usage = DxsoUsage::Position;
+
+ if (elementSemantic == decl.semantic) {
+ attrib.binding = uint32_t(element.Stream);
+ attrib.format = DecodeDecltype(D3DDECLTYPE(element.Type));
+ attrib.offset = element.Offset;
+
+ cIaState.streamsUsed |= 1u << attrib.binding;
+ break;
+ }
+ }
+
+ attrList[i] = attrib;
+
+ DxvkVertexBinding binding;
+ binding.binding = attrib.binding;
+
+ uint32_t instanceData = cStreamFreq[binding.binding % caps::MaxStreams];
+ if (instanceData & D3DSTREAMSOURCE_INSTANCEDATA) {
+ binding.fetchRate = instanceData & 0x7FFFFF; // Remove instance packed-in flags in the data.
+ binding.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
+ }
+ else {
+ binding.fetchRate = 0;
+ binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+ }
+
+ // Check if the binding was already defined.
+ bool bindingDefined = false;
+
+ for (uint32_t j = 0; j < i; j++) {
+ uint32_t bindingId = attrList.at(j).binding;
+
+ if (binding.binding == bindingId) {
+ bindingDefined = true;
+ }
+ }
+
+ if (!bindingDefined)
+ bindList.at(binding.binding) = binding;
+
+ attrMask |= 1u << i;
+ bindMask |= 1u << binding.binding;
+ }
+
+ // Compact the attribute and binding lists to filter
+ // out attributes and bindings not used by the shader
+ uint32_t attrCount = CompactSparseList(attrList.data(), attrMask);
+ uint32_t bindCount = CompactSparseList(bindList.data(), bindMask);
+
+ ctx->setInputLayout(
+ attrCount, attrList.data(),
+ bindCount, bindList.data());
+ });
+ }
+ }
+
+
+ void D3D9DeviceEx::BindVertexBuffer(
+ UINT Slot,
+ D3D9VertexBuffer* pBuffer,
+ UINT Offset,
+ UINT Stride) {
+ EmitCs([
+ cSlotId = Slot,
+ cBufferSlice = pBuffer != nullptr ?
+ pBuffer->GetCommonBuffer()->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>(Offset)
+ : DxvkBufferSlice(),
+ cStride = pBuffer != nullptr ? Stride : 0
+ ] (DxvkContext* ctx) {
+ ctx->bindVertexBuffer(cSlotId, cBufferSlice, cStride);
+ });
+ }
+
+ void D3D9DeviceEx::BindIndices() {
+ D3D9CommonBuffer* buffer = GetCommonBuffer(m_state.indices);
+
+ D3D9Format format = buffer != nullptr
+ ? buffer->Desc()->Format
+ : D3D9Format::INDEX32;
+
+ const VkIndexType indexType = DecodeIndexType(format);
+
+ EmitCs([
+ cBufferSlice = buffer != nullptr ? buffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>() : DxvkBufferSlice(),
+ cIndexType = indexType
+ ](DxvkContext* ctx) {
+ ctx->bindIndexBuffer(cBufferSlice, cIndexType);
+ });
+ }
+
+
+ void D3D9DeviceEx::Begin(D3D9Query* pQuery) {
+ D3D9DeviceLock lock = LockDevice();
+
+ EmitCs([cQuery = Com<D3D9Query, false>(pQuery)](DxvkContext* ctx) {
+ cQuery->Begin(ctx);
+ });
+ }
+
+
+ void D3D9DeviceEx::End(D3D9Query* pQuery) {
+ D3D9DeviceLock lock = LockDevice();
+
+ EmitCs([cQuery = Com<D3D9Query, false>(pQuery)](DxvkContext* ctx) {
+ cQuery->End(ctx);
+ });
+
+ pQuery->NotifyEnd();
+ if (unlikely(pQuery->IsEvent())) {
+ pQuery->IsStalling()
+ ? Flush()
+ : FlushImplicit(TRUE);
+ } else if (pQuery->IsStalling()) {
+ FlushImplicit(FALSE);
+ }
+ }
+
+
+ void D3D9DeviceEx::SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
+ m_state.vsConsts.bConsts[idx] &= ~mask;
+ m_state.vsConsts.bConsts[idx] |= bits & mask;
+
+ m_consts[DxsoProgramTypes::VertexShader].dirty = true;
+ }
+
+
+ void D3D9DeviceEx::SetPixelBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
+ m_state.psConsts.bConsts[idx] &= ~mask;
+ m_state.psConsts.bConsts[idx] |= bits & mask;
+
+ m_consts[DxsoProgramTypes::PixelShader].dirty = true;
+ }
+
+
+ HRESULT D3D9DeviceEx::CreateShaderModule(
+ D3D9CommonShader* pShaderModule,
+ VkShaderStageFlagBits ShaderStage,
+ const DWORD* pShaderBytecode,
+ const DxsoModuleInfo* pModuleInfo) {
+ try {
+ m_shaderModules->GetShaderModule(this, pShaderModule,
+ ShaderStage, pModuleInfo, pShaderBytecode);
+
+ return D3D_OK;
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+
+ template <
+ DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType,
+ typename T>
+ HRESULT D3D9DeviceEx::SetShaderConstants(
+ UINT StartRegister,
+ const T* pConstantData,
+ UINT Count) {
+ const uint32_t regCountHardware = DetermineHardwareRegCount<ProgramType, ConstantType>();
+ constexpr uint32_t regCountSoftware = DetermineSoftwareRegCount<ProgramType, ConstantType>();
+
+ if (unlikely(StartRegister + Count > regCountSoftware))
+ return D3DERR_INVALIDCALL;
+
+ Count = UINT(
+ std::max<INT>(
+ std::clamp<INT>(Count + StartRegister, 0, regCountHardware) - INT(StartRegister),
+ 0));
+
+ if (unlikely(Count == 0))
+ return D3D_OK;
+
+ if (unlikely(pConstantData == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ShouldRecord()))
+ return m_recorder->SetShaderConstants<ProgramType, ConstantType, T>(
+ StartRegister,
+ pConstantData,
+ Count);
+
+ if constexpr (ConstantType != D3D9ConstantType::Bool) {
+ uint32_t maxCount = ConstantType == D3D9ConstantType::Float
+ ? m_consts[ProgramType].meta.maxConstIndexF
+ : m_consts[ProgramType].meta.maxConstIndexI;
+
+ m_consts[ProgramType].dirty |= StartRegister < maxCount;
+ }
+
+ UpdateStateConstants<ProgramType, ConstantType, T>(
+ &m_state,
+ StartRegister,
+ pConstantData,
+ Count,
+ m_d3d9Options.d3d9FloatEmulation);
+
+ return D3D_OK;
+ }
+
+
+ void D3D9DeviceEx::UpdateFixedFunctionVS() {
+ // Shader...
+ bool hasPositionT = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasPositionT) : false;
+ bool hasBlendWeight = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasBlendWeight) : false;
+ bool hasBlendIndices = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasBlendIndices) : false;
+
+ bool indexedVertexBlend = hasBlendIndices && m_state.renderStates[D3DRS_INDEXEDVERTEXBLENDENABLE];
+
+ D3D9FF_VertexBlendMode vertexBlendMode = D3D9FF_VertexBlendMode_Disabled;
+
+ if (m_state.renderStates[D3DRS_VERTEXBLEND] != D3DVBF_DISABLE && !hasPositionT) {
+ vertexBlendMode = m_state.renderStates[D3DRS_VERTEXBLEND] == D3DVBF_TWEENING
+ ? D3D9FF_VertexBlendMode_Tween
+ : D3D9FF_VertexBlendMode_Normal;
+
+ if (m_state.renderStates[D3DRS_VERTEXBLEND] != D3DVBF_0WEIGHTS) {
+ if (!hasBlendWeight)
+ vertexBlendMode = D3D9FF_VertexBlendMode_Disabled;
+ }
+ else if (!indexedVertexBlend)
+ vertexBlendMode = D3D9FF_VertexBlendMode_Disabled;
+ }
+
+ if (unlikely(hasPositionT && m_state.vertexShader != nullptr && !m_flags.test(D3D9DeviceFlag::DirtyProgVertexShader))) {
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+ m_flags.set(D3D9DeviceFlag::DirtyProgVertexShader);
+ }
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFFVertexShader)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFVertexShader);
+
+ D3D9FFShaderKeyVS key;
+ key.Data.Contents.HasPositionT = hasPositionT;
+ key.Data.Contents.HasColor0 = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasColor0) : false;
+ key.Data.Contents.HasColor1 = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasColor1) : false;
+ key.Data.Contents.HasPointSize = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasPointSize) : false;
+ key.Data.Contents.HasFog = m_state.vertexDecl != nullptr ? m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasFog) : false;
+
+ bool lighting = m_state.renderStates[D3DRS_LIGHTING] != 0 && !key.Data.Contents.HasPositionT;
+ bool colorVertex = m_state.renderStates[D3DRS_COLORVERTEX] != 0;
+ uint32_t mask = (lighting && colorVertex)
+ ? (key.Data.Contents.HasColor0 ? D3DMCS_COLOR1 : D3DMCS_MATERIAL)
+ | (key.Data.Contents.HasColor1 ? D3DMCS_COLOR2 : D3DMCS_MATERIAL)
+ : 0;
+
+ key.Data.Contents.UseLighting = lighting;
+ key.Data.Contents.NormalizeNormals = m_state.renderStates[D3DRS_NORMALIZENORMALS];
+ key.Data.Contents.LocalViewer = m_state.renderStates[D3DRS_LOCALVIEWER] && lighting;
+
+ key.Data.Contents.RangeFog = m_state.renderStates[D3DRS_RANGEFOGENABLE];
+
+ key.Data.Contents.DiffuseSource = m_state.renderStates[D3DRS_DIFFUSEMATERIALSOURCE] & mask;
+ key.Data.Contents.AmbientSource = m_state.renderStates[D3DRS_AMBIENTMATERIALSOURCE] & mask;
+ key.Data.Contents.SpecularSource = m_state.renderStates[D3DRS_SPECULARMATERIALSOURCE] & mask;
+ key.Data.Contents.EmissiveSource = m_state.renderStates[D3DRS_EMISSIVEMATERIALSOURCE] & mask;
+
+ uint32_t lightCount = 0;
+
+ if (key.Data.Contents.UseLighting) {
+ for (uint32_t i = 0; i < caps::MaxEnabledLights; i++) {
+ if (m_state.enabledLightIndices[i] != UINT32_MAX)
+ lightCount++;
+ }
+ }
+
+ key.Data.Contents.LightCount = lightCount;
+
+ for (uint32_t i = 0; i < caps::MaxTextureBlendStages; i++) {
+ uint32_t transformFlags = m_state.textureStages[i][DXVK_TSS_TEXTURETRANSFORMFLAGS] & ~(D3DTTFF_PROJECTED);
+ uint32_t index = m_state.textureStages[i][DXVK_TSS_TEXCOORDINDEX];
+ uint32_t indexFlags = (index & TCIMask) >> TCIOffset;
+
+ transformFlags &= 0b111;
+ index &= 0b111;
+
+ key.Data.Contents.TransformFlags |= transformFlags << (i * 3);
+ key.Data.Contents.TexcoordFlags |= indexFlags << (i * 3);
+ key.Data.Contents.TexcoordIndices |= index << (i * 3);
+ }
+
+ key.Data.Contents.TexcoordDeclMask = m_state.vertexDecl != nullptr ? m_state.vertexDecl->GetTexcoordMask() : 0;
+
+ key.Data.Contents.VertexBlendMode = uint32_t(vertexBlendMode);
+
+ if (vertexBlendMode == D3D9FF_VertexBlendMode_Normal) {
+ key.Data.Contents.VertexBlendIndexed = indexedVertexBlend;
+ key.Data.Contents.VertexBlendCount = m_state.renderStates[D3DRS_VERTEXBLEND] & 0xff;
+ }
+
+ key.Data.Contents.VertexClipping = IsClipPlaneEnabled();
+
+ EmitCs([
+ this,
+ cKey = key,
+ &cShaders = m_ffModules
+ ](DxvkContext* ctx) {
+ auto shader = cShaders.GetShaderModule(this, cKey);
+ ctx->bindShader(VK_SHADER_STAGE_VERTEX_BIT, shader.GetShader());
+ });
+ }
+
+ if (hasPositionT && (m_flags.test(D3D9DeviceFlag::DirtyFFViewport) || m_ffZTest != IsZTestEnabled())) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFViewport);
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ const auto& vp = m_state.viewport;
+ // For us to account for the Vulkan viewport rules
+ // when translating Window Coords -> Real Coords:
+ // We need to negate the inverse extent we multiply by,
+ // this follows through to the offset when that gets
+ // timesed by it.
+ // The 1.0f additional offset however does not,
+ // so we account for that there manually.
+
+ m_ffZTest = IsZTestEnabled();
+
+ m_viewportInfo.inverseExtent = Vector4(
+ 2.0f / float(vp.Width),
+ -2.0f / float(vp.Height),
+ m_ffZTest ? 1.0f : 0.0f,
+ 1.0f);
+
+ m_viewportInfo.inverseOffset = Vector4(
+ -float(vp.X), -float(vp.Y),
+ 0.0f, 0.0f);
+
+ m_viewportInfo.inverseOffset = m_viewportInfo.inverseOffset * m_viewportInfo.inverseExtent;
+
+ m_viewportInfo.inverseOffset = m_viewportInfo.inverseOffset + Vector4(-1.0f, 1.0f, 0.0f, 0.0f);
+ }
+
+ // Constants...
+ if (m_flags.test(D3D9DeviceFlag::DirtyFFVertexData)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFVertexData);
+
+ DxvkBufferSliceHandle slice = m_vsFixedFunction->allocSlice();
+
+ EmitCs([
+ cBuffer = m_vsFixedFunction,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+
+ auto WorldView = m_state.transforms[GetTransformIndex(D3DTS_VIEW)] * m_state.transforms[GetTransformIndex(D3DTS_WORLD)];
+ auto NormalMatrix = inverse(WorldView);
+
+ D3D9FixedFunctionVS* data = reinterpret_cast<D3D9FixedFunctionVS*>(slice.mapPtr);
+ data->WorldView = WorldView;
+ data->NormalMatrix = NormalMatrix;
+ data->InverseView = transpose(inverse(m_state.transforms[GetTransformIndex(D3DTS_VIEW)]));
+ data->Projection = m_state.transforms[GetTransformIndex(D3DTS_PROJECTION)];
+
+ for (uint32_t i = 0; i < data->TexcoordMatrices.size(); i++)
+ data->TexcoordMatrices[i] = m_state.transforms[GetTransformIndex(D3DTS_TEXTURE0) + i];
+
+ data->ViewportInfo = m_viewportInfo;
+
+ DecodeD3DCOLOR(m_state.renderStates[D3DRS_AMBIENT], data->GlobalAmbient.data);
+
+ uint32_t lightIdx = 0;
+ for (uint32_t i = 0; i < caps::MaxEnabledLights; i++) {
+ auto idx = m_state.enabledLightIndices[i];
+ if (idx == UINT32_MAX)
+ continue;
+
+ data->Lights[lightIdx++] = D3D9Light(m_state.lights[idx].value(), m_state.transforms[GetTransformIndex(D3DTS_VIEW)]);
+ }
+
+ data->Material = m_state.material;
+ data->TweenFactor = bit::cast<float>(m_state.renderStates[D3DRS_TWEENFACTOR]);
+ }
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFFVertexBlend) && vertexBlendMode == D3D9FF_VertexBlendMode_Normal) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFVertexBlend);
+
+ DxvkBufferSliceHandle slice = m_vsVertexBlend->allocSlice();
+
+ EmitCs([
+ cBuffer = m_vsVertexBlend,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+
+ auto UploadVertexBlendData = [&](auto data) {
+ for (uint32_t i = 0; i < std::size(data->WorldView); i++)
+ data->WorldView[i] = m_state.transforms[GetTransformIndex(D3DTS_VIEW)] * m_state.transforms[GetTransformIndex(D3DTS_WORLDMATRIX(i))];
+ };
+
+ (m_isSWVP && indexedVertexBlend)
+ ? UploadVertexBlendData(reinterpret_cast<D3D9FixedFunctionVertexBlendDataSW*>(slice.mapPtr))
+ : UploadVertexBlendData(reinterpret_cast<D3D9FixedFunctionVertexBlendDataHW*>(slice.mapPtr));
+ }
+ }
+
+
+ void D3D9DeviceEx::UpdateFixedFunctionPS() {
+ // Shader...
+ if (m_flags.test(D3D9DeviceFlag::DirtyFFPixelShader) || m_lastSamplerTypesFF != m_textureTypes) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFPixelShader);
+ m_lastSamplerTypesFF = m_textureTypes;
+
+ // Used args for a given operation.
+ auto ArgsMask = [](DWORD Op) {
+ switch (Op) {
+ case D3DTOP_DISABLE:
+ return 0b000u; // No Args
+ case D3DTOP_SELECTARG1:
+ case D3DTOP_PREMODULATE:
+ return 0b010u; // Arg 1
+ case D3DTOP_SELECTARG2:
+ return 0b100u; // Arg 2
+ case D3DTOP_MULTIPLYADD:
+ case D3DTOP_LERP:
+ return 0b111u; // Arg 0, 1, 2
+ default:
+ return 0b110u; // Arg 1, 2
+ }
+ };
+
+ D3D9FFShaderKeyFS key;
+
+ uint32_t idx;
+ for (idx = 0; idx < caps::TextureStageCount; idx++) {
+ auto& stage = key.Stages[idx].Contents;
+ auto& data = m_state.textureStages[idx];
+
+ // Subsequent stages do not occur if this is true.
+ if (data[DXVK_TSS_COLOROP] == D3DTOP_DISABLE)
+ break;
+
+ // If the stage is invalid (ie. no texture bound),
+ // this and all subsequent stages get disabled.
+ if (m_state.textures[idx] == nullptr) {
+ if (((data[DXVK_TSS_COLORARG0] & D3DTA_SELECTMASK) == D3DTA_TEXTURE && (ArgsMask(data[DXVK_TSS_COLOROP]) & (1 << 0u)))
+ || ((data[DXVK_TSS_COLORARG1] & D3DTA_SELECTMASK) == D3DTA_TEXTURE && (ArgsMask(data[DXVK_TSS_COLOROP]) & (1 << 1u)))
+ || ((data[DXVK_TSS_COLORARG2] & D3DTA_SELECTMASK) == D3DTA_TEXTURE && (ArgsMask(data[DXVK_TSS_COLOROP]) & (1 << 2u))))
+ break;
+ }
+
+ stage.ColorOp = data[DXVK_TSS_COLOROP];
+ stage.AlphaOp = data[DXVK_TSS_ALPHAOP];
+
+ stage.ColorArg0 = data[DXVK_TSS_COLORARG0];
+ stage.ColorArg1 = data[DXVK_TSS_COLORARG1];
+ stage.ColorArg2 = data[DXVK_TSS_COLORARG2];
+
+ stage.AlphaArg0 = data[DXVK_TSS_ALPHAARG0];
+ stage.AlphaArg1 = data[DXVK_TSS_ALPHAARG1];
+ stage.AlphaArg2 = data[DXVK_TSS_ALPHAARG2];
+
+ const uint32_t samplerOffset = idx * 2;
+ stage.Type = (m_textureTypes >> samplerOffset) & 0xffu;
+ stage.ResultIsTemp = data[DXVK_TSS_RESULTARG] == D3DTA_TEMP;
+
+ uint32_t ttff = data[DXVK_TSS_TEXTURETRANSFORMFLAGS];
+ uint32_t count = ttff & ~D3DTTFF_PROJECTED;
+
+ stage.Projected = (ttff & D3DTTFF_PROJECTED) ? 1 : 0;
+ stage.ProjectedCount = (ttff & D3DTTFF_PROJECTED) ? count : 0;
+ }
+
+ auto& stage0 = key.Stages[0].Contents;
+
+ if (stage0.ResultIsTemp &&
+ stage0.ColorOp != D3DTOP_DISABLE &&
+ stage0.AlphaOp == D3DTOP_DISABLE) {
+ stage0.AlphaOp = D3DTOP_SELECTARG1;
+ stage0.AlphaArg1 = D3DTA_DIFFUSE;
+ }
+
+ stage0.GlobalSpecularEnable = m_state.renderStates[D3DRS_SPECULARENABLE];
+ stage0.GlobalFlatShade = m_state.renderStates[D3DRS_SHADEMODE] == D3DSHADE_FLAT;
+
+ // The last stage *always* writes to current.
+ if (idx >= 1)
+ key.Stages[idx - 1].Contents.ResultIsTemp = false;
+
+ EmitCs([
+ this,
+ cKey = key,
+ &cShaders = m_ffModules
+ ](DxvkContext* ctx) {
+ auto shader = cShaders.GetShaderModule(this, cKey);
+ ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, shader.GetShader());
+ });
+ }
+
+ // Constants
+
+ if (m_flags.test(D3D9DeviceFlag::DirtyFFPixelData)) {
+ m_flags.clr(D3D9DeviceFlag::DirtyFFPixelData);
+
+ DxvkBufferSliceHandle slice = m_psFixedFunction->allocSlice();
+
+ EmitCs([
+ cBuffer = m_psFixedFunction,
+ cSlice = slice
+ ] (DxvkContext* ctx) {
+ ctx->invalidateBuffer(cBuffer, cSlice);
+ });
+
+ auto& rs = m_state.renderStates;
+
+ D3D9FixedFunctionPS* data = reinterpret_cast<D3D9FixedFunctionPS*>(slice.mapPtr);
+ DecodeD3DCOLOR((D3DCOLOR)rs[D3DRS_TEXTUREFACTOR], data->textureFactor.data);
+ }
+ }
+
+
+ bool D3D9DeviceEx::UseProgrammableVS() {
+ if (!config::FixedFunctionEnabled)
+ return true;
+
+ return m_state.vertexShader != nullptr
+ && m_state.vertexDecl != nullptr
+ && !m_state.vertexDecl->TestFlag(D3D9VertexDeclFlag::HasPositionT);
+ }
+
+
+ bool D3D9DeviceEx::UseProgrammablePS() {
+ if (!config::FixedFunctionEnabled)
+ return true;
+
+ return m_state.pixelShader != nullptr;
+ }
+
+
+ void D3D9DeviceEx::UpdateBoolSpecConstantVertex(uint32_t value) {
+ if (value == m_lastBoolSpecConstantVertex)
+ return;
+
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::VertexShaderBools, cBitfield);
+ });
+
+ m_lastBoolSpecConstantVertex = value;
+ }
+
+
+ void D3D9DeviceEx::UpdateBoolSpecConstantPixel(uint32_t value) {
+ if (value == m_lastBoolSpecConstantPixel)
+ return;
+
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::PixelShaderBools, cBitfield);
+ });
+
+ m_lastBoolSpecConstantPixel = value;
+ }
+
+
+ void D3D9DeviceEx::UpdateSamplerSpecConsant(uint32_t value) {
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::SamplerType, cBitfield);
+ });
+
+ m_lastSamplerTypes = value;
+ }
+
+
+ void D3D9DeviceEx::UpdateProjectionSpecConstant(uint32_t value) {
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::ProjectionType, cBitfield);
+ });
+
+ m_lastProjectionBitfield = value;
+ }
+
+
+ void D3D9DeviceEx::UpdateFetch4SpecConstant(uint32_t value) {
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::Fetch4, cBitfield);
+ });
+
+ m_lastFetch4 = value;
+ }
+
+
+ void D3D9DeviceEx::UpdateSamplerDepthModeSpecConstant(uint32_t value) {
+ EmitCs([cBitfield = value](DxvkContext* ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, D3D9SpecConstantId::SamplerDepthMode, cBitfield);
+ });
+
+ m_lastSamplerDepthMode = value;
+ }
+
+
+ void D3D9DeviceEx::ApplyPrimitiveType(
+ DxvkContext* pContext,
+ D3DPRIMITIVETYPE PrimType) {
+ if (m_iaState.primitiveType != PrimType) {
+ m_iaState.primitiveType = PrimType;
+
+ auto iaState = DecodeInputAssemblyState(PrimType);
+ pContext->setInputAssemblyState(iaState);
+ }
+ }
+
+
+ void D3D9DeviceEx::ResolveZ() {
+ D3D9Surface* src = m_state.depthStencil.ptr();
+ IDirect3DBaseTexture9* dst = m_state.textures[0];
+
+ if (unlikely(!src || !dst))
+ return;
+
+ D3D9CommonTexture* srcTextureInfo = GetCommonTexture(src);
+ D3D9CommonTexture* dstTextureInfo = GetCommonTexture(dst);
+
+ const D3D9_COMMON_TEXTURE_DESC* srcDesc = srcTextureInfo->Desc();
+ const D3D9_COMMON_TEXTURE_DESC* dstDesc = dstTextureInfo->Desc();
+
+ VkSampleCountFlagBits dstSampleCount;
+ DecodeMultiSampleType(dstDesc->MultiSample, dstDesc->MultisampleQuality, &dstSampleCount);
+
+ if (unlikely(dstSampleCount != VK_SAMPLE_COUNT_1_BIT)) {
+ Logger::warn("D3D9DeviceEx::ResolveZ: dstSampleCount != 1. Discarding.");
+ return;
+ }
+
+ const D3D9_VK_FORMAT_MAPPING srcFormatInfo = LookupFormat(srcDesc->Format);
+ const D3D9_VK_FORMAT_MAPPING dstFormatInfo = LookupFormat(dstDesc->Format);
+
+ auto srcVulkanFormatInfo = imageFormatInfo(srcFormatInfo.FormatColor);
+ auto dstVulkanFormatInfo = imageFormatInfo(dstFormatInfo.FormatColor);
+
+ const VkImageSubresource dstSubresource =
+ dstTextureInfo->GetSubresourceFromIndex(
+ dstVulkanFormatInfo->aspectMask, 0);
+
+ const VkImageSubresource srcSubresource =
+ srcTextureInfo->GetSubresourceFromIndex(
+ srcVulkanFormatInfo->aspectMask, src->GetSubresource());
+
+ const VkImageSubresourceLayers dstSubresourceLayers = {
+ dstSubresource.aspectMask,
+ dstSubresource.mipLevel,
+ dstSubresource.arrayLayer, 1 };
+
+ const VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ VkSampleCountFlagBits srcSampleCount;
+ DecodeMultiSampleType(srcDesc->MultiSample, srcDesc->MultisampleQuality, &srcSampleCount);
+
+ if (srcSampleCount == VK_SAMPLE_COUNT_1_BIT) {
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstLayers = dstSubresourceLayers,
+ cSrcLayers = srcSubresourceLayers
+ ] (DxvkContext* ctx) {
+ ctx->copyImage(
+ cDstImage, cDstLayers, VkOffset3D { 0, 0, 0 },
+ cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 },
+ cDstImage->mipLevelExtent(cDstLayers.mipLevel));
+ });
+ } else {
+ EmitCs([
+ cDstImage = dstTextureInfo->GetImage(),
+ cSrcImage = srcTextureInfo->GetImage(),
+ cDstSubres = dstSubresourceLayers,
+ cSrcSubres = srcSubresourceLayers
+ ] (DxvkContext* ctx) {
+ // We should resolve using the first sample according to
+ // http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Advanced-DX9-Capabilities-for-ATI-Radeon-Cards_v2.pdf
+ // "The resolve operation copies the depth value from the *first sample only* into the resolved depth stencil texture."
+ constexpr auto resolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;
+
+ VkImageResolve region;
+ region.srcSubresource = cSrcSubres;
+ region.srcOffset = VkOffset3D { 0, 0, 0 };
+ region.dstSubresource = cDstSubres;
+ region.dstOffset = VkOffset3D { 0, 0, 0 };
+ region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel);
+
+ ctx->resolveDepthStencilImage(cDstImage, cSrcImage, region, resolveMode, resolveMode);
+ });
+ }
+
+ dstTextureInfo->MarkAllWrittenByGPU();
+ }
+
+
+ void D3D9DeviceEx::TransitionImage(D3D9CommonTexture* pResource, VkImageLayout NewLayout) {
+ EmitCs([
+ cImage = pResource->GetImage(),
+ cNewLayout = NewLayout
+ ] (DxvkContext* ctx) {
+ ctx->changeImageLayout(
+ cImage, cNewLayout);
+ });
+ }
+
+
+ void D3D9DeviceEx::TransformImage(
+ D3D9CommonTexture* pResource,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout) {
+ EmitCs([
+ cImage = pResource->GetImage(),
+ cSubresources = *pSubresources,
+ cOldLayout = OldLayout,
+ cNewLayout = NewLayout
+ ] (DxvkContext* ctx) {
+ ctx->transformImage(
+ cImage, cSubresources,
+ cOldLayout, cNewLayout);
+ });
+ }
+
+
+ HRESULT D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
+ if (!pPresentationParameters->EnableAutoDepthStencil)
+ SetDepthStencilSurface(nullptr);
+
+ for (uint32_t i = 1; i < caps::MaxSimultaneousRenderTargets; i++)
+ SetRenderTarget(i, nullptr);
+
+ auto& rs = m_state.renderStates;
+
+ rs[D3DRS_SEPARATEALPHABLENDENABLE] = FALSE;
+ rs[D3DRS_ALPHABLENDENABLE] = FALSE;
+ rs[D3DRS_BLENDOP] = D3DBLENDOP_ADD;
+ rs[D3DRS_BLENDOPALPHA] = D3DBLENDOP_ADD;
+ rs[D3DRS_DESTBLEND] = D3DBLEND_ZERO;
+ rs[D3DRS_DESTBLENDALPHA] = D3DBLEND_ZERO;
+ rs[D3DRS_COLORWRITEENABLE] = 0x0000000f;
+ rs[D3DRS_COLORWRITEENABLE1] = 0x0000000f;
+ rs[D3DRS_COLORWRITEENABLE2] = 0x0000000f;
+ rs[D3DRS_COLORWRITEENABLE3] = 0x0000000f;
+ rs[D3DRS_SRCBLEND] = D3DBLEND_ONE;
+ rs[D3DRS_SRCBLENDALPHA] = D3DBLEND_ONE;
+ BindBlendState();
+
+ rs[D3DRS_BLENDFACTOR] = 0xffffffff;
+ BindBlendFactor();
+
+ rs[D3DRS_ZENABLE] = pPresentationParameters->EnableAutoDepthStencil
+ ? D3DZB_TRUE
+ : D3DZB_FALSE;
+ rs[D3DRS_ZFUNC] = D3DCMP_LESSEQUAL;
+ rs[D3DRS_TWOSIDEDSTENCILMODE] = FALSE;
+ rs[D3DRS_ZWRITEENABLE] = TRUE;
+ rs[D3DRS_STENCILENABLE] = FALSE;
+ rs[D3DRS_STENCILFAIL] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_STENCILZFAIL] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_STENCILPASS] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_STENCILFUNC] = D3DCMP_ALWAYS;
+ rs[D3DRS_CCW_STENCILFAIL] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_CCW_STENCILZFAIL] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_CCW_STENCILPASS] = D3DSTENCILOP_KEEP;
+ rs[D3DRS_CCW_STENCILFUNC] = D3DCMP_ALWAYS;
+ rs[D3DRS_STENCILMASK] = 0xFFFFFFFF;
+ rs[D3DRS_STENCILWRITEMASK] = 0xFFFFFFFF;
+ BindDepthStencilState();
+
+ rs[D3DRS_STENCILREF] = 0;
+ BindDepthStencilRefrence();
+
+ rs[D3DRS_FILLMODE] = D3DFILL_SOLID;
+ rs[D3DRS_CULLMODE] = D3DCULL_CCW;
+ rs[D3DRS_DEPTHBIAS] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_SLOPESCALEDEPTHBIAS] = bit::cast<DWORD>(0.0f);
+ BindRasterizerState();
+ BindDepthBias();
+
+ rs[D3DRS_SCISSORTESTENABLE] = FALSE;
+
+ rs[D3DRS_ALPHATESTENABLE] = FALSE;
+ rs[D3DRS_ALPHAFUNC] = D3DCMP_ALWAYS;
+ BindAlphaTestState();
+ rs[D3DRS_ALPHAREF] = 0;
+ UpdatePushConstant<D3D9RenderStateItem::AlphaRef>();
+
+ rs[D3DRS_MULTISAMPLEMASK] = 0xffffffff;
+ BindMultiSampleState();
+
+ rs[D3DRS_TEXTUREFACTOR] = 0xffffffff;
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelData);
+
+ rs[D3DRS_DIFFUSEMATERIALSOURCE] = D3DMCS_COLOR1;
+ rs[D3DRS_SPECULARMATERIALSOURCE] = D3DMCS_COLOR2;
+ rs[D3DRS_AMBIENTMATERIALSOURCE] = D3DMCS_MATERIAL;
+ rs[D3DRS_EMISSIVEMATERIALSOURCE] = D3DMCS_MATERIAL;
+ rs[D3DRS_LIGHTING] = TRUE;
+ rs[D3DRS_COLORVERTEX] = TRUE;
+ rs[D3DRS_LOCALVIEWER] = TRUE;
+ rs[D3DRS_RANGEFOGENABLE] = FALSE;
+ rs[D3DRS_NORMALIZENORMALS] = FALSE;
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexShader);
+
+ // PS
+ rs[D3DRS_SPECULARENABLE] = FALSE;
+
+ rs[D3DRS_AMBIENT] = 0;
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexData);
+
+ rs[D3DRS_FOGENABLE] = FALSE;
+ rs[D3DRS_FOGCOLOR] = 0;
+ rs[D3DRS_FOGTABLEMODE] = D3DFOG_NONE;
+ rs[D3DRS_FOGSTART] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_FOGEND] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_FOGDENSITY] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_FOGVERTEXMODE] = D3DFOG_NONE;
+ m_flags.set(D3D9DeviceFlag::DirtyFogColor);
+ m_flags.set(D3D9DeviceFlag::DirtyFogDensity);
+ m_flags.set(D3D9DeviceFlag::DirtyFogEnd);
+ m_flags.set(D3D9DeviceFlag::DirtyFogScale);
+ m_flags.set(D3D9DeviceFlag::DirtyFogState);
+
+ rs[D3DRS_CLIPPLANEENABLE] = 0;
+ m_flags.set(D3D9DeviceFlag::DirtyClipPlanes);
+
+ rs[D3DRS_POINTSPRITEENABLE] = FALSE;
+ rs[D3DRS_POINTSCALEENABLE] = FALSE;
+ rs[D3DRS_POINTSCALE_A] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_POINTSCALE_B] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_POINTSCALE_C] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_POINTSIZE] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_POINTSIZE_MIN] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_POINTSIZE_MAX] = bit::cast<DWORD>(64.0f);
+ UpdatePushConstant<D3D9RenderStateItem::PointSize>();
+ UpdatePushConstant<D3D9RenderStateItem::PointSizeMin>();
+ UpdatePushConstant<D3D9RenderStateItem::PointSizeMax>();
+ m_flags.set(D3D9DeviceFlag::DirtyPointScale);
+ UpdatePointMode<false>();
+
+ rs[D3DRS_SRGBWRITEENABLE] = 0;
+
+ rs[D3DRS_SHADEMODE] = D3DSHADE_GOURAUD;
+
+ rs[D3DRS_VERTEXBLEND] = D3DVBF_DISABLE;
+ rs[D3DRS_INDEXEDVERTEXBLENDENABLE] = FALSE;
+ rs[D3DRS_TWEENFACTOR] = bit::cast<DWORD>(0.0f);
+ m_flags.set(D3D9DeviceFlag::DirtyFFVertexBlend);
+
+ // Render States not implemented beyond this point.
+ rs[D3DRS_LASTPIXEL] = TRUE;
+ rs[D3DRS_DITHERENABLE] = FALSE;
+ rs[D3DRS_WRAP0] = 0;
+ rs[D3DRS_WRAP1] = 0;
+ rs[D3DRS_WRAP2] = 0;
+ rs[D3DRS_WRAP3] = 0;
+ rs[D3DRS_WRAP4] = 0;
+ rs[D3DRS_WRAP5] = 0;
+ rs[D3DRS_WRAP6] = 0;
+ rs[D3DRS_WRAP7] = 0;
+ rs[D3DRS_CLIPPING] = TRUE;
+ rs[D3DRS_MULTISAMPLEANTIALIAS] = TRUE;
+ rs[D3DRS_PATCHEDGESTYLE] = D3DPATCHEDGE_DISCRETE;
+ rs[D3DRS_DEBUGMONITORTOKEN] = D3DDMT_ENABLE;
+ rs[D3DRS_POSITIONDEGREE] = D3DDEGREE_CUBIC;
+ rs[D3DRS_NORMALDEGREE] = D3DDEGREE_LINEAR;
+ rs[D3DRS_ANTIALIASEDLINEENABLE] = FALSE;
+ rs[D3DRS_MINTESSELLATIONLEVEL] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_MAXTESSELLATIONLEVEL] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_ADAPTIVETESS_X] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_ADAPTIVETESS_Y] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_ADAPTIVETESS_Z] = bit::cast<DWORD>(1.0f);
+ rs[D3DRS_ADAPTIVETESS_W] = bit::cast<DWORD>(0.0f);
+ rs[D3DRS_ENABLEADAPTIVETESSELLATION] = FALSE;
+ rs[D3DRS_WRAP8] = 0;
+ rs[D3DRS_WRAP9] = 0;
+ rs[D3DRS_WRAP10] = 0;
+ rs[D3DRS_WRAP11] = 0;
+ rs[D3DRS_WRAP12] = 0;
+ rs[D3DRS_WRAP13] = 0;
+ rs[D3DRS_WRAP14] = 0;
+ rs[D3DRS_WRAP15] = 0;
+ // End Unimplemented Render States
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ auto& stage = m_state.textureStages[i];
+
+ stage[DXVK_TSS_COLOROP] = i == 0 ? D3DTOP_MODULATE : D3DTOP_DISABLE;
+ stage[DXVK_TSS_COLORARG1] = D3DTA_TEXTURE;
+ stage[DXVK_TSS_COLORARG2] = D3DTA_CURRENT;
+ stage[DXVK_TSS_ALPHAOP] = i == 0 ? D3DTOP_SELECTARG1 : D3DTOP_DISABLE;
+ stage[DXVK_TSS_ALPHAARG1] = D3DTA_TEXTURE;
+ stage[DXVK_TSS_ALPHAARG2] = D3DTA_CURRENT;
+ stage[DXVK_TSS_BUMPENVMAT00] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_BUMPENVMAT01] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_BUMPENVMAT10] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_BUMPENVMAT11] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_TEXCOORDINDEX] = i;
+ stage[DXVK_TSS_BUMPENVLSCALE] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_BUMPENVLOFFSET] = bit::cast<DWORD>(0.0f);
+ stage[DXVK_TSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE;
+ stage[DXVK_TSS_COLORARG0] = D3DTA_CURRENT;
+ stage[DXVK_TSS_ALPHAARG0] = D3DTA_CURRENT;
+ stage[DXVK_TSS_RESULTARG] = D3DTA_CURRENT;
+ stage[DXVK_TSS_CONSTANT] = 0x00000000;
+ }
+ m_flags.set(D3D9DeviceFlag::DirtySharedPixelShaderData);
+ m_flags.set(D3D9DeviceFlag::DirtyFFPixelShader);
+
+ for (uint32_t i = 0; i < caps::MaxStreams; i++)
+ m_state.streamFreq[i] = 1;
+
+ for (uint32_t i = 0; i < m_state.textures.size(); i++)
+ TextureChangePrivate(m_state.textures[i], nullptr);
+
+ EmitCs([
+ cSize = m_state.textures.size()
+ ](DxvkContext* ctx) {
+ for (uint32_t i = 0; i < cSize; i++) {
+ auto samplerInfo = RemapStateSamplerShader(DWORD(i));
+ uint32_t slot = computeResourceSlotId(samplerInfo.first, DxsoBindingType::Image, uint32_t(samplerInfo.second));
+ ctx->bindResourceView(slot, nullptr, nullptr);
+ }
+ });
+
+ m_dirtyTextures = 0;
+ m_depthTextures = 0;
+
+ auto& ss = m_state.samplerStates;
+ for (uint32_t i = 0; i < ss.size(); i++) {
+ auto& state = ss[i];
+ state[D3DSAMP_ADDRESSU] = D3DTADDRESS_WRAP;
+ state[D3DSAMP_ADDRESSV] = D3DTADDRESS_WRAP;
+ state[D3DSAMP_ADDRESSW] = D3DTADDRESS_WRAP;
+ state[D3DSAMP_BORDERCOLOR] = 0x00000000;
+ state[D3DSAMP_MAGFILTER] = D3DTEXF_POINT;
+ state[D3DSAMP_MINFILTER] = D3DTEXF_POINT;
+ state[D3DSAMP_MIPFILTER] = D3DTEXF_NONE;
+ state[D3DSAMP_MIPMAPLODBIAS] = bit::cast<DWORD>(0.0f);
+ state[D3DSAMP_MAXMIPLEVEL] = 0;
+ state[D3DSAMP_MAXANISOTROPY] = 1;
+ state[D3DSAMP_SRGBTEXTURE] = 0;
+ state[D3DSAMP_ELEMENTINDEX] = 0;
+ state[D3DSAMP_DMAPOFFSET] = 0;
+
+ BindSampler(i);
+ }
+
+ m_dirtySamplerStates = 0;
+
+ for (uint32_t i = 0; i < caps::MaxClipPlanes; i++) {
+ float plane[4] = { 0, 0, 0, 0 };
+ SetClipPlane(i, plane);
+ }
+
+ // We should do this...
+ m_flags.set(D3D9DeviceFlag::DirtyInputLayout);
+
+ UpdateSamplerSpecConsant(0u);
+ UpdateBoolSpecConstantVertex(0u);
+ UpdateBoolSpecConstantPixel(0u);
+ UpdateSamplerDepthModeSpecConstant(0u);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ D3D9Format backBufferFmt = EnumerateFormat(pPresentationParameters->BackBufferFormat);
+
+ Logger::info(str::format(
+ "D3D9DeviceEx::ResetSwapChain:\n",
+ " Requested Presentation Parameters\n",
+ " - Width: ", pPresentationParameters->BackBufferWidth, "\n",
+ " - Height: ", pPresentationParameters->BackBufferHeight, "\n",
+ " - Format: ", backBufferFmt, "\n"
+ " - Auto Depth Stencil: ", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false", "\n",
+ " ^ Format: ", EnumerateFormat(pPresentationParameters->AutoDepthStencilFormat), "\n",
+ " - Windowed: ", pPresentationParameters->Windowed ? "true" : "false", "\n"));
+
+ if (backBufferFmt != D3D9Format::Unknown) {
+ if (!IsSupportedBackBufferFormat(backBufferFmt)) {
+ Logger::err(str::format("D3D9DeviceEx::ResetSwapChain: Unsupported backbuffer format: ",
+ EnumerateFormat(pPresentationParameters->BackBufferFormat)));
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+ if (m_implicitSwapchain != nullptr) {
+ if (FAILED(m_implicitSwapchain->Reset(pPresentationParameters, pFullscreenDisplayMode)))
+ return D3DERR_INVALIDCALL;
+ }
+ else
+ m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
+
+ if (pPresentationParameters->EnableAutoDepthStencil) {
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = pPresentationParameters->BackBufferWidth;
+ desc.Height = pPresentationParameters->BackBufferHeight;
+ desc.Depth = 1;
+ desc.ArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Usage = D3DUSAGE_DEPTHSTENCIL;
+ desc.Format = EnumerateFormat(pPresentationParameters->AutoDepthStencilFormat);
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.Discard = FALSE;
+ desc.MultiSample = pPresentationParameters->MultiSampleType;
+ desc.MultisampleQuality = pPresentationParameters->MultiSampleQuality;
+ desc.IsBackBuffer = FALSE;
+ desc.IsAttachmentOnly = TRUE;
+
+ if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
+ return D3DERR_NOTAVAILABLE;
+
+ m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr);
+ m_initializer->InitTexture(m_autoDepthStencil->GetCommonTexture());
+ SetDepthStencilSurface(m_autoDepthStencil.ptr());
+ }
+
+ SetRenderTarget(0, m_implicitSwapchain->GetBackBuffer(0));
+
+ // Force this if we end up binding the same RT to make scissor change go into effect.
+ BindViewportAndScissor();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9DeviceEx::InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ HRESULT hr = ResetSwapChain(pPresentationParameters, pFullscreenDisplayMode);
+ if (FAILED(hr))
+ return hr;
+
+ hr = ResetState(pPresentationParameters);
+ if (FAILED(hr))
+ return hr;
+
+ Flush();
+ SynchronizeCsThread();
+
+ return D3D_OK;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.h
new file mode 100644
index 00000000..57260419
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device.h
@@ -0,0 +1,1250 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+#include "../dxvk/dxvk_cs.h"
+
+#include "d3d9_include.h"
+#include "d3d9_cursor.h"
+#include "d3d9_format.h"
+#include "d3d9_multithread.h"
+#include "d3d9_adapter.h"
+#include "d3d9_constant_set.h"
+
+#include "d3d9_state.h"
+
+#include "d3d9_options.h"
+
+#include "../dxso/dxso_module.h"
+#include "../dxso/dxso_util.h"
+#include "../dxso/dxso_options.h"
+#include "../dxso/dxso_modinfo.h"
+
+#include "d3d9_sampler.h"
+#include "d3d9_fixed_function.h"
+#include "d3d9_swvp_emu.h"
+#include "d3d9_config.h"
+
+#include "d3d9_shader_permutations.h"
+
+#include <vector>
+#include <type_traits>
+#include <unordered_map>
+
+namespace dxvk {
+
+ class D3D9InterfaceEx;
+ class D3D9SwapChainEx;
+ class D3D9CommonTexture;
+ class D3D9CommonBuffer;
+ class D3D9CommonShader;
+ class D3D9ShaderModuleSet;
+ class D3D9Initializer;
+ class D3D9Query;
+ class D3D9StateBlock;
+ class D3D9FormatHelper;
+
+ enum class D3D9DeviceFlag : uint32_t {
+ DirtyFramebuffer,
+ DirtyClipPlanes,
+ DirtyDepthStencilState,
+ DirtyBlendState,
+ DirtyRasterizerState,
+ DirtyDepthBias,
+ DirtyAlphaTestState,
+ DirtyInputLayout,
+ DirtyViewportScissor,
+ DirtyMultiSampleState,
+
+ DirtyFogState,
+ DirtyFogColor,
+ DirtyFogDensity,
+ DirtyFogScale,
+ DirtyFogEnd,
+
+ DirtyFFVertexData,
+ DirtyFFVertexBlend,
+ DirtyFFVertexShader,
+ DirtyFFPixelShader,
+ DirtyFFViewport,
+ DirtyFFPixelData,
+ DirtyProgVertexShader,
+ DirtySharedPixelShaderData,
+ ValidSampleMask,
+ DirtyDepthBounds,
+ DirtyPointScale,
+
+ InScene,
+ };
+
+ using D3D9DeviceFlags = Flags<D3D9DeviceFlag>;
+
+ struct D3D9DrawInfo {
+ uint32_t vertexCount;
+ uint32_t instanceCount;
+ };
+
+ struct D3D9BufferSlice {
+ DxvkBufferSlice slice = {};
+ void* mapPtr = nullptr;
+ };
+
+ class D3D9DeviceEx final : public ComObjectClamp<IDirect3DDevice9Ex> {
+ constexpr static uint32_t DefaultFrameLatency = 3;
+ constexpr static uint32_t MaxFrameLatency = 20;
+
+ constexpr static uint32_t MinFlushIntervalUs = 750;
+ constexpr static uint32_t IncFlushIntervalUs = 250;
+ constexpr static uint32_t MaxPendingSubmits = 6;
+
+ constexpr static uint32_t NullStreamIdx = caps::MaxStreams;
+
+ friend class D3D9SwapChainEx;
+ public:
+
+ D3D9DeviceEx(
+ D3D9InterfaceEx* pParent,
+ D3D9Adapter* pAdapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ Rc<DxvkDevice> dxvkDevice);
+
+ ~D3D9DeviceEx();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE TestCooperativeLevel();
+
+ UINT STDMETHODCALLTYPE GetAvailableTextureMem();
+
+ HRESULT STDMETHODCALLTYPE EvictManagedResources();
+
+ HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D9** ppD3D9);
+
+ HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS9* pCaps);
+
+ HRESULT STDMETHODCALLTYPE GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode);
+
+ HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters);
+
+ HRESULT STDMETHODCALLTYPE SetCursorProperties(
+ UINT XHotSpot,
+ UINT YHotSpot,
+ IDirect3DSurface9* pCursorBitmap);
+
+ void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags);
+
+ BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow);
+
+ HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ IDirect3DSwapChain9** ppSwapChain);
+
+ HRESULT STDMETHODCALLTYPE GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain);
+
+ UINT STDMETHODCALLTYPE GetNumberOfSwapChains();
+
+ HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS* pPresentationParameters);
+
+ HRESULT STDMETHODCALLTYPE Present(
+ const RECT* pSourceRect,
+ const RECT* pDestRect, HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion);
+
+ HRESULT STDMETHODCALLTYPE GetBackBuffer(
+ UINT iSwapChain,
+ UINT iBackBuffer,
+ D3DBACKBUFFER_TYPE Type,
+ IDirect3DSurface9** ppBackBuffer);
+
+ HRESULT STDMETHODCALLTYPE GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus);
+
+ HRESULT STDMETHODCALLTYPE SetDialogBoxMode(BOOL bEnableDialogs);
+
+ void STDMETHODCALLTYPE SetGammaRamp(
+ UINT iSwapChain,
+ DWORD Flags,
+ const D3DGAMMARAMP* pRamp);
+
+ void STDMETHODCALLTYPE GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp);
+
+ HRESULT STDMETHODCALLTYPE CreateTexture(
+ UINT Width,
+ UINT Height,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DTexture9** ppTexture,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateVolumeTexture(
+ UINT Width,
+ UINT Height,
+ UINT Depth,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DVolumeTexture9** ppVolumeTexture,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateCubeTexture(
+ UINT EdgeLength,
+ UINT Levels,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DCubeTexture9** ppCubeTexture,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateVertexBuffer(
+ UINT Length,
+ DWORD Usage,
+ DWORD FVF,
+ D3DPOOL Pool,
+ IDirect3DVertexBuffer9** ppVertexBuffer,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateIndexBuffer(
+ UINT Length,
+ DWORD Usage,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DIndexBuffer9** ppIndexBuffer,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateRenderTarget(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Lockable,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Discard,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE UpdateSurface(
+ IDirect3DSurface9* pSourceSurface,
+ const RECT* pSourceRect,
+ IDirect3DSurface9* pDestinationSurface,
+ const POINT* pDestPoint);
+
+ HRESULT STDMETHODCALLTYPE UpdateTexture(
+ IDirect3DBaseTexture9* pSourceTexture,
+ IDirect3DBaseTexture9* pDestinationTexture);
+
+ HRESULT STDMETHODCALLTYPE GetRenderTargetData(
+ IDirect3DSurface9* pRenderTarget,
+ IDirect3DSurface9* pDestSurface);
+
+ HRESULT STDMETHODCALLTYPE GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface);
+
+ HRESULT STDMETHODCALLTYPE StretchRect(
+ IDirect3DSurface9* pSourceSurface,
+ const RECT* pSourceRect,
+ IDirect3DSurface9* pDestSurface,
+ const RECT* pDestRect,
+ D3DTEXTUREFILTERTYPE Filter);
+
+ HRESULT STDMETHODCALLTYPE ColorFill(
+ IDirect3DSurface9* pSurface,
+ const RECT* pRect,
+ D3DCOLOR Color);
+
+ HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurface(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle);
+
+ HRESULT STDMETHODCALLTYPE SetRenderTarget(
+ DWORD RenderTargetIndex,
+ IDirect3DSurface9* pRenderTarget);
+
+ HRESULT STDMETHODCALLTYPE GetRenderTarget(
+ DWORD RenderTargetIndex,
+ IDirect3DSurface9** ppRenderTarget);
+
+ HRESULT STDMETHODCALLTYPE SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil);
+
+ HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface);
+
+ HRESULT STDMETHODCALLTYPE BeginScene();
+
+ HRESULT STDMETHODCALLTYPE EndScene();
+
+ HRESULT STDMETHODCALLTYPE Clear(
+ DWORD Count,
+ const D3DRECT* pRects,
+ DWORD Flags,
+ D3DCOLOR Color,
+ float Z,
+ DWORD Stencil);
+
+ HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX* pMatrix);
+
+ HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix);
+
+ HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE TransformState, const D3DMATRIX* pMatrix);
+
+ HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT9* pViewport);
+
+ HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT9* pViewport);
+
+ HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL9* pMaterial);
+
+ HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL9* pMaterial);
+
+ HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT9* pLight);
+
+ HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT9* pLight);
+
+ HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable);
+
+ HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL* pEnable);
+
+ HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float* pPlane);
+
+ HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float* pPlane);
+
+ HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
+
+ HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
+
+ HRESULT STDMETHODCALLTYPE CreateStateBlock(
+ D3DSTATEBLOCKTYPE Type,
+ IDirect3DStateBlock9** ppSB);
+
+ HRESULT STDMETHODCALLTYPE BeginStateBlock();
+
+ HRESULT STDMETHODCALLTYPE EndStateBlock(IDirect3DStateBlock9** ppSB);
+
+ HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS9* pClipStatus);
+
+ HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS9* pClipStatus);
+
+ HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture);
+
+ HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture);
+
+ HRESULT STDMETHODCALLTYPE GetTextureStageState(
+ DWORD Stage,
+ D3DTEXTURESTAGESTATETYPE Type,
+ DWORD* pValue);
+
+ HRESULT STDMETHODCALLTYPE SetTextureStageState(
+ DWORD Stage,
+ D3DTEXTURESTAGESTATETYPE Type,
+ DWORD Value);
+
+ HRESULT STDMETHODCALLTYPE GetSamplerState(
+ DWORD Sampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD* pValue);
+
+ HRESULT STDMETHODCALLTYPE SetSamplerState(
+ DWORD Sampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value);
+
+ HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD* pNumPasses);
+
+ HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY* pEntries);
+
+ HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries);
+
+ HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber);
+
+ HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT *PaletteNumber);
+
+ HRESULT STDMETHODCALLTYPE SetScissorRect(const RECT* pRect);
+
+ HRESULT STDMETHODCALLTYPE GetScissorRect(RECT* pRect);
+
+ HRESULT STDMETHODCALLTYPE SetSoftwareVertexProcessing(BOOL bSoftware);
+
+ BOOL STDMETHODCALLTYPE GetSoftwareVertexProcessing();
+
+ HRESULT STDMETHODCALLTYPE SetNPatchMode(float nSegments);
+
+ float STDMETHODCALLTYPE GetNPatchMode();
+
+ HRESULT STDMETHODCALLTYPE DrawPrimitive(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT StartVertex,
+ UINT PrimitiveCount);
+
+ HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(
+ D3DPRIMITIVETYPE PrimitiveType,
+ INT BaseVertexIndex,
+ UINT MinVertexIndex,
+ UINT NumVertices,
+ UINT StartIndex,
+ UINT PrimitiveCount);
+
+ HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT PrimitiveCount,
+ const void* pVertexStreamZeroData,
+ UINT VertexStreamZeroStride);
+
+ HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT MinVertexIndex,
+ UINT NumVertices,
+ UINT PrimitiveCount,
+ const void* pIndexData,
+ D3DFORMAT IndexDataFormat,
+ const void* pVertexStreamZeroData,
+ UINT VertexStreamZeroStride);
+
+ HRESULT STDMETHODCALLTYPE ProcessVertices(
+ UINT SrcStartIndex,
+ UINT DestIndex,
+ UINT VertexCount,
+ IDirect3DVertexBuffer9* pDestBuffer,
+ IDirect3DVertexDeclaration9* pVertexDecl,
+ DWORD Flags);
+
+ HRESULT STDMETHODCALLTYPE CreateVertexDeclaration(
+ const D3DVERTEXELEMENT9* pVertexElements,
+ IDirect3DVertexDeclaration9** ppDecl);
+
+ HRESULT STDMETHODCALLTYPE SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl);
+
+ HRESULT STDMETHODCALLTYPE GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl);
+
+ HRESULT STDMETHODCALLTYPE SetFVF(DWORD FVF);
+
+ HRESULT STDMETHODCALLTYPE GetFVF(DWORD* pFVF);
+
+ HRESULT STDMETHODCALLTYPE CreateVertexShader(
+ const DWORD* pFunction,
+ IDirect3DVertexShader9** ppShader);
+
+ HRESULT STDMETHODCALLTYPE SetVertexShader(IDirect3DVertexShader9* pShader);
+
+ HRESULT STDMETHODCALLTYPE GetVertexShader(IDirect3DVertexShader9** ppShader);
+
+ HRESULT STDMETHODCALLTYPE SetVertexShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT STDMETHODCALLTYPE GetVertexShaderConstantF(
+ UINT StartRegister,
+ float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT STDMETHODCALLTYPE SetVertexShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT STDMETHODCALLTYPE GetVertexShaderConstantI(
+ UINT StartRegister,
+ int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT STDMETHODCALLTYPE SetVertexShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount);
+
+ HRESULT STDMETHODCALLTYPE GetVertexShaderConstantB(
+ UINT StartRegister,
+ BOOL* pConstantData,
+ UINT BoolCount);
+
+ HRESULT STDMETHODCALLTYPE SetStreamSource(
+ UINT StreamNumber,
+ IDirect3DVertexBuffer9* pStreamData,
+ UINT OffsetInBytes,
+ UINT Stride);
+
+ HRESULT STDMETHODCALLTYPE GetStreamSource(
+ UINT StreamNumber,
+ IDirect3DVertexBuffer9** ppStreamData,
+ UINT* pOffsetInBytes,
+ UINT* pStride);
+
+ HRESULT STDMETHODCALLTYPE SetStreamSourceFreq(UINT StreamNumber, UINT Setting);
+
+ HRESULT STDMETHODCALLTYPE GetStreamSourceFreq(UINT StreamNumber, UINT* pSetting);
+
+ HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer9* pIndexData);
+
+ HRESULT STDMETHODCALLTYPE GetIndices(IDirect3DIndexBuffer9** ppIndexData);
+
+ HRESULT STDMETHODCALLTYPE CreatePixelShader(
+ const DWORD* pFunction,
+ IDirect3DPixelShader9** ppShader);
+
+ HRESULT STDMETHODCALLTYPE SetPixelShader(IDirect3DPixelShader9* pShader);
+
+ HRESULT STDMETHODCALLTYPE GetPixelShader(IDirect3DPixelShader9** ppShader);
+
+ HRESULT STDMETHODCALLTYPE SetPixelShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT STDMETHODCALLTYPE GetPixelShaderConstantF(
+ UINT StartRegister,
+ float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT STDMETHODCALLTYPE SetPixelShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT STDMETHODCALLTYPE GetPixelShaderConstantI(
+ UINT StartRegister,
+ int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT STDMETHODCALLTYPE SetPixelShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount);
+
+ HRESULT STDMETHODCALLTYPE GetPixelShaderConstantB(
+ UINT StartRegister,
+ BOOL* pConstantData,
+ UINT BoolCount);
+
+ HRESULT STDMETHODCALLTYPE DrawRectPatch(
+ UINT Handle,
+ const float* pNumSegs,
+ const D3DRECTPATCH_INFO* pRectPatchInfo);
+
+ HRESULT STDMETHODCALLTYPE DrawTriPatch(
+ UINT Handle,
+ const float* pNumSegs,
+ const D3DTRIPATCH_INFO* pTriPatchInfo);
+
+ HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle);
+
+ HRESULT STDMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery);
+
+ // Ex Methods
+
+ HRESULT STDMETHODCALLTYPE SetConvolutionMonoKernel(
+ UINT width,
+ UINT height,
+ float* rows,
+ float* columns);
+
+ HRESULT STDMETHODCALLTYPE ComposeRects(
+ IDirect3DSurface9* pSrc,
+ IDirect3DSurface9* pDst,
+ IDirect3DVertexBuffer9* pSrcRectDescs,
+ UINT NumRects,
+ IDirect3DVertexBuffer9* pDstRectDescs,
+ D3DCOMPOSERECTSOP Operation,
+ int Xoffset,
+ int Yoffset);
+
+ HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(INT* pPriority);
+
+ HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(INT Priority);
+
+ HRESULT STDMETHODCALLTYPE WaitForVBlank(UINT iSwapChain);
+
+ HRESULT STDMETHODCALLTYPE CheckResourceResidency(IDirect3DResource9** pResourceArray, UINT32 NumResources);
+
+ HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(UINT MaxLatency);
+
+ HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(UINT* pMaxLatency);
+
+ HRESULT STDMETHODCALLTYPE CheckDeviceState(HWND hDestinationWindow);
+
+ HRESULT STDMETHODCALLTYPE PresentEx(
+ const RECT* pSourceRect,
+ const RECT* pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion,
+ DWORD dwFlags);
+
+ HRESULT STDMETHODCALLTYPE CreateRenderTargetEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Lockable,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage);
+
+ HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurfaceEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DPOOL Pool,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage);
+
+ HRESULT STDMETHODCALLTYPE CreateDepthStencilSurfaceEx(
+ UINT Width,
+ UINT Height,
+ D3DFORMAT Format,
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ BOOL Discard,
+ IDirect3DSurface9** ppSurface,
+ HANDLE* pSharedHandle,
+ DWORD Usage);
+
+ HRESULT STDMETHODCALLTYPE ResetEx(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ HRESULT STDMETHODCALLTYPE GetDisplayModeEx(
+ UINT iSwapChain,
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation);
+
+ HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChainEx(
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ IDirect3DSwapChain9** ppSwapChain);
+
+ HRESULT SetStateSamplerState(
+ DWORD StateSampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value);
+
+ HRESULT SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture);
+
+ HRESULT SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix);
+
+ HRESULT SetStateTextureStageState(
+ DWORD Stage,
+ D3D9TextureStageStateTypes Type,
+ DWORD Value);
+
+ VkPipelineStageFlags GetEnabledShaderStages() const {
+ return m_dxvkDevice->getShaderPipelineStages();
+ }
+
+ static DxvkDeviceFeatures GetDeviceFeatures(const Rc<DxvkAdapter>& adapter);
+
+ bool SupportsSWVP();
+
+ bool IsExtended();
+
+ HWND GetWindow();
+
+ Rc<DxvkDevice> GetDXVKDevice() {
+ return m_dxvkDevice;
+ }
+
+ D3D9_VK_FORMAT_MAPPING LookupFormat(
+ D3D9Format Format) const;
+
+ const DxvkFormatInfo* UnsupportedFormatInfo(
+ D3D9Format Format) const;
+
+ bool WaitForResource(
+ const Rc<DxvkResource>& Resource,
+ DWORD MapFlags);
+
+ /**
+ * \brief Locks a subresource of an image
+ *
+ * \param [in] Subresource The subresource of the image to lock
+ * \param [out] pLockedBox The returned locked box of the image, containing data ptr and strides
+ * \param [in] pBox The region of the subresource to lock. This offsets the returned data ptr
+ * \param [in] Flags The D3DLOCK_* flags to lock the image with
+ * \returns \c D3D_OK if the parameters are valid or D3DERR_INVALIDCALL if it fails.
+ */
+ HRESULT LockImage(
+ D3D9CommonTexture* pResource,
+ UINT Face,
+ UINT Mip,
+ D3DLOCKED_BOX* pLockedBox,
+ const D3DBOX* pBox,
+ DWORD Flags);
+
+ uint32_t CalcImageLockOffset(
+ uint32_t SlicePitch,
+ uint32_t RowPitch,
+ const DxvkFormatInfo* FormatInfo,
+ const D3DBOX* pBox);
+
+ /**
+ * \brief Unlocks a subresource of an image
+ *
+ * Passthrough to device unlock.
+ * \param [in] Subresource The subresource of the image to unlock
+ * \returns \c D3D_OK if the parameters are valid or D3DERR_INVALIDCALL if it fails.
+ */
+ HRESULT UnlockImage(
+ D3D9CommonTexture* pResource,
+ UINT Face,
+ UINT MipLevel);
+
+ HRESULT FlushImage(
+ D3D9CommonTexture* pResource,
+ UINT Subresource);
+
+ void EmitGenerateMips(
+ D3D9CommonTexture* pResource);
+
+ HRESULT LockBuffer(
+ D3D9CommonBuffer* pResource,
+ UINT OffsetToLock,
+ UINT SizeToLock,
+ void** ppbData,
+ DWORD Flags);
+
+ HRESULT FlushBuffer(
+ D3D9CommonBuffer* pResource);
+
+ HRESULT UnlockBuffer(
+ D3D9CommonBuffer* pResource);
+
+ void SetupFPU();
+
+ int64_t DetermineInitialTextureMemory();
+
+ Rc<DxvkBuffer> CreateConstantBuffer(
+ bool SSBO,
+ VkDeviceSize Size,
+ DxsoProgramType ShaderStage,
+ DxsoConstantBuffers BufferType);
+
+ void CreateConstantBuffers();
+
+ void SynchronizeCsThread();
+
+ void Flush();
+
+ void UpdateBoundRTs(uint32_t index);
+
+ void UpdateActiveRTs(uint32_t index);
+
+ void UpdateActiveTextures(uint32_t index, DWORD combinedUsage);
+
+ void UpdateActiveHazardsRT(uint32_t rtMask);
+
+ void UpdateActiveHazardsDS(uint32_t texMask);
+
+ void MarkRenderHazards();
+
+ void UploadManagedTexture(D3D9CommonTexture* pResource);
+
+ void UploadManagedTextures(uint32_t mask);
+
+ void GenerateTextureMips(uint32_t mask);
+
+ void MarkTextureMipsDirty(D3D9CommonTexture* pResource);
+
+ void MarkTextureMipsUnDirty(D3D9CommonTexture* pResource);
+
+ void MarkTextureUploaded(D3D9CommonTexture* pResource);
+
+ template <bool Points>
+ void UpdatePointMode();
+
+ void UpdateFog();
+
+ void BindFramebuffer();
+
+ void BindViewportAndScissor();
+
+ inline bool IsAlphaToCoverageEnabled() {
+ const bool alphaTest = m_state.renderStates[D3DRS_ALPHATESTENABLE] != 0;
+
+ return m_amdATOC || (m_nvATOC && alphaTest);
+ }
+
+ inline bool IsDepthBiasEnabled() {
+ const auto& rs = m_state.renderStates;
+
+ float depthBias = bit::cast<float>(rs[D3DRS_DEPTHBIAS]);
+ float slopeScaledDepthBias = bit::cast<float>(rs[D3DRS_SLOPESCALEDEPTHBIAS]);
+
+ return depthBias != 0.0f || slopeScaledDepthBias != 0.0f;
+ }
+
+ inline bool IsAlphaTestEnabled() {
+ return m_state.renderStates[D3DRS_ALPHATESTENABLE] && !IsAlphaToCoverageEnabled();
+ }
+
+ inline bool IsZTestEnabled() {
+ return m_state.renderStates[D3DRS_ZENABLE] && m_state.depthStencil != nullptr;
+ }
+
+ inline bool IsClipPlaneEnabled() {
+ return m_state.renderStates[D3DRS_CLIPPLANEENABLE] != 0;
+ }
+
+ void BindMultiSampleState();
+
+ void BindBlendState();
+
+ void BindBlendFactor();
+
+ void BindDepthStencilState();
+
+ void BindDepthStencilRefrence();
+
+ void BindRasterizerState();
+
+ void BindDepthBias();
+
+ void BindAlphaTestState();
+
+ template <DxsoProgramType ShaderStage, typename HardwareLayoutType, typename SoftwareLayoutType, typename ShaderType>
+ inline void UploadHardwareConstantSet(void* pData, const SoftwareLayoutType& Src, const ShaderType& Shader);
+
+ template <typename SoftwareLayoutType, typename ShaderType>
+ inline void UploadSoftwareConstantSet(void* pData, const SoftwareLayoutType& Src, const D3D9ConstantLayout& Layout, const ShaderType& Shader);
+
+ template <DxsoProgramType ShaderStage, typename HardwareLayoutType, typename SoftwareLayoutType, typename ShaderType>
+ inline void UploadConstantSet(const SoftwareLayoutType& Src, const D3D9ConstantLayout& Layout, const ShaderType& Shader);
+
+ template <DxsoProgramType ShaderStage>
+ void UploadConstants();
+
+ void UpdateClipPlanes();
+
+ template <uint32_t Offset, uint32_t Length>
+ void UpdatePushConstant(const void* pData);
+
+ template <D3D9RenderStateItem Item>
+ void UpdatePushConstant();
+
+ void BindSampler(DWORD Sampler);
+
+ void BindTexture(DWORD SamplerSampler);
+
+ void UnbindTextures(uint32_t mask);
+
+ void UndirtySamplers(uint32_t mask);
+
+ void UndirtyTextures(uint32_t usedMask);
+
+ void MarkTextureBindingDirty(IDirect3DBaseTexture9* texture);
+
+ D3D9DrawInfo GenerateDrawInfo(
+ D3DPRIMITIVETYPE PrimitiveType,
+ UINT PrimitiveCount,
+ UINT InstanceCount);
+
+ uint32_t GetInstanceCount() const;
+
+ void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType);
+
+ template <DxsoProgramType ShaderStage>
+ void BindShader(
+ const D3D9CommonShader* pShaderModule,
+ D3D9ShaderPermutation Permutation);
+
+ void BindInputLayout();
+
+ void BindVertexBuffer(
+ UINT Slot,
+ D3D9VertexBuffer* pBuffer,
+ UINT Offset,
+ UINT Stride);
+
+ void BindIndices();
+
+ D3D9DeviceLock LockDevice() {
+ return m_multithread.AcquireLock();
+ }
+
+ const D3D9Options* GetOptions() const {
+ return &m_d3d9Options;
+ }
+
+ Direct3DState9* GetRawState() {
+ return &m_state;
+ }
+
+ void Begin(D3D9Query* pQuery);
+ void End(D3D9Query* pQuery);
+
+ void SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
+ void SetPixelBoolBitfield (uint32_t idx, uint32_t mask, uint32_t bits);
+
+ void FlushImplicit(BOOL StrongHint);
+
+ bool ChangeReportedMemory(int64_t delta) {
+ if (IsExtended())
+ return true;
+
+ int64_t availableMemory = m_availableMemory.fetch_add(delta);
+
+ return !m_d3d9Options.memoryTrackTest || availableMemory >= delta;
+ }
+
+ void ResolveZ();
+
+ void TransitionImage(D3D9CommonTexture* pResource, VkImageLayout NewLayout);
+
+ void TransformImage(
+ D3D9CommonTexture* pResource,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout);
+
+ const D3D9ConstantLayout& GetVertexConstantLayout() { return m_vsLayout; }
+ const D3D9ConstantLayout& GetPixelConstantLayout() { return m_psLayout; }
+
+ HRESULT ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters);
+ HRESULT ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ UINT GetSamplerCount() const {
+ return m_samplerCount.load();
+ }
+
+ private:
+
+ DxvkCsChunkRef AllocCsChunk() {
+ DxvkCsChunk* chunk = m_csChunkPool.allocChunk(DxvkCsChunkFlag::SingleUse);
+ return DxvkCsChunkRef(chunk, &m_csChunkPool);
+ }
+
+ template<typename Cmd>
+ void EmitCs(Cmd&& command) {
+ if (unlikely(!m_csChunk->push(command))) {
+ EmitCsChunk(std::move(m_csChunk));
+
+ m_csChunk = AllocCsChunk();
+ m_csChunk->push(command);
+ }
+ }
+
+ void EmitCsChunk(DxvkCsChunkRef&& chunk);
+
+ void FlushCsChunk() {
+ if (likely(!m_csChunk->empty())) {
+ EmitCsChunk(std::move(m_csChunk));
+ m_csChunk = AllocCsChunk();
+ }
+ }
+
+ bool CanSWVP() {
+ if (!config::SWVPEnabled)
+ return false;
+
+ return m_behaviorFlags & (D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING);
+ }
+
+ inline constexpr D3D9ShaderPermutation GetVertexShaderPermutation() {
+ return D3D9ShaderPermutations::None;
+ }
+
+ inline D3D9ShaderPermutation GetPixelShaderPermutation() {
+ if (unlikely(m_state.renderStates[D3DRS_SHADEMODE] == D3DSHADE_FLAT))
+ return D3D9ShaderPermutations::FlatShade;
+
+ return D3D9ShaderPermutations::None;
+ }
+
+ void DetermineConstantLayouts(bool canSWVP);
+
+ template<bool UpBuffer>
+ D3D9BufferSlice AllocTempBuffer(VkDeviceSize size);
+
+ bool ShouldRecord();
+
+ HRESULT CreateShaderModule(
+ D3D9CommonShader* pShaderModule,
+ VkShaderStageFlagBits ShaderStage,
+ const DWORD* pShaderBytecode,
+ const DxsoModuleInfo* pModuleInfo);
+
+ inline uint32_t GetUPDataSize(uint32_t vertexCount, uint32_t stride) {
+ return vertexCount * stride;
+ }
+
+ inline uint32_t GetUPBufferSize(uint32_t vertexCount, uint32_t stride) {
+ return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(), stride);
+ }
+
+ inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
+ uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
+ // Don't copy excess data if we don't end up needing it.
+ dataSize = std::min(dataSize, bufferSize);
+ std::memcpy(data, userData, dataSize);
+ // Pad out with 0 to make buffer range checks happy
+ // Some games have components out of range in the vertex decl
+ // that they don't read from the shader.
+ // My tests show that these are read back as 0 always if out of range of
+ // the dataSize.
+ //
+ // So... make the actual buffer the range that satisfies the range of the vertex
+ // declaration and pad with 0s outside of it.
+ if (dataSize < bufferSize)
+ std::memset(data + dataSize, 0, bufferSize - dataSize);
+ }
+
+ // So we don't do OOB.
+ template <DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType>
+ inline static constexpr uint32_t DetermineSoftwareRegCount() {
+ constexpr bool isVS = ProgramType == DxsoProgramType::VertexShader;
+
+ switch (ConstantType) {
+ default:
+ case D3D9ConstantType::Float: return isVS ? caps::MaxFloatConstantsSoftware : caps::MaxFloatConstantsPS;
+ case D3D9ConstantType::Int: return isVS ? caps::MaxOtherConstantsSoftware : caps::MaxOtherConstants;
+ case D3D9ConstantType::Bool: return isVS ? caps::MaxOtherConstantsSoftware : caps::MaxOtherConstants;
+ }
+ }
+
+ // So we don't copy more than we need.
+ template <DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType>
+ inline uint32_t DetermineHardwareRegCount() const {
+ const auto& layout = ProgramType == DxsoProgramType::VertexShader
+ ? m_vsLayout : m_psLayout;
+
+ switch (ConstantType) {
+ default:
+ case D3D9ConstantType::Float: return layout.floatCount;
+ case D3D9ConstantType::Int: return layout.intCount;
+ case D3D9ConstantType::Bool: return layout.boolCount;
+ }
+ }
+
+ inline uint32_t GetFrameLatency() {
+ return m_frameLatency;
+ }
+
+ template <
+ DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType,
+ typename T>
+ HRESULT SetShaderConstants(
+ UINT StartRegister,
+ const T* pConstantData,
+ UINT Count);
+
+ template <
+ DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType,
+ typename T>
+ HRESULT GetShaderConstants(
+ UINT StartRegister,
+ T* pConstantData,
+ UINT Count) {
+ auto GetHelper = [&] (const auto& set) {
+ const uint32_t regCountHardware = DetermineHardwareRegCount<ProgramType, ConstantType>();
+ constexpr uint32_t regCountSoftware = DetermineSoftwareRegCount<ProgramType, ConstantType>();
+
+ if (StartRegister + Count > regCountSoftware)
+ return D3DERR_INVALIDCALL;
+
+ Count = UINT(
+ std::max<INT>(
+ std::clamp<INT>(Count + StartRegister, 0, regCountHardware) - INT(StartRegister),
+ 0));
+
+ if (Count == 0)
+ return D3D_OK;
+
+ if (pConstantData == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ if constexpr (ConstantType == D3D9ConstantType::Float) {
+ const float* source = set.fConsts[StartRegister].data;
+ const size_t size = Count * sizeof(Vector4);
+
+ std::memcpy(pConstantData, source, size);
+ }
+ else if constexpr (ConstantType == D3D9ConstantType::Int) {
+ const int* source = set.iConsts[StartRegister].data;
+ const size_t size = Count * sizeof(Vector4i);
+
+ std::memcpy(pConstantData, source, size);
+ }
+ else {
+ for (uint32_t i = 0; i < Count; i++) {
+ const uint32_t constantIdx = StartRegister + i;
+ const uint32_t arrayIdx = constantIdx / 32;
+ const uint32_t bitIdx = constantIdx % 32;
+
+ const uint32_t bit = (1u << bitIdx);
+
+ bool constValue = set.bConsts[arrayIdx] & bit;
+ pConstantData[i] = constValue ? TRUE : FALSE;
+ }
+ }
+
+ return D3D_OK;
+ };
+
+ return ProgramType == DxsoProgramTypes::VertexShader
+ ? GetHelper(m_state.vsConsts)
+ : GetHelper(m_state.psConsts);
+ }
+
+ void UpdateFixedFunctionVS();
+
+ void UpdateFixedFunctionPS();
+
+ void ApplyPrimitiveType(
+ DxvkContext* pContext,
+ D3DPRIMITIVETYPE PrimType);
+
+ bool UseProgrammableVS();
+
+ bool UseProgrammablePS();
+
+ void UpdateBoolSpecConstantVertex(uint32_t value);
+
+ void UpdateBoolSpecConstantPixel(uint32_t value);
+
+ void UpdateSamplerSpecConsant(uint32_t value);
+
+ void UpdateProjectionSpecConstant(uint32_t value);
+
+ void UpdateFetch4SpecConstant(uint32_t value);
+
+ void UpdateSamplerDepthModeSpecConstant(uint32_t value);
+
+ Com<D3D9InterfaceEx> m_parent;
+ D3DDEVTYPE m_deviceType;
+ HWND m_window;
+ WORD m_behaviorFlags;
+ D3DPRESENT_PARAMETERS m_presentParams;
+
+ D3D9Adapter* m_adapter;
+ Rc<DxvkDevice> m_dxvkDevice;
+
+ uint32_t m_frameLatency = DefaultFrameLatency;
+
+ D3D9Initializer* m_initializer = nullptr;
+ D3D9FormatHelper* m_converter = nullptr;
+
+ D3D9FFShaderModuleSet m_ffModules;
+ D3D9SWVPEmulator m_swvpEmulator;
+
+ Com<D3D9StateBlock, false> m_recorder;
+
+ Rc<D3D9ShaderModuleSet> m_shaderModules;
+
+ Rc<DxvkBuffer> m_vsClipPlanes;
+
+ Rc<DxvkBuffer> m_vsFixedFunction;
+ Rc<DxvkBuffer> m_vsVertexBlend;
+ Rc<DxvkBuffer> m_psFixedFunction;
+ Rc<DxvkBuffer> m_psShared;
+
+ D3D9BufferSlice m_upBuffer;
+ D3D9BufferSlice m_managedUploadBuffer;
+
+ D3D9Cursor m_cursor;
+
+ Com<D3D9Surface, false> m_autoDepthStencil;
+
+ Com<D3D9SwapChainEx, false> m_implicitSwapchain;
+
+ const D3D9Options m_d3d9Options;
+ DxsoOptions m_dxsoOptions;
+
+ std::unordered_map<
+ D3D9SamplerKey,
+ Rc<DxvkSampler>,
+ D3D9SamplerKeyHash,
+ D3D9SamplerKeyEq> m_samplers;
+
+ std::unordered_map<
+ DWORD,
+ Com<D3D9VertexDecl,
+ false>> m_fvfTable;
+
+ D3D9Multithread m_multithread;
+ D3D9InputAssemblyState m_iaState;
+
+ D3D9DeviceFlags m_flags;
+ // Last state of depth textures. Doesn't update when NULL is bound.
+ // & with m_activeTextures to normalize.
+ uint32_t m_instancedData = 0;
+
+ uint32_t m_depthTextures = 0;
+ uint32_t m_textureTypes = 0;
+ uint32_t m_projectionBitfield = 0;
+
+ uint32_t m_dirtySamplerStates = 0;
+ uint32_t m_dirtyTextures = 0;
+
+ uint32_t m_boundRTs = 0;
+
+ uint32_t m_activeRTs = 0;
+ uint32_t m_activeRTTextures = 0;
+ uint32_t m_activeDSTextures = 0;
+ uint32_t m_activeHazardsRT = 0;
+ uint32_t m_activeHazardsDS = 0;
+ uint32_t m_alphaSwizzleRTs = 0;
+ uint32_t m_activeTextures = 0;
+ uint32_t m_activeTexturesToUpload = 0;
+ uint32_t m_activeTexturesToGen = 0;
+
+ uint32_t m_fetch4Enabled = 0;
+ uint32_t m_fetch4 = 0;
+
+ uint32_t m_lastBoolSpecConstantVertex = 0;
+ uint32_t m_lastBoolSpecConstantPixel = 0;
+ uint32_t m_lastSamplerDepthMode = 0;
+ uint32_t m_lastProjectionBitfield = 0;
+ uint32_t m_lastSamplerTypes = 0;
+ uint32_t m_lastPointMode = 0;
+ uint32_t m_lastFetch4 = 0;
+ uint32_t m_lastHazardsDS = 0;
+ uint32_t m_lastSamplerTypesFF = 0;
+
+ D3D9ShaderMasks m_vsShaderMasks = D3D9ShaderMasks();
+ D3D9ShaderMasks m_psShaderMasks = FixedFunctionMask;
+
+ bool m_isSWVP;
+ bool m_amdATOC = false;
+ bool m_nvATOC = false;
+ bool m_ffZTest = false;
+
+ float m_depthBiasScale = 0.0f;
+
+ D3D9ConstantLayout m_vsLayout;
+ D3D9ConstantLayout m_psLayout;
+ D3D9ConstantSets m_consts[DxsoProgramTypes::Count];
+
+ D3D9ViewportInfo m_viewportInfo;
+
+ DxvkCsChunkPool m_csChunkPool;
+ dxvk::high_resolution_clock::time_point m_lastFlush
+ = dxvk::high_resolution_clock::now();
+ DxvkCsThread m_csThread;
+ DxvkCsChunkRef m_csChunk;
+ bool m_csIsBusy = false;
+
+ std::atomic<int64_t> m_availableMemory = { 0 };
+ std::atomic<int32_t> m_samplerCount = { 0 };
+
+ Direct3DState9 m_state;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device_child.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device_child.h
new file mode 100644
index 00000000..433a269a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_device_child.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ class D3D9DeviceEx;
+
+ template <typename Base>
+ class D3D9DeviceChild : public ComObjectClamp<Base> {
+
+ public:
+
+ D3D9DeviceChild(D3D9DeviceEx* pDevice)
+ : m_parent( pDevice ) { }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ uint32_t refCount = this->m_refCount++;
+ if (unlikely(!refCount)) {
+ this->AddRefPrivate();
+ GetDevice()->AddRef();
+ }
+
+ return refCount + 1;
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ uint32_t refCount = --this->m_refCount;
+ if (unlikely(!refCount)) {
+ auto* pDevice = GetDevice();
+ this->ReleasePrivate();
+ pDevice->Release();
+ }
+ return refCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9** ppDevice) {
+ InitReturnPtr(ppDevice);
+
+ if (ppDevice == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *ppDevice = ref(GetDevice());
+ return D3D_OK;
+ }
+
+ IDirect3DDevice9Ex* GetDevice() {
+ return reinterpret_cast<IDirect3DDevice9Ex*>(m_parent);
+ }
+
+ D3D9DeviceEx* GetParent() {
+ return m_parent;
+ }
+
+ protected:
+
+ D3D9DeviceEx* m_parent;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.cpp
new file mode 100644
index 00000000..e1f9b536
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.cpp
@@ -0,0 +1,2486 @@
+#include "d3d9_fixed_function.h"
+
+#include "d3d9_device.h"
+#include "d3d9_util.h"
+#include "d3d9_spec_constants.h"
+
+#include "../dxvk/dxvk_hash.h"
+#include "../dxvk/dxvk_spec_const.h"
+
+#include "../spirv/spirv_module.h"
+
+#include <cfloat>
+
+namespace dxvk {
+
+ D3D9FixedFunctionOptions::D3D9FixedFunctionOptions(const D3D9Options* options) {
+ invariantPosition = options->invariantPosition;
+ }
+
+ uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx) {
+ uint32_t floatType = spvModule.defFloatType(32);
+ uint32_t uint32Type = spvModule.defIntType(32, 0);
+ uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
+ uint32_t vec4Type = spvModule.defVectorType(floatType, 4);
+ uint32_t floatPtr = spvModule.defPointerType(floatType, spv::StorageClassPushConstant);
+ uint32_t vec3Ptr = spvModule.defPointerType(vec3Type, spv::StorageClassPushConstant);
+
+ uint32_t fogColorMember = spvModule.constu32(uint32_t(D3D9RenderStateItem::FogColor));
+ uint32_t fogColor = spvModule.opLoad(vec3Type,
+ spvModule.opAccessChain(vec3Ptr, fogCtx.RenderState, 1, &fogColorMember));
+
+ uint32_t fogScaleMember = spvModule.constu32(uint32_t(D3D9RenderStateItem::FogScale));
+ uint32_t fogScale = spvModule.opLoad(floatType,
+ spvModule.opAccessChain(floatPtr, fogCtx.RenderState, 1, &fogScaleMember));
+
+ uint32_t fogEndMember = spvModule.constu32(uint32_t(D3D9RenderStateItem::FogEnd));
+ uint32_t fogEnd = spvModule.opLoad(floatType,
+ spvModule.opAccessChain(floatPtr, fogCtx.RenderState, 1, &fogEndMember));
+
+ uint32_t fogDensityMember = spvModule.constu32(uint32_t(D3D9RenderStateItem::FogDensity));
+ uint32_t fogDensity = spvModule.opLoad(floatType,
+ spvModule.opAccessChain(floatPtr, fogCtx.RenderState, 1, &fogDensityMember));
+
+ uint32_t fogMode = spvModule.specConst32(uint32Type, 0);
+
+ if (!fogCtx.IsPixel) {
+ spvModule.setDebugName(fogMode, "vertex_fog_mode");
+ spvModule.decorateSpecId(fogMode, getSpecId(D3D9SpecConstantId::VertexFogMode));
+ }
+ else {
+ spvModule.setDebugName(fogMode, "pixel_fog_mode");
+ spvModule.decorateSpecId(fogMode, getSpecId(D3D9SpecConstantId::PixelFogMode));
+ }
+
+ uint32_t fogEnabled = spvModule.specConstBool(false);
+ spvModule.setDebugName(fogEnabled, "fog_enabled");
+ spvModule.decorateSpecId(fogEnabled, getSpecId(D3D9SpecConstantId::FogEnabled));
+
+ uint32_t doFog = spvModule.allocateId();
+ uint32_t skipFog = spvModule.allocateId();
+
+ uint32_t returnType = fogCtx.IsPixel ? vec4Type : floatType;
+ uint32_t returnTypePtr = spvModule.defPointerType(returnType, spv::StorageClassPrivate);
+ uint32_t returnValuePtr = spvModule.newVar(returnTypePtr, spv::StorageClassPrivate);
+ spvModule.opStore(returnValuePtr, fogCtx.IsPixel ? fogCtx.oColor : spvModule.constf32(0.0f));
+
+ // Actually do the fog now we have all the vars in-place.
+
+ spvModule.opSelectionMerge(skipFog, spv::SelectionControlMaskNone);
+ spvModule.opBranchConditional(fogEnabled, doFog, skipFog);
+
+ spvModule.opLabel(doFog);
+
+ uint32_t wIndex = 3;
+ uint32_t zIndex = 2;
+
+ uint32_t w = spvModule.opCompositeExtract(floatType, fogCtx.vPos, 1, &wIndex);
+ uint32_t z = spvModule.opCompositeExtract(floatType, fogCtx.vPos, 1, &zIndex);
+
+ uint32_t depth = 0;
+ if (fogCtx.IsPixel)
+ depth = spvModule.opFMul(floatType, z, spvModule.opFDiv(floatType, spvModule.constf32(1.0f), w));
+ else {
+ if (fogCtx.RangeFog) {
+ std::array<uint32_t, 3> indices = { 0, 1, 2 };
+ uint32_t pos3 = spvModule.opVectorShuffle(vec3Type, fogCtx.vPos, fogCtx.vPos, indices.size(), indices.data());
+ depth = spvModule.opLength(floatType, pos3);
+ }
+ else
+ depth = fogCtx.HasFogInput
+ ? fogCtx.vFog
+ : spvModule.opFAbs(floatType, z);
+ }
+ uint32_t fogFactor;
+ if (!fogCtx.IsPixel && fogCtx.IsFixedFunction && fogCtx.IsPositionT) {
+ fogFactor = fogCtx.HasSpecular
+ ? spvModule.opCompositeExtract(floatType, fogCtx.Specular, 1, &wIndex)
+ : spvModule.constf32(1.0f);
+ } else {
+ uint32_t applyFogFactor = spvModule.allocateId();
+
+ std::array<SpirvPhiLabel, 4> fogVariables;
+
+ std::array<SpirvSwitchCaseLabel, 4> fogCaseLabels = { {
+ { uint32_t(D3DFOG_NONE), spvModule.allocateId() },
+ { uint32_t(D3DFOG_EXP), spvModule.allocateId() },
+ { uint32_t(D3DFOG_EXP2), spvModule.allocateId() },
+ { uint32_t(D3DFOG_LINEAR), spvModule.allocateId() },
+ } };
+
+ spvModule.opSelectionMerge(applyFogFactor, spv::SelectionControlMaskNone);
+ spvModule.opSwitch(fogMode,
+ fogCaseLabels[D3DFOG_NONE].labelId,
+ fogCaseLabels.size(),
+ fogCaseLabels.data());
+
+ for (uint32_t i = 0; i < fogCaseLabels.size(); i++) {
+ spvModule.opLabel(fogCaseLabels[i].labelId);
+
+ fogVariables[i].labelId = fogCaseLabels[i].labelId;
+ fogVariables[i].varId = [&] {
+ auto mode = D3DFOGMODE(fogCaseLabels[i].literal);
+ switch (mode) {
+ default:
+ // vFog
+ case D3DFOG_NONE: {
+ if (fogCtx.IsPixel)
+ return fogCtx.vFog;
+
+ if (fogCtx.IsFixedFunction && fogCtx.HasSpecular)
+ return spvModule.opCompositeExtract(floatType, fogCtx.Specular, 1, &wIndex);
+
+ return spvModule.constf32(1.0f);
+ }
+
+ // (end - d) / (end - start)
+ case D3DFOG_LINEAR: {
+ uint32_t fogFactor = spvModule.opFSub(floatType, fogEnd, depth);
+ fogFactor = spvModule.opFMul(floatType, fogFactor, fogScale);
+ fogFactor = spvModule.opNClamp(floatType, fogFactor, spvModule.constf32(0.0f), spvModule.constf32(1.0f));
+ return fogFactor;
+ }
+
+ // 1 / (e^[d * density])^2
+ case D3DFOG_EXP2:
+ // 1 / (e^[d * density])
+ case D3DFOG_EXP: {
+ uint32_t fogFactor = spvModule.opFMul(floatType, depth, fogDensity);
+
+ if (mode == D3DFOG_EXP2)
+ fogFactor = spvModule.opFMul(floatType, fogFactor, fogFactor);
+
+ // Provides the rcp.
+ fogFactor = spvModule.opFNegate(floatType, fogFactor);
+ fogFactor = spvModule.opExp(floatType, fogFactor);
+ return fogFactor;
+ }
+ }
+ }();
+
+ spvModule.opBranch(applyFogFactor);
+ }
+
+ spvModule.opLabel(applyFogFactor);
+
+ fogFactor = spvModule.opPhi(floatType,
+ fogVariables.size(),
+ fogVariables.data());
+ }
+
+ uint32_t fogRetValue = 0;
+
+ // Return the new color if we are doing this in PS
+ // or just the fog factor for oFog in VS
+ if (fogCtx.IsPixel) {
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 6 };
+
+ uint32_t color = fogCtx.oColor;
+
+ uint32_t color3 = spvModule.opVectorShuffle(vec3Type, color, color, 3, indices.data());
+
+ std::array<uint32_t, 3> fogFacIndices = { fogFactor, fogFactor, fogFactor };
+ uint32_t fogFact3 = spvModule.opCompositeConstruct(vec3Type, fogFacIndices.size(), fogFacIndices.data());
+
+ uint32_t lerpedFrog = spvModule.opFMix(vec3Type, fogColor, color3, fogFact3);
+
+ fogRetValue = spvModule.opVectorShuffle(vec4Type, lerpedFrog, color, indices.size(), indices.data());
+ }
+ else
+ fogRetValue = fogFactor;
+
+ spvModule.opStore(returnValuePtr, fogRetValue);
+
+ spvModule.opBranch(skipFog);
+
+ spvModule.opLabel(skipFog);
+
+ return spvModule.opLoad(returnType, returnValuePtr);
+ }
+
+
+ uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) {
+ uint32_t floatType = spvModule.defFloatType(32);
+ uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
+
+ std::array<uint32_t, 11> rsMembers = {{
+ vec3Type,
+ floatType,
+ floatType,
+ floatType,
+ floatType,
+
+ floatType,
+ floatType,
+ floatType,
+ floatType,
+ floatType,
+ floatType,
+ }};
+
+ uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data());
+ uint32_t rsBlock = spvModule.newVar(
+ spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
+ spv::StorageClassPushConstant);
+
+ spvModule.setDebugName (rsBlock, "render_state");
+
+ spvModule.setDebugName (rsStruct, "render_state_t");
+ spvModule.decorate (rsStruct, spv::DecorationBlock);
+
+ uint32_t memberIdx = 0;
+ auto SetMemberName = [&](const char* name, uint32_t offset) {
+ if (memberIdx >= count)
+ return;
+
+ spvModule.setDebugMemberName (rsStruct, memberIdx, name);
+ spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
+ memberIdx++;
+ };
+
+ SetMemberName("fog_color", offsetof(D3D9RenderStateInfo, fogColor));
+ SetMemberName("fog_scale", offsetof(D3D9RenderStateInfo, fogScale));
+ SetMemberName("fog_end", offsetof(D3D9RenderStateInfo, fogEnd));
+ SetMemberName("fog_density", offsetof(D3D9RenderStateInfo, fogDensity));
+ SetMemberName("alpha_ref", offsetof(D3D9RenderStateInfo, alphaRef));
+ SetMemberName("point_size", offsetof(D3D9RenderStateInfo, pointSize));
+ SetMemberName("point_size_min", offsetof(D3D9RenderStateInfo, pointSizeMin));
+ SetMemberName("point_size_max", offsetof(D3D9RenderStateInfo, pointSizeMax));
+ SetMemberName("point_scale_a", offsetof(D3D9RenderStateInfo, pointScaleA));
+ SetMemberName("point_scale_b", offsetof(D3D9RenderStateInfo, pointScaleB));
+ SetMemberName("point_scale_c", offsetof(D3D9RenderStateInfo, pointScaleC));
+
+ return rsBlock;
+ }
+
+
+ D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction) {
+ uint32_t floatType = spvModule.defFloatType(32);
+ uint32_t floatPtr = spvModule.defPointerType(floatType, spv::StorageClassPushConstant);
+ uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
+ uint32_t vec4Type = spvModule.defVectorType(floatType, 4);
+ uint32_t uint32Type = spvModule.defIntType(32, 0);
+ uint32_t boolType = spvModule.defBoolType();
+
+ auto LoadFloat = [&](D3D9RenderStateItem item) {
+ uint32_t index = spvModule.constu32(uint32_t(item));
+ return spvModule.opLoad(floatType, spvModule.opAccessChain(floatPtr, rsBlock, 1, &index));
+ };
+
+ uint32_t value = perVertPointSize != 0 ? perVertPointSize : LoadFloat(D3D9RenderStateItem::PointSize);
+
+ if (isFixedFunction) {
+ uint32_t pointMode = spvModule.specConst32(uint32Type, 0);
+ spvModule.setDebugName(pointMode, "point_mode");
+ spvModule.decorateSpecId(pointMode, getSpecId(D3D9SpecConstantId::PointMode));
+
+ uint32_t scaleBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(0), spvModule.consti32(1));
+ uint32_t isScale = spvModule.opIEqual(boolType, scaleBit, spvModule.constu32(1));
+
+ uint32_t scaleC = LoadFloat(D3D9RenderStateItem::PointScaleC);
+ uint32_t scaleB = LoadFloat(D3D9RenderStateItem::PointScaleB);
+ uint32_t scaleA = LoadFloat(D3D9RenderStateItem::PointScaleA);
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ uint32_t vtx3;
+ if (vPos != 0) {
+ vPos = spvModule.opLoad(vec4Type, vPos);
+
+ uint32_t rhw = spvModule.opCompositeExtract(floatType, vPos, 1, &indices[3]);
+ rhw = spvModule.opFDiv(floatType, spvModule.constf32(1.0f), rhw);
+ uint32_t pos3 = spvModule.opVectorShuffle(vec3Type, vPos, vPos, 3, indices.data());
+ vtx3 = spvModule.opVectorTimesScalar(vec3Type, pos3, rhw);
+ } else {
+ vtx3 = spvModule.opVectorShuffle(vec3Type, vtx, vtx, 3, indices.data());
+ }
+
+ uint32_t DeSqr = spvModule.opDot (floatType, vtx3, vtx3);
+ uint32_t De = spvModule.opSqrt(floatType, DeSqr);
+ uint32_t scaleValue = spvModule.opFMul(floatType, scaleC, DeSqr);
+ scaleValue = spvModule.opFFma(floatType, scaleB, De, scaleValue);
+ scaleValue = spvModule.opFAdd(floatType, scaleA, scaleValue);
+ scaleValue = spvModule.opSqrt(floatType, scaleValue);
+ scaleValue = spvModule.opFDiv(floatType, value, scaleValue);
+
+ value = spvModule.opSelect(floatType, isScale, scaleValue, value);
+ }
+
+ uint32_t min = LoadFloat(D3D9RenderStateItem::PointSizeMin);
+ uint32_t max = LoadFloat(D3D9RenderStateItem::PointSizeMax);
+
+ D3D9PointSizeInfoVS info;
+ info.defaultValue = value;
+ info.min = min;
+ info.max = max;
+
+ return info;
+ }
+
+
+ D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock) {
+ uint32_t uint32Type = spvModule.defIntType(32, 0);
+ uint32_t boolType = spvModule.defBoolType();
+ uint32_t boolVec4 = spvModule.defVectorType(boolType, 4);
+
+ uint32_t pointMode = spvModule.specConst32(uint32Type, 0);
+ spvModule.setDebugName(pointMode, "point_mode");
+ spvModule.decorateSpecId(pointMode, getSpecId(D3D9SpecConstantId::PointMode));
+
+ uint32_t spriteBit = spvModule.opBitFieldUExtract(uint32Type, pointMode, spvModule.consti32(1), spvModule.consti32(1));
+ uint32_t isSprite = spvModule.opIEqual(boolType, spriteBit, spvModule.constu32(1));
+
+ std::array<uint32_t, 4> isSpriteIndices;
+ for (uint32_t i = 0; i < isSpriteIndices.size(); i++)
+ isSpriteIndices[i] = isSprite;
+
+ isSprite = spvModule.opCompositeConstruct(boolVec4, isSpriteIndices.size(), isSpriteIndices.data());
+
+ D3D9PointSizeInfoPS info;
+ info.isSprite = isSprite;
+
+ return info;
+ }
+
+
+ uint32_t GetPointCoord(SpirvModule& spvModule, std::vector<uint32_t>& entryPointInterfaces) {
+ uint32_t floatType = spvModule.defFloatType(32);
+ uint32_t vec2Type = spvModule.defVectorType(floatType, 2);
+ uint32_t vec4Type = spvModule.defVectorType(floatType, 4);
+ uint32_t vec2Ptr = spvModule.defPointerType(vec2Type, spv::StorageClassInput);
+
+ uint32_t pointCoordPtr = spvModule.newVar(vec2Ptr, spv::StorageClassInput);
+
+ spvModule.decorateBuiltIn(pointCoordPtr, spv::BuiltInPointCoord);
+ entryPointInterfaces.push_back(pointCoordPtr);
+
+ uint32_t pointCoord = spvModule.opLoad(vec2Type, pointCoordPtr);
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ std::array<uint32_t, 4> pointCoordIndices = {
+ spvModule.opCompositeExtract(floatType, pointCoord, 1, &indices[0]),
+ spvModule.opCompositeExtract(floatType, pointCoord, 1, &indices[1]),
+ spvModule.constf32(0.0f),
+ spvModule.constf32(0.0f)
+ };
+
+ return spvModule.opCompositeConstruct(vec4Type, pointCoordIndices.size(), pointCoordIndices.data());
+ }
+
+
+ uint32_t GetSharedConstants(SpirvModule& spvModule) {
+ uint32_t float_t = spvModule.defFloatType(32);
+ uint32_t vec2_t = spvModule.defVectorType(float_t, 2);
+ uint32_t vec4_t = spvModule.defVectorType(float_t, 4);
+
+ std::array<uint32_t, D3D9SharedPSStages_Count> stageMembers = {
+ vec4_t,
+
+ vec2_t,
+ vec2_t,
+
+ float_t,
+ float_t,
+ };
+
+ std::array<decltype(stageMembers), caps::TextureStageCount> members;
+
+ for (auto& member : members)
+ member = stageMembers;
+
+ const uint32_t structType =
+ spvModule.defStructType(members.size() * stageMembers.size(), members[0].data());
+
+ spvModule.decorateBlock(structType);
+
+ uint32_t offset = 0;
+ for (uint32_t stage = 0; stage < caps::TextureStageCount; stage++) {
+ spvModule.memberDecorateOffset(structType, stage * D3D9SharedPSStages_Count + D3D9SharedPSStages_Constant, offset);
+ offset += sizeof(float) * 4;
+
+ spvModule.memberDecorateOffset(structType, stage * D3D9SharedPSStages_Count + D3D9SharedPSStages_BumpEnvMat0, offset);
+ offset += sizeof(float) * 2;
+
+ spvModule.memberDecorateOffset(structType, stage * D3D9SharedPSStages_Count + D3D9SharedPSStages_BumpEnvMat1, offset);
+ offset += sizeof(float) * 2;
+
+ spvModule.memberDecorateOffset(structType, stage * D3D9SharedPSStages_Count + D3D9SharedPSStages_BumpEnvLScale, offset);
+ offset += sizeof(float);
+
+ spvModule.memberDecorateOffset(structType, stage * D3D9SharedPSStages_Count + D3D9SharedPSStages_BumpEnvLOffset, offset);
+ offset += sizeof(float);
+
+ // Padding...
+ offset += sizeof(float) * 2;
+ }
+
+ uint32_t sharedState = spvModule.newVar(
+ spvModule.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ spvModule.setDebugName(sharedState, "D3D9SharedPS");
+
+ return sharedState;
+ }
+
+
+ enum class D3D9FFVSMembers {
+ WorldViewMatrix,
+ NormalMatrix,
+ InverseViewMatrix,
+ ProjMatrix,
+
+ Texcoord0,
+ Texcoord1,
+ Texcoord2,
+ Texcoord3,
+ Texcoord4,
+ Texcoord5,
+ Texcoord6,
+ Texcoord7,
+
+ InverseOffset,
+ InverseExtent,
+
+ GlobalAmbient,
+
+ Light0,
+ Light1,
+ Light2,
+ Light3,
+ Light4,
+ Light5,
+ Light6,
+ Light7,
+
+ MaterialDiffuse,
+ MaterialAmbient,
+ MaterialSpecular,
+ MaterialEmissive,
+ MaterialPower,
+
+ TweenFactor,
+
+ MemberCount
+ };
+
+ struct D3D9FFVertexData {
+ uint32_t constantBuffer;
+ uint32_t vertexBlendData;
+ uint32_t lightType;
+
+ struct {
+ uint32_t worldview;
+ uint32_t normal;
+ uint32_t inverseView;
+ uint32_t proj;
+
+ uint32_t texcoord[8];
+
+ uint32_t invOffset;
+ uint32_t invExtent;
+
+ uint32_t globalAmbient;
+
+ uint32_t materialDiffuse;
+ uint32_t materialSpecular;
+ uint32_t materialAmbient;
+ uint32_t materialEmissive;
+ uint32_t materialPower;
+ uint32_t tweenFactor;
+ } constants;
+
+ struct {
+ uint32_t POSITION;
+ uint32_t POSITION1;
+ uint32_t POINTSIZE;
+ uint32_t NORMAL;
+ uint32_t NORMAL1;
+ uint32_t TEXCOORD[8];
+ uint32_t COLOR[2];
+ uint32_t FOG;
+
+ uint32_t BLENDWEIGHT;
+ uint32_t BLENDINDICES;
+ } in;
+
+ struct {
+ uint32_t POSITION;
+ uint32_t POINTSIZE;
+ uint32_t NORMAL;
+ uint32_t TEXCOORD[8];
+ uint32_t COLOR[2];
+ uint32_t FOG;
+ } out;
+ };
+
+ enum D3D9FFPSMembers {
+ TextureFactor = 0,
+
+ MemberCount
+ };
+
+ struct D3D9FFPixelData {
+ uint32_t constantBuffer;
+ uint32_t sharedState;
+
+ struct {
+ uint32_t textureFactor;
+ } constants;
+
+ struct {
+ uint32_t TEXCOORD[8];
+ uint32_t COLOR[2];
+ uint32_t FOG;
+ uint32_t POS;
+ } in;
+
+ struct {
+ uint32_t texcoordCnt;
+ uint32_t typeId;
+ uint32_t varId;
+ uint32_t bound;
+ } samplers[8];
+
+ struct {
+ uint32_t COLOR;
+ } out;
+ };
+
+ class D3D9FFShaderCompiler {
+
+ public:
+
+ D3D9FFShaderCompiler(
+ Rc<DxvkDevice> Device,
+ const D3D9FFShaderKeyVS& Key,
+ const std::string& Name,
+ D3D9FixedFunctionOptions Options);
+
+ D3D9FFShaderCompiler(
+ Rc<DxvkDevice> Device,
+ const D3D9FFShaderKeyFS& Key,
+ const std::string& Name,
+ D3D9FixedFunctionOptions Options);
+
+ Rc<DxvkShader> compile();
+
+ DxsoIsgn isgn() { return m_isgn; }
+
+ private:
+
+ // Returns value for inputs
+ // Returns ptr for outputs
+ uint32_t declareIO(bool input, DxsoSemantic semantic, spv::BuiltIn builtin = spv::BuiltInMax);
+
+ void compileVS();
+
+ void setupRenderStateInfo();
+
+ void emitLightTypeDecl();
+
+ void emitBaseBufferDecl();
+
+ void emitVertexBlendDecl();
+
+ void setupVS();
+
+ void compilePS();
+
+ void setupPS();
+
+ void emitPsSharedConstants();
+
+ void emitVsClipping(uint32_t vtx);
+
+ void alphaTestPS();
+
+ bool isVS() { return m_programType == DxsoProgramType::VertexShader; }
+ bool isPS() { return !isVS(); }
+
+ std::string m_filename;
+
+ SpirvModule m_module;
+ std::vector
+ <DxvkResourceSlot> m_resourceSlots;
+ DxvkInterfaceSlots m_interfaceSlots;
+ std::vector<uint32_t> m_entryPointInterfaces;
+
+ DxsoProgramType m_programType;
+ D3D9FFShaderKeyVS m_vsKey;
+ D3D9FFShaderKeyFS m_fsKey;
+
+ D3D9FFVertexData m_vs = { };
+ D3D9FFPixelData m_ps = { };
+
+ DxsoIsgn m_isgn;
+ DxsoIsgn m_osgn;
+
+ uint32_t m_floatType;
+ uint32_t m_uint32Type;
+ uint32_t m_vec4Type;
+ uint32_t m_vec3Type;
+ uint32_t m_vec2Type;
+ uint32_t m_mat3Type;
+ uint32_t m_mat4Type;
+
+ uint32_t m_entryPointId;
+
+ uint32_t m_rsBlock;
+ uint32_t m_mainFuncLabel;
+
+ D3D9FixedFunctionOptions m_options;
+ };
+
+ D3D9FFShaderCompiler::D3D9FFShaderCompiler(
+ Rc<DxvkDevice> Device,
+ const D3D9FFShaderKeyVS& Key,
+ const std::string& Name,
+ D3D9FixedFunctionOptions Options)
+ : m_module(spvVersion(1, 3)), m_options(Options) {
+ m_programType = DxsoProgramTypes::VertexShader;
+ m_vsKey = Key;
+ m_filename = Name;
+ }
+
+
+ D3D9FFShaderCompiler::D3D9FFShaderCompiler(
+ Rc<DxvkDevice> Device,
+ const D3D9FFShaderKeyFS& Key,
+ const std::string& Name,
+ D3D9FixedFunctionOptions Options)
+ : m_module(spvVersion(1, 3)), m_options(Options) {
+ m_programType = DxsoProgramTypes::PixelShader;
+ m_fsKey = Key;
+ m_filename = Name;
+ }
+
+
+ Rc<DxvkShader> D3D9FFShaderCompiler::compile() {
+ m_floatType = m_module.defFloatType(32);
+ m_uint32Type = m_module.defIntType(32, 0);
+ m_vec4Type = m_module.defVectorType(m_floatType, 4);
+ m_vec3Type = m_module.defVectorType(m_floatType, 3);
+ m_vec2Type = m_module.defVectorType(m_floatType, 2);
+ m_mat3Type = m_module.defMatrixType(m_vec3Type, 3);
+ m_mat4Type = m_module.defMatrixType(m_vec4Type, 4);
+
+ m_entryPointId = m_module.allocateId();
+
+ // Set the shader name so that we recognize it in renderdoc
+ m_module.setDebugSource(
+ spv::SourceLanguageUnknown, 0,
+ m_module.addDebugString(m_filename.c_str()),
+ nullptr);
+
+ // Set the memory model. This is the same for all shaders.
+ m_module.setMemoryModel(
+ spv::AddressingModelLogical,
+ spv::MemoryModelGLSL450);
+
+ m_module.enableCapability(spv::CapabilityShader);
+ m_module.enableCapability(spv::CapabilityImageQuery);
+
+ m_module.functionBegin(
+ m_module.defVoidType(), m_entryPointId, m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr),
+ spv::FunctionControlMaskNone);
+ m_module.setDebugName(m_entryPointId, "main");
+
+ m_mainFuncLabel = m_module.allocateId();
+ m_module.opLabel(m_mainFuncLabel);
+
+ if (isVS())
+ compileVS();
+ else
+ compilePS();
+
+ m_module.opReturn();
+ m_module.functionEnd();
+
+ // Declare the entry point, we now have all the
+ // information we need, including the interfaces
+ m_module.addEntryPoint(m_entryPointId,
+ isVS() ? spv::ExecutionModelVertex : spv::ExecutionModelFragment, "main",
+ m_entryPointInterfaces.size(),
+ m_entryPointInterfaces.data());
+
+ DxvkShaderOptions shaderOptions = { };
+
+ DxvkShaderConstData constData = { };
+
+ // Create the shader module object
+ return new DxvkShader(
+ isVS() ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT,
+ m_resourceSlots.size(),
+ m_resourceSlots.data(),
+ m_interfaceSlots,
+ m_module.compile(),
+ shaderOptions,
+ std::move(constData));
+ }
+
+
+ uint32_t D3D9FFShaderCompiler::declareIO(bool input, DxsoSemantic semantic, spv::BuiltIn builtin) {
+ // Declare in ISGN and do linkage
+ auto& sgn = input
+ ? m_isgn : m_osgn;
+
+ uint32_t& slots = input
+ ? m_interfaceSlots.inputSlots
+ : m_interfaceSlots.outputSlots;
+
+ uint32_t i = sgn.elemCount++;
+
+ uint32_t slot = i;
+
+ if (builtin == spv::BuiltInMax) {
+ if (input != isVS()) {
+ slot = RegisterLinkerSlot(semantic); // Requires linkage...
+ }
+
+ slots |= 1u << slot;
+ }
+
+ auto& elem = sgn.elems[i];
+ elem.slot = slot;
+ elem.semantic = semantic;
+
+ // Declare variable
+ spv::StorageClass storageClass = input ?
+ spv::StorageClassInput : spv::StorageClassOutput;
+
+ const bool scalar = semantic.usage == DxsoUsage::Fog || semantic.usage == DxsoUsage::PointSize;
+ uint32_t type = scalar ? m_floatType : m_vec4Type;
+
+ uint32_t ptrType = m_module.defPointerType(type, storageClass);
+
+ uint32_t ptr = m_module.newVar(ptrType, storageClass);
+
+ if (builtin == spv::BuiltInMax)
+ m_module.decorateLocation(ptr, slot);
+ else
+ m_module.decorateBuiltIn(ptr, builtin);
+
+ bool diffuseOrSpec = semantic == DxsoSemantic{ DxsoUsage::Color, 0 }
+ || semantic == DxsoSemantic{ DxsoUsage::Color, 1 };
+
+ if (diffuseOrSpec && m_fsKey.Stages[0].Contents.GlobalFlatShade)
+ m_module.decorate(ptr, spv::DecorationFlat);
+
+ std::string name = str::format(input ? "in_" : "out_", semantic.usage, semantic.usageIndex);
+ m_module.setDebugName(ptr, name.c_str());
+
+ m_entryPointInterfaces.push_back(ptr);
+
+ if (input)
+ return m_module.opLoad(type, ptr);
+
+ return ptr;
+ }
+
+
+ void D3D9FFShaderCompiler::compileVS() {
+ setupVS();
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ uint32_t gl_Position = m_vs.in.POSITION;
+ uint32_t vtx = m_vs.in.POSITION;
+ uint32_t normal = m_module.opVectorShuffle(m_vec3Type, m_vs.in.NORMAL, m_vs.in.NORMAL, 3, indices.data());
+
+ if (m_vsKey.Data.Contents.VertexBlendMode == D3D9FF_VertexBlendMode_Tween) {
+ uint32_t vtx1 = m_vs.in.POSITION1;
+ uint32_t normal1 = m_module.opVectorShuffle(m_vec3Type, m_vs.in.NORMAL1, m_vs.in.NORMAL1, 3, indices.data());
+
+ vtx = m_module.opFMix(m_vec3Type, vtx, vtx1, m_vs.constants.tweenFactor);
+ normal = m_module.opFMix(m_vec3Type, normal, normal1, m_vs.constants.tweenFactor);
+ }
+
+ const uint32_t wIndex = 3;
+
+ if (!m_vsKey.Data.Contents.HasPositionT) {
+ if (m_vsKey.Data.Contents.VertexBlendMode == D3D9FF_VertexBlendMode_Normal) {
+ uint32_t blendWeightRemaining = m_module.constf32(1);
+ uint32_t vtxSum = m_module.constvec4f32(0, 0, 0, 0);
+ uint32_t nrmSum = m_module.constvec3f32(0, 0, 0);
+
+ for (uint32_t i = 0; i <= m_vsKey.Data.Contents.VertexBlendCount; i++) {
+ std::array<uint32_t, 2> arrayIndices;
+
+ if (m_vsKey.Data.Contents.VertexBlendIndexed) {
+ uint32_t index = m_module.opCompositeExtract(m_floatType, m_vs.in.BLENDINDICES, 1, &i);
+ index = m_module.opConvertFtoU(m_uint32Type, m_module.opRound(m_floatType, index));
+
+ arrayIndices = { m_module.constu32(0), index };
+ }
+ else
+ arrayIndices = { m_module.constu32(0), m_module.constu32(i) };
+
+ uint32_t worldview = m_module.opLoad(m_mat4Type,
+ m_module.opAccessChain(
+ m_module.defPointerType(m_mat4Type, spv::StorageClassUniform), m_vs.vertexBlendData, arrayIndices.size(), arrayIndices.data()));
+
+ uint32_t nrmMtx = worldview;
+
+ std::array<uint32_t, 3> mtxIndices;
+ for (uint32_t i = 0; i < 3; i++) {
+ mtxIndices[i] = m_module.opCompositeExtract(m_vec4Type, nrmMtx, 1, &i);
+ mtxIndices[i] = m_module.opVectorShuffle(m_vec3Type, mtxIndices[i], mtxIndices[i], 3, indices.data());
+ }
+ nrmMtx = m_module.opCompositeConstruct(m_mat3Type, mtxIndices.size(), mtxIndices.data());
+
+ uint32_t vtxResult = m_module.opVectorTimesMatrix(m_vec4Type, vtx, worldview);
+ uint32_t nrmResult = m_module.opVectorTimesMatrix(m_vec3Type, normal, nrmMtx);
+
+ uint32_t weight;
+ if (i != m_vsKey.Data.Contents.VertexBlendCount) {
+ weight = m_module.opCompositeExtract(m_floatType, m_vs.in.BLENDWEIGHT, 1, &i);
+ blendWeightRemaining = m_module.opFSub(m_floatType, blendWeightRemaining, weight);
+ }
+ else
+ weight = blendWeightRemaining;
+
+ vtxResult = m_module.opVectorTimesScalar(m_vec4Type, vtxResult, weight);
+ nrmResult = m_module.opVectorTimesScalar(m_vec3Type, nrmResult, weight);
+
+ vtxSum = m_module.opFAdd(m_vec4Type, vtxSum, vtxResult);
+ nrmSum = m_module.opFAdd(m_vec3Type, nrmSum, nrmResult);
+ }
+
+ vtx = vtxSum;
+ normal = nrmSum;
+ }
+ else {
+ vtx = m_module.opVectorTimesMatrix(m_vec4Type, vtx, m_vs.constants.worldview);
+
+ uint32_t nrmMtx = m_vs.constants.normal;
+
+ std::array<uint32_t, 3> mtxIndices;
+ for (uint32_t i = 0; i < 3; i++) {
+ mtxIndices[i] = m_module.opCompositeExtract(m_vec4Type, nrmMtx, 1, &i);
+ mtxIndices[i] = m_module.opVectorShuffle(m_vec3Type, mtxIndices[i], mtxIndices[i], 3, indices.data());
+ }
+ nrmMtx = m_module.opCompositeConstruct(m_mat3Type, mtxIndices.size(), mtxIndices.data());
+
+ normal = m_module.opMatrixTimesVector(m_vec3Type, nrmMtx, normal);
+ }
+
+ // Some games rely no normals not being normal.
+ if (m_vsKey.Data.Contents.NormalizeNormals) {
+ uint32_t bool_t = m_module.defBoolType();
+ uint32_t bool3_t = m_module.defVectorType(bool_t, 3);
+
+ uint32_t isZeroNormal = m_module.opAll(bool_t, m_module.opFOrdEqual(bool3_t, normal, m_module.constvec3f32(0.0f, 0.0f, 0.0f)));
+
+ std::array<uint32_t, 3> members = { isZeroNormal, isZeroNormal, isZeroNormal };
+ uint32_t isZeroNormal3 = m_module.opCompositeConstruct(bool3_t, members.size(), members.data());
+
+ normal = m_module.opNormalize(m_vec3Type, normal);
+ normal = m_module.opSelect(m_vec3Type, isZeroNormal3, m_module.constvec3f32(0.0f, 0.0f, 0.0f), normal);
+ }
+
+ gl_Position = m_module.opVectorTimesMatrix(m_vec4Type, vtx, m_vs.constants.proj);
+ } else {
+ gl_Position = m_module.opFMul(m_vec4Type, gl_Position, m_vs.constants.invExtent);
+ gl_Position = m_module.opFAdd(m_vec4Type, gl_Position, m_vs.constants.invOffset);
+
+ // We still need to account for perspective correction here...
+
+ // gl_Position.w = 1.0f / gl_Position.w
+ // gl_Position.xyz *= gl_Position.w;
+
+ uint32_t bool_t = m_module.defBoolType();
+
+ uint32_t w = m_module.opCompositeExtract (m_floatType, gl_Position, 1, &wIndex); // w = gl_Position.w
+ uint32_t is0 = m_module.opFOrdEqual (bool_t, w, m_module.constf32(0)); // is0 = w == 0
+ uint32_t rhw = m_module.opFDiv (m_floatType, m_module.constf32(1.0f), w); // rhw = 1.0f / w
+ rhw = m_module.opSelect (m_floatType, is0, m_module.constf32(1.0), rhw); // rhw = w == 0 ? 1.0 : rhw
+ gl_Position = m_module.opVectorTimesScalar(m_vec4Type, gl_Position, rhw); // gl_Position.xyz *= rhw
+ gl_Position = m_module.opCompositeInsert (m_vec4Type, rhw, gl_Position, 1, &wIndex); // gl_Position.w = rhw
+ }
+
+ m_module.opStore(m_vs.out.POSITION, gl_Position);
+
+ std::array<uint32_t, 4> outNrmIndices;
+ for (uint32_t i = 0; i < 3; i++)
+ outNrmIndices[i] = m_module.opCompositeExtract(m_floatType, normal, 1, &i);
+ outNrmIndices[3] = m_module.constf32(1.0f);
+
+ uint32_t outNrm = m_module.opCompositeConstruct(m_vec4Type, outNrmIndices.size(), outNrmIndices.data());
+
+ m_module.opStore(m_vs.out.NORMAL, outNrm);
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ uint32_t inputIndex = (m_vsKey.Data.Contents.TexcoordIndices >> (i * 3)) & 0b111;
+ uint32_t inputFlags = (m_vsKey.Data.Contents.TexcoordFlags >> (i * 3)) & 0b111;
+
+ uint32_t transformed;
+
+ const uint32_t wIndex = 3;
+
+ uint32_t flags = (m_vsKey.Data.Contents.TransformFlags >> (i * 3)) & 0b111;
+ uint32_t count = flags;
+ switch (inputFlags) {
+ default:
+ case (DXVK_TSS_TCI_PASSTHRU >> TCIOffset):
+ transformed = m_vs.in.TEXCOORD[inputIndex & 0xFF];
+ break;
+
+ case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset):
+ transformed = outNrm;
+ count = 4;
+ break;
+
+ case (DXVK_TSS_TCI_CAMERASPACEPOSITION >> TCIOffset):
+ transformed = m_module.opCompositeInsert(m_vec4Type, m_module.constf32(1.0f), vtx, 1, &wIndex);
+ count = 4;
+ break;
+
+ case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): {
+ uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
+ vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
+
+ uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
+
+ std::array<uint32_t, 4> transformIndices;
+ for (uint32_t i = 0; i < 3; i++)
+ transformIndices[i] = m_module.opCompositeExtract(m_floatType, reflection, 1, &i);
+ transformIndices[3] = m_module.constf32(1.0f);
+
+ transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
+ count = 4;
+ break;
+ }
+
+ case (DXVK_TSS_TCI_SPHEREMAP >> TCIOffset): {
+ uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
+ vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
+
+ uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
+ uint32_t m = m_module.opFAdd(m_vec3Type, reflection, m_module.constvec3f32(0, 0, 1));
+ m = m_module.opLength(m_floatType, m);
+ m = m_module.opFMul(m_floatType, m, m_module.constf32(2.0f));
+
+ std::array<uint32_t, 4> transformIndices;
+ for (uint32_t i = 0; i < 2; i++) {
+ transformIndices[i] = m_module.opCompositeExtract(m_floatType, reflection, 1, &i);
+ transformIndices[i] = m_module.opFDiv(m_floatType, transformIndices[i], m);
+ transformIndices[i] = m_module.opFAdd(m_floatType, transformIndices[i], m_module.constf32(0.5f));
+ }
+
+ transformIndices[2] = m_module.constf32(0.0f);
+ transformIndices[3] = m_module.constf32(1.0f);
+
+ transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
+ count = 4;
+ break;
+ }
+ }
+
+ uint32_t type = flags;
+ if (type != D3DTTFF_DISABLE) {
+ if (!m_vsKey.Data.Contents.HasPositionT) {
+ for (uint32_t j = count; j < 4; j++) {
+ // If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes.
+ // Otherwise, pad with ones.
+
+ // Very weird quirk in order to get texcoord transforms to work like they do in native.
+ // In future, maybe we could sort this out properly by chopping matrices of different sizes, but thats
+ // a project for another day.
+ uint32_t texcoordCount = (m_vsKey.Data.Contents.TexcoordDeclMask >> (3 * inputIndex)) & 0x7;
+ uint32_t value = j > texcoordCount ? m_module.constf32(0) : m_module.constf32(1);
+ transformed = m_module.opCompositeInsert(m_vec4Type, value, transformed, 1, &j);
+ }
+
+ transformed = m_module.opVectorTimesMatrix(m_vec4Type, transformed, m_vs.constants.texcoord[i]);
+ }
+
+ // Pad the unused section of it with the value for projection.
+ uint32_t lastIdx = count - 1;
+ uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &lastIdx);
+
+ for (uint32_t j = count; j < 4; j++)
+ transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &j);
+ }
+
+ m_module.opStore(m_vs.out.TEXCOORD[i], transformed);
+ }
+
+ if (m_vsKey.Data.Contents.UseLighting) {
+ auto PickSource = [&](uint32_t Source, uint32_t Material) {
+ if (Source == D3DMCS_MATERIAL)
+ return Material;
+ else if (Source == D3DMCS_COLOR1)
+ return m_vs.in.COLOR[0];
+ else
+ return m_vs.in.COLOR[1];
+ };
+
+ uint32_t diffuseValue = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+ uint32_t specularValue = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+ uint32_t ambientValue = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (uint32_t i = 0; i < m_vsKey.Data.Contents.LightCount; i++) {
+ uint32_t light_ptr_t = m_module.defPointerType(m_vs.lightType, spv::StorageClassUniform);
+
+ uint32_t indexVal = m_module.constu32(uint32_t(D3D9FFVSMembers::Light0) + i);
+ uint32_t lightPtr = m_module.opAccessChain(light_ptr_t, m_vs.constantBuffer, 1, &indexVal);
+
+ auto LoadLightItem = [&](uint32_t type, uint32_t idx) {
+ uint32_t typePtr = m_module.defPointerType(type, spv::StorageClassUniform);
+
+ idx = m_module.constu32(idx);
+
+ return m_module.opLoad(type,
+ m_module.opAccessChain(typePtr, lightPtr, 1, &idx));
+ };
+
+ uint32_t diffuse = LoadLightItem(m_vec4Type, 0);
+ uint32_t specular = LoadLightItem(m_vec4Type, 1);
+ uint32_t ambient = LoadLightItem(m_vec4Type, 2);
+ uint32_t position = LoadLightItem(m_vec4Type, 3);
+ uint32_t direction = LoadLightItem(m_vec4Type, 4);
+ uint32_t type = LoadLightItem(m_uint32Type, 5);
+ uint32_t range = LoadLightItem(m_floatType, 6);
+ uint32_t falloff = LoadLightItem(m_floatType, 7);
+ uint32_t atten0 = LoadLightItem(m_floatType, 8);
+ uint32_t atten1 = LoadLightItem(m_floatType, 9);
+ uint32_t atten2 = LoadLightItem(m_floatType, 10);
+ uint32_t theta = LoadLightItem(m_floatType, 11);
+ uint32_t phi = LoadLightItem(m_floatType, 12);
+
+ uint32_t bool_t = m_module.defBoolType();
+ uint32_t bool3_t = m_module.defVectorType(bool_t, 3);
+
+ uint32_t isSpot = m_module.opIEqual(bool_t, type, m_module.constu32(D3DLIGHT_SPOT));
+ uint32_t isDirectional = m_module.opIEqual(bool_t, type, m_module.constu32(D3DLIGHT_DIRECTIONAL));
+
+ std::array<uint32_t, 3> members = { isDirectional, isDirectional, isDirectional };
+
+ uint32_t isDirectional3 = m_module.opCompositeConstruct(bool3_t, members.size(), members.data());
+
+ uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
+ position = m_module.opVectorShuffle(m_vec3Type, position, position, 3, indices.data());
+ direction = m_module.opVectorShuffle(m_vec3Type, direction, direction, 3, indices.data());
+
+ uint32_t delta = m_module.opFSub(m_vec3Type, position, vtx3);
+ uint32_t d = m_module.opLength(m_floatType, delta);
+ uint32_t hitDir = m_module.opFNegate(m_vec3Type, direction);
+ hitDir = m_module.opSelect(m_vec3Type, isDirectional3, hitDir, delta);
+ hitDir = m_module.opNormalize(m_vec3Type, hitDir);
+
+ uint32_t atten = m_module.opFFma (m_floatType, d, atten2, atten1);
+ atten = m_module.opFFma (m_floatType, d, atten, atten0);
+ atten = m_module.opFDiv (m_floatType, m_module.constf32(1.0f), atten);
+ atten = m_module.opNMin (m_floatType, atten, m_module.constf32(FLT_MAX));
+
+ atten = m_module.opSelect(m_floatType, m_module.opFOrdGreaterThan(bool_t, d, range), m_module.constf32(0.0f), atten);
+ atten = m_module.opSelect(m_floatType, isDirectional, m_module.constf32(1.0f), atten);
+
+ // Spot Lighting
+ {
+ uint32_t rho = m_module.opDot (m_floatType, m_module.opFNegate(m_vec3Type, hitDir), direction);
+ uint32_t spotAtten = m_module.opFSub(m_floatType, rho, phi);
+ spotAtten = m_module.opFDiv(m_floatType, spotAtten, m_module.opFSub(m_floatType, theta, phi));
+ spotAtten = m_module.opPow (m_floatType, spotAtten, falloff);
+
+ uint32_t insideThetaAndPhi = m_module.opFOrdLessThanEqual(bool_t, rho, theta);
+ uint32_t insidePhi = m_module.opFOrdGreaterThan(bool_t, rho, phi);
+ spotAtten = m_module.opSelect(m_floatType, insidePhi, spotAtten, m_module.constf32(0.0f));
+ spotAtten = m_module.opSelect(m_floatType, insideThetaAndPhi, spotAtten, m_module.constf32(1.0f));
+ spotAtten = m_module.opFClamp(m_floatType, spotAtten, m_module.constf32(0.0f), m_module.constf32(1.0f));
+
+ spotAtten = m_module.opFMul(m_floatType, atten, spotAtten);
+ atten = m_module.opSelect(m_floatType, isSpot, spotAtten, atten);
+ }
+
+
+ uint32_t hitDot = m_module.opDot(m_floatType, normal, hitDir);
+ hitDot = m_module.opFClamp(m_floatType, hitDot, m_module.constf32(0.0f), m_module.constf32(1.0f));
+
+ uint32_t diffuseness = m_module.opFMul(m_floatType, hitDot, atten);
+
+ uint32_t mid;
+ if (m_vsKey.Data.Contents.LocalViewer) {
+ mid = m_module.opNormalize(m_vec3Type, vtx3);
+ mid = m_module.opFSub(m_vec3Type, hitDir, mid);
+ }
+ else
+ mid = m_module.opFSub(m_vec3Type, hitDir, m_module.constvec3f32(0.0f, 0.0f, 1.0f));
+
+ mid = m_module.opNormalize(m_vec3Type, mid);
+
+ uint32_t midDot = m_module.opDot(m_floatType, normal, mid);
+ midDot = m_module.opFClamp(m_floatType, midDot, m_module.constf32(0.0f), m_module.constf32(1.0f));
+ uint32_t doSpec = m_module.opFOrdGreaterThan(bool_t, midDot, m_module.constf32(0.0f));
+ uint32_t specularness = m_module.opPow(m_floatType, midDot, m_vs.constants.materialPower);
+ specularness = m_module.opFMul(m_floatType, specularness, atten);
+ specularness = m_module.opSelect(m_floatType, doSpec, specularness, m_module.constf32(0.0f));
+
+ uint32_t lightAmbient = m_module.opVectorTimesScalar(m_vec4Type, ambient, atten);
+ uint32_t lightDiffuse = m_module.opVectorTimesScalar(m_vec4Type, diffuse, diffuseness);
+ uint32_t lightSpecular = m_module.opVectorTimesScalar(m_vec4Type, specular, specularness);
+
+ ambientValue = m_module.opFAdd(m_vec4Type, ambientValue, lightAmbient);
+ diffuseValue = m_module.opFAdd(m_vec4Type, diffuseValue, lightDiffuse);
+ specularValue = m_module.opFAdd(m_vec4Type, specularValue, lightSpecular);
+ }
+
+ uint32_t mat_diffuse = PickSource(m_vsKey.Data.Contents.DiffuseSource, m_vs.constants.materialDiffuse);
+ uint32_t mat_ambient = PickSource(m_vsKey.Data.Contents.AmbientSource, m_vs.constants.materialAmbient);
+ uint32_t mat_emissive = PickSource(m_vsKey.Data.Contents.EmissiveSource, m_vs.constants.materialEmissive);
+ uint32_t mat_specular = PickSource(m_vsKey.Data.Contents.SpecularSource, m_vs.constants.materialSpecular);
+
+ std::array<uint32_t, 4> alphaSwizzle = {0, 1, 2, 7};
+ uint32_t finalColor0 = m_module.opFFma(m_vec4Type, mat_ambient, m_vs.constants.globalAmbient, mat_emissive);
+ finalColor0 = m_module.opFFma(m_vec4Type, mat_ambient, ambientValue, finalColor0);
+ finalColor0 = m_module.opFFma(m_vec4Type, mat_diffuse, diffuseValue, finalColor0);
+ finalColor0 = m_module.opVectorShuffle(m_vec4Type, finalColor0, mat_diffuse, alphaSwizzle.size(), alphaSwizzle.data());
+
+ uint32_t finalColor1 = m_module.opFMul(m_vec4Type, mat_specular, specularValue);
+
+ // Saturate
+ finalColor0 = m_module.opFClamp(m_vec4Type, finalColor0,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f),
+ m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f));
+
+ finalColor1 = m_module.opFClamp(m_vec4Type, finalColor1,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f),
+ m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f));
+
+ m_module.opStore(m_vs.out.COLOR[0], finalColor0);
+ m_module.opStore(m_vs.out.COLOR[1], finalColor1);
+ }
+ else {
+ m_module.opStore(m_vs.out.COLOR[0], m_vs.in.COLOR[0]);
+ m_module.opStore(m_vs.out.COLOR[1], m_vs.in.COLOR[1]);
+ }
+
+ D3D9FogContext fogCtx;
+ fogCtx.IsPixel = false;
+ fogCtx.RangeFog = m_vsKey.Data.Contents.RangeFog;
+ fogCtx.RenderState = m_rsBlock;
+ fogCtx.vPos = vtx;
+ fogCtx.HasFogInput = m_vsKey.Data.Contents.HasFog;
+ fogCtx.vFog = m_vs.in.FOG;
+ fogCtx.oColor = 0;
+ fogCtx.IsFixedFunction = true;
+ fogCtx.IsPositionT = m_vsKey.Data.Contents.HasPositionT;
+ fogCtx.HasSpecular = m_vsKey.Data.Contents.HasColor1;
+ fogCtx.Specular = m_vs.in.COLOR[1];
+ m_module.opStore(m_vs.out.FOG, DoFixedFunctionFog(m_module, fogCtx));
+
+ auto pointInfo = GetPointSizeInfoVS(m_module, 0, vtx, m_vs.in.POINTSIZE, m_rsBlock, true);
+
+ uint32_t pointSize = m_module.opFClamp(m_floatType, pointInfo.defaultValue, pointInfo.min, pointInfo.max);
+ m_module.opStore(m_vs.out.POINTSIZE, pointSize);
+
+ if (m_vsKey.Data.Contents.VertexClipping)
+ emitVsClipping(vtx);
+ }
+
+
+ void D3D9FFShaderCompiler::setupRenderStateInfo() {
+ uint32_t count;
+
+ if (m_programType == DxsoProgramType::PixelShader) {
+ m_interfaceSlots.pushConstOffset = 0;
+ m_interfaceSlots.pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
+ count = 5;
+ }
+ else {
+ m_interfaceSlots.pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
+ m_interfaceSlots.pushConstSize = sizeof(float) * 6;
+ count = 11;
+ }
+
+ m_rsBlock = SetupRenderStateBlock(m_module, count);
+ }
+
+
+ void D3D9FFShaderCompiler::emitLightTypeDecl() {
+ std::array<uint32_t, 13> light_members = {
+ m_vec4Type, // Diffuse
+ m_vec4Type, // Specular
+ m_vec4Type, // Ambient
+ m_vec4Type, // Position
+ m_vec4Type, // Direction
+ m_uint32Type, // Type
+ m_floatType, // Range
+ m_floatType, // Falloff
+ m_floatType, // Attenuation0
+ m_floatType, // Attenuation1
+ m_floatType, // Attenuation2
+ m_floatType, // Theta
+ m_floatType, // Phi
+ };
+
+ m_vs.lightType =
+ m_module.defStructType(light_members.size(), light_members.data());
+
+ m_module.setDebugName(m_vs.lightType, "light_t");
+
+ uint32_t offset = 0;
+
+ m_module.memberDecorateOffset(m_vs.lightType, 0, offset); offset += 4 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 0, "Diffuse");
+ m_module.memberDecorateOffset(m_vs.lightType, 1, offset); offset += 4 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 1, "Specular");
+ m_module.memberDecorateOffset(m_vs.lightType, 2, offset); offset += 4 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 2, "Ambient");
+
+ m_module.memberDecorateOffset(m_vs.lightType, 3, offset); offset += 4 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 3, "Position");
+ m_module.memberDecorateOffset(m_vs.lightType, 4, offset); offset += 4 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 4, "Direction");
+
+ m_module.memberDecorateOffset(m_vs.lightType, 5, offset); offset += 1 * sizeof(uint32_t);
+ m_module.setDebugMemberName (m_vs.lightType, 5, "Type");
+
+ m_module.memberDecorateOffset(m_vs.lightType, 6, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 6, "Range");
+ m_module.memberDecorateOffset(m_vs.lightType, 7, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 7, "Falloff");
+
+ m_module.memberDecorateOffset(m_vs.lightType, 8, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 8, "Attenuation0");
+ m_module.memberDecorateOffset(m_vs.lightType, 9, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 9, "Attenuation1");
+ m_module.memberDecorateOffset(m_vs.lightType, 10, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 10, "Attenuation2");
+
+ m_module.memberDecorateOffset(m_vs.lightType, 11, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 11, "Theta");
+ m_module.memberDecorateOffset(m_vs.lightType, 12, offset); offset += 1 * sizeof(float);
+ m_module.setDebugMemberName (m_vs.lightType, 12, "Phi");
+ }
+
+
+ void D3D9FFShaderCompiler::emitBaseBufferDecl() {
+ // Constant Buffer for VS.
+ std::array<uint32_t, uint32_t(D3D9FFVSMembers::MemberCount)> members = {
+ m_mat4Type, // World
+ m_mat4Type, // View
+ m_mat4Type, // InverseView
+ m_mat4Type, // Proj
+
+ m_mat4Type, // Texture0
+ m_mat4Type, // Texture1
+ m_mat4Type, // Texture2
+ m_mat4Type, // Texture3
+ m_mat4Type, // Texture4
+ m_mat4Type, // Texture5
+ m_mat4Type, // Texture6
+ m_mat4Type, // Texture7
+
+ m_vec4Type, // Inverse Offset
+ m_vec4Type, // Inverse Extent
+
+ m_vec4Type, // Global Ambient
+
+ m_vs.lightType, // Light0
+ m_vs.lightType, // Light1
+ m_vs.lightType, // Light2
+ m_vs.lightType, // Light3
+ m_vs.lightType, // Light4
+ m_vs.lightType, // Light5
+ m_vs.lightType, // Light6
+ m_vs.lightType, // Light7
+
+ m_vec4Type, // Material Diffuse
+ m_vec4Type, // Material Ambient
+ m_vec4Type, // Material Specular
+ m_vec4Type, // Material Emissive
+ m_floatType, // Material Power
+
+ m_floatType, // Tween Factor
+ };
+
+ const uint32_t structType =
+ m_module.defStructType(members.size(), members.data());
+
+ m_module.decorateBlock(structType);
+
+ uint32_t offset = 0;
+
+ for (uint32_t i = 0; i < uint32_t(D3D9FFVSMembers::InverseOffset); i++) {
+ m_module.memberDecorateOffset(structType, i, offset);
+ offset += sizeof(Matrix4);
+ m_module.memberDecorateMatrixStride(structType, i, 16);
+ m_module.memberDecorate(structType, i, spv::DecorationRowMajor);
+ }
+
+ for (uint32_t i = uint32_t(D3D9FFVSMembers::InverseOffset); i < uint32_t(D3D9FFVSMembers::Light0); i++) {
+ m_module.memberDecorateOffset(structType, i, offset);
+ offset += sizeof(Vector4);
+ }
+
+ for (uint32_t i = 0; i < caps::MaxEnabledLights; i++) {
+ m_module.memberDecorateOffset(structType, uint32_t(D3D9FFVSMembers::Light0) + i, offset);
+ offset += sizeof(D3D9Light);
+ }
+
+ for (uint32_t i = uint32_t(D3D9FFVSMembers::MaterialDiffuse); i < uint32_t(D3D9FFVSMembers::MaterialPower); i++) {
+ m_module.memberDecorateOffset(structType, i, offset);
+ offset += sizeof(Vector4);
+ }
+
+ m_module.memberDecorateOffset(structType, uint32_t(D3D9FFVSMembers::MaterialPower), offset);
+ offset += sizeof(float);
+
+ m_module.memberDecorateOffset(structType, uint32_t(D3D9FFVSMembers::TweenFactor), offset);
+ offset += sizeof(float);
+
+ m_module.setDebugName(structType, "D3D9FixedFunctionVS");
+ uint32_t member = 0;
+ m_module.setDebugMemberName(structType, member++, "WorldView");
+ m_module.setDebugMemberName(structType, member++, "Normal");
+ m_module.setDebugMemberName(structType, member++, "InverseView");
+ m_module.setDebugMemberName(structType, member++, "Projection");
+
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform0");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform1");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform2");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform3");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform4");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform5");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform6");
+ m_module.setDebugMemberName(structType, member++, "TexcoordTransform7");
+
+ m_module.setDebugMemberName(structType, member++, "ViewportInfo_InverseOffset");
+ m_module.setDebugMemberName(structType, member++, "ViewportInfo_InverseExtent");
+
+ m_module.setDebugMemberName(structType, member++, "GlobalAmbient");
+
+ m_module.setDebugMemberName(structType, member++, "Light0");
+ m_module.setDebugMemberName(structType, member++, "Light1");
+ m_module.setDebugMemberName(structType, member++, "Light2");
+ m_module.setDebugMemberName(structType, member++, "Light3");
+ m_module.setDebugMemberName(structType, member++, "Light4");
+ m_module.setDebugMemberName(structType, member++, "Light5");
+ m_module.setDebugMemberName(structType, member++, "Light6");
+ m_module.setDebugMemberName(structType, member++, "Light7");
+
+ m_module.setDebugMemberName(structType, member++, "Material_Diffuse");
+ m_module.setDebugMemberName(structType, member++, "Material_Ambient");
+ m_module.setDebugMemberName(structType, member++, "Material_Specular");
+ m_module.setDebugMemberName(structType, member++, "Material_Emissive");
+ m_module.setDebugMemberName(structType, member++, "Material_Power");
+
+ m_module.setDebugMemberName(structType, member++, "TweenFactor");
+
+ m_vs.constantBuffer = m_module.newVar(
+ m_module.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.setDebugName(m_vs.constantBuffer, "consts");
+
+ const uint32_t bindingId = computeResourceSlotId(
+ DxsoProgramType::VertexShader, DxsoBindingType::ConstantBuffer,
+ DxsoConstantBuffers::VSFixedFunction);
+
+ m_module.decorateDescriptorSet(m_vs.constantBuffer, 0);
+ m_module.decorateBinding(m_vs.constantBuffer, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void D3D9FFShaderCompiler::emitVertexBlendDecl() {
+ const uint32_t arrayType = m_module.defRuntimeArrayTypeUnique(m_mat4Type);
+ m_module.decorateArrayStride(arrayType, sizeof(Matrix4));
+
+ const uint32_t structType = m_module.defStructTypeUnique(1, &arrayType);
+
+ m_module.memberDecorateMatrixStride(structType, 0, 16);
+ m_module.memberDecorate(structType, 0, spv::DecorationRowMajor);
+
+ m_module.decorate(structType, spv::DecorationBufferBlock);
+
+ m_module.memberDecorateOffset(structType, 0, 0);
+
+ m_module.setDebugName(structType, "D3D9FF_VertexBlendData");
+ m_module.setDebugMemberName(structType, 0, "WorldViewArray");
+
+ m_vs.vertexBlendData = m_module.newVar(
+ m_module.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.setDebugName(m_vs.vertexBlendData, "VertexBlendData");
+
+ const uint32_t bindingId = computeResourceSlotId(
+ DxsoProgramType::VertexShader, DxsoBindingType::ConstantBuffer,
+ DxsoConstantBuffers::VSVertexBlendData);
+
+ m_module.decorateDescriptorSet(m_vs.vertexBlendData, 0);
+ m_module.decorateBinding(m_vs.vertexBlendData, bindingId);
+
+ m_module.decorate(m_vs.vertexBlendData, spv::DecorationNonWritable);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_SHADER_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void D3D9FFShaderCompiler::setupVS() {
+ setupRenderStateInfo();
+
+ // VS Caps
+ m_module.enableCapability(spv::CapabilityClipDistance);
+
+ emitLightTypeDecl();
+ emitBaseBufferDecl();
+
+ if (m_vsKey.Data.Contents.VertexBlendMode == D3D9FF_VertexBlendMode_Normal)
+ emitVertexBlendDecl();
+
+ // Load constants
+ auto LoadConstant = [&](uint32_t type, uint32_t idx) {
+ uint32_t offset = m_module.constu32(idx);
+ uint32_t typePtr = m_module.defPointerType(type, spv::StorageClassUniform);
+
+ return m_module.opLoad(type,
+ m_module.opAccessChain(typePtr, m_vs.constantBuffer, 1, &offset));
+ };
+
+ m_vs.constants.worldview = LoadConstant(m_mat4Type, uint32_t(D3D9FFVSMembers::WorldViewMatrix));
+ m_vs.constants.normal = LoadConstant(m_mat4Type, uint32_t(D3D9FFVSMembers::NormalMatrix));
+ m_vs.constants.inverseView = LoadConstant(m_mat4Type, uint32_t(D3D9FFVSMembers::InverseViewMatrix));
+ m_vs.constants.proj = LoadConstant(m_mat4Type, uint32_t(D3D9FFVSMembers::ProjMatrix));
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++)
+ m_vs.constants.texcoord[i] = LoadConstant(m_mat4Type, uint32_t(D3D9FFVSMembers::Texcoord0) + i);
+
+ m_vs.constants.invOffset = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::InverseOffset));
+ m_vs.constants.invExtent = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::InverseExtent));
+
+ m_vs.constants.globalAmbient = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::GlobalAmbient));
+
+ m_vs.constants.materialDiffuse = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::MaterialDiffuse));
+ m_vs.constants.materialAmbient = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::MaterialAmbient));
+ m_vs.constants.materialSpecular = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::MaterialSpecular));
+ m_vs.constants.materialEmissive = LoadConstant(m_vec4Type, uint32_t(D3D9FFVSMembers::MaterialEmissive));
+ m_vs.constants.materialPower = LoadConstant(m_floatType, uint32_t(D3D9FFVSMembers::MaterialPower));
+ m_vs.constants.tweenFactor = LoadConstant(m_floatType, uint32_t(D3D9FFVSMembers::TweenFactor));
+
+ // Do IO
+ m_vs.in.POSITION = declareIO(true, DxsoSemantic{ DxsoUsage::Position, 0 });
+ m_vs.in.NORMAL = declareIO(true, DxsoSemantic{ DxsoUsage::Normal, 0 });
+
+ if (m_vsKey.Data.Contents.VertexBlendMode == D3D9FF_VertexBlendMode_Tween) {
+ m_vs.in.POSITION1 = declareIO(true, DxsoSemantic{ DxsoUsage::Position, 1 });
+ m_vs.in.NORMAL1 = declareIO(true, DxsoSemantic{ DxsoUsage::Normal, 1 });
+ }
+ else {
+ m_isgn.elemCount++;
+ m_isgn.elemCount++;
+ }
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++)
+ m_vs.in.TEXCOORD[i] = declareIO(true, DxsoSemantic{ DxsoUsage::Texcoord, i });
+
+ if (m_vsKey.Data.Contents.HasColor0)
+ m_vs.in.COLOR[0] = declareIO(true, DxsoSemantic{ DxsoUsage::Color, 0 });
+ else {
+ m_vs.in.COLOR[0] = m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f);
+ m_isgn.elemCount++;
+ }
+
+ if (m_vsKey.Data.Contents.HasColor1)
+ m_vs.in.COLOR[1] = declareIO(true, DxsoSemantic{ DxsoUsage::Color, 1 });
+ else {
+ m_vs.in.COLOR[1] = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+ m_isgn.elemCount++;
+ }
+
+ if (m_vsKey.Data.Contents.HasFog)
+ m_vs.in.FOG = declareIO(true, DxsoSemantic{ DxsoUsage::Fog, 0 });
+ else
+ m_isgn.elemCount++;
+
+ if (m_vsKey.Data.Contents.HasPointSize)
+ m_vs.in.POINTSIZE = declareIO(true, DxsoSemantic{ DxsoUsage::PointSize, 0 });
+ else
+ m_isgn.elemCount++;
+
+ if (m_vsKey.Data.Contents.VertexBlendMode == D3D9FF_VertexBlendMode_Normal) {
+ m_vs.in.BLENDWEIGHT = declareIO(true, DxsoSemantic{ DxsoUsage::BlendWeight, 0 });
+ m_vs.in.BLENDINDICES = declareIO(true, DxsoSemantic{ DxsoUsage::BlendIndices, 0 });
+ }
+ else {
+ m_isgn.elemCount++;
+ m_isgn.elemCount++;
+ }
+
+ // Declare Outputs
+ m_vs.out.POSITION = declareIO(false, DxsoSemantic{ DxsoUsage::Position, 0 }, spv::BuiltInPosition);
+ if (m_options.invariantPosition)
+ m_module.decorate(m_vs.out.POSITION, spv::DecorationInvariant);
+
+ m_vs.out.POINTSIZE = declareIO(false, DxsoSemantic{ DxsoUsage::PointSize, 0 }, spv::BuiltInPointSize);
+
+ m_vs.out.NORMAL = declareIO(false, DxsoSemantic{ DxsoUsage::Normal, 0 });
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++)
+ m_vs.out.TEXCOORD[i] = declareIO(false, DxsoSemantic{ DxsoUsage::Texcoord, i });
+
+ m_vs.out.COLOR[0] = declareIO(false, DxsoSemantic{ DxsoUsage::Color, 0 });
+ m_vs.out.COLOR[1] = declareIO(false, DxsoSemantic{ DxsoUsage::Color, 1 });
+
+ m_vs.out.FOG = declareIO(false, DxsoSemantic{ DxsoUsage::Fog, 0 });
+ }
+
+
+ void D3D9FFShaderCompiler::compilePS() {
+ setupPS();
+
+ uint32_t diffuse = m_ps.in.COLOR[0];
+ uint32_t specular = m_ps.in.COLOR[1];
+
+ // Current starts of as equal to diffuse.
+ uint32_t current = diffuse;
+ // Temp starts off as equal to vec4(0)
+ uint32_t temp = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+
+ uint32_t texture = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 1.0f);
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ const auto& stage = m_fsKey.Stages[i].Contents;
+
+ bool processedTexture = false;
+
+ auto DoBumpmapCoords = [&](uint32_t typeId, uint32_t baseCoords) {
+ uint32_t stage = i - 1;
+
+ uint32_t coords = baseCoords;
+ for (uint32_t i = 0; i < 2; i++) {
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ uint32_t tc_m_n = m_module.opCompositeExtract(m_floatType, coords, 1, &i);
+
+ uint32_t offset = m_module.constu32(D3D9SharedPSStages_Count * stage + D3D9SharedPSStages_BumpEnvMat0 + i);
+ uint32_t bm = m_module.opAccessChain(m_module.defPointerType(m_vec2Type, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &offset);
+ bm = m_module.opLoad(m_vec2Type, bm);
+
+ uint32_t t = m_module.opVectorShuffle(m_vec2Type, texture, texture, 2, indices.data());
+
+ uint32_t dot = m_module.opDot(m_floatType, bm, t);
+
+ uint32_t result = m_module.opFAdd(m_floatType, tc_m_n, dot);
+ coords = m_module.opCompositeInsert(typeId, result, coords, 1, &i);
+ }
+
+ return coords;
+ };
+
+ auto GetTexture = [&]() {
+ if (!processedTexture) {
+ SpirvImageOperands imageOperands;
+ uint32_t imageVarId = m_module.opLoad(m_ps.samplers[i].typeId, m_ps.samplers[i].varId);
+
+ uint32_t texcoordCnt = m_ps.samplers[i].texcoordCnt;
+
+ // Add one for the texcoord count
+ // if we need to include the divider
+ if (m_fsKey.Stages[i].Contents.Projected)
+ texcoordCnt++;
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ uint32_t texcoord = m_ps.in.TEXCOORD[i];
+ uint32_t texcoord_t = m_module.defVectorType(m_floatType, texcoordCnt);
+ texcoord = m_module.opVectorShuffle(texcoord_t,
+ texcoord, texcoord, texcoordCnt, indices.data());
+
+ uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount;
+ if (projIdx == 0)
+ projIdx = texcoordCnt;
+ else
+ projIdx--;
+
+ uint32_t projValue = 0;
+
+ if (m_fsKey.Stages[i].Contents.Projected) {
+ projValue = m_module.opCompositeExtract(m_floatType, m_ps.in.TEXCOORD[i], 1, &projIdx);
+ uint32_t insertIdx = texcoordCnt - 1;
+ texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx);
+ }
+
+ bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
+
+ if (i != 0 && (
+ m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP ||
+ m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {
+ if (shouldProject) {
+ uint32_t projRcp = m_module.opFDiv(m_floatType, m_module.constf32(1.0), projValue);
+ texcoord = m_module.opVectorTimesScalar(texcoord_t, texcoord, projRcp);
+ }
+
+ texcoord = DoBumpmapCoords(texcoord_t, texcoord);
+
+ shouldProject = false;
+ }
+
+ if (shouldProject)
+ texture = m_module.opImageSampleProjImplicitLod(m_vec4Type, imageVarId, texcoord, imageOperands);
+ else
+ texture = m_module.opImageSampleImplicitLod(m_vec4Type, imageVarId, texcoord, imageOperands);
+
+ if (i != 0 && m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE) {
+ uint32_t index = m_module.constu32(D3D9SharedPSStages_Count * (i - 1) + D3D9SharedPSStages_BumpEnvLScale);
+ uint32_t lScale = m_module.opAccessChain(m_module.defPointerType(m_floatType, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &index);
+ lScale = m_module.opLoad(m_floatType, lScale);
+
+ index = m_module.constu32(D3D9SharedPSStages_Count * (i - 1) + D3D9SharedPSStages_BumpEnvLOffset);
+ uint32_t lOffset = m_module.opAccessChain(m_module.defPointerType(m_floatType, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &index);
+ lOffset = m_module.opLoad(m_floatType, lOffset);
+
+ uint32_t zIndex = 2;
+ uint32_t scale = m_module.opCompositeExtract(m_floatType, texture, 1, &zIndex);
+ scale = m_module.opFMul(m_floatType, scale, lScale);
+ scale = m_module.opFAdd(m_floatType, scale, lOffset);
+ scale = m_module.opFClamp(m_floatType, scale, m_module.constf32(0.0f), m_module.constf32(1.0));
+
+ texture = m_module.opVectorTimesScalar(m_vec4Type, texture, scale);
+ }
+
+ uint32_t bool_t = m_module.defBoolType();
+ uint32_t bvec4_t = m_module.defVectorType(bool_t, 4);
+ std::array<uint32_t, 4> boundIndices = { m_ps.samplers[i].bound, m_ps.samplers[i].bound, m_ps.samplers[i].bound, m_ps.samplers[i].bound };
+ uint32_t bound4 = m_module.opCompositeConstruct(bvec4_t, boundIndices.size(), boundIndices.data());
+ texture = m_module.opSelect(m_vec4Type, bound4, texture, m_module.constvec4f32(0.0f, 0.0f, 0.0f, 1.0f));
+ }
+
+ processedTexture = true;
+
+ return texture;
+ };
+
+ auto ScalarReplicate = [&](uint32_t reg) {
+ std::array<uint32_t, 4> replicant = { reg, reg, reg, reg };
+ return m_module.opCompositeConstruct(m_vec4Type, replicant.size(), replicant.data());
+ };
+
+ auto AlphaReplicate = [&](uint32_t reg) {
+ uint32_t alphaComponentId = 3;
+ uint32_t alpha = m_module.opCompositeExtract(m_floatType, reg, 1, &alphaComponentId);
+
+ return ScalarReplicate(alpha);
+ };
+
+ auto Complement = [&](uint32_t reg) {
+ return m_module.opFSub(m_vec4Type,
+ m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f),
+ reg);
+ };
+
+ auto Saturate = [&](uint32_t reg) {
+ return m_module.opFClamp(m_vec4Type, reg,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f),
+ m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f));
+ };
+
+ auto GetArg = [&] (uint32_t arg) {
+ uint32_t reg = m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f);
+
+ switch (arg & D3DTA_SELECTMASK) {
+ case D3DTA_CONSTANT: {
+ uint32_t offset = m_module.constu32(D3D9SharedPSStages_Count * i + D3D9SharedPSStages_Constant);
+ uint32_t ptr = m_module.opAccessChain(m_module.defPointerType(m_vec4Type, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &offset);
+
+ reg = m_module.opLoad(m_vec4Type, ptr);
+ break;
+ }
+ case D3DTA_CURRENT:
+ reg = current;
+ break;
+ case D3DTA_DIFFUSE:
+ reg = diffuse;
+ break;
+ case D3DTA_SPECULAR:
+ reg = specular;
+ break;
+ case D3DTA_TEMP:
+ reg = temp;
+ break;
+ case D3DTA_TEXTURE:
+ reg = GetTexture();
+ break;
+ case D3DTA_TFACTOR:
+ reg = m_ps.constants.textureFactor;
+ break;
+ default:
+ break;
+ }
+
+ // reg = 1 - reg
+ if (arg & D3DTA_COMPLEMENT)
+ reg = Complement(reg);
+
+ // reg = reg.wwww
+ if (arg & D3DTA_ALPHAREPLICATE)
+ reg = AlphaReplicate(reg);
+
+ return reg;
+ };
+
+ auto DoOp = [&](D3DTEXTUREOP op, uint32_t dst, std::array<uint32_t, TextureArgCount> arg) {
+ switch (op) {
+ case D3DTOP_SELECTARG1:
+ dst = arg[1];
+ break;
+
+ case D3DTOP_SELECTARG2:
+ dst = arg[2];
+ break;
+
+ case D3DTOP_MODULATE4X:
+ dst = m_module.opFMul(m_vec4Type, arg[1], arg[2]);
+ dst = m_module.opVectorTimesScalar(m_vec4Type, dst, m_module.constf32(4.0f));
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_MODULATE2X:
+ dst = m_module.opFMul(m_vec4Type, arg[1], arg[2]);
+ dst = m_module.opVectorTimesScalar(m_vec4Type, dst, m_module.constf32(2.0f));
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_MODULATE:
+ dst = m_module.opFMul(m_vec4Type, arg[1], arg[2]);
+ break;
+
+ case D3DTOP_ADDSIGNED2X:
+ arg[2] = m_module.opFSub(m_vec4Type, arg[2],
+ m_module.constvec4f32(0.5f, 0.5f, 0.5f, 0.5f));
+
+ dst = m_module.opFAdd(m_vec4Type, arg[1], arg[2]);
+ dst = m_module.opVectorTimesScalar(m_vec4Type, dst, m_module.constf32(2.0f));
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_ADDSIGNED:
+ arg[2] = m_module.opFSub(m_vec4Type, arg[2],
+ m_module.constvec4f32(0.5f, 0.5f, 0.5f, 0.5f));
+
+ dst = m_module.opFAdd(m_vec4Type, arg[1], arg[2]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_ADD:
+ dst = m_module.opFAdd(m_vec4Type, arg[1], arg[2]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_SUBTRACT:
+ dst = m_module.opFSub(m_vec4Type, arg[1], arg[2]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_ADDSMOOTH:
+ dst = m_module.opFFma(m_vec4Type, Complement(arg[1]), arg[2], arg[1]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_BLENDDIFFUSEALPHA:
+ dst = m_module.opFMix(m_vec4Type, arg[2], arg[1], AlphaReplicate(diffuse));
+ break;
+
+ case D3DTOP_BLENDTEXTUREALPHA:
+ dst = m_module.opFMix(m_vec4Type, arg[2], arg[1], AlphaReplicate(GetTexture()));
+ break;
+
+ case D3DTOP_BLENDFACTORALPHA:
+ dst = m_module.opFMix(m_vec4Type, arg[2], arg[1], AlphaReplicate(m_ps.constants.textureFactor));
+ break;
+
+ case D3DTOP_BLENDTEXTUREALPHAPM:
+ dst = m_module.opFFma(m_vec4Type, arg[2], Complement(AlphaReplicate(GetTexture())), arg[1]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_BLENDCURRENTALPHA:
+ dst = m_module.opFMix(m_vec4Type, arg[2], arg[1], AlphaReplicate(current));
+ break;
+
+ case D3DTOP_PREMODULATE:
+ Logger::warn("D3DTOP_PREMODULATE: not implemented");
+ break;
+
+ case D3DTOP_MODULATEALPHA_ADDCOLOR:
+ dst = m_module.opFFma(m_vec4Type, AlphaReplicate(arg[1]), arg[2], arg[1]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_MODULATECOLOR_ADDALPHA:
+ dst = m_module.opFFma(m_vec4Type, arg[1], arg[2], AlphaReplicate(arg[1]));
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_MODULATEINVALPHA_ADDCOLOR:
+ dst = m_module.opFFma(m_vec4Type, Complement(AlphaReplicate(arg[1])), arg[2], arg[1]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_MODULATEINVCOLOR_ADDALPHA:
+ dst = m_module.opFFma(m_vec4Type, Complement(arg[1]), arg[2], AlphaReplicate(arg[1]));
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_BUMPENVMAPLUMINANCE:
+ case D3DTOP_BUMPENVMAP:
+ // Load texture for the next stage...
+ texture = GetTexture();
+ break;
+
+ case D3DTOP_DOTPRODUCT3: {
+ // Get vec3 of arg1 & 2
+ uint32_t vec3Type = m_module.defVectorType(m_floatType, 3);
+ std::array<uint32_t, 3> indices = { 0, 1, 2 };
+ arg[1] = m_module.opVectorShuffle(vec3Type, arg[1], arg[1], indices.size(), indices.data());
+ arg[2] = m_module.opVectorShuffle(vec3Type, arg[2], arg[2], indices.size(), indices.data());
+
+ // Bias according to spec.
+ arg[1] = m_module.opFSub(vec3Type, arg[1], m_module.constvec3f32(0.5f, 0.5f, 0.5f));
+ arg[2] = m_module.opFSub(vec3Type, arg[2], m_module.constvec3f32(0.5f, 0.5f, 0.5f));
+
+ // Do the dotting!
+ dst = m_module.opDot(m_floatType, arg[1], arg[2]);
+
+ // Multiply by 4 and replicate -> vec4
+ dst = m_module.opFMul(m_floatType, dst, m_module.constf32(4.0f));
+ dst = ScalarReplicate(dst);
+
+ // Saturate
+ dst = Saturate(dst);
+
+ break;
+ }
+
+ case D3DTOP_MULTIPLYADD:
+ dst = m_module.opFFma(m_vec4Type, arg[1], arg[2], arg[0]);
+ dst = Saturate(dst);
+ break;
+
+ case D3DTOP_LERP:
+ dst = m_module.opFMix(m_vec4Type, arg[2], arg[1], arg[0]);
+ break;
+
+ default:
+ Logger::warn("Unhandled texture op!");
+ break;
+ }
+
+ return dst;
+ };
+
+ uint32_t& dst = stage.ResultIsTemp ? temp : current;
+
+ D3DTEXTUREOP colorOp = (D3DTEXTUREOP)stage.ColorOp;
+
+ // This cancels all subsequent stages.
+ if (colorOp == D3DTOP_DISABLE)
+ break;
+
+ std::array<uint32_t, TextureArgCount> colorArgs = {
+ stage.ColorArg0,
+ stage.ColorArg1,
+ stage.ColorArg2};
+
+ D3DTEXTUREOP alphaOp = (D3DTEXTUREOP)stage.AlphaOp;
+ std::array<uint32_t, TextureArgCount> alphaArgs = {
+ stage.AlphaArg0,
+ stage.AlphaArg1,
+ stage.AlphaArg2};
+
+ auto ProcessArgs = [&](auto op, auto& args) {
+ for (uint32_t& arg : args)
+ arg = GetArg(arg);
+ };
+
+ // Fast path if alpha/color path is identical.
+ // D3DTOP_DOTPRODUCT3 also has special quirky behaviour here.
+ const bool fastPath = colorOp == alphaOp && colorArgs == alphaArgs;
+ if (fastPath || colorOp == D3DTOP_DOTPRODUCT3) {
+ if (colorOp != D3DTOP_DISABLE) {
+ ProcessArgs(colorOp, colorArgs);
+ dst = DoOp(colorOp, dst, colorArgs);
+ }
+ }
+ else {
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 4 + 3 };
+
+ uint32_t colorResult = dst;
+ uint32_t alphaResult = dst;
+ if (colorOp != D3DTOP_DISABLE) {
+ ProcessArgs(colorOp, colorArgs);
+ colorResult = DoOp(colorOp, dst, colorArgs);
+ }
+
+ if (alphaOp != D3DTOP_DISABLE) {
+ ProcessArgs(alphaOp, alphaArgs);
+ alphaResult = DoOp(alphaOp, dst, alphaArgs);
+ }
+
+ // src0.x, src0.y, src0.z src1.w
+ if (colorResult != dst)
+ dst = m_module.opVectorShuffle(m_vec4Type, colorResult, dst, indices.size(), indices.data());
+
+ // src0.x, src0.y, src0.z src1.w
+ // But we flip src0, src1 to be inverse of color.
+ if (alphaResult != dst)
+ dst = m_module.opVectorShuffle(m_vec4Type, dst, alphaResult, indices.size(), indices.data());
+ }
+ }
+
+ if (m_fsKey.Stages[0].Contents.GlobalSpecularEnable) {
+ uint32_t specular = m_module.opFMul(m_vec4Type, m_ps.in.COLOR[1], m_module.constvec4f32(1.0f, 1.0f, 1.0f, 0.0f));
+
+ current = m_module.opFAdd(m_vec4Type, current, specular);
+ }
+
+ D3D9FogContext fogCtx;
+ fogCtx.IsPixel = true;
+ fogCtx.RangeFog = false;
+ fogCtx.RenderState = m_rsBlock;
+ fogCtx.vPos = m_ps.in.POS;
+ fogCtx.vFog = m_ps.in.FOG;
+ fogCtx.oColor = current;
+ fogCtx.IsFixedFunction = true;
+ fogCtx.IsPositionT = false;
+ fogCtx.HasSpecular = false;
+ fogCtx.Specular = 0;
+ current = DoFixedFunctionFog(m_module, fogCtx);
+
+ m_module.opStore(m_ps.out.COLOR, current);
+
+ alphaTestPS();
+ }
+
+ void D3D9FFShaderCompiler::setupPS() {
+ setupRenderStateInfo();
+
+ // PS Caps
+ m_module.enableCapability(spv::CapabilityDerivativeControl);
+
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeOriginUpperLeft);
+
+ uint32_t pointCoord = GetPointCoord(m_module, m_entryPointInterfaces);
+ auto pointInfo = GetPointSizeInfoPS(m_module, m_rsBlock);
+
+ // We need to replace TEXCOORD inputs with gl_PointCoord
+ // if D3DRS_POINTSPRITEENABLE is set.
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ m_ps.in.TEXCOORD[i] = declareIO(true, DxsoSemantic{ DxsoUsage::Texcoord, i });
+ m_ps.in.TEXCOORD[i] = m_module.opSelect(m_vec4Type, pointInfo.isSprite, pointCoord, m_ps.in.TEXCOORD[i]);
+ }
+
+ m_ps.in.COLOR[0] = declareIO(true, DxsoSemantic{ DxsoUsage::Color, 0 });
+ m_ps.in.COLOR[1] = declareIO(true, DxsoSemantic{ DxsoUsage::Color, 1 });
+
+ m_ps.in.FOG = declareIO(true, DxsoSemantic{ DxsoUsage::Fog, 0 });
+ m_ps.in.POS = declareIO(true, DxsoSemantic{ DxsoUsage::Position, 0 }, spv::BuiltInFragCoord);
+
+ m_ps.out.COLOR = declareIO(false, DxsoSemantic{ DxsoUsage::Color, 0 });
+
+ // Constant Buffer for PS.
+ std::array<uint32_t, uint32_t(D3D9FFPSMembers::MemberCount)> members = {
+ m_vec4Type // Texture Factor
+ };
+
+ const uint32_t structType =
+ m_module.defStructType(members.size(), members.data());
+
+ m_module.decorateBlock(structType);
+ uint32_t offset = 0;
+
+ for (uint32_t i = 0; i < uint32_t(D3D9FFPSMembers::MemberCount); i++) {
+ m_module.memberDecorateOffset(structType, i, offset);
+ offset += sizeof(Vector4);
+ }
+
+ m_module.setDebugName(structType, "D3D9FixedFunctionPS");
+ m_module.setDebugMemberName(structType, 0, "textureFactor");
+
+ m_ps.constantBuffer = m_module.newVar(
+ m_module.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.setDebugName(m_ps.constantBuffer, "consts");
+
+ const uint32_t bindingId = computeResourceSlotId(
+ DxsoProgramType::PixelShader, DxsoBindingType::ConstantBuffer,
+ DxsoConstantBuffers::PSFixedFunction);
+
+ m_module.decorateDescriptorSet(m_ps.constantBuffer, 0);
+ m_module.decorateBinding(m_ps.constantBuffer, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+
+ // Load constants
+ auto LoadConstant = [&](uint32_t type, uint32_t idx) {
+ uint32_t offset = m_module.constu32(idx);
+ uint32_t typePtr = m_module.defPointerType(type, spv::StorageClassUniform);
+
+ return m_module.opLoad(type,
+ m_module.opAccessChain(typePtr, m_ps.constantBuffer, 1, &offset));
+ };
+
+ m_ps.constants.textureFactor = LoadConstant(m_vec4Type, uint32_t(D3D9FFPSMembers::TextureFactor));
+
+ // Samplers
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ auto& sampler = m_ps.samplers[i];
+ D3DRESOURCETYPE type = D3DRESOURCETYPE(m_fsKey.Stages[i].Contents.Type + D3DRTYPE_TEXTURE);
+
+ spv::Dim dimensionality;
+ VkImageViewType viewType;
+
+ switch (type) {
+ default:
+ case D3DRTYPE_TEXTURE:
+ dimensionality = spv::Dim2D;
+ sampler.texcoordCnt = 2;
+ viewType = VK_IMAGE_VIEW_TYPE_2D;
+ break;
+ case D3DRTYPE_CUBETEXTURE:
+ dimensionality = spv::DimCube;
+ sampler.texcoordCnt = 3;
+ viewType = VK_IMAGE_VIEW_TYPE_CUBE;
+ break;
+ case D3DRTYPE_VOLUMETEXTURE:
+ dimensionality = spv::Dim3D;
+ sampler.texcoordCnt = 3;
+ viewType = VK_IMAGE_VIEW_TYPE_3D;
+ break;
+ }
+
+ sampler.typeId = m_module.defImageType(
+ m_module.defFloatType(32),
+ dimensionality, 0, 0, 0, 1,
+ spv::ImageFormatUnknown);
+
+ sampler.typeId = m_module.defSampledImageType(sampler.typeId);
+
+ sampler.varId = m_module.newVar(
+ m_module.defPointerType(
+ sampler.typeId, spv::StorageClassUniformConstant),
+ spv::StorageClassUniformConstant);
+
+ std::string name = str::format("s", i);
+ m_module.setDebugName(sampler.varId, name.c_str());
+
+ const uint32_t bindingId = computeResourceSlotId(DxsoProgramType::PixelShader,
+ DxsoBindingType::Image, i);
+
+ sampler.bound = m_module.specConstBool(true);
+ m_module.decorateSpecId(sampler.bound, bindingId);
+ m_module.setDebugName(sampler.bound,
+ str::format("s", i, "_bound").c_str());
+
+ m_module.decorateDescriptorSet(sampler.varId, 0);
+ m_module.decorateBinding(sampler.varId, bindingId);
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ resource.view = viewType;
+ resource.access = VK_ACCESS_SHADER_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+ emitPsSharedConstants();
+ }
+
+
+ void D3D9FFShaderCompiler::emitPsSharedConstants() {
+ m_ps.sharedState = GetSharedConstants(m_module);
+
+ const uint32_t bindingId = computeResourceSlotId(
+ m_programType, DxsoBindingType::ConstantBuffer,
+ PSShared);
+
+ m_module.decorateDescriptorSet(m_ps.sharedState, 0);
+ m_module.decorateBinding(m_ps.sharedState, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void D3D9FFShaderCompiler::emitVsClipping(uint32_t vtx) {
+ uint32_t worldPos = m_module.opMatrixTimesVector(m_vec4Type, m_vs.constants.inverseView, vtx);
+
+ uint32_t clipPlaneCountId = m_module.constu32(caps::MaxClipPlanes);
+
+ uint32_t floatType = m_module.defFloatType(32);
+ uint32_t vec4Type = m_module.defVectorType(floatType, 4);
+
+ // Declare uniform buffer containing clip planes
+ uint32_t clipPlaneArray = m_module.defArrayTypeUnique(vec4Type, clipPlaneCountId);
+ uint32_t clipPlaneStruct = m_module.defStructTypeUnique(1, &clipPlaneArray);
+ uint32_t clipPlaneBlock = m_module.newVar(
+ m_module.defPointerType(clipPlaneStruct, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.decorateArrayStride (clipPlaneArray, 16);
+
+ m_module.setDebugName (clipPlaneStruct, "clip_info_t");
+ m_module.setDebugMemberName (clipPlaneStruct, 0, "clip_planes");
+ m_module.decorate (clipPlaneStruct, spv::DecorationBlock);
+ m_module.memberDecorateOffset (clipPlaneStruct, 0, 0);
+
+ uint32_t bindingId = computeResourceSlotId(
+ DxsoProgramType::VertexShader,
+ DxsoBindingType::ConstantBuffer,
+ DxsoConstantBuffers::VSClipPlanes);
+
+ m_module.setDebugName (clipPlaneBlock, "clip_info");
+ m_module.decorateDescriptorSet(clipPlaneBlock, 0);
+ m_module.decorateBinding (clipPlaneBlock, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+
+ // Declare output array for clip distances
+ uint32_t clipDistArray = m_module.newVar(
+ m_module.defPointerType(
+ m_module.defArrayType(floatType, clipPlaneCountId),
+ spv::StorageClassOutput),
+ spv::StorageClassOutput);
+
+ m_module.decorateBuiltIn(clipDistArray, spv::BuiltInClipDistance);
+ m_entryPointInterfaces.push_back(clipDistArray);
+
+ // Compute clip distances
+ for (uint32_t i = 0; i < caps::MaxClipPlanes; i++) {
+ std::array<uint32_t, 2> blockMembers = {{
+ m_module.constu32(0),
+ m_module.constu32(i),
+ }};
+
+ uint32_t planeId = m_module.opLoad(vec4Type,
+ m_module.opAccessChain(
+ m_module.defPointerType(vec4Type, spv::StorageClassUniform),
+ clipPlaneBlock, blockMembers.size(), blockMembers.data()));
+
+ uint32_t distId = m_module.opDot(floatType, worldPos, planeId);
+
+ m_module.opStore(
+ m_module.opAccessChain(
+ m_module.defPointerType(floatType, spv::StorageClassOutput),
+ clipDistArray, 1, &blockMembers[1]),
+ distId);
+ }
+ }
+
+
+ void D3D9FFShaderCompiler::alphaTestPS() {
+ // Alpha testing
+ uint32_t boolType = m_module.defBoolType();
+ uint32_t floatPtr = m_module.defPointerType(m_floatType, spv::StorageClassPushConstant);
+
+ // Declare spec constants for render states
+ uint32_t alphaFuncId = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.setDebugName(alphaFuncId, "alpha_func");
+ m_module.decorateSpecId(alphaFuncId, getSpecId(D3D9SpecConstantId::AlphaCompareOp));
+
+ // Implement alpha test
+ auto oC0 = m_ps.out.COLOR;
+ // Labels for the alpha test
+ std::array<SpirvSwitchCaseLabel, 8> atestCaseLabels = { {
+ { uint32_t(VK_COMPARE_OP_NEVER), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_LESS), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_LESS_OR_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_GREATER), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_NOT_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_GREATER_OR_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_ALWAYS), m_module.allocateId() },
+ } };
+
+ uint32_t atestBeginLabel = m_module.allocateId();
+ uint32_t atestTestLabel = m_module.allocateId();
+ uint32_t atestDiscardLabel = m_module.allocateId();
+ uint32_t atestKeepLabel = m_module.allocateId();
+ uint32_t atestSkipLabel = m_module.allocateId();
+
+ // if (alpha_test) { ... }
+ uint32_t isNotAlways = m_module.opINotEqual(boolType, alphaFuncId, m_module.constu32(VK_COMPARE_OP_ALWAYS));
+ m_module.opSelectionMerge(atestSkipLabel, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(isNotAlways, atestBeginLabel, atestSkipLabel);
+ m_module.opLabel(atestBeginLabel);
+
+ // Load alpha component
+ uint32_t alphaComponentId = 3;
+ uint32_t alphaId = m_module.opCompositeExtract(m_floatType,
+ m_module.opLoad(m_vec4Type, oC0),
+ 1, &alphaComponentId);
+
+ // Load alpha reference
+ uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
+ uint32_t alphaRefId = m_module.opLoad(m_floatType,
+ m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
+
+ // switch (alpha_func) { ... }
+ m_module.opSelectionMerge(atestTestLabel, spv::SelectionControlMaskNone);
+ m_module.opSwitch(alphaFuncId,
+ atestCaseLabels[uint32_t(VK_COMPARE_OP_ALWAYS)].labelId,
+ atestCaseLabels.size(),
+ atestCaseLabels.data());
+
+ std::array<SpirvPhiLabel, 8> atestVariables;
+
+ for (uint32_t i = 0; i < atestCaseLabels.size(); i++) {
+ m_module.opLabel(atestCaseLabels[i].labelId);
+
+ atestVariables[i].labelId = atestCaseLabels[i].labelId;
+ atestVariables[i].varId = [&] {
+ switch (VkCompareOp(atestCaseLabels[i].literal)) {
+ case VK_COMPARE_OP_NEVER: return m_module.constBool(false);
+ case VK_COMPARE_OP_LESS: return m_module.opFOrdLessThan(boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_EQUAL: return m_module.opFOrdEqual(boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_LESS_OR_EQUAL: return m_module.opFOrdLessThanEqual(boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_GREATER: return m_module.opFOrdGreaterThan(boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_NOT_EQUAL: return m_module.opFOrdNotEqual(boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_GREATER_OR_EQUAL: return m_module.opFOrdGreaterThanEqual(boolType, alphaId, alphaRefId);
+ default:
+ case VK_COMPARE_OP_ALWAYS: return m_module.constBool(true);
+ }
+ }();
+
+ m_module.opBranch(atestTestLabel);
+ }
+
+ // end switch
+ m_module.opLabel(atestTestLabel);
+
+ uint32_t atestResult = m_module.opPhi(boolType,
+ atestVariables.size(),
+ atestVariables.data());
+ uint32_t atestDiscard = m_module.opLogicalNot(boolType, atestResult);
+
+ // if (do_discard) { ... }
+ m_module.opSelectionMerge(atestKeepLabel, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(atestDiscard, atestDiscardLabel, atestKeepLabel);
+
+ m_module.opLabel(atestDiscardLabel);
+ m_module.opKill();
+
+ // end if (do_discard)
+ m_module.opLabel(atestKeepLabel);
+ m_module.opBranch(atestSkipLabel);
+
+ // end if (alpha_test)
+ m_module.opLabel(atestSkipLabel);
+ }
+
+
+ D3D9FFShader::D3D9FFShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyVS& Key) {
+ Sha1Hash hash = Sha1Hash::compute(&Key, sizeof(Key));
+ DxvkShaderKey shaderKey = { VK_SHADER_STAGE_VERTEX_BIT, hash };
+
+ std::string name = str::format("FF_", shaderKey.toString());
+
+ D3D9FFShaderCompiler compiler(
+ pDevice->GetDXVKDevice(),
+ Key, name,
+ pDevice->GetOptions());
+
+ m_shader = compiler.compile();
+ m_isgn = compiler.isgn();
+
+ Dump(Key, name);
+
+ m_shader->setShaderKey(shaderKey);
+ pDevice->GetDXVKDevice()->registerShader(m_shader);
+ }
+
+
+ D3D9FFShader::D3D9FFShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyFS& Key) {
+ Sha1Hash hash = Sha1Hash::compute(&Key, sizeof(Key));
+ DxvkShaderKey shaderKey = { VK_SHADER_STAGE_FRAGMENT_BIT, hash };
+
+ std::string name = str::format("FF_", shaderKey.toString());
+
+ D3D9FFShaderCompiler compiler(
+ pDevice->GetDXVKDevice(),
+ Key, name,
+ pDevice->GetOptions());
+
+ m_shader = compiler.compile();
+ m_isgn = compiler.isgn();
+
+ Dump(Key, name);
+
+ m_shader->setShaderKey(shaderKey);
+ pDevice->GetDXVKDevice()->registerShader(m_shader);
+ }
+
+ template <typename T>
+ void D3D9FFShader::Dump(const T& Key, const std::string& Name) {
+ const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
+
+ if (dumpPath.size() != 0) {
+#ifdef _WIN32
+ std::ofstream dumpStream(
+ str::tows(str::format(dumpPath, "/", Name, ".spv").c_str()).c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#else
+ std::ofstream dumpStream(
+ str::format(dumpPath, "/", Name, ".spv").c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#endif
+
+ m_shader->dump(dumpStream);
+ }
+ }
+
+
+ D3D9FFShader D3D9FFShaderModuleSet::GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyVS& ShaderKey) {
+ // Use the shader's unique key for the lookup
+ auto entry = m_vsModules.find(ShaderKey);
+ if (entry != m_vsModules.end())
+ return entry->second;
+
+ D3D9FFShader shader(
+ pDevice, ShaderKey);
+
+ m_vsModules.insert({ShaderKey, shader});
+
+ return shader;
+ }
+
+
+ D3D9FFShader D3D9FFShaderModuleSet::GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyFS& ShaderKey) {
+ // Use the shader's unique key for the lookup
+ auto entry = m_fsModules.find(ShaderKey);
+ if (entry != m_fsModules.end())
+ return entry->second;
+
+ D3D9FFShader shader(
+ pDevice, ShaderKey);
+
+ m_fsModules.insert({ShaderKey, shader});
+
+ return shader;
+ }
+
+
+ size_t D3D9FFShaderKeyHash::operator () (const D3D9FFShaderKeyVS& key) const {
+ DxvkHashState state;
+
+ std::hash<uint32_t> uint32hash;
+
+ for (uint32_t i = 0; i < std::size(key.Data.Primitive); i++)
+ state.add(uint32hash(key.Data.Primitive[i]));
+
+ return state;
+ }
+
+
+ size_t D3D9FFShaderKeyHash::operator () (const D3D9FFShaderKeyFS& key) const {
+ DxvkHashState state;
+
+ std::hash<uint32_t> uint32hash;
+
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ for (uint32_t j = 0; j < std::size(key.Stages[i].Primitive); j++)
+ state.add(uint32hash(key.Stages[i].Primitive[j]));
+ }
+
+ return state;
+ }
+
+
+ bool operator == (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) {
+ return std::memcmp(&a, &b, sizeof(D3D9FFShaderKeyVS)) == 0;
+ }
+
+
+ bool operator == (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) {
+ return std::memcmp(&a, &b, sizeof(D3D9FFShaderKeyFS)) == 0;
+ }
+
+
+ bool operator != (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) {
+ return !(a == b);
+ }
+
+
+ bool operator != (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) {
+ return !(a == b);
+ }
+
+
+ bool D3D9FFShaderKeyEq::operator () (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) const {
+ return a == b;
+ }
+
+
+ bool D3D9FFShaderKeyEq::operator () (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) const {
+ return a == b;
+ }
+
+
+ static inline DxsoIsgn CreateFixedFunctionIsgn() {
+ DxsoIsgn ffIsgn;
+
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Position, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Normal, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Position, 1 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Normal, 1 };
+ for (uint32_t i = 0; i < 8; i++)
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Texcoord, i };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Color, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Color, 1 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::Fog, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::PointSize, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::BlendWeight, 0 };
+ ffIsgn.elems[ffIsgn.elemCount++].semantic = DxsoSemantic{ DxsoUsage::BlendIndices, 0 };
+
+ return ffIsgn;
+ }
+
+
+ DxsoIsgn g_ffIsgn = CreateFixedFunctionIsgn();
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.h
new file mode 100644
index 00000000..8e312aa2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_fixed_function.h
@@ -0,0 +1,254 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+#include "d3d9_caps.h"
+
+#include "../dxvk/dxvk_shader.h"
+
+#include "../dxso/dxso_isgn.h"
+
+#include <unordered_map>
+#include <bitset>
+
+namespace dxvk {
+
+ class D3D9DeviceEx;
+ class SpirvModule;
+
+ struct D3D9Options;
+
+ struct D3D9FogContext {
+ // General inputs...
+ bool IsPixel;
+ bool RangeFog;
+ uint32_t RenderState;
+ uint32_t vPos;
+ uint32_t vFog;
+
+ uint32_t oColor;
+
+ bool HasFogInput;
+
+ bool IsFixedFunction;
+ bool IsPositionT;
+ bool HasSpecular;
+ uint32_t Specular;
+ };
+
+ struct D3D9FixedFunctionOptions {
+ D3D9FixedFunctionOptions(const D3D9Options* options);
+
+ bool invariantPosition;
+ };
+
+ // Returns new oFog if VS
+ // Returns new oColor if PS
+ uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx);
+
+ // Returns a render state block
+ uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
+
+ struct D3D9PointSizeInfoVS {
+ uint32_t defaultValue;
+ uint32_t min;
+ uint32_t max;
+ };
+
+ // Default point size and point scale magic!
+ D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock, bool isFixedFunction);
+
+ struct D3D9PointSizeInfoPS {
+ uint32_t isSprite;
+ };
+
+ D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock);
+
+ uint32_t GetPointCoord(SpirvModule& spvModule, std::vector<uint32_t>& entryPointInterfaces);
+
+ uint32_t GetSharedConstants(SpirvModule& spvModule);
+
+ constexpr uint32_t TCIOffset = 16;
+ constexpr uint32_t TCIMask = 0b111 << TCIOffset;
+
+ enum D3D9FF_VertexBlendMode {
+ D3D9FF_VertexBlendMode_Disabled,
+ D3D9FF_VertexBlendMode_Normal,
+ D3D9FF_VertexBlendMode_Tween,
+ };
+
+ struct D3D9FFShaderKeyVSData {
+ union {
+ struct {
+ uint32_t TexcoordIndices : 24;
+
+ uint32_t HasPositionT : 1;
+
+ uint32_t HasColor0 : 1; // Diffuse
+ uint32_t HasColor1 : 1; // Specular
+
+ uint32_t HasPointSize : 1;
+
+ uint32_t UseLighting : 1;
+
+ uint32_t NormalizeNormals : 1;
+ uint32_t LocalViewer : 1;
+ uint32_t RangeFog : 1;
+
+ uint32_t TexcoordFlags : 24;
+
+ uint32_t DiffuseSource : 2;
+ uint32_t AmbientSource : 2;
+ uint32_t SpecularSource : 2;
+ uint32_t EmissiveSource : 2;
+
+ uint32_t TransformFlags : 24;
+
+ uint32_t LightCount : 4;
+
+ uint32_t TexcoordDeclMask : 24;
+ uint32_t HasFog : 1;
+
+ uint32_t VertexBlendMode : 2;
+ uint32_t VertexBlendIndexed : 1;
+ uint32_t VertexBlendCount : 3;
+
+ uint32_t VertexClipping : 1;
+ } Contents;
+
+ uint32_t Primitive[4];
+ };
+ };
+
+ struct D3D9FFShaderKeyVS {
+ D3D9FFShaderKeyVS() {
+ // memcmp safety
+ std::memset(&Data, 0, sizeof(Data));
+ }
+
+ D3D9FFShaderKeyVSData Data;
+ };
+
+ constexpr uint32_t TextureArgCount = 3;
+
+ struct D3D9FFShaderStage {
+ union {
+ struct {
+ uint32_t ColorOp : 5;
+ uint32_t ColorArg0 : 6;
+ uint32_t ColorArg1 : 6;
+ uint32_t ColorArg2 : 6;
+
+ uint32_t AlphaOp : 5;
+ uint32_t AlphaArg0 : 6;
+ uint32_t AlphaArg1 : 6;
+ uint32_t AlphaArg2 : 6;
+
+ uint32_t Type : 2;
+ uint32_t ResultIsTemp : 1;
+ uint32_t Projected : 1;
+
+ uint32_t ProjectedCount : 3;
+
+ // Included in here, read from Stage 0 for packing reasons
+ // Affects all stages.
+ uint32_t GlobalSpecularEnable : 1;
+ uint32_t GlobalFlatShade : 1;
+ } Contents;
+
+ uint32_t Primitive[2];
+ };
+ };
+
+ struct D3D9FFShaderKeyFS {
+ D3D9FFShaderKeyFS() {
+ // memcmp safety
+ std::memset(Stages, 0, sizeof(Stages));
+
+ // Normalize this. DISABLE != 0.
+ for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
+ Stages[i].Contents.ColorOp = D3DTOP_DISABLE;
+ Stages[i].Contents.AlphaOp = D3DTOP_DISABLE;
+ }
+ }
+
+ D3D9FFShaderStage Stages[caps::TextureStageCount];
+ };
+
+ struct D3D9FFShaderKeyHash {
+ size_t operator () (const D3D9FFShaderKeyVS& key) const;
+ size_t operator () (const D3D9FFShaderKeyFS& key) const;
+ };
+
+ bool operator == (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
+ bool operator != (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
+ bool operator == (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);
+ bool operator != (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);
+
+ struct D3D9FFShaderKeyEq {
+ bool operator () (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) const;
+ bool operator () (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) const;
+ };
+
+ class D3D9FFShader {
+
+ public:
+
+ D3D9FFShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyVS& Key);
+
+ D3D9FFShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyFS& Key);
+
+ template <typename T>
+ void Dump(const T& Key, const std::string& Name);
+
+ Rc<DxvkShader> GetShader() const {
+ return m_shader;
+ }
+
+ private:
+
+ Rc<DxvkShader> m_shader;
+
+ DxsoIsgn m_isgn;
+
+ };
+
+
+ class D3D9FFShaderModuleSet : public RcObject {
+
+ public:
+
+ D3D9FFShader GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyVS& ShaderKey);
+
+ D3D9FFShader GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ const D3D9FFShaderKeyFS& ShaderKey);
+
+ private:
+
+ std::unordered_map<
+ D3D9FFShaderKeyVS,
+ D3D9FFShader,
+ D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_vsModules;
+
+ std::unordered_map<
+ D3D9FFShaderKeyFS,
+ D3D9FFShader,
+ D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_fsModules;
+
+ };
+
+
+ inline const DxsoIsgn& GetFixedFunctionIsgn() {
+ extern DxsoIsgn g_ffIsgn;
+
+ return g_ffIsgn;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.cpp
new file mode 100644
index 00000000..424d0413
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.cpp
@@ -0,0 +1,568 @@
+#include "d3d9_format.h"
+
+namespace dxvk {
+
+ // It is also worth noting that the msb/lsb-ness is flipped between VK and D3D9.
+ D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format) {
+ switch (Format) {
+ case D3D9Format::Unknown: return {};
+
+ case D3D9Format::R8G8B8: return {}; // Unsupported
+
+ case D3D9Format::A8R8G8B8: return {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::X8R8G8B8: return {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::R5G6B5: return {
+ VK_FORMAT_R5G6B5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT};
+
+ case D3D9Format::X1R5G5B5: return {
+ VK_FORMAT_A1R5G5B5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A1R5G5B5: return {
+ VK_FORMAT_A1R5G5B5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::A4R4G4B4: return {
+ VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::R3G3B2: return {}; // Unsupported
+
+ case D3D9Format::A8: return {
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }};
+
+ case D3D9Format::A8R3G3B2: return {}; // Unsupported
+
+ case D3D9Format::X4R4G4B4: return {
+ VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::A2B10G10R10: return {
+ VK_FORMAT_A2B10G10R10_UNORM_PACK32, // The A2 is out of place here. This should be investigated.
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::A8B8G8R8: return {
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SRGB,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::X8B8G8R8: return {
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SRGB,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::G16R16: return {
+ VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A2R10G10B10: return {
+ VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::A16B16G16R16: return {
+ VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::A8P8: return {}; // Unsupported
+
+ case D3D9Format::P8: return {}; // Unsupported
+
+ case D3D9Format::L8: return {
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8_SRGB,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A8L8: return {
+ VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G }};
+
+ case D3D9Format::A4L4: return {
+ VK_FORMAT_R4G4_UNORM_PACK8,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R }};
+
+ case D3D9Format::V8U8: return {
+ VK_FORMAT_R8G8_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::L6V5U5: return {
+ // Any PACK16 format will do...
+ VK_FORMAT_B5G6R5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
+ { D3D9ConversionFormat_L6V5U5, 1u,
+ // Convert -> float (this is a mixed snorm and unorm type)
+ VK_FORMAT_R16G16B16A16_SFLOAT } };
+
+ case D3D9Format::X8L8V8U8: return {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE },
+ { D3D9ConversionFormat_X8L8V8U8, 1u,
+ // Convert -> float (this is a mixed snorm and unorm type)
+ VK_FORMAT_R16G16B16A16_SFLOAT } };
+
+ case D3D9Format::Q8W8V8U8: return {
+ VK_FORMAT_R8G8B8A8_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::V16U16: return {
+ VK_FORMAT_R16G16_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A2W10V10U10: return {
+ VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
+ { D3D9ConversionFormat_A2W10V10U10, 1u,
+ // Convert -> float (this is a mixed snorm and unorm type)
+ VK_FORMAT_R16G16B16A16_SFLOAT } };
+
+ case D3D9Format::UYVY: return {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
+ { D3D9ConversionFormat_UYVY, 1u }
+ };
+
+ case D3D9Format::R8G8_B8G8: return {
+ VK_FORMAT_G8B8G8R8_422_UNORM, // This format may have been _SCALED in DX9.
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::YUY2: return {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
+ { D3D9ConversionFormat_YUY2, 1u }
+ };
+
+ case D3D9Format::G8R8_G8B8: return {
+ VK_FORMAT_B8G8R8G8_422_UNORM, // This format may have been _SCALED in DX9.
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::DXT1: return {
+ VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::DXT2: return {
+ VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_BC2_SRGB_BLOCK,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::DXT3: return {
+ VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_BC2_SRGB_BLOCK,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::DXT4: return {
+ VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_BC3_SRGB_BLOCK,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::DXT5: return {
+ VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_BC3_SRGB_BLOCK,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::D16_LOCKABLE: return {
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::D32: return {
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::D15S1: return {}; // Unsupported (everywhere)
+
+ case D3D9Format::D24S8: return {
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };
+
+ case D3D9Format::D24X8: return {
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::D24X4S4: return {}; // Unsupported (everywhere)
+
+ case D3D9Format::D16: return {
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::D32F_LOCKABLE: return {
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::D24FS8: return {
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };
+
+ case D3D9Format::D32_LOCKABLE: return {
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT };
+
+ case D3D9Format::S8_LOCKABLE: return {
+ VK_FORMAT_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_STENCIL_BIT };
+
+ case D3D9Format::L16: return {
+ VK_FORMAT_R16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::VERTEXDATA: return {
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0 };
+
+ case D3D9Format::INDEX16: return {
+ VK_FORMAT_R16_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0 };
+
+ case D3D9Format::INDEX32: return {
+ VK_FORMAT_R32_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0 };
+
+ case D3D9Format::Q16W16V16U16: return {
+ VK_FORMAT_R16G16B16A16_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::MULTI2_ARGB8: return {}; // Unsupported
+
+ case D3D9Format::R16F: return {
+ VK_FORMAT_R16_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::G16R16F: return {
+ VK_FORMAT_R16G16_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A16B16G16R16F: return {
+ VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::R32F: return {
+ VK_FORMAT_R32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::G32R32F: return {
+ VK_FORMAT_R32G32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::A32B32G32R32F: return {
+ VK_FORMAT_R32G32B32A32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::CxV8U8: return {}; // Unsupported
+
+ case D3D9Format::A1: return {}; // Unsupported
+
+ case D3D9Format::A2B10G10R10_XR_BIAS: return {
+ VK_FORMAT_A2B10G10R10_SNORM_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT };
+
+ case D3D9Format::BINARYBUFFER: return {
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0 };
+
+ case D3D9Format::ATI1: return {
+ VK_FORMAT_BC4_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::ATI2: return {
+ VK_FORMAT_BC5_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::INST: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::DF24: return {
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::DF16: return {
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
+
+ case D3D9Format::NULL_FORMAT: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::GET4: return {}; // Unsupported
+
+ case D3D9Format::GET1: return {}; // Unsupported
+
+ case D3D9Format::NVDB: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::A2M1: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::A2M0: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::ATOC: return {}; // Driver hack, handled elsewhere
+
+ case D3D9Format::INTZ: return {
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R }};
+
+ case D3D9Format::NV12: return {
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
+ { D3D9ConversionFormat_NV12, 2u, VK_FORMAT_B8G8R8A8_UNORM }
+ };
+
+ case D3D9Format::YV12: return {
+ VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
+ { D3D9ConversionFormat_YV12, 3u, VK_FORMAT_B8G8R8A8_UNORM }
+ };
+
+ case D3D9Format::RAWZ: return {}; // Unsupported
+
+ default:
+ Logger::warn(str::format("ConvertFormat: Unknown format encountered: ", Format));
+ return {}; // Unsupported
+ }
+ }
+
+ D3D9VkFormatTable::D3D9VkFormatTable(
+ const Rc<DxvkAdapter>& adapter,
+ const D3D9Options& options) {
+ m_dfSupport = options.supportDFFormats;
+ m_x4r4g4b4Support = options.supportX4R4G4B4;
+ m_d32supportFinal = options.supportD32;
+
+ // AMD do not support 24-bit depth buffers on Vulkan,
+ // so we have to fall back to a 32-bit depth format.
+ m_d24s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+
+ // NVIDIA do not support 16-bit depth buffers with stencil on Vulkan,
+ // so we have to fall back to a 32-bit depth format.
+ m_d16s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D16_UNORM_S8_UINT,
+ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+
+ // VK_EXT_4444_formats
+ m_a4r4g4b4Support = CheckImageFormatSupport(adapter, VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
+
+ if (!m_d24s8Support)
+ Logger::info("D3D9: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
+
+ if (!m_d16s8Support) {
+ if (m_d24s8Support)
+ Logger::info("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D24_UNORM_S8_UINT");
+ else
+ Logger::info("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
+ }
+
+ if (!m_a4r4g4b4Support)
+ Logger::warn("D3D9: VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT -> VK_FORMAT_B4G4R4A4_UNORM_PACK16");
+ }
+
+ D3D9_VK_FORMAT_MAPPING D3D9VkFormatTable::GetFormatMapping(
+ D3D9Format Format) const {
+ D3D9_VK_FORMAT_MAPPING mapping = ConvertFormatUnfixed(Format);
+
+ if (Format == D3D9Format::X4R4G4B4 && !m_x4r4g4b4Support)
+ return D3D9_VK_FORMAT_MAPPING();
+
+ if (Format == D3D9Format::DF16 && !m_dfSupport)
+ return D3D9_VK_FORMAT_MAPPING();
+
+ if (Format == D3D9Format::DF24 && !m_dfSupport)
+ return D3D9_VK_FORMAT_MAPPING();
+
+ if (Format == D3D9Format::D32 && !m_d32supportFinal)
+ return D3D9_VK_FORMAT_MAPPING();
+
+ if (!m_d24s8Support && mapping.FormatColor == VK_FORMAT_D24_UNORM_S8_UINT)
+ mapping.FormatColor = VK_FORMAT_D32_SFLOAT_S8_UINT;
+
+ if (!m_d16s8Support && mapping.FormatColor == VK_FORMAT_D16_UNORM_S8_UINT)
+ mapping.FormatColor = m_d24s8Support ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT;
+
+ if (!m_a4r4g4b4Support && mapping.FormatColor == VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT) {
+ VkComponentSwizzle alphaSwizzle = Format == D3D9Format::A4R4G4B4
+ ? VK_COMPONENT_SWIZZLE_B
+ : VK_COMPONENT_SWIZZLE_ONE;
+
+ mapping.FormatColor = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
+ mapping.Swizzle = {
+ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_A, alphaSwizzle };
+ }
+
+ return mapping;
+ }
+
+
+ const DxvkFormatInfo* D3D9VkFormatTable::GetUnsupportedFormatInfo(
+ D3D9Format Format) const {
+ static const DxvkFormatInfo r8b8g8 = { 3, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo r3g3b2 = { 1, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo a8r3g3b2 = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo a8p8 = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo p8 = { 1, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo l6v5u5 = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo x8l8v8u8 = { 4, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo a2w10v10u10 = { 4, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo cxv8u8 = { 2, VK_IMAGE_ASPECT_COLOR_BIT };
+ static const DxvkFormatInfo unknown = {};
+
+ switch (Format) {
+ case D3D9Format::R8G8B8:
+ return &r8b8g8;
+
+ case D3D9Format::R3G3B2:
+ return &r3g3b2;
+
+ case D3D9Format::A8R3G3B2:
+ return &a8r3g3b2;
+
+ case D3D9Format::A8P8:
+ return &a8p8;
+
+ case D3D9Format::P8:
+ return &p8;
+
+ case D3D9Format::L6V5U5:
+ return &l6v5u5;
+
+ case D3D9Format::X8L8V8U8:
+ return &x8l8v8u8;
+
+ case D3D9Format::A2W10V10U10:
+ return &a2w10v10u10;
+
+ // MULTI2_ARGB8 -> Don't have a clue what this is.
+
+ case D3D9Format::CxV8U8:
+ return &cxv8u8;
+
+ // A1 -> Doesn't map nicely here cause it's not byte aligned.
+ // Gonna just pretend that doesn't exist until something
+ // depends on that.
+
+ default:
+ return &unknown;
+ }
+ }
+
+
+ bool D3D9VkFormatTable::CheckImageFormatSupport(
+ const Rc<DxvkAdapter>& Adapter,
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const {
+ VkFormatProperties supported = Adapter->formatProperties(Format);
+
+ return (supported.linearTilingFeatures & Features) == Features
+ || (supported.optimalTilingFeatures & Features) == Features;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.h
new file mode 100644
index 00000000..43ec8629
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format.h
@@ -0,0 +1,223 @@
+#pragma once
+
+#include "d3d9_include.h"
+#include "d3d9_options.h"
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_format.h"
+
+#include <unordered_map>
+
+namespace dxvk {
+
+ enum class D3D9Format : uint32_t {
+ Unknown = 0,
+
+ R8G8B8 = 20,
+ A8R8G8B8 = 21,
+ X8R8G8B8 = 22,
+ R5G6B5 = 23,
+ X1R5G5B5 = 24,
+ A1R5G5B5 = 25,
+ A4R4G4B4 = 26,
+ R3G3B2 = 27,
+ A8 = 28,
+ A8R3G3B2 = 29,
+ X4R4G4B4 = 30,
+ A2B10G10R10 = 31,
+ A8B8G8R8 = 32,
+ X8B8G8R8 = 33,
+ G16R16 = 34,
+ A2R10G10B10 = 35,
+ A16B16G16R16 = 36,
+ A8P8 = 40,
+ P8 = 41,
+ L8 = 50,
+ A8L8 = 51,
+ A4L4 = 52,
+ V8U8 = 60,
+ L6V5U5 = 61,
+ X8L8V8U8 = 62,
+ Q8W8V8U8 = 63,
+ V16U16 = 64,
+ A2W10V10U10 = 67,
+ UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'),
+ R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'),
+ YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'),
+ G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'),
+ DXT1 = MAKEFOURCC('D', 'X', 'T', '1'),
+ DXT2 = MAKEFOURCC('D', 'X', 'T', '2'),
+ DXT3 = MAKEFOURCC('D', 'X', 'T', '3'),
+ DXT4 = MAKEFOURCC('D', 'X', 'T', '4'),
+ DXT5 = MAKEFOURCC('D', 'X', 'T', '5'),
+ D16_LOCKABLE = 70,
+ D32 = 71,
+ D15S1 = 73,
+ D24S8 = 75,
+ D24X8 = 77,
+ D24X4S4 = 79,
+ D16 = 80,
+ D32F_LOCKABLE = 82,
+ D24FS8 = 83,
+ D32_LOCKABLE = 84,
+ S8_LOCKABLE = 85,
+ L16 = 81,
+ VERTEXDATA = 100,
+ INDEX16 = 101,
+ INDEX32 = 102,
+ Q16W16V16U16 = 110,
+ MULTI2_ARGB8 = MAKEFOURCC('M', 'E', 'T', '1'),
+ R16F = 111,
+ G16R16F = 112,
+ A16B16G16R16F = 113,
+ R32F = 114,
+ G32R32F = 115,
+ A32B32G32R32F = 116,
+ CxV8U8 = 117,
+ A1 = 118,
+ A2B10G10R10_XR_BIAS = 119,
+ BINARYBUFFER = 199,
+
+ // Driver Hacks / Unofficial Formats
+ ATI1 = MAKEFOURCC('A', 'T', 'I', '1'),
+ ATI2 = MAKEFOURCC('A', 'T', 'I', '2'),
+ INST = MAKEFOURCC('I', 'N', 'S', 'T'),
+ DF24 = MAKEFOURCC('D', 'F', '2', '4'),
+ DF16 = MAKEFOURCC('D', 'F', '1', '6'),
+ NULL_FORMAT = MAKEFOURCC('N', 'U', 'L', 'L'),
+ GET4 = MAKEFOURCC('G', 'E', 'T', '4'),
+ GET1 = MAKEFOURCC('G', 'E', 'T', '1'),
+ NVDB = MAKEFOURCC('N', 'V', 'D', 'B'),
+ A2M1 = MAKEFOURCC('A', '2', 'M', '1'),
+ A2M0 = MAKEFOURCC('A', '2', 'M', '0'),
+ ATOC = MAKEFOURCC('A', 'T', 'O', 'C'),
+ INTZ = MAKEFOURCC('I', 'N', 'T', 'Z'),
+ RAWZ = MAKEFOURCC('R', 'A', 'W', 'Z'),
+ RESZ = MAKEFOURCC('R', 'E', 'S', 'Z'),
+
+ NV11 = MAKEFOURCC('N', 'V', '1', '1'),
+ NV12 = MAKEFOURCC('N', 'V', '1', '2'),
+ P010 = MAKEFOURCC('P', '0', '1', '0'), // Same as NV12 but 10 bit
+ P016 = MAKEFOURCC('P', '0', '1', '6'), // Same as NV12 but 16 bit
+ Y210 = MAKEFOURCC('Y', '2', '1', '0'),
+ Y216 = MAKEFOURCC('Y', '2', '1', '6'),
+ Y410 = MAKEFOURCC('Y', '4', '1', '0'),
+ AYUV = MAKEFOURCC('A', 'Y', 'U', 'V'),
+ YV12 = MAKEFOURCC('Y', 'V', '1', '2'),
+ OPAQUE_420 = MAKEFOURCC('4', '2', '0', 'O'),
+
+ // Not supported but exist
+ AI44 = MAKEFOURCC('A', 'I', '4', '4'),
+ IA44 = MAKEFOURCC('I', 'A', '4', '4'),
+ R2VB = MAKEFOURCC('R', '2', 'V', 'B'),
+ COPM = MAKEFOURCC('C', 'O', 'P', 'M'),
+ SSAA = MAKEFOURCC('S', 'S', 'A', 'A'),
+ AL16 = MAKEFOURCC('A', 'L', '1', '6'),
+ R16 = MAKEFOURCC(' ', 'R', '1', '6'),
+
+ EXT1 = MAKEFOURCC('E', 'X', 'T', '1'),
+ FXT1 = MAKEFOURCC('F', 'X', 'T', '1'),
+ GXT1 = MAKEFOURCC('G', 'X', 'T', '1'),
+ HXT1 = MAKEFOURCC('H', 'X', 'T', '1'),
+ };
+
+ inline D3D9Format EnumerateFormat(D3DFORMAT format) {
+ return static_cast<D3D9Format>(format);
+ }
+
+ std::ostream& operator << (std::ostream& os, D3D9Format format);
+
+ enum D3D9ConversionFormat : uint32_t {
+ D3D9ConversionFormat_None = 0,
+ D3D9ConversionFormat_YUY2 = 1,
+ D3D9ConversionFormat_UYVY,
+ D3D9ConversionFormat_L6V5U5,
+ D3D9ConversionFormat_X8L8V8U8,
+ D3D9ConversionFormat_A2W10V10U10,
+ D3D9ConversionFormat_NV12,
+ D3D9ConversionFormat_YV12,
+ D3D9ConversionFormat_Count
+ };
+
+ struct D3D9_CONVERSION_FORMAT_INFO {
+ D3D9ConversionFormat FormatType = D3D9ConversionFormat_None;
+ uint32_t PlaneCount = 1;
+ VkFormat FormatColor = VK_FORMAT_UNDEFINED;
+ VkFormat FormatSrgb = VK_FORMAT_UNDEFINED;
+ };
+
+ /**
+ * \brief Format mapping
+ *
+ * Maps a D3D9 format to a set of Vulkan formats.
+ */
+ struct D3D9_VK_FORMAT_MAPPING {
+ union {
+ struct {
+ VkFormat FormatColor; ///< Corresponding color format
+ VkFormat FormatSrgb; ///< Corresponding color format
+ };
+ VkFormat Formats[2];
+ };
+ VkImageAspectFlags Aspect = 0; ///< Defined aspects for the color format
+ VkComponentMapping Swizzle = { ///< Color component swizzle
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ D3D9_CONVERSION_FORMAT_INFO ConversionFormatInfo = { };
+
+ bool IsValid() const { return FormatColor != VK_FORMAT_UNDEFINED; }
+ };
+
+ D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format);
+
+ /**
+ * \brief Format table
+ *
+ * Initializes a format table for a specific
+ * device and provides methods to look up
+ * formats.
+ */
+ class D3D9VkFormatTable {
+
+ public:
+
+ D3D9VkFormatTable(
+ const Rc<DxvkAdapter>& adapter,
+ const D3D9Options& options);
+
+ /**
+ * \brief Retrieves info for a given D3D9 format
+ *
+ * \param [in] Format The D3D9 format to look up
+ * \param [in] Mode the format lookup mode
+ * \returns Format info
+ */
+ D3D9_VK_FORMAT_MAPPING GetFormatMapping(
+ D3D9Format Format) const;
+
+ /**
+ * \brief Retrieves format info for unsupported
+ * formats.
+ *
+ * \param [in] Format The D3D9 format to look up
+ */
+ const DxvkFormatInfo* GetUnsupportedFormatInfo(
+ D3D9Format Format) const;
+
+ private:
+
+ bool CheckImageFormatSupport(
+ const Rc<DxvkAdapter>& Adapter,
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const;
+
+ bool m_a4r4g4b4Support;
+ bool m_d24s8Support;
+ bool m_d16s8Support;
+
+ bool m_dfSupport;
+ bool m_x4r4g4b4Support;
+ bool m_d32supportFinal;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.cpp
new file mode 100644
index 00000000..0e346636
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.cpp
@@ -0,0 +1,146 @@
+#include "d3d9_format_helpers.h"
+
+#include <d3d9_convert_yuy2_uyvy.h>
+#include <d3d9_convert_l6v5u5.h>
+#include <d3d9_convert_x8l8v8u8.h>
+#include <d3d9_convert_a2w10v10u10.h>
+#include <d3d9_convert_nv12.h>
+#include <d3d9_convert_yv12.h>
+
+namespace dxvk {
+
+ D3D9FormatHelper::D3D9FormatHelper(const Rc<DxvkDevice>& device)
+ : m_device(device), m_context(m_device->createContext()) {
+ m_context->beginRecording(
+ m_device->createCommandList());
+
+ InitShaders();
+ }
+
+
+ void D3D9FormatHelper::Flush() {
+ if (m_transferCommands != 0)
+ FlushInternal();
+ }
+
+
+ void D3D9FormatHelper::ConvertFormat(
+ D3D9_CONVERSION_FORMAT_INFO conversionFormat,
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ const DxvkBufferSlice& srcSlice) {
+ switch (conversionFormat.FormatType) {
+ case D3D9ConversionFormat_YUY2:
+ case D3D9ConversionFormat_UYVY: {
+ uint32_t specConstant = conversionFormat.FormatType == D3D9ConversionFormat_UYVY ? 1 : 0;
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, specConstant, { 2u, 1u });
+ break;
+ }
+
+ case D3D9ConversionFormat_NV12:
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 2u, 1u });
+ break;
+
+ case D3D9ConversionFormat_YV12:
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R8_UINT, 0, { 1u, 1u });
+ break;
+
+ case D3D9ConversionFormat_L6V5U5:
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R16_UINT, 0, { 1u, 1u });
+ break;
+
+ case D3D9ConversionFormat_X8L8V8U8:
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u });
+ break;
+
+ case D3D9ConversionFormat_A2W10V10U10:
+ ConvertGenericFormat(conversionFormat, dstImage, dstSubresource, srcSlice, VK_FORMAT_R32_UINT, 0, { 1u, 1u });
+ break;
+
+ default:
+ Logger::warn("Unimplemented format conversion");
+ }
+ }
+
+
+ void D3D9FormatHelper::ConvertGenericFormat(
+ D3D9_CONVERSION_FORMAT_INFO videoFormat,
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ const DxvkBufferSlice& srcSlice,
+ VkFormat bufferFormat,
+ uint32_t specConstantValue,
+ VkExtent2D macroPixelRun) {
+ DxvkImageViewCreateInfo imageViewInfo;
+ imageViewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ imageViewInfo.format = dstImage->info().format;
+ imageViewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
+ imageViewInfo.aspect = dstSubresource.aspectMask;
+ imageViewInfo.minLevel = dstSubresource.mipLevel;
+ imageViewInfo.numLevels = 1;
+ imageViewInfo.minLayer = dstSubresource.baseArrayLayer;
+ imageViewInfo.numLayers = dstSubresource.layerCount;
+ auto tmpImageView = m_device->createImageView(dstImage, imageViewInfo);
+
+ VkExtent3D imageExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
+ imageExtent = VkExtent3D{ imageExtent.width / macroPixelRun.width,
+ imageExtent.height / macroPixelRun.height,
+ 1 };
+
+ DxvkBufferViewCreateInfo bufferViewInfo;
+ bufferViewInfo.format = bufferFormat;
+ bufferViewInfo.rangeOffset = srcSlice.offset();
+ bufferViewInfo.rangeLength = srcSlice.length();
+ auto tmpBufferView = m_device->createBufferView(srcSlice.buffer(), bufferViewInfo);
+
+ if (specConstantValue)
+ m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, specConstantValue);
+
+ m_context->bindResourceView(BindingIds::Image, tmpImageView, nullptr);
+ m_context->bindResourceView(BindingIds::Buffer, nullptr, tmpBufferView);
+ m_context->bindShader(VK_SHADER_STAGE_COMPUTE_BIT, m_shaders[videoFormat.FormatType]);
+ m_context->pushConstants(0, sizeof(VkExtent2D), &imageExtent);
+ m_context->dispatch(
+ (imageExtent.width / 8) + (imageExtent.width % 8),
+ (imageExtent.height / 8) + (imageExtent.height % 8),
+ 1);
+
+ // Reset the spec constants used...
+ if (specConstantValue)
+ m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, 0);
+
+ m_transferCommands += 1;
+ }
+
+
+ void D3D9FormatHelper::InitShaders() {
+ m_shaders[D3D9ConversionFormat_YUY2] = InitShader(d3d9_convert_yuy2_uyvy);
+ m_shaders[D3D9ConversionFormat_UYVY] = m_shaders[D3D9ConversionFormat_YUY2];
+ m_shaders[D3D9ConversionFormat_L6V5U5] = InitShader(d3d9_convert_l6v5u5);
+ m_shaders[D3D9ConversionFormat_X8L8V8U8] = InitShader(d3d9_convert_x8l8v8u8);
+ m_shaders[D3D9ConversionFormat_A2W10V10U10] = InitShader(d3d9_convert_a2w10v10u10);
+ m_shaders[D3D9ConversionFormat_NV12] = InitShader(d3d9_convert_nv12);
+ m_shaders[D3D9ConversionFormat_YV12] = InitShader(d3d9_convert_yv12);
+ }
+
+
+ Rc<DxvkShader> D3D9FormatHelper::InitShader(SpirvCodeBuffer code) {
+ const std::array<DxvkResourceSlot, 2> resourceSlots = { {
+ { BindingIds::Image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
+ { BindingIds::Buffer, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_IMAGE_VIEW_TYPE_1D },
+ } };
+
+ return m_device->createShader(
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ resourceSlots.size(), resourceSlots.data(),
+ { 0u, 0u, 0u, sizeof(VkExtent2D) }, code);
+ }
+
+
+ void D3D9FormatHelper::FlushInternal() {
+ m_context->flushCommandList();
+
+ m_transferCommands = 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.h
new file mode 100644
index 00000000..16348eda
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_format_helpers.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "d3d9_include.h"
+#include "d3d9_format.h"
+#include "../dxvk/dxvk_device.h"
+#include "../dxvk/dxvk_context.h"
+
+namespace dxvk {
+
+ class D3D9FormatHelper {
+
+ public:
+
+ D3D9FormatHelper(const Rc<DxvkDevice>& device);
+
+ void Flush();
+
+ void ConvertFormat(
+ D3D9_CONVERSION_FORMAT_INFO conversionFormat,
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ const DxvkBufferSlice& srcSlice);
+
+ private:
+
+ void ConvertGenericFormat(
+ D3D9_CONVERSION_FORMAT_INFO videoFormat,
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ const DxvkBufferSlice& srcSlice,
+ VkFormat bufferFormat,
+ uint32_t specConstantValue,
+ VkExtent2D macroPixelRun);
+
+ enum BindingIds : uint32_t {
+ Image = 0,
+ Buffer = 1,
+ };
+
+ void InitShaders();
+
+ Rc<DxvkShader> InitShader(SpirvCodeBuffer code);
+
+ void FlushInternal();
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkContext> m_context;
+
+ size_t m_transferCommands = 0;
+
+ std::array<Rc<DxvkShader>, D3D9ConversionFormat_Count> m_shaders;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.cpp
new file mode 100644
index 00000000..e37a5a0e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.cpp
@@ -0,0 +1,36 @@
+#include "d3d9_hud.h"
+
+namespace dxvk::hud {
+
+ HudSamplerCount::HudSamplerCount(D3D9DeviceEx* device)
+ : m_device (device)
+ , m_samplerCount ("0"){
+
+ }
+
+
+ void HudSamplerCount::update(dxvk::high_resolution_clock::time_point time) {
+ m_samplerCount = str::format(m_device->GetSamplerCount());
+ }
+
+
+ HudPos HudSamplerCount::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 0.0f, 1.0f, 0.75f, 1.0f },
+ "Samplers:");
+
+ renderer.drawText(16.0f,
+ { position.x + 120.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_samplerCount);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.h
new file mode 100644
index 00000000..b500e48b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_hud.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "d3d9_device.h"
+#include "../dxvk/hud/dxvk_hud_item.h"
+
+namespace dxvk::hud {
+
+ /**
+ * \brief HUD item to display DXVK version
+ */
+ class HudSamplerCount : public HudItem {
+
+ public:
+
+ HudSamplerCount(D3D9DeviceEx* device);
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ D3D9DeviceEx* m_device;
+
+ std::string m_samplerCount;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_include.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_include.h
new file mode 100644
index 00000000..99a233d1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_include.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#ifndef _MSC_VER
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0A00
+#endif
+
+#include <stdint.h>
+#include <d3d9.h>
+
+//for some reason we need to specify __declspec(dllexport) for MinGW
+#if defined(__WINE__) || (defined(DXVK_NATIVE) && !defined(_WIN32))
+#define DLLEXPORT __attribute__((visibility("default")))
+#else
+#define DLLEXPORT
+#endif
+
+
+#include "../util/com/com_guid.h"
+#include "../util/com/com_object.h"
+#include "../util/com/com_pointer.h"
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#include "../util/sync/sync_recursive.h"
+
+#include "../util/util_env.h"
+#include "../util/util_enum.h"
+#include "../util/util_error.h"
+#include "../util/util_flags.h"
+#include "../util/util_likely.h"
+#include "../util/util_math.h"
+#include "../util/util_monitor.h"
+#include "../util/util_string.h"
+
+// Missed definitions in Wine/MinGW.
+
+#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
+#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
+#endif
+
+#ifndef D3DSI_OPCODE_MASK
+#define D3DSI_OPCODE_MASK 0x0000FFFF
+#endif
+
+#ifndef D3DSP_TEXTURETYPE_MASK
+#define D3DSP_TEXTURETYPE_MASK 0x78000000
+#endif
+
+#ifndef D3DUSAGE_AUTOGENMIPMAP
+#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
+#endif
+
+#ifndef D3DSP_DCL_USAGE_MASK
+#define D3DSP_DCL_USAGE_MASK 0x0000000f
+#endif
+
+#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
+#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
+#endif
+
+#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
+#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
+#endif
+
+#ifndef D3DCURSOR_IMMEDIATE_UPDATE
+#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
+#endif
+
+#ifndef D3DPRESENT_FORCEIMMEDIATE
+#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
+#endif
+
+// MinGW headers are broken. Who'dve guessed?
+#ifndef _MSC_VER
+typedef struct _D3DDEVINFO_RESOURCEMANAGER
+{
+ char dummy;
+} D3DDEVINFO_RESOURCEMANAGER, * LPD3DDEVINFO_RESOURCEMANAGER;
+
+#ifndef __WINE__
+extern "C" WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID);
+#endif
+#endif
+
+// This is the managed pool on D3D9Ex, it's just hidden!
+#define D3DPOOL_MANAGED_EX D3DPOOL(6)
+
+using D3D9VertexElements = std::vector<D3DVERTEXELEMENT9>;
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.cpp
new file mode 100644
index 00000000..d3076954
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.cpp
@@ -0,0 +1,183 @@
+#include <cstring>
+
+#include "d3d9_initializer.h"
+
+namespace dxvk {
+
+ D3D9Initializer::D3D9Initializer(
+ const Rc<DxvkDevice>& Device)
+ : m_device(Device), m_context(m_device->createContext()) {
+ m_context->beginRecording(
+ m_device->createCommandList());
+ }
+
+
+ D3D9Initializer::~D3D9Initializer() {
+
+ }
+
+
+ void D3D9Initializer::Flush() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_transferCommands != 0)
+ FlushInternal();
+ }
+
+
+ void D3D9Initializer::InitBuffer(
+ D3D9CommonBuffer* pBuffer) {
+ VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>()->memFlags();
+
+ (memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ ? InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>())
+ : InitDeviceLocalBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>());
+
+ if (pBuffer->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
+ InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_STAGING>());
+ }
+
+
+ void D3D9Initializer::InitTexture(
+ D3D9CommonTexture* pTexture,
+ void* pInitialData) {
+ if (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_NONE)
+ return;
+
+ (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)
+ ? InitDeviceLocalTexture(pTexture)
+ : InitHostVisibleTexture(pTexture, pInitialData);
+ }
+
+
+ void D3D9Initializer::InitDeviceLocalBuffer(
+ DxvkBufferSlice Slice) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ m_transferCommands += 1;
+
+ m_context->clearBuffer(
+ Slice.buffer(),
+ Slice.offset(),
+ Slice.length(),
+ 0u);
+
+ FlushImplicit();
+ }
+
+
+ void D3D9Initializer::InitHostVisibleBuffer(
+ DxvkBufferSlice Slice) {
+ // If the buffer is mapped, we can write data directly
+ // to the mapped memory region instead of doing it on
+ // the GPU. Same goes for zero-initialization.
+ std::memset(
+ Slice.mapPtr(0), 0,
+ Slice.length());
+ }
+
+
+ void D3D9Initializer::InitDeviceLocalTexture(
+ D3D9CommonTexture* pTexture) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ auto InitImage = [&](Rc<DxvkImage> image) {
+ if (image == nullptr)
+ return;
+
+ auto formatInfo = imageFormatInfo(image->info().format);
+
+ m_transferCommands += 1;
+
+ // While the Microsoft docs state that resource contents are
+ // undefined if no initial data is provided, some applications
+ // expect a resource to be pre-cleared. We can only do that
+ // for non-compressed images, but that should be fine.
+ VkImageSubresourceRange subresources;
+ subresources.aspectMask = formatInfo->aspectMask;
+ subresources.baseMipLevel = 0;
+ subresources.levelCount = image->info().mipLevels;
+ subresources.baseArrayLayer = 0;
+ subresources.layerCount = image->info().numLayers;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::BlockCompressed)) {
+ m_context->clearCompressedColorImage(image, subresources);
+ } else {
+ if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
+ VkClearColorValue value = { };
+
+ m_context->clearColorImage(
+ image, value, subresources);
+ } else {
+ VkClearDepthStencilValue value;
+ value.depth = 0.0f;
+ value.stencil = 0;
+
+ m_context->clearDepthStencilImage(
+ image, value, subresources);
+ }
+ }
+ };
+
+ InitImage(pTexture->GetImage());
+
+ FlushImplicit();
+ }
+
+
+ void D3D9Initializer::InitHostVisibleTexture(
+ D3D9CommonTexture* pTexture,
+ void* pInitialData) {
+ // If the buffer is mapped, we can write data directly
+ // to the mapped memory region instead of doing it on
+ // the GPU. Same goes for zero-initialization.
+ const D3D9_COMMON_TEXTURE_DESC* desc = pTexture->Desc();
+ for (uint32_t a = 0; a < desc->ArraySize; a++) {
+ for (uint32_t m = 0; m < desc->MipLevels; m++) {
+ uint32_t subresource = pTexture->CalcSubresource(a, m);
+ DxvkBufferSliceHandle mapSlice = pTexture->GetBuffer(subresource)->getSliceHandle();
+
+ if (pInitialData != nullptr) {
+ VkExtent3D mipExtent = pTexture->GetExtentMip(m);
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(pTexture->GetFormatMapping().FormatColor);
+ VkExtent3D blockCount = util::computeBlockCount(mipExtent, formatInfo->blockSize);
+ uint32_t pitch = blockCount.width * formatInfo->elementSize;
+ uint32_t alignedPitch = align(pitch, 4);
+
+ util::packImageData(
+ mapSlice.mapPtr,
+ pInitialData,
+ pitch,
+ pitch * blockCount.height,
+ alignedPitch,
+ alignedPitch * blockCount.height,
+ D3D9CommonTexture::GetImageTypeFromResourceType(pTexture->GetType()),
+ mipExtent,
+ pTexture->Desc()->ArraySize,
+ formatInfo,
+ VK_IMAGE_ASPECT_COLOR_BIT);
+ } else {
+ std::memset(
+ mapSlice.mapPtr, 0,
+ mapSlice.length);
+ }
+ }
+ }
+ }
+
+
+ void D3D9Initializer::FlushImplicit() {
+ if (m_transferCommands > MaxTransferCommands
+ || m_transferMemory > MaxTransferMemory)
+ FlushInternal();
+ }
+
+
+ void D3D9Initializer::FlushInternal() {
+ m_context->flushCommandList();
+
+ m_transferCommands = 0;
+ m_transferMemory = 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.h
new file mode 100644
index 00000000..59802f95
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_initializer.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "d3d9_common_buffer.h"
+#include "d3d9_common_texture.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Resource initialization context
+ *
+ * Manages a context which is used for resource
+ * initialization. This includes
+ * zero-initialization for buffers and images.
+ */
+ class D3D9Initializer {
+ constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
+ constexpr static size_t MaxTransferCommands = 512;
+ public:
+
+ D3D9Initializer(
+ const Rc<DxvkDevice>& Device);
+
+ ~D3D9Initializer();
+
+ void Flush();
+
+ void InitBuffer(
+ D3D9CommonBuffer* pBuffer);
+
+ void InitTexture(
+ D3D9CommonTexture* pTexture,
+ void* pInitialData = nullptr);
+
+ private:
+
+ dxvk::mutex m_mutex;
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkContext> m_context;
+
+ size_t m_transferCommands = 0;
+ size_t m_transferMemory = 0;
+
+ void InitDeviceLocalBuffer(
+ DxvkBufferSlice Slice);
+
+ void InitHostVisibleBuffer(
+ DxvkBufferSlice Slice);
+
+ void InitDeviceLocalTexture(
+ D3D9CommonTexture* pTexture);
+
+ void InitHostVisibleTexture(
+ D3D9CommonTexture* pTexture,
+ void* pInitialData);
+
+ void FlushImplicit();
+ void FlushInternal();
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.cpp
new file mode 100644
index 00000000..dd141333
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.cpp
@@ -0,0 +1,374 @@
+#include "d3d9_interface.h"
+
+#include "d3d9_monitor.h"
+#include "d3d9_caps.h"
+#include "d3d9_device.h"
+
+#include <algorithm>
+
+namespace dxvk {
+
+ D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended)
+ : m_instance ( new DxvkInstance() )
+ , m_extended ( bExtended )
+ , m_d3d9Options ( nullptr, m_instance->config() ) {
+
+#ifndef DXVK_NATIVE
+ // D3D9 doesn't enumerate adapters like physical adapters...
+ // only as connected displays.
+
+ // Let's create some "adapters" for the amount of displays we have.
+ // We'll go through and match up displays -> our adapters in order.
+ // If we run out of adapters, then we'll just make repeats of the first one.
+ // We can't match up by names on Linux/Wine as they don't match at all
+ // like on Windows, so this is our best option.
+ if (m_d3d9Options.enumerateByDisplays) {
+ DISPLAY_DEVICEA device = { };
+ device.cb = sizeof(device);
+
+ uint32_t adapterOrdinal = 0;
+ uint32_t i = 0;
+ while (::EnumDisplayDevicesA(nullptr, i++, &device, 0)) {
+ // If we aren't attached, skip over.
+ if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
+ continue;
+
+ // If we are a mirror, skip over this device.
+ if (device.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
+ continue;
+
+ Rc<DxvkAdapter> adapter = adapterOrdinal >= m_instance->adapterCount()
+ ? m_instance->enumAdapters(0)
+ : m_instance->enumAdapters(adapterOrdinal);
+
+ if (adapter != nullptr)
+ m_adapters.emplace_back(this, adapter, adapterOrdinal++, i - 1);
+ }
+ }
+ else
+#endif
+ {
+ const uint32_t adapterCount = m_instance->adapterCount();
+ m_adapters.reserve(adapterCount);
+
+ for (uint32_t i = 0; i < adapterCount; i++)
+ m_adapters.emplace_back(this, m_instance->enumAdapters(i), i, 0);
+ }
+
+#ifndef DXVK_NATIVE
+ if (m_d3d9Options.dpiAware) {
+ Logger::info("Process set as DPI aware");
+ SetProcessDPIAware();
+ }
+#endif
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3D9)
+ || (m_extended && riid == __uuidof(IDirect3D9Ex))) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9InterfaceEx::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::RegisterSoftwareDevice(void* pInitializeFunction) {
+ Logger::warn("D3D9InterfaceEx::RegisterSoftwareDevice: Stub");
+ return D3D_OK;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterCount() {
+ return UINT(m_adapters.size());
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterIdentifier(
+ UINT Adapter,
+ DWORD Flags,
+ D3DADAPTER_IDENTIFIER9* pIdentifier) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetAdapterIdentifier(Flags, pIdentifier);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) {
+ D3DDISPLAYMODEFILTER filter;
+ filter.Size = sizeof(D3DDISPLAYMODEFILTER);
+ filter.Format = Format;
+ filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+
+ return this->GetAdapterModeCountEx(Adapter, &filter);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) {
+ if (auto* adapter = GetAdapter(Adapter)) {
+ D3DDISPLAYMODEEX modeEx = { };
+ modeEx.Size = sizeof(D3DDISPLAYMODEEX);
+ HRESULT hr = adapter->GetAdapterDisplayModeEx(&modeEx, nullptr);
+
+ if (FAILED(hr))
+ return hr;
+
+ pMode->Width = modeEx.Width;
+ pMode->Height = modeEx.Height;
+ pMode->RefreshRate = modeEx.RefreshRate;
+ pMode->Format = modeEx.Format;
+
+ return D3D_OK;
+ }
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceType(
+ UINT Adapter,
+ D3DDEVTYPE DevType,
+ D3DFORMAT AdapterFormat,
+ D3DFORMAT BackBufferFormat,
+ BOOL bWindowed) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->CheckDeviceType(
+ DevType, EnumerateFormat(AdapterFormat),
+ EnumerateFormat(BackBufferFormat), bWindowed);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormat(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT AdapterFormat,
+ DWORD Usage,
+ D3DRESOURCETYPE RType,
+ D3DFORMAT CheckFormat) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->CheckDeviceFormat(
+ DeviceType, EnumerateFormat(AdapterFormat),
+ Usage, RType,
+ EnumerateFormat(CheckFormat));
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceMultiSampleType(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT SurfaceFormat,
+ BOOL Windowed,
+ D3DMULTISAMPLE_TYPE MultiSampleType,
+ DWORD* pQualityLevels) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->CheckDeviceMultiSampleType(
+ DeviceType, EnumerateFormat(SurfaceFormat),
+ Windowed, MultiSampleType,
+ pQualityLevels);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDepthStencilMatch(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT AdapterFormat,
+ D3DFORMAT RenderTargetFormat,
+ D3DFORMAT DepthStencilFormat) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->CheckDepthStencilMatch(
+ DeviceType, EnumerateFormat(AdapterFormat),
+ EnumerateFormat(RenderTargetFormat),
+ EnumerateFormat(DepthStencilFormat));
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormatConversion(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT SourceFormat,
+ D3DFORMAT TargetFormat) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->CheckDeviceFormatConversion(
+ DeviceType, EnumerateFormat(SourceFormat),
+ EnumerateFormat(TargetFormat));
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetDeviceCaps(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DCAPS9* pCaps) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetDeviceCaps(
+ DeviceType, pCaps);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HMONITOR STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterMonitor(UINT Adapter) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetMonitor();
+
+ return nullptr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDevice(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ IDirect3DDevice9** ppReturnedDeviceInterface) {
+ return this->CreateDeviceEx(
+ Adapter,
+ DeviceType,
+ hFocusWindow,
+ BehaviorFlags,
+ pPresentationParameters,
+ nullptr, // <-- pFullscreenDisplayMode
+ reinterpret_cast<IDirect3DDevice9Ex**>(ppReturnedDeviceInterface));
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModes(
+ UINT Adapter,
+ D3DFORMAT Format,
+ UINT Mode,
+ D3DDISPLAYMODE* pMode) {
+ if (pMode == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ D3DDISPLAYMODEFILTER filter;
+ filter.Format = Format;
+ filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+ filter.Size = sizeof(D3DDISPLAYMODEFILTER);
+
+ D3DDISPLAYMODEEX modeEx = { };
+ modeEx.Size = sizeof(D3DDISPLAYMODEEX);
+ HRESULT hr = this->EnumAdapterModesEx(Adapter, &filter, Mode, &modeEx);
+
+ if (FAILED(hr))
+ return hr;
+
+ pMode->Width = modeEx.Width;
+ pMode->Height = modeEx.Height;
+ pMode->RefreshRate = modeEx.RefreshRate;
+ pMode->Format = modeEx.Format;
+
+ return D3D_OK;
+ }
+
+
+ // Ex Methods
+
+
+ UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetAdapterModeCountEx(pFilter);
+
+ return 0;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModesEx(
+ UINT Adapter,
+ const D3DDISPLAYMODEFILTER* pFilter,
+ UINT Mode,
+ D3DDISPLAYMODEEX* pMode) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->EnumAdapterModesEx(pFilter, Mode, pMode);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayModeEx(
+ UINT Adapter,
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetAdapterDisplayModeEx(pMode, pRotation);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDeviceEx(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ IDirect3DDevice9Ex** ppReturnedDeviceInterface) {
+ InitReturnPtr(ppReturnedDeviceInterface);
+
+ if (ppReturnedDeviceInterface == nullptr
+ || pPresentationParameters == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto* adapter = GetAdapter(Adapter);
+
+ if (adapter == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto dxvkAdapter = adapter->GetDXVKAdapter();
+
+ try {
+ auto dxvkDevice = dxvkAdapter->createDevice(m_instance, D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter));
+
+ auto* device = new D3D9DeviceEx(
+ this,
+ adapter,
+ DeviceType,
+ hFocusWindow,
+ BehaviorFlags,
+ dxvkDevice);
+
+ HRESULT hr = device->InitialReset(pPresentationParameters, pFullscreenDisplayMode);
+
+ if (FAILED(hr))
+ return hr;
+
+ *ppReturnedDeviceInterface = ref(device);
+ }
+ catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_NOTAVAILABLE;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterLUID(UINT Adapter, LUID* pLUID) {
+ if (auto* adapter = GetAdapter(Adapter))
+ return adapter->GetAdapterLUID(pLUID);
+
+ return D3DERR_INVALIDCALL;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.h
new file mode 100644
index 00000000..85cc5a03
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_interface.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#include "d3d9_adapter.h"
+
+#include "../dxvk/dxvk_instance.h"
+
+namespace dxvk {
+
+ /**
+ * \brief D3D9 interface implementation
+ *
+ * Implements the IDirect3DDevice9Ex interfaces
+ * which provides the way to get adapters and create other objects such as \ref IDirect3DDevice9Ex.
+ * similar to \ref DxgiFactory but for D3D9.
+ */
+ class D3D9InterfaceEx final : public ComObjectClamp<IDirect3D9Ex> {
+
+ public:
+
+ D3D9InterfaceEx(bool bExtended);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction);
+
+ UINT STDMETHODCALLTYPE GetAdapterCount();
+
+ HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(
+ UINT Adapter,
+ DWORD Flags,
+ D3DADAPTER_IDENTIFIER9* pIdentifier);
+
+ UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format);
+
+ HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode);
+
+ HRESULT STDMETHODCALLTYPE CheckDeviceType(
+ UINT Adapter,
+ D3DDEVTYPE DevType,
+ D3DFORMAT AdapterFormat,
+ D3DFORMAT BackBufferFormat,
+ BOOL bWindowed);
+
+ HRESULT STDMETHODCALLTYPE CheckDeviceFormat(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT AdapterFormat,
+ DWORD Usage,
+ D3DRESOURCETYPE RType,
+ D3DFORMAT CheckFormat);
+
+ HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT SurfaceFormat,
+ BOOL Windowed,
+ D3DMULTISAMPLE_TYPE MultiSampleType,
+ DWORD* pQualityLevels);
+
+ HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT AdapterFormat,
+ D3DFORMAT RenderTargetFormat,
+ D3DFORMAT DepthStencilFormat);
+
+ HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DFORMAT SourceFormat,
+ D3DFORMAT TargetFormat);
+
+ HRESULT STDMETHODCALLTYPE GetDeviceCaps(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ D3DCAPS9* pCaps);
+
+ HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter);
+
+ HRESULT STDMETHODCALLTYPE CreateDevice(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ IDirect3DDevice9** ppReturnedDeviceInterface);
+
+ HRESULT STDMETHODCALLTYPE EnumAdapterModes(
+ UINT Adapter,
+ D3DFORMAT Format,
+ UINT Mode,
+ D3DDISPLAYMODE* pMode);
+
+ // Ex Methods
+
+ UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter);
+
+ HRESULT STDMETHODCALLTYPE EnumAdapterModesEx(
+ UINT Adapter,
+ const D3DDISPLAYMODEFILTER* pFilter,
+ UINT Mode,
+ D3DDISPLAYMODEEX* pMode);
+
+ HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(
+ UINT Adapter,
+ D3DDISPLAYMODEEX* pMode,
+ D3DDISPLAYROTATION* pRotation);
+
+ HRESULT STDMETHODCALLTYPE CreateDeviceEx(
+ UINT Adapter,
+ D3DDEVTYPE DeviceType,
+ HWND hFocusWindow,
+ DWORD BehaviorFlags,
+ D3DPRESENT_PARAMETERS* pPresentationParameters,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ IDirect3DDevice9Ex** ppReturnedDeviceInterface);
+
+ HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID* pLUID);
+
+ const D3D9Options& GetOptions() { return m_d3d9Options; }
+
+ D3D9Adapter* GetAdapter(UINT Ordinal) {
+ return Ordinal < m_adapters.size()
+ ? &m_adapters[Ordinal]
+ : nullptr;
+ }
+
+ bool IsExtended() { return m_extended; }
+
+ Rc<DxvkInstance> GetInstance() { return m_instance; }
+
+ private:
+
+ void CacheModes(D3D9Format Format);
+
+ static const char* GetDriverDllName(DxvkGpuVendor vendor);
+
+ Rc<DxvkInstance> m_instance;
+
+ bool m_extended;
+
+ D3D9Options m_d3d9Options;
+
+ std::vector<D3D9Adapter> m_adapters;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_main.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_main.cpp
new file mode 100644
index 00000000..dfca9c1d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_main.cpp
@@ -0,0 +1,86 @@
+#include "../dxvk/dxvk_instance.h"
+
+#include "d3d9_interface.h"
+#include "d3d9_shader_validator.h"
+
+class D3DFE_PROCESSVERTICES;
+using PSGPERRORID = UINT;
+
+namespace dxvk {
+ Logger Logger::s_instance("d3d9.log");
+
+ HRESULT CreateD3D9(
+ bool Extended,
+ IDirect3D9Ex** ppDirect3D9Ex) {
+ if (!ppDirect3D9Ex)
+ return D3DERR_INVALIDCALL;
+
+ *ppDirect3D9Ex = ref(new D3D9InterfaceEx( Extended ));
+ return D3D_OK;
+ }
+}
+
+extern "C" {
+
+ DLLEXPORT IDirect3D9* __stdcall Direct3DCreate9(UINT nSDKVersion) {
+ IDirect3D9Ex* pDirect3D = nullptr;
+ dxvk::CreateD3D9(false, &pDirect3D);
+
+ return pDirect3D;
+ }
+
+ DLLEXPORT HRESULT __stdcall Direct3DCreate9Ex(UINT nSDKVersion, IDirect3D9Ex** ppDirect3D9Ex) {
+ return dxvk::CreateD3D9(true, ppDirect3D9Ex);
+ }
+
+ DLLEXPORT int __stdcall D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) {
+ return 0;
+ }
+
+ DLLEXPORT int __stdcall D3DPERF_EndEvent(void) {
+ return 0;
+ }
+
+ DLLEXPORT void __stdcall D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
+ }
+
+ DLLEXPORT void __stdcall D3DPERF_SetRegion(D3DCOLOR col, LPCWSTR wszName) {
+ }
+
+ DLLEXPORT BOOL __stdcall D3DPERF_QueryRepeatFrame(void) {
+ return FALSE;
+ }
+
+ DLLEXPORT void __stdcall D3DPERF_SetOptions(DWORD dwOptions) {
+ }
+
+ DLLEXPORT DWORD __stdcall D3DPERF_GetStatus(void) {
+ return 0;
+ }
+
+
+ DLLEXPORT void __stdcall DebugSetMute(void) {
+ }
+
+ DLLEXPORT int __stdcall DebugSetLevel(void) {
+ return 0;
+ }
+
+ // Processor Specific Geometry Pipeline
+ // for P3 SIMD/AMD 3DNow.
+
+ DLLEXPORT void __stdcall PSGPError(D3DFE_PROCESSVERTICES* a, PSGPERRORID b, UINT c) {
+ }
+
+ DLLEXPORT void __stdcall PSGPSampleTexture(D3DFE_PROCESSVERTICES* a, UINT b, float(*const c)[4], UINT d, float(*const e)[4]) {
+ }
+
+ DLLEXPORT dxvk::D3D9ShaderValidator* __stdcall Direct3DShaderValidatorCreate9(void) {
+ return ref(new dxvk::D3D9ShaderValidator());
+ }
+
+ DLLEXPORT int __stdcall Direct3D9EnableMaximizedWindowedModeShim(UINT a) {
+ return 0;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.cpp
new file mode 100644
index 00000000..f6fa0640
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.cpp
@@ -0,0 +1,66 @@
+#include "d3d9_monitor.h"
+
+#include "d3d9_format.h"
+
+#include "../wsi/wsi_window.h"
+#include "../wsi/wsi_monitor.h"
+
+namespace dxvk {
+
+ uint32_t GetMonitorFormatBpp(D3D9Format Format) {
+ switch (Format) {
+ case D3D9Format::A8R8G8B8:
+ case D3D9Format::X8R8G8B8: // This is still 32 bit even though the alpha is unspecified.
+ case D3D9Format::A2R10G10B10:
+ return 32;
+
+ case D3D9Format::A1R5G5B5:
+ case D3D9Format::X1R5G5B5:
+ case D3D9Format::R5G6B5:
+ return 16;
+
+ default:
+ Logger::warn(str::format(
+ "GetMonitorFormatBpp: Unknown format: ",
+ Format));
+ return 32;
+ }
+ }
+
+
+ bool IsSupportedAdapterFormat(
+ D3D9Format Format) {
+ return Format == D3D9Format::A2R10G10B10
+ || Format == D3D9Format::X8R8G8B8
+ || Format == D3D9Format::X1R5G5B5
+ || Format == D3D9Format::R5G6B5;
+ }
+
+
+ bool IsSupportedBackBufferFormat(
+ D3D9Format AdapterFormat,
+ D3D9Format BackBufferFormat,
+ BOOL Windowed) {
+ if (!Windowed) {
+ return (AdapterFormat == D3D9Format::A2R10G10B10 && BackBufferFormat == D3D9Format::A2R10G10B10) ||
+ (AdapterFormat == D3D9Format::X8R8G8B8 && BackBufferFormat == D3D9Format::X8R8G8B8) ||
+ (AdapterFormat == D3D9Format::X8R8G8B8 && BackBufferFormat == D3D9Format::A8R8G8B8) ||
+ (AdapterFormat == D3D9Format::X1R5G5B5 && BackBufferFormat == D3D9Format::X1R5G5B5) ||
+ (AdapterFormat == D3D9Format::X1R5G5B5 && BackBufferFormat == D3D9Format::A1R5G5B5) ||
+ (AdapterFormat == D3D9Format::R5G6B5 && BackBufferFormat == D3D9Format::R5G6B5);
+ }
+
+ return IsSupportedBackBufferFormat(BackBufferFormat);
+ }
+
+ bool IsSupportedBackBufferFormat(
+ D3D9Format BackBufferFormat) {
+ return BackBufferFormat == D3D9Format::A2R10G10B10
+ || BackBufferFormat == D3D9Format::A8R8G8B8
+ || BackBufferFormat == D3D9Format::X8R8G8B8
+ || BackBufferFormat == D3D9Format::A1R5G5B5
+ || BackBufferFormat == D3D9Format::X1R5G5B5
+ || BackBufferFormat == D3D9Format::R5G6B5;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.h
new file mode 100644
index 00000000..0a9d1a89
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_monitor.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+#include "d3d9_format.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Queries bits per pixel for a format
+ *
+ * The format must be a valid swap chain format.
+ * \param [in] Format The D3D9 format to query
+ * \returns Bits per pixel for this format
+ */
+ uint32_t GetMonitorFormatBpp(
+ D3D9Format Format);
+
+ /**
+ * \brief Returns if a format is supported for a backbuffer/swapchain.
+ *
+ * \param [in] Format The D3D9 format to query
+ * \returns If it is supported as a swapchain/backbuffer format.
+ */
+ bool IsSupportedAdapterFormat(
+ D3D9Format Format);
+
+ bool IsSupportedBackBufferFormat(
+ D3D9Format AdapterFormat,
+ D3D9Format BackBufferFormat,
+ BOOL Windowed);
+
+ bool IsSupportedBackBufferFormat(
+ D3D9Format BackBufferFormat);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.cpp
new file mode 100644
index 00000000..603d4b6b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.cpp
@@ -0,0 +1,9 @@
+#include "d3d9_device.h"
+
+namespace dxvk {
+
+ D3D9Multithread::D3D9Multithread(
+ BOOL Protected)
+ : m_protected( Protected ) { }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.h
new file mode 100644
index 00000000..f91857b6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_multithread.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Device lock
+ *
+ * Lightweight RAII wrapper that implements
+ * a subset of the functionality provided by
+ * \c std::unique_lock, with the goal of being
+ * cheaper to construct and destroy.
+ */
+ class D3D9DeviceLock {
+
+ public:
+
+ D3D9DeviceLock()
+ : m_mutex(nullptr) { }
+
+ D3D9DeviceLock(sync::RecursiveSpinlock& mutex)
+ : m_mutex(&mutex) {
+ mutex.lock();
+ }
+
+ D3D9DeviceLock(D3D9DeviceLock&& other)
+ : m_mutex(other.m_mutex) {
+ other.m_mutex = nullptr;
+ }
+
+ D3D9DeviceLock& operator = (D3D9DeviceLock&& other) {
+ if (m_mutex)
+ m_mutex->unlock();
+
+ m_mutex = other.m_mutex;
+ other.m_mutex = nullptr;
+ return *this;
+ }
+
+ ~D3D9DeviceLock() {
+ if (m_mutex != nullptr)
+ m_mutex->unlock();
+ }
+
+ private:
+
+ sync::RecursiveSpinlock* m_mutex;
+
+ };
+
+
+ /**
+ * \brief D3D9 context lock
+ */
+ class D3D9Multithread {
+
+ public:
+
+ D3D9Multithread(
+ BOOL Protected);
+
+ D3D9DeviceLock AcquireLock() {
+ return m_protected
+ ? D3D9DeviceLock(m_mutex)
+ : D3D9DeviceLock();
+ }
+
+ private:
+
+ BOOL m_protected;
+
+ sync::RecursiveSpinlock m_mutex;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.cpp
new file mode 100644
index 00000000..e7b7b6a6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.cpp
@@ -0,0 +1,230 @@
+#include "d3d9_format.h"
+
+namespace dxvk {
+
+ std::ostream& operator << (std::ostream& os, D3D9Format e) {
+ switch (e) {
+ ENUM_NAME(D3D9Format::Unknown);
+
+ ENUM_NAME(D3D9Format::R8G8B8);
+ ENUM_NAME(D3D9Format::A8R8G8B8);
+ ENUM_NAME(D3D9Format::X8R8G8B8);
+ ENUM_NAME(D3D9Format::R5G6B5);
+ ENUM_NAME(D3D9Format::X1R5G5B5);
+ ENUM_NAME(D3D9Format::A1R5G5B5);
+ ENUM_NAME(D3D9Format::A4R4G4B4);
+ ENUM_NAME(D3D9Format::R3G3B2);
+ ENUM_NAME(D3D9Format::A8);
+ ENUM_NAME(D3D9Format::A8R3G3B2);
+ ENUM_NAME(D3D9Format::X4R4G4B4);
+ ENUM_NAME(D3D9Format::A2B10G10R10);
+ ENUM_NAME(D3D9Format::A8B8G8R8);
+ ENUM_NAME(D3D9Format::X8B8G8R8);
+ ENUM_NAME(D3D9Format::G16R16);
+ ENUM_NAME(D3D9Format::A2R10G10B10);
+ ENUM_NAME(D3D9Format::A16B16G16R16);
+ ENUM_NAME(D3D9Format::A8P8);
+ ENUM_NAME(D3D9Format::P8);
+ ENUM_NAME(D3D9Format::L8);
+ ENUM_NAME(D3D9Format::A8L8);
+ ENUM_NAME(D3D9Format::A4L4);
+ ENUM_NAME(D3D9Format::V8U8);
+ ENUM_NAME(D3D9Format::L6V5U5);
+ ENUM_NAME(D3D9Format::X8L8V8U8);
+ ENUM_NAME(D3D9Format::Q8W8V8U8);
+ ENUM_NAME(D3D9Format::V16U16);
+ ENUM_NAME(D3D9Format::A2W10V10U10);
+ ENUM_NAME(D3D9Format::UYVY);
+ ENUM_NAME(D3D9Format::R8G8_B8G8);
+ ENUM_NAME(D3D9Format::YUY2);
+ ENUM_NAME(D3D9Format::G8R8_G8B8);
+ ENUM_NAME(D3D9Format::DXT1);
+ ENUM_NAME(D3D9Format::DXT2);
+ ENUM_NAME(D3D9Format::DXT3);
+ ENUM_NAME(D3D9Format::DXT4);
+ ENUM_NAME(D3D9Format::DXT5);
+ ENUM_NAME(D3D9Format::D16_LOCKABLE);
+ ENUM_NAME(D3D9Format::D32);
+ ENUM_NAME(D3D9Format::D15S1);
+ ENUM_NAME(D3D9Format::D24S8);
+ ENUM_NAME(D3D9Format::D24X8);
+ ENUM_NAME(D3D9Format::D24X4S4);
+ ENUM_NAME(D3D9Format::D16);
+ ENUM_NAME(D3D9Format::D32F_LOCKABLE);
+ ENUM_NAME(D3D9Format::D24FS8);
+ ENUM_NAME(D3D9Format::D32_LOCKABLE);
+ ENUM_NAME(D3D9Format::S8_LOCKABLE);
+ ENUM_NAME(D3D9Format::L16);
+ ENUM_NAME(D3D9Format::VERTEXDATA);
+ ENUM_NAME(D3D9Format::INDEX16);
+ ENUM_NAME(D3D9Format::INDEX32);
+ ENUM_NAME(D3D9Format::Q16W16V16U16);
+ ENUM_NAME(D3D9Format::MULTI2_ARGB8);
+ ENUM_NAME(D3D9Format::R16F);
+ ENUM_NAME(D3D9Format::G16R16F);
+ ENUM_NAME(D3D9Format::A16B16G16R16F);
+ ENUM_NAME(D3D9Format::R32F);
+ ENUM_NAME(D3D9Format::G32R32F);
+ ENUM_NAME(D3D9Format::A32B32G32R32F);
+ ENUM_NAME(D3D9Format::CxV8U8);
+ ENUM_NAME(D3D9Format::A1);
+ ENUM_NAME(D3D9Format::A2B10G10R10_XR_BIAS);
+ ENUM_NAME(D3D9Format::BINARYBUFFER);
+
+ // Driver Hacks / Unofficial Formats
+ ENUM_NAME(D3D9Format::ATI1);
+ ENUM_NAME(D3D9Format::ATI2);
+ ENUM_NAME(D3D9Format::INST);
+ ENUM_NAME(D3D9Format::DF24);
+ ENUM_NAME(D3D9Format::DF16);
+ ENUM_NAME(D3D9Format::NULL_FORMAT);
+ ENUM_NAME(D3D9Format::GET4);
+ ENUM_NAME(D3D9Format::GET1);
+ ENUM_NAME(D3D9Format::NVDB);
+ ENUM_NAME(D3D9Format::A2M1);
+ ENUM_NAME(D3D9Format::A2M0);
+ ENUM_NAME(D3D9Format::ATOC);
+ ENUM_NAME(D3D9Format::INTZ);
+ ENUM_NAME(D3D9Format::RAWZ);
+ ENUM_NAME(D3D9Format::RESZ);
+
+ ENUM_NAME(D3D9Format::NV11);
+ ENUM_NAME(D3D9Format::NV12);
+ ENUM_NAME(D3D9Format::P010);
+ ENUM_NAME(D3D9Format::P016);
+ ENUM_NAME(D3D9Format::Y210);
+ ENUM_NAME(D3D9Format::Y216);
+ ENUM_NAME(D3D9Format::Y410);
+ ENUM_NAME(D3D9Format::AYUV);
+ ENUM_NAME(D3D9Format::YV12);
+ ENUM_NAME(D3D9Format::OPAQUE_420);
+
+ ENUM_NAME(D3D9Format::AI44);
+ ENUM_NAME(D3D9Format::IA44);
+ ENUM_NAME(D3D9Format::R2VB);
+ ENUM_NAME(D3D9Format::COPM);
+ ENUM_NAME(D3D9Format::SSAA);
+ ENUM_NAME(D3D9Format::AL16);
+ ENUM_NAME(D3D9Format::R16);
+
+ ENUM_NAME(D3D9Format::EXT1);
+ ENUM_NAME(D3D9Format::FXT1);
+ ENUM_NAME(D3D9Format::GXT1);
+ ENUM_NAME(D3D9Format::HXT1);
+
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e) {
+ switch (e) {
+ ENUM_NAME(D3DRS_ZENABLE);
+ ENUM_NAME(D3DRS_FILLMODE);
+ ENUM_NAME(D3DRS_SHADEMODE);
+ ENUM_NAME(D3DRS_ZWRITEENABLE);
+ ENUM_NAME(D3DRS_ALPHATESTENABLE);
+ ENUM_NAME(D3DRS_LASTPIXEL);
+ ENUM_NAME(D3DRS_SRCBLEND);
+ ENUM_NAME(D3DRS_DESTBLEND);
+ ENUM_NAME(D3DRS_CULLMODE);
+ ENUM_NAME(D3DRS_ZFUNC);
+ ENUM_NAME(D3DRS_ALPHAREF);
+ ENUM_NAME(D3DRS_ALPHAFUNC);
+ ENUM_NAME(D3DRS_DITHERENABLE);
+ ENUM_NAME(D3DRS_ALPHABLENDENABLE);
+ ENUM_NAME(D3DRS_FOGENABLE);
+ ENUM_NAME(D3DRS_SPECULARENABLE);
+ ENUM_NAME(D3DRS_FOGCOLOR);
+ ENUM_NAME(D3DRS_FOGTABLEMODE);
+ ENUM_NAME(D3DRS_FOGSTART);
+ ENUM_NAME(D3DRS_FOGEND);
+ ENUM_NAME(D3DRS_FOGDENSITY);
+ ENUM_NAME(D3DRS_RANGEFOGENABLE);
+ ENUM_NAME(D3DRS_STENCILENABLE);
+ ENUM_NAME(D3DRS_STENCILFAIL);
+ ENUM_NAME(D3DRS_STENCILZFAIL);
+ ENUM_NAME(D3DRS_STENCILPASS);
+ ENUM_NAME(D3DRS_STENCILFUNC);
+ ENUM_NAME(D3DRS_STENCILREF);
+ ENUM_NAME(D3DRS_STENCILMASK);
+ ENUM_NAME(D3DRS_STENCILWRITEMASK);
+ ENUM_NAME(D3DRS_TEXTUREFACTOR);
+ ENUM_NAME(D3DRS_WRAP0);
+ ENUM_NAME(D3DRS_WRAP1);
+ ENUM_NAME(D3DRS_WRAP2);
+ ENUM_NAME(D3DRS_WRAP3);
+ ENUM_NAME(D3DRS_WRAP4);
+ ENUM_NAME(D3DRS_WRAP5);
+ ENUM_NAME(D3DRS_WRAP6);
+ ENUM_NAME(D3DRS_WRAP7);
+ ENUM_NAME(D3DRS_CLIPPING);
+ ENUM_NAME(D3DRS_LIGHTING);
+ ENUM_NAME(D3DRS_AMBIENT);
+ ENUM_NAME(D3DRS_FOGVERTEXMODE);
+ ENUM_NAME(D3DRS_COLORVERTEX);
+ ENUM_NAME(D3DRS_LOCALVIEWER);
+ ENUM_NAME(D3DRS_NORMALIZENORMALS);
+ ENUM_NAME(D3DRS_DIFFUSEMATERIALSOURCE);
+ ENUM_NAME(D3DRS_SPECULARMATERIALSOURCE);
+ ENUM_NAME(D3DRS_AMBIENTMATERIALSOURCE);
+ ENUM_NAME(D3DRS_EMISSIVEMATERIALSOURCE);
+ ENUM_NAME(D3DRS_VERTEXBLEND);
+ ENUM_NAME(D3DRS_CLIPPLANEENABLE);
+ ENUM_NAME(D3DRS_POINTSIZE);
+ ENUM_NAME(D3DRS_POINTSIZE_MIN);
+ ENUM_NAME(D3DRS_POINTSPRITEENABLE);
+ ENUM_NAME(D3DRS_POINTSCALEENABLE);
+ ENUM_NAME(D3DRS_POINTSCALE_A);
+ ENUM_NAME(D3DRS_POINTSCALE_B);
+ ENUM_NAME(D3DRS_POINTSCALE_C);
+ ENUM_NAME(D3DRS_MULTISAMPLEANTIALIAS);
+ ENUM_NAME(D3DRS_MULTISAMPLEMASK);
+ ENUM_NAME(D3DRS_PATCHEDGESTYLE);
+ ENUM_NAME(D3DRS_DEBUGMONITORTOKEN);
+ ENUM_NAME(D3DRS_POINTSIZE_MAX);
+ ENUM_NAME(D3DRS_INDEXEDVERTEXBLENDENABLE);
+ ENUM_NAME(D3DRS_COLORWRITEENABLE);
+ ENUM_NAME(D3DRS_TWEENFACTOR);
+ ENUM_NAME(D3DRS_BLENDOP);
+ ENUM_NAME(D3DRS_POSITIONDEGREE);
+ ENUM_NAME(D3DRS_NORMALDEGREE);
+ ENUM_NAME(D3DRS_SCISSORTESTENABLE);
+ ENUM_NAME(D3DRS_SLOPESCALEDEPTHBIAS);
+ ENUM_NAME(D3DRS_ANTIALIASEDLINEENABLE);
+ ENUM_NAME(D3DRS_MINTESSELLATIONLEVEL);
+ ENUM_NAME(D3DRS_MAXTESSELLATIONLEVEL);
+ ENUM_NAME(D3DRS_ADAPTIVETESS_X);
+ ENUM_NAME(D3DRS_ADAPTIVETESS_Y);
+ ENUM_NAME(D3DRS_ADAPTIVETESS_Z);
+ ENUM_NAME(D3DRS_ADAPTIVETESS_W);
+ ENUM_NAME(D3DRS_ENABLEADAPTIVETESSELLATION);
+ ENUM_NAME(D3DRS_TWOSIDEDSTENCILMODE);
+ ENUM_NAME(D3DRS_CCW_STENCILFAIL);
+ ENUM_NAME(D3DRS_CCW_STENCILZFAIL);
+ ENUM_NAME(D3DRS_CCW_STENCILPASS);
+ ENUM_NAME(D3DRS_CCW_STENCILFUNC);
+ ENUM_NAME(D3DRS_COLORWRITEENABLE1);
+ ENUM_NAME(D3DRS_COLORWRITEENABLE2);
+ ENUM_NAME(D3DRS_COLORWRITEENABLE3);
+ ENUM_NAME(D3DRS_BLENDFACTOR);
+ ENUM_NAME(D3DRS_SRGBWRITEENABLE);
+ ENUM_NAME(D3DRS_DEPTHBIAS);
+ ENUM_NAME(D3DRS_WRAP8);
+ ENUM_NAME(D3DRS_WRAP9);
+ ENUM_NAME(D3DRS_WRAP10);
+ ENUM_NAME(D3DRS_WRAP11);
+ ENUM_NAME(D3DRS_WRAP12);
+ ENUM_NAME(D3DRS_WRAP13);
+ ENUM_NAME(D3DRS_WRAP14);
+ ENUM_NAME(D3DRS_WRAP15);
+ ENUM_NAME(D3DRS_SEPARATEALPHABLENDENABLE);
+ ENUM_NAME(D3DRS_SRCBLENDALPHA);
+ ENUM_NAME(D3DRS_DESTBLENDALPHA);
+ ENUM_NAME(D3DRS_BLENDOPALPHA);
+
+ ENUM_DEFAULT(e);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.h
new file mode 100644
index 00000000..82d9c479
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_names.h
@@ -0,0 +1,7 @@
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.cpp
new file mode 100644
index 00000000..0f99fefd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.cpp
@@ -0,0 +1,92 @@
+#include "d3d9_options.h"
+
+#include "d3d9_caps.h"
+#include "d3d9_config.h"
+
+namespace dxvk {
+
+ static int32_t parsePciId(const std::string& str) {
+ if (str.size() != 4)
+ return -1;
+
+ int32_t id = 0;
+
+ for (size_t i = 0; i < str.size(); i++) {
+ id *= 16;
+
+ if (str[i] >= '0' && str[i] <= '9')
+ id += str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ id += str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ id += str[i] - 'a' + 10;
+ else
+ return -1;
+ }
+
+ return id;
+ }
+
+
+ D3D9Options::D3D9Options(const Rc<DxvkDevice>& device, const Config& config) {
+ const Rc<DxvkAdapter> adapter = device != nullptr ? device->adapter() : nullptr;
+
+ // Fetch these as a string representing a hexadecimal number and parse it.
+ this->customVendorId = parsePciId(config.getOption<std::string>("d3d9.customVendorId"));
+ this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
+ this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
+
+ const int32_t vendorId = this->customDeviceId != -1
+ ? this->customDeviceId
+ : (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
+
+ this->maxFrameLatency = config.getOption<int32_t> ("d3d9.maxFrameLatency", 0);
+ this->maxFrameRate = config.getOption<int32_t> ("d3d9.maxFrameRate", 0);
+ this->presentInterval = config.getOption<int32_t> ("d3d9.presentInterval", -1);
+ this->shaderModel = config.getOption<int32_t> ("d3d9.shaderModel", 3);
+ this->evictManagedOnUnlock = config.getOption<bool> ("d3d9.evictManagedOnUnlock", false);
+ this->dpiAware = config.getOption<bool> ("d3d9.dpiAware", true);
+ this->strictConstantCopies = config.getOption<bool> ("d3d9.strictConstantCopies", false);
+ this->strictPow = config.getOption<bool> ("d3d9.strictPow", true);
+ this->lenientClear = config.getOption<bool> ("d3d9.lenientClear", false);
+ this->numBackBuffers = config.getOption<int32_t> ("d3d9.numBackBuffers", 0);
+ this->noExplicitFrontBuffer = config.getOption<bool> ("d3d9.noExplicitFrontBuffer", false);
+ this->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
+ this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
+ this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
+ this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", true);
+ this->supportX4R4G4B4 = config.getOption<bool> ("d3d9.supportX4R4G4B4", true);
+ this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
+ this->swvpFloatCount = config.getOption<int32_t> ("d3d9.swvpFloatCount", caps::MaxFloatConstantsSoftware);
+ this->swvpIntCount = config.getOption<int32_t> ("d3d9.swvpIntCount", caps::MaxOtherConstantsSoftware);
+ this->swvpBoolCount = config.getOption<int32_t> ("d3d9.swvpBoolCount", caps::MaxOtherConstantsSoftware);
+ this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
+ this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", false);
+ this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
+ this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == 0x10de);
+ this->enableDialogMode = config.getOption<bool> ("d3d9.enableDialogMode", false);
+ this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
+ this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
+ this->forceAspectRatio = config.getOption<std::string> ("d3d9.forceAspectRatio", "");
+ this->allowDoNotWait = config.getOption<bool> ("d3d9.allowDoNotWait", true);
+ this->allowDiscard = config.getOption<bool> ("d3d9.allowDiscard", true);
+ this->enumerateByDisplays = config.getOption<bool> ("d3d9.enumerateByDisplays", true);
+ this->longMad = config.getOption<bool> ("d3d9.longMad", false);
+ this->tearFree = config.getOption<Tristate> ("d3d9.tearFree", Tristate::Auto);
+ this->alphaTestWiggleRoom = config.getOption<bool> ("d3d9.alphaTestWiggleRoom", false);
+ this->apitraceMode = config.getOption<bool> ("d3d9.apitraceMode", false);
+ this->deviceLocalConstantBuffers = config.getOption<bool> ("d3d9.deviceLocalConstantBuffers", false);
+
+ // If we are not Nvidia, enable general hazards.
+ this->generalHazards = adapter != nullptr
+ && !adapter->matchesDriver(
+ DxvkGpuVendor::Nvidia,
+ VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR,
+ 0, 0);
+ applyTristate(this->generalHazards, config.getOption<Tristate>("d3d9.generalHazards", Tristate::Auto));
+
+ this->d3d9FloatEmulation = config::FloatEmulationByDefault; // <-- Future Extension?
+ applyTristate(this->d3d9FloatEmulation, config.getOption<Tristate>("d3d9.floatEmulation", Tristate::Auto));
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.h
new file mode 100644
index 00000000..e49bb61e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_options.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include "../util/config/config.h"
+#include "../dxvk/dxvk_device.h"
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ struct D3D9Options {
+
+ D3D9Options(const Rc<DxvkDevice>& device, const Config& config);
+
+ /// Override PCI vendor and device IDs reported to the
+ /// application. This may make apps think they are running
+ /// on a different GPU than they do and behave differently.
+ int32_t customVendorId;
+ int32_t customDeviceId;
+ std::string customDeviceDesc;
+
+ /// Present interval. Overrides the value
+ /// in D3DPRESENT_PARAMS used in swapchain present.
+ int32_t presentInterval;
+
+ /// Override maximum frame latency if the app specifies
+ /// a higher value. May help with frame timing issues.
+ int32_t maxFrameLatency;
+
+ /// Limit frame rate
+ int32_t maxFrameRate;
+
+ /// Set the max shader model the device can support in the caps.
+ int32_t shaderModel;
+
+ /// Whether or not managed resources should stay in memory until unlock, or until manually evicted.
+ bool evictManagedOnUnlock;
+
+ /// Whether or not to set the process as DPI aware in Windows when the API interface is created.
+ bool dpiAware;
+
+ /// True: Copy our constant set into UBO if we are relative indexing ever.
+ /// False: Copy our constant set into UBO if we are relative indexing at the start of a defined constant
+ /// Why?: In theory, FXC should never generate code where this would be an issue.
+ bool strictConstantCopies;
+
+ /// Whether or not we should care about pow(0, 0) = 1
+ bool strictPow;
+
+ /// Whether or not to do a fast path clear if we're close enough to the whole render target.
+ bool lenientClear;
+
+ /// Back buffer count for the Vulkan swap chain.
+ /// Overrides buffer count in present parameters.
+ int32_t numBackBuffers;
+
+ /// Don't create an explicit front buffer in our own swapchain. The Vulkan swapchain is unaffected.
+ /// Some games don't handle front/backbuffer flipping very well because they don't always redraw
+ /// each frame completely, and rely on old pixel data from the previous frame to still be there.
+ /// When this option is set and a game only requests one backbuffer, there will be no flipping in
+ /// our own swapchain, so the game will always draw to the same buffer and can rely on old pixel
+ /// data to still be there after a Present call.
+ /// This means that D3D9SwapChainEx::GetFrontBufferData returns data from the backbuffer of the
+ /// previous frame, which is the same as the current backbuffer if only 1 backbuffer was requested.
+ bool noExplicitFrontBuffer;
+
+ /// Defer surface creation
+ bool deferSurfaceCreation;
+
+ /// Whether to transition to general
+ /// for rendering hazards
+ bool generalHazards;
+
+ /// Anisotropic filter override
+ ///
+ /// Enforces anisotropic filtering with the
+ /// given anisotropy value for all samplers.
+ int32_t samplerAnisotropy;
+
+ /// Max available memory override
+ ///
+ /// Changes the max initial value used in
+ /// tracking and GetAvailableTextureMem
+ uint32_t maxAvailableMemory;
+
+ /// D3D9 Floating Point Emulation (anything * 0 = 0)
+ bool d3d9FloatEmulation;
+
+ /// Support the DF16 & DF24 texture format
+ bool supportDFFormats;
+
+ /// Support X4R4G4B4
+ bool supportX4R4G4B4;
+
+ /// Support D32
+ bool supportD32;
+
+ /// SWVP Constant Limits
+ int32_t swvpFloatCount;
+ int32_t swvpIntCount;
+ int32_t swvpBoolCount;
+
+ /// Disable D3DFMT_A8 for render targets.
+ /// Specifically to work around a game
+ /// bug in The Sims 2 that happens on native too!
+ bool disableA8RT;
+
+ /// Work around a NV driver quirk
+ /// Fixes flickering/z-fighting in some games.
+ bool invariantPosition;
+
+ /// Whether or not to respect memory tracking for
+ /// failing resource allocation.
+ bool memoryTrackTest;
+
+ /// Support VCACHE query
+ bool supportVCache;
+
+ /// Forced aspect ratio, disable other modes
+ std::string forceAspectRatio;
+
+ /// Enable dialog mode (ie. no exclusive fullscreen)
+ bool enableDialogMode;
+
+ /// Always use a spec constant to determine sampler type (instead of just in PS 1.x)
+ /// Works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
+ bool forceSamplerTypeSpecConstants;
+
+ /// Forces an MSAA level on the swapchain
+ int32_t forceSwapchainMSAA;
+
+ /// Allow D3DLOCK_DONOTWAIT
+ bool allowDoNotWait;
+
+ /// Allow D3DLOCK_DISCARD
+ bool allowDiscard;
+
+ /// Enumerate adapters by displays
+ bool enumerateByDisplays;
+
+ /// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
+ /// This solves some rendering bugs in games that have z-pass shaders which
+ /// don't match entirely to the regular vertex shader in this way.
+ bool longMad;
+
+ /// Tear-free mode if vsync is disabled
+ /// Tearing mode if vsync is enabled
+ Tristate tearFree;
+
+ /// Workaround for games using alpha test == 1.0, etc due to wonky interpolation or
+ /// misc. imprecision on some vendors
+ bool alphaTestWiggleRoom;
+
+ /// Apitrace mode: Maps all buffers in cached memory.
+ bool apitraceMode;
+
+ /// Use device local memory for constant buffers.
+ bool deviceLocalConstantBuffers;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.cpp
new file mode 100644
index 00000000..7ce47cf9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.cpp
@@ -0,0 +1,338 @@
+#include "d3d9_query.h"
+
+#include "d3d9_device.h"
+
+namespace dxvk {
+
+ D3D9Query::D3D9Query(
+ D3D9DeviceEx* pDevice,
+ D3DQUERYTYPE QueryType)
+ : D3D9DeviceChild<IDirect3DQuery9>(pDevice)
+ , m_queryType (QueryType)
+ , m_state (D3D9_VK_QUERY_INITIAL) {
+ Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice();
+
+ switch (m_queryType) {
+ case D3DQUERYTYPE_VCACHE:
+ break;
+
+ case D3DQUERYTYPE_EVENT:
+ m_event[0] = dxvkDevice->createGpuEvent();
+ break;
+
+ case D3DQUERYTYPE_OCCLUSION:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_OCCLUSION,
+ VK_QUERY_CONTROL_PRECISE_BIT, 0);
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMP:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TIMESTAMP, 0, 0);
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+ for (uint32_t i = 0; i < 2; i++) {
+ m_query[i] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_TIMESTAMP, 0, 0);
+ }
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMPFREQ:
+ break;
+
+ case D3DQUERYTYPE_VERTEXSTATS:
+ m_query[0] = dxvkDevice->createGpuQuery(
+ VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
+ break;
+
+ default:
+ throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Query::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DQuery9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Query::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DQUERYTYPE STDMETHODCALLTYPE D3D9Query::GetType() {
+ return m_queryType;
+ }
+
+
+ DWORD STDMETHODCALLTYPE D3D9Query::GetDataSize() {
+ switch (m_queryType) {
+ case D3DQUERYTYPE_VCACHE: return sizeof(D3DDEVINFO_VCACHE);
+ case D3DQUERYTYPE_RESOURCEMANAGER: return sizeof(D3DDEVINFO_RESOURCEMANAGER);
+ case D3DQUERYTYPE_VERTEXSTATS: return sizeof(D3DDEVINFO_D3DVERTEXSTATS);
+ case D3DQUERYTYPE_EVENT: return sizeof(BOOL);
+ case D3DQUERYTYPE_OCCLUSION: return sizeof(DWORD);
+ case D3DQUERYTYPE_TIMESTAMP: return sizeof(UINT64);
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT: return sizeof(BOOL);
+ case D3DQUERYTYPE_TIMESTAMPFREQ: return sizeof(UINT64);
+ case D3DQUERYTYPE_PIPELINETIMINGS: return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
+ case D3DQUERYTYPE_INTERFACETIMINGS: return sizeof(D3DDEVINFO_D3D9INTERFACETIMINGS);
+ case D3DQUERYTYPE_VERTEXTIMINGS: return sizeof(D3DDEVINFO_D3D9STAGETIMINGS);
+ case D3DQUERYTYPE_PIXELTIMINGS: return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
+ case D3DQUERYTYPE_BANDWIDTHTIMINGS: return sizeof(D3DDEVINFO_D3D9BANDWIDTHTIMINGS);
+ case D3DQUERYTYPE_CACHEUTILIZATION: return sizeof(D3DDEVINFO_D3D9CACHEUTILIZATION);
+ default: return 0;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Query::Issue(DWORD dwIssueFlags) {
+ // Note: No need to submit to CS if we don't do anything!
+
+ if (dwIssueFlags == D3DISSUE_BEGIN) {
+ if (QueryBeginnable(m_queryType)) {
+ if (m_state == D3D9_VK_QUERY_BEGUN && QueryEndable(m_queryType))
+ m_parent->End(this);
+
+ m_parent->Begin(this);
+
+ m_state = D3D9_VK_QUERY_BEGUN;
+ }
+ }
+ else {
+ if (QueryEndable(m_queryType)) {
+ if (m_state != D3D9_VK_QUERY_BEGUN && QueryBeginnable(m_queryType))
+ m_parent->Begin(this);
+
+ m_resetCtr.fetch_add(1, std::memory_order_acquire);
+
+ m_parent->End(this);
+
+ }
+ m_state = D3D9_VK_QUERY_ENDED;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Query::GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
+ if (m_state == D3D9_VK_QUERY_CACHED) {
+ // Query data was already retrieved once.
+ // Use cached query data to prevent having to check the VK event
+ // and having to iterate over the VK queries again
+ if (likely(pData && dwSize)) {
+ if (m_queryType != D3DQUERYTYPE_EVENT) {
+ memcpy(pData, &m_dataCache, dwSize);
+ } else {
+ *static_cast<bool*>(pData) = true;
+ }
+ }
+ return D3D_OK;
+ }
+
+ HRESULT hr = this->GetQueryData(pData, dwSize);
+
+ bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;
+
+ // If we get S_FALSE and it's not from the fact
+ // they didn't call end, do some flushy stuff...
+ if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
+ this->NotifyStall();
+ m_parent->FlushImplicit(FALSE);
+ }
+
+ return hr;
+ }
+
+
+ HRESULT D3D9Query::GetQueryData(void* pData, DWORD dwSize) {
+ // Let the game know that calling end might be a good idea...
+ if (m_state == D3D9_VK_QUERY_BEGUN)
+ return S_FALSE;
+
+ if (unlikely(!pData && dwSize))
+ return D3DERR_INVALIDCALL;
+
+ // The game forgot to even issue the query!
+ // Let's do it for them...
+ // This will issue both the begin, and the end.
+ if (m_state == D3D9_VK_QUERY_INITIAL)
+ this->Issue(D3DISSUE_END);
+
+ if (m_resetCtr != 0u)
+ return S_FALSE;
+
+ if (m_queryType == D3DQUERYTYPE_EVENT) {
+ DxvkGpuEventStatus status = m_event[0]->test();
+
+ if (status == DxvkGpuEventStatus::Invalid)
+ return D3DERR_INVALIDCALL;
+
+ bool signaled = status == DxvkGpuEventStatus::Signaled;
+
+ if (pData != nullptr)
+ *static_cast<BOOL*>(pData) = signaled;
+
+ if (signaled) {
+ m_state = D3D9_VK_QUERY_CACHED;
+ return D3D_OK;
+ } else {
+ return S_FALSE;
+ }
+ }
+ else {
+ std::array<DxvkQueryData, MaxGpuQueries> queryData = { };
+
+ for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) {
+ DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]);
+
+ if (status == DxvkGpuQueryStatus::Invalid
+ || status == DxvkGpuQueryStatus::Failed)
+ return D3DERR_INVALIDCALL;
+
+ if (status == DxvkGpuQueryStatus::Pending)
+ return S_FALSE;
+ }
+
+ if (pData == nullptr)
+ return D3D_OK;
+
+
+ switch (m_queryType) {
+ case D3DQUERYTYPE_VCACHE:
+ // Don't know what the hell any of this means.
+ // Nor do I care. This just makes games work.
+ m_dataCache.VCache.Pattern = MAKEFOURCC('H', 'C', 'A', 'C');
+ m_dataCache.VCache.OptMethod = 1;
+ m_dataCache.VCache.CacheSize = 24;
+ m_dataCache.VCache.MagicNumber = 20;
+ break;
+
+ case D3DQUERYTYPE_OCCLUSION:
+ m_dataCache.Occlusion = DWORD(queryData[0].occlusion.samplesPassed);
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMP:
+ m_dataCache.Timestamp = queryData[0].timestamp.time;
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+ m_dataCache.TimestampDisjoint = queryData[0].timestamp.time < queryData[1].timestamp.time;
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMPFREQ:
+ m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
+ break;
+
+ case D3DQUERYTYPE_VERTEXSTATS:
+ m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
+ m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
+ break;
+
+ default:
+ break;
+ }
+
+ if (likely(pData && dwSize))
+ memcpy(pData, &m_dataCache, dwSize);
+
+ m_state = D3D9_VK_QUERY_CACHED;
+ return D3D_OK;
+ }
+ }
+
+
+ UINT64 D3D9Query::GetTimestampQueryFrequency() const {
+ Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
+ Rc<DxvkAdapter> adapter = device->adapter();
+
+ VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits;
+ return uint64_t(1'000'000'000.0f / limits.timestampPeriod);
+ }
+
+
+ void D3D9Query::Begin(DxvkContext* ctx) {
+ switch (m_queryType) {
+ case D3DQUERYTYPE_OCCLUSION:
+ case D3DQUERYTYPE_VERTEXSTATS:
+ ctx->beginQuery(m_query[0]);
+ break;
+
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+ ctx->writeTimestamp(m_query[1]);
+ break;
+
+ default: break;
+ }
+ }
+
+
+ void D3D9Query::End(DxvkContext* ctx) {
+ switch (m_queryType) {
+ case D3DQUERYTYPE_TIMESTAMP:
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+ ctx->writeTimestamp(m_query[0]);
+ break;
+
+ case D3DQUERYTYPE_VERTEXSTATS:
+ case D3DQUERYTYPE_OCCLUSION:
+ ctx->endQuery(m_query[0]);
+ break;
+
+ case D3DQUERYTYPE_EVENT:
+ ctx->signalGpuEvent(m_event[0]);
+ break;
+
+ default: break;
+ }
+
+ m_resetCtr.fetch_sub(1, std::memory_order_release);
+ }
+
+
+ bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
+ return QueryType == D3DQUERYTYPE_OCCLUSION
+ || QueryType == D3DQUERYTYPE_VERTEXSTATS
+ || QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
+ }
+
+
+ bool D3D9Query::QueryEndable(D3DQUERYTYPE QueryType) {
+ return QueryBeginnable(QueryType)
+ || QueryType == D3DQUERYTYPE_TIMESTAMP
+ || QueryType == D3DQUERYTYPE_EVENT;
+ }
+
+
+ HRESULT D3D9Query::QuerySupported(D3D9DeviceEx* pDevice, D3DQUERYTYPE QueryType) {
+ switch (QueryType) {
+ case D3DQUERYTYPE_VCACHE:
+ if (!pDevice->GetOptions()->supportVCache)
+ return D3DERR_NOTAVAILABLE;
+
+ return D3D_OK;
+ case D3DQUERYTYPE_EVENT:
+ case D3DQUERYTYPE_OCCLUSION:
+ case D3DQUERYTYPE_TIMESTAMP:
+ case D3DQUERYTYPE_TIMESTAMPDISJOINT:
+ case D3DQUERYTYPE_TIMESTAMPFREQ:
+ case D3DQUERYTYPE_VERTEXSTATS:
+ return D3D_OK;
+
+ default:
+ return D3DERR_NOTAVAILABLE;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.h
new file mode 100644
index 00000000..8d742c96
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_query.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "d3d9_device_child.h"
+
+#include "../dxvk/dxvk_context.h"
+
+namespace dxvk {
+
+ enum D3D9_VK_QUERY_STATE : uint32_t {
+ D3D9_VK_QUERY_INITIAL,
+ D3D9_VK_QUERY_BEGUN,
+ D3D9_VK_QUERY_ENDED,
+ D3D9_VK_QUERY_CACHED
+ };
+
+ union D3D9_QUERY_DATA {
+ D3DDEVINFO_VCACHE VCache;
+ DWORD Occlusion;
+ UINT64 Timestamp;
+ BOOL TimestampDisjoint;
+ UINT64 TimestampFreq;
+ D3DDEVINFO_D3DVERTEXSTATS VertexStats;
+ };
+
+ class D3D9Query : public D3D9DeviceChild<IDirect3DQuery9> {
+ constexpr static uint32_t MaxGpuQueries = 2;
+ constexpr static uint32_t MaxGpuEvents = 1;
+ public:
+
+ D3D9Query(
+ D3D9DeviceEx* pDevice,
+ D3DQUERYTYPE QueryType);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ D3DQUERYTYPE STDMETHODCALLTYPE GetType() final;
+
+ DWORD STDMETHODCALLTYPE GetDataSize() final;
+
+ HRESULT STDMETHODCALLTYPE Issue(DWORD dwIssueFlags) final;
+
+ HRESULT STDMETHODCALLTYPE GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) final;
+
+ HRESULT GetQueryData(void* pData, DWORD dwSize);
+
+ void Begin(DxvkContext* ctx);
+ void End(DxvkContext* ctx);
+
+ static bool QueryBeginnable(D3DQUERYTYPE QueryType);
+ static bool QueryEndable(D3DQUERYTYPE QueryType);
+
+ static HRESULT QuerySupported(D3D9DeviceEx* pDevice, D3DQUERYTYPE QueryType);
+
+ bool IsEvent() const {
+ return m_queryType == D3DQUERYTYPE_EVENT;
+ }
+
+ bool IsStalling() const {
+ return m_stallFlag;
+ }
+
+ void NotifyEnd() {
+ m_stallMask <<= 1;
+ }
+
+ void NotifyStall() {
+ m_stallMask |= 1;
+ m_stallFlag |= bit::popcnt(m_stallMask) >= 16;
+ }
+
+ private:
+
+ D3DQUERYTYPE m_queryType;
+
+ D3D9_VK_QUERY_STATE m_state;
+
+ std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
+ std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
+
+ uint32_t m_stallMask = 0;
+ bool m_stallFlag = false;
+
+ std::atomic<uint32_t> m_resetCtr = { 0u };
+
+ D3D9_QUERY_DATA m_dataCache;
+
+ UINT64 GetTimestampQueryFrequency() const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_resource.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_resource.h
new file mode 100644
index 00000000..5d343e20
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_resource.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include "d3d9_device_child.h"
+
+#include "../util/com/com_private_data.h"
+
+namespace dxvk {
+
+ template <typename... Type>
+ class D3D9Resource : public D3D9DeviceChild<Type...> {
+
+ public:
+
+ D3D9Resource(D3D9DeviceEx* pDevice)
+ : D3D9DeviceChild<Type...>(pDevice)
+ , m_priority ( 0 ) { }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID refguid,
+ const void* pData,
+ DWORD SizeOfData,
+ DWORD Flags) final {
+ HRESULT hr;
+ if (Flags & D3DSPD_IUNKNOWN) {
+ IUnknown* unknown =
+ const_cast<IUnknown*>(
+ reinterpret_cast<const IUnknown*>(pData));
+ hr = m_privateData.setInterface(
+ refguid, unknown);
+ }
+ else
+ hr = m_privateData.setData(
+ refguid, SizeOfData, pData);
+
+ if (FAILED(hr))
+ return D3DERR_INVALIDCALL;
+
+ return D3D_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID refguid,
+ void* pData,
+ DWORD* pSizeOfData) final {
+ HRESULT hr = m_privateData.getData(
+ refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
+
+ if (FAILED(hr))
+ return D3DERR_INVALIDCALL;
+
+ return D3D_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
+ HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
+
+ if (FAILED(hr))
+ return D3DERR_INVALIDCALL;
+
+ return D3D_OK;
+ }
+
+ DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
+ DWORD oldPriority = m_priority;
+ m_priority = PriorityNew;
+ return oldPriority;
+ }
+
+ DWORD STDMETHODCALLTYPE GetPriority() {
+ return m_priority;
+ }
+
+
+ protected:
+
+ DWORD m_priority;
+
+ private:
+
+ ComPrivateData m_privateData;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.cpp
new file mode 100644
index 00000000..6a68f220
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.cpp
@@ -0,0 +1,44 @@
+#include "d3d9_sampler.h"
+
+namespace dxvk {
+
+ size_t D3D9SamplerKeyHash::operator () (const D3D9SamplerKey& key) const {
+ DxvkHashState state;
+
+ std::hash<DWORD> dhash;
+ std::hash<D3DTEXTUREADDRESS> tahash;
+ std::hash<D3DTEXTUREFILTERTYPE> tfhash;
+ std::hash<float> fhash;
+ std::hash<bool> bhash;
+
+ state.add(tahash(key.AddressU));
+ state.add(tahash(key.AddressV));
+ state.add(tahash(key.AddressW));
+ state.add(tfhash(key.MagFilter));
+ state.add(tfhash(key.MinFilter));
+ state.add(tfhash(key.MipFilter));
+ state.add(dhash (key.MaxAnisotropy));
+ state.add(fhash (key.MipmapLodBias));
+ state.add(dhash (key.MaxMipLevel));
+ state.add(dhash (key.BorderColor));
+ state.add(bhash (key.Depth));
+
+ return state;
+ }
+
+
+ bool D3D9SamplerKeyEq::operator () (const D3D9SamplerKey& a, const D3D9SamplerKey& b) const {
+ return a.AddressU == b.AddressU
+ && a.AddressV == b.AddressV
+ && a.AddressW == b.AddressW
+ && a.MagFilter == b.MagFilter
+ && a.MinFilter == b.MinFilter
+ && a.MipFilter == b.MipFilter
+ && a.MaxAnisotropy == b.MaxAnisotropy
+ && a.MipmapLodBias == b.MipmapLodBias
+ && a.MaxMipLevel == b.MaxMipLevel
+ && a.BorderColor == b.BorderColor
+ && a.Depth == b.Depth;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.h
new file mode 100644
index 00000000..44471094
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_sampler.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+#include "d3d9_util.h"
+
+#include "../dxvk/dxvk_hash.h"
+
+#include "../util/util_math.h"
+
+namespace dxvk {
+
+ struct D3D9SamplerKey {
+ D3DTEXTUREADDRESS AddressU;
+ D3DTEXTUREADDRESS AddressV;
+ D3DTEXTUREADDRESS AddressW;
+ D3DTEXTUREFILTERTYPE MagFilter;
+ D3DTEXTUREFILTERTYPE MinFilter;
+ D3DTEXTUREFILTERTYPE MipFilter;
+ DWORD MaxAnisotropy;
+ float MipmapLodBias;
+ DWORD MaxMipLevel;
+ D3DCOLOR BorderColor;
+ bool Depth;
+ };
+
+ struct D3D9SamplerKeyHash {
+ size_t operator () (const D3D9SamplerKey& key) const;
+ };
+
+ struct D3D9SamplerKeyEq {
+ bool operator () (const D3D9SamplerKey& a, const D3D9SamplerKey& b) const;
+ };
+
+ inline void NormalizeSamplerKey(D3D9SamplerKey& key) {
+ key.AddressU = std::clamp(key.AddressU, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
+ key.AddressV = std::clamp(key.AddressV, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
+ key.AddressW = std::clamp(key.AddressW, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
+
+ bool hasAnisotropy = IsAnisotropic(key.MagFilter) || IsAnisotropic(key.MinFilter);
+
+ key.MagFilter = std::clamp(key.MagFilter, D3DTEXF_NONE, D3DTEXF_LINEAR);
+ key.MinFilter = std::clamp(key.MinFilter, D3DTEXF_NONE, D3DTEXF_LINEAR);
+ key.MipFilter = std::clamp(key.MipFilter, D3DTEXF_NONE, D3DTEXF_LINEAR);
+
+ key.MaxAnisotropy = hasAnisotropy
+ ? std::clamp<DWORD>(key.MaxAnisotropy, 1, 16)
+ : 1;
+
+ if (key.MipFilter == D3DTEXF_NONE) {
+ // May as well try and keep slots down.
+ key.MipmapLodBias = 0;
+ }
+ else {
+ // Games also pass NAN here, this accounts for that.
+ if (unlikely(key.MipmapLodBias != key.MipmapLodBias))
+ key.MipmapLodBias = 0.0f;
+
+ // Clamp between -15.0f and 15.0f, matching mip limits of d3d9.
+ key.MipmapLodBias = std::clamp(key.MipmapLodBias, -15.0f, 15.0f);
+
+ // Round to the nearest .5
+ // Fixes sampler leaks in UE3 games w/ mip streaming
+ // eg. Borderlands 2
+ key.MipmapLodBias = std::round(key.MipmapLodBias * 2.0f) / 2.0f;
+ }
+
+ if (key.AddressU != D3DTADDRESS_BORDER
+ && key.AddressV != D3DTADDRESS_BORDER
+ && key.AddressW != D3DTADDRESS_BORDER) {
+ key.BorderColor = 0;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp
new file mode 100644
index 00000000..8c717db0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp
@@ -0,0 +1,192 @@
+#include "d3d9_shader.h"
+
+#include "d3d9_device.h"
+#include "d3d9_util.h"
+
+namespace dxvk {
+
+#ifndef DXVK_NATIVE
+ typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) (
+ const void* pShader,
+ BOOL EnableColorCode,
+ char* pComments,
+ ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start.
+
+ D3DXDisassembleShader g_pfnDisassembleShader = nullptr;
+
+ HRESULT DisassembleShader(
+ const void* pShader,
+ BOOL EnableColorCode,
+ char* pComments,
+ ID3DBlob** ppDisassembly) {
+ if (g_pfnDisassembleShader == nullptr) {
+ HMODULE d3d9x = LoadLibraryA("d3dx9.dll");
+
+ if (d3d9x == nullptr)
+ d3d9x = LoadLibraryA("d3dx9_43.dll");
+
+ g_pfnDisassembleShader =
+ reinterpret_cast<D3DXDisassembleShader>(GetProcAddress(d3d9x, "D3DXDisassembleShader"));
+ }
+
+ if (g_pfnDisassembleShader == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ return g_pfnDisassembleShader(
+ pShader,
+ EnableColorCode,
+ pComments,
+ ppDisassembly);
+ }
+#endif
+
+
+ D3D9CommonShader::D3D9CommonShader() {}
+
+ D3D9CommonShader::D3D9CommonShader(
+ D3D9DeviceEx* pDevice,
+ VkShaderStageFlagBits ShaderStage,
+ const DxvkShaderKey& Key,
+ const DxsoModuleInfo* pDxsoModuleInfo,
+ const void* pShaderBytecode,
+ const DxsoAnalysisInfo& AnalysisInfo,
+ DxsoModule* pModule) {
+ const uint32_t bytecodeLength = AnalysisInfo.bytecodeByteLength;
+ m_bytecode.resize(bytecodeLength);
+ std::memcpy(m_bytecode.data(), pShaderBytecode, bytecodeLength);
+
+ const std::string name = Key.toString();
+ Logger::debug(str::format("Compiling shader ", name));
+
+ const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
+#ifndef DXVK_NATIVE
+ // If requested by the user, dump both the raw DXBC
+ // shader and the compiled SPIR-V module to a file.
+ if (dumpPath.size() != 0) {
+ DxsoReader reader(
+ reinterpret_cast<const char*>(pShaderBytecode));
+
+ reader.store(std::ofstream(str::tows(str::format(dumpPath, "/", name, ".dxso").c_str()).c_str(),
+ std::ios_base::binary | std::ios_base::trunc), bytecodeLength);
+
+ char comment[2048];
+ Com<ID3DBlob> blob;
+ HRESULT hr = DisassembleShader(
+ pShaderBytecode,
+ TRUE,
+ comment,
+ &blob);
+
+ if (SUCCEEDED(hr)) {
+ std::ofstream disassembledOut(str::tows(str::format(dumpPath, "/", name, ".dxso.dis").c_str()).c_str(), std::ios_base::binary | std::ios_base::trunc);
+ disassembledOut.write(
+ reinterpret_cast<const char*>(blob->GetBufferPointer()),
+ blob->GetBufferSize());
+ }
+ }
+#endif
+
+ // Decide whether we need to create a pass-through
+ // geometry shader for vertex shader stream output
+
+ const D3D9ConstantLayout& constantLayout = ShaderStage == VK_SHADER_STAGE_VERTEX_BIT
+ ? pDevice->GetVertexConstantLayout()
+ : pDevice->GetPixelConstantLayout();
+ m_shaders = pModule->compile(*pDxsoModuleInfo, name, AnalysisInfo, constantLayout);
+ m_isgn = pModule->isgn();
+ m_usedSamplers = pModule->usedSamplers();
+
+ // Shift up these sampler bits so we can just
+ // do an or per-draw in the device.
+ // We shift by 17 because 16 ps samplers + 1 dmap (tess)
+ if (ShaderStage == VK_SHADER_STAGE_VERTEX_BIT)
+ m_usedSamplers <<= 17;
+
+ m_usedRTs = pModule->usedRTs();
+
+ m_info = pModule->info();
+ m_meta = pModule->meta();
+ m_constants = pModule->constants();
+
+ m_shaders[0]->setShaderKey(Key);
+
+ if (m_shaders[1] != nullptr) {
+ // Lets lie about the shader key type for the state cache.
+ m_shaders[1]->setShaderKey({ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, Key.sha1() });
+ }
+
+ if (dumpPath.size() != 0) {
+#ifdef _WIN32
+ std::ofstream dumpStream(
+ str::tows(str::format(dumpPath, "/", name, ".spv").c_str()).c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#else
+ std::ofstream dumpStream(
+ str::format(dumpPath, "/", name, ".spv").c_str(),
+ std::ios_base::binary | std::ios_base::trunc);
+#endif
+
+ m_shaders[0]->dump(dumpStream);
+ }
+
+ pDevice->GetDXVKDevice()->registerShader(m_shaders[0]);
+
+ if (m_shaders[1] != nullptr)
+ pDevice->GetDXVKDevice()->registerShader(m_shaders[1]);
+ }
+
+
+ void D3D9ShaderModuleSet::GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonShader* pShaderModule,
+ VkShaderStageFlagBits ShaderStage,
+ const DxsoModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode) {
+ DxsoReader reader(
+ reinterpret_cast<const char*>(pShaderBytecode));
+
+ DxsoModule module(reader);
+
+ if (module.info().majorVersion() > pDxbcModuleInfo->options.shaderModel)
+ throw DxvkError("GetShaderModule: Out of range of supported shader model");
+
+ if (module.info().shaderStage() != ShaderStage)
+ throw DxvkError("GetShaderModule: Bytecode does not match shader stage");
+
+ DxsoAnalysisInfo info = module.analyze();
+
+ DxvkShaderKey lookupKey = DxvkShaderKey(
+ ShaderStage,
+ Sha1Hash::compute(pShaderBytecode, info.bytecodeByteLength));
+
+ // Use the shader's unique key for the lookup
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto entry = m_modules.find(lookupKey);
+ if (entry != m_modules.end()) {
+ *pShaderModule = entry->second;
+ return;
+ }
+ }
+
+ // This shader has not been compiled yet, so we have to create a
+ // new module. This takes a while, so we won't lock the structure.
+ *pShaderModule = D3D9CommonShader(
+ pDevice, ShaderStage, lookupKey,
+ pDxbcModuleInfo, pShaderBytecode,
+ info, &module);
+
+ // Insert the new module into the lookup table. If another thread
+ // has compiled the same shader in the meantime, we should return
+ // that object instead and discard the newly created module.
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto status = m_modules.insert({ lookupKey, *pShaderModule });
+ if (!status.second) {
+ *pShaderModule = status.first->second;
+ return;
+ }
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.h
new file mode 100644
index 00000000..9bfc3100
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.h
@@ -0,0 +1,196 @@
+#pragma once
+
+#include "d3d9_resource.h"
+#include "../dxso/dxso_module.h"
+#include "d3d9_shader_permutations.h"
+#include "d3d9_util.h"
+
+#include <array>
+
+namespace dxvk {
+
+
+ /**
+ * \brief Common shader object
+ *
+ * Stores the compiled SPIR-V shader and the SHA-1
+ * hash of the original DXBC shader, which can be
+ * used to identify the shader.
+ */
+ class D3D9CommonShader {
+
+ public:
+
+ D3D9CommonShader();
+
+ D3D9CommonShader(
+ D3D9DeviceEx* pDevice,
+ VkShaderStageFlagBits ShaderStage,
+ const DxvkShaderKey& Key,
+ const DxsoModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode,
+ const DxsoAnalysisInfo& AnalysisInfo,
+ DxsoModule* pModule);
+
+
+ Rc<DxvkShader> GetShader(D3D9ShaderPermutation Permutation) const {
+ return m_shaders[Permutation];
+ }
+
+ std::string GetName() const {
+ return m_shaders[D3D9ShaderPermutations::None]->debugName();
+ }
+
+ const std::vector<uint8_t>& GetBytecode() const {
+ return m_bytecode;
+ }
+
+ const DxsoIsgn& GetIsgn() const {
+ return m_isgn;
+ }
+
+ const DxsoShaderMetaInfo& GetMeta() const { return m_meta; }
+ const DxsoDefinedConstants& GetConstants() const { return m_constants; }
+
+ D3D9ShaderMasks GetShaderMask() const { return D3D9ShaderMasks{ m_usedSamplers, m_usedRTs }; }
+
+ const DxsoProgramInfo& GetInfo() const { return m_info; }
+
+ private:
+
+ DxsoIsgn m_isgn;
+ uint32_t m_usedSamplers;
+ uint32_t m_usedRTs;
+
+ DxsoProgramInfo m_info;
+ DxsoShaderMetaInfo m_meta;
+ DxsoDefinedConstants m_constants;
+
+ DxsoPermutations m_shaders;
+
+ std::vector<uint8_t> m_bytecode;
+
+ };
+
+ /**
+ * \brief Common shader interface
+ *
+ * Implements methods for all D3D11*Shader
+ * interfaces and stores the actual shader
+ * module object.
+ */
+ template <typename Base>
+ class D3D9Shader : public D3D9DeviceChild<Base> {
+
+ public:
+
+ D3D9Shader(
+ D3D9DeviceEx* pDevice,
+ const D3D9CommonShader& CommonShader)
+ : D3D9DeviceChild<Base>( pDevice )
+ , m_shader ( CommonShader ) { }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(Base)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Shader::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetFunction(void* pOut, UINT* pSizeOfData) {
+ if (pSizeOfData == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ const auto& bytecode = m_shader.GetBytecode();
+
+ if (pOut == nullptr) {
+ *pSizeOfData = bytecode.size();
+ return D3D_OK;
+ }
+
+ size_t copyAmount = std::min(size_t(*pSizeOfData), bytecode.size());
+ std::memcpy(pOut, bytecode.data(), copyAmount);
+
+ return D3D_OK;
+ }
+
+ const D3D9CommonShader* GetCommonShader() const {
+ return &m_shader;
+ }
+
+ private:
+
+ D3D9CommonShader m_shader;
+
+ };
+
+ // Needs their own classes and not usings for forward decl.
+
+ class D3D9VertexShader final : public D3D9Shader<IDirect3DVertexShader9> {
+
+ public:
+
+ D3D9VertexShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9CommonShader& CommonShader)
+ : D3D9Shader<IDirect3DVertexShader9>( pDevice, CommonShader ) { }
+
+ };
+
+ class D3D9PixelShader final : public D3D9Shader<IDirect3DPixelShader9> {
+
+ public:
+
+ D3D9PixelShader(
+ D3D9DeviceEx* pDevice,
+ const D3D9CommonShader& CommonShader)
+ : D3D9Shader<IDirect3DPixelShader9>( pDevice, CommonShader ) { }
+
+ };
+
+ /**
+ * \brief Shader module set
+ *
+ * Some applications may compile the same shader multiple
+ * times, so we should cache the resulting shader modules
+ * and reuse them rather than creating new ones. This
+ * class is thread-safe.
+ */
+ class D3D9ShaderModuleSet : public RcObject {
+
+ public:
+
+ void GetShaderModule(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonShader* pShaderModule,
+ VkShaderStageFlagBits ShaderStage,
+ const DxsoModuleInfo* pDxbcModuleInfo,
+ const void* pShaderBytecode);
+
+ private:
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkShaderKey,
+ D3D9CommonShader,
+ DxvkHash, DxvkEq> m_modules;
+
+ };
+
+ template<typename T>
+ const D3D9CommonShader* GetCommonShader(const T& pShader) {
+ return pShader != nullptr ? pShader->GetCommonShader() : nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_permutations.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_permutations.h
new file mode 100644
index 00000000..cf2301d2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_permutations.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ class DxvkShader;
+
+ namespace D3D9ShaderPermutations {
+ enum D3D9ShaderPermutation {
+ None,
+ FlatShade,
+ Count
+ };
+ }
+ using D3D9ShaderPermutation = D3D9ShaderPermutations::D3D9ShaderPermutation;
+
+ using DxsoPermutations = std::array<Rc<DxvkShader>, D3D9ShaderPermutations::Count>;
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_validator.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_validator.h
new file mode 100644
index 00000000..8e433027
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader_validator.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+namespace dxvk {
+
+ class IDirect3DShaderValidator9 : public IUnknown {
+
+ public:
+
+ virtual HRESULT STDMETHODCALLTYPE Begin(
+ void* pCallback,
+ void* pUserParam,
+ DWORD Unknown) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Instruction(
+ const char* pUnknown1,
+ UINT Unknown2,
+ const DWORD* pInstruction,
+ DWORD InstructionLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE End() = 0;
+
+ };
+
+ class D3D9ShaderValidator final : public ComObjectClamp<IDirect3DShaderValidator9> {
+
+ public:
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE Begin(
+ void* pCallback,
+ void* pUserParam,
+ DWORD Unknown) {
+ Logger::debug("D3D9ShaderValidator::Begin: Stub");
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE Instruction(
+ const char* pUnknown1,
+ UINT Unknown2,
+ const DWORD* pInstruction,
+ DWORD InstructionLength) {
+ Logger::debug("D3D9ShaderValidator::Instruction: Stub");
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE End() {
+ Logger::debug("D3D9ShaderValidator::End: Stub");
+
+ return D3D_OK;
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_spec_constants.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_spec_constants.h
new file mode 100644
index 00000000..7a8a33d5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_spec_constants.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <cstdint>
+
+namespace dxvk {
+
+ enum D3D9SpecConstantId : uint32_t {
+ AlphaCompareOp = 0,
+ SamplerType = 1,
+ FogEnabled = 2,
+ VertexFogMode = 3,
+ PixelFogMode = 4,
+
+ PointMode = 5,
+ ProjectionType = 6,
+
+ VertexShaderBools = 7,
+ PixelShaderBools = 8,
+ Fetch4 = 9,
+
+ SamplerDepthMode = 10,
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.cpp
new file mode 100644
index 00000000..c0ee06ec
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.cpp
@@ -0,0 +1,26 @@
+#include "d3d9_state.h"
+
+#include "d3d9_texture.h"
+
+namespace dxvk {
+
+ D3D9CapturableState::D3D9CapturableState() {
+ for (uint32_t i = 0; i < textures.size(); i++)
+ textures[i] = nullptr;
+
+ for (uint32_t i = 0; i < clipPlanes.size(); i++)
+ clipPlanes[i] = D3D9ClipPlane();
+
+ for (uint32_t i = 0; i < streamFreq.size(); i++)
+ streamFreq[i] = 1;
+
+ for (uint32_t i = 0; i < enabledLightIndices.size(); i++)
+ enabledLightIndices[i] = UINT32_MAX;
+ }
+
+ D3D9CapturableState::~D3D9CapturableState() {
+ for (uint32_t i = 0; i < textures.size(); i++)
+ TextureChangePrivate(textures[i], nullptr);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.h
new file mode 100644
index 00000000..e895f5db
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_state.h
@@ -0,0 +1,300 @@
+#pragma once
+
+#include "d3d9_caps.h"
+#include "d3d9_constant_set.h"
+#include "../dxso/dxso_common.h"
+#include "../util/util_matrix.h"
+
+#include "d3d9_surface.h"
+#include "d3d9_shader.h"
+#include "d3d9_vertex_declaration.h"
+#include "d3d9_buffer.h"
+
+#include <array>
+#include <bitset>
+#include <optional>
+
+namespace dxvk {
+
+ static constexpr uint32_t RenderStateCount = 256;
+ static constexpr uint32_t SamplerStateCount = D3DSAMP_DMAPOFFSET + 1;
+ static constexpr uint32_t SamplerCount = 21;
+ static constexpr uint32_t TextureStageStateCount = DXVK_TSS_COUNT;
+
+ namespace hacks::PointSize {
+ static constexpr DWORD AlphaToCoverageDisabled = MAKEFOURCC('A', '2', 'M', '0');
+ static constexpr DWORD AlphaToCoverageEnabled = MAKEFOURCC('A', '2', 'M', '1');
+ }
+
+ struct D3D9ClipPlane {
+ float coeff[4];
+ };
+
+ struct D3D9RenderStateInfo {
+ std::array<float, 3> fogColor = { };
+ float fogScale = 0.0f;
+ float fogEnd = 1.0f;
+ float fogDensity = 1.0f;
+
+ float alphaRef = 0.0f;
+
+ float pointSize = 1.0f;
+ float pointSizeMin = 1.0f;
+ float pointSizeMax = 64.0f;
+ float pointScaleA = 1.0f;
+ float pointScaleB = 0.0f;
+ float pointScaleC = 0.0f;
+ };
+
+ enum class D3D9RenderStateItem {
+ FogColor = 0,
+ FogScale = 1,
+ FogEnd,
+ FogDensity,
+ AlphaRef,
+
+ PointSize,
+ PointSizeMin,
+ PointSizeMax,
+ PointScaleA,
+ PointScaleB,
+ PointScaleC,
+
+ Count
+ };
+
+
+ // This is needed in fixed function for POSITION_T support.
+ // These are constants we need to * and add to move
+ // Window Coords -> Real Coords w/ respect to the viewport.
+ struct D3D9ViewportInfo {
+ Vector4 inverseOffset;
+ Vector4 inverseExtent;
+ };
+
+ struct D3D9Light {
+ D3D9Light(const D3DLIGHT9& light, Matrix4 viewMtx) {
+ Diffuse = Vector4(light.Diffuse.r, light.Diffuse.g, light.Diffuse.b, light.Diffuse.a);
+ Specular = Vector4(light.Specular.r, light.Specular.g, light.Specular.b, light.Specular.a);
+ Ambient = Vector4(light.Ambient.r, light.Ambient.g, light.Ambient.b, light.Ambient.a);
+
+ Position = viewMtx * Vector4(light.Position.x, light.Position.y, light.Position.z, 1.0f);
+ Direction = Vector4(light.Direction.x, light.Direction.y, light.Direction.z, 0.0f);
+ Direction = normalize(viewMtx * Direction);
+
+ Type = light.Type;
+ Range = light.Range;
+ Falloff = light.Falloff;
+ Attenuation0 = light.Attenuation0;
+ Attenuation1 = light.Attenuation1;
+ Attenuation2 = light.Attenuation2;
+ Theta = cosf(light.Theta / 2.0f);
+ Phi = cosf(light.Phi / 2.0f);
+ }
+
+ Vector4 Diffuse;
+ Vector4 Specular;
+ Vector4 Ambient;
+
+ Vector4 Position;
+ Vector4 Direction;
+
+ D3DLIGHTTYPE Type;
+ float Range;
+ float Falloff;
+ float Attenuation0;
+ float Attenuation1;
+ float Attenuation2;
+ float Theta;
+ float Phi;
+ };
+
+
+ struct D3D9FixedFunctionVS {
+ Matrix4 WorldView;
+ Matrix4 NormalMatrix;
+ Matrix4 InverseView;
+ Matrix4 Projection;
+
+ std::array<Matrix4, 8> TexcoordMatrices;
+
+ D3D9ViewportInfo ViewportInfo;
+
+ Vector4 GlobalAmbient;
+ std::array<D3D9Light, caps::MaxEnabledLights> Lights;
+ D3DMATERIAL9 Material;
+ float TweenFactor;
+ };
+
+
+ struct D3D9FixedFunctionVertexBlendDataHW {
+ Matrix4 WorldView[8];
+ };
+
+
+ struct D3D9FixedFunctionVertexBlendDataSW {
+ Matrix4 WorldView[256];
+ };
+
+
+ struct D3D9FixedFunctionPS {
+ Vector4 textureFactor;
+ };
+
+ enum D3D9SharedPSStages {
+ D3D9SharedPSStages_Constant,
+ D3D9SharedPSStages_BumpEnvMat0,
+ D3D9SharedPSStages_BumpEnvMat1,
+ D3D9SharedPSStages_BumpEnvLScale,
+ D3D9SharedPSStages_BumpEnvLOffset,
+ D3D9SharedPSStages_Count,
+ };
+
+ struct D3D9SharedPS {
+ struct Stage {
+ float Constant[4];
+ float BumpEnvMat[2][2];
+ float BumpEnvLScale;
+ float BumpEnvLOffset;
+ float Padding[2];
+ } Stages[8];
+ };
+
+ struct D3D9VBO {
+ Com<D3D9VertexBuffer, false> vertexBuffer;
+
+ UINT offset = 0;
+ UINT stride = 0;
+ };
+
+ constexpr D3DLIGHT9 DefaultLight = {
+ D3DLIGHT_DIRECTIONAL, // Type
+ {1.0f, 1.0f, 1.0f, 1.0f}, // Diffuse
+ {0.0f, 0.0f, 0.0f, 0.0f}, // Specular
+ {0.0f, 0.0f, 0.0f, 0.0f}, // Ambient
+ {0.0f, 0.0f, 0.0f}, // Position
+ {0.0f, 0.0f, 0.0f}, // Direction
+ 0.0f, // Range
+ 0.0f, // Falloff
+ 0.0f, 0.0f, 0.0f, // Attenuations [constant, linear, quadratic]
+ 0.0f, // Theta
+ 0.0f // Phi
+ };
+
+ struct D3D9CapturableState {
+ D3D9CapturableState();
+
+ ~D3D9CapturableState();
+
+ Com<D3D9VertexDecl, false> vertexDecl;
+ Com<D3D9IndexBuffer, false> indices;
+
+ std::array<DWORD, RenderStateCount> renderStates = { 0 };
+
+ std::array<
+ std::array<DWORD, SamplerStateCount>,
+ SamplerCount> samplerStates;
+
+ std::array<D3D9VBO, caps::MaxStreams> vertexBuffers;
+
+ std::array<
+ IDirect3DBaseTexture9*,
+ SamplerCount> textures;
+
+ Com<D3D9VertexShader, false> vertexShader;
+ Com<D3D9PixelShader, false> pixelShader;
+
+ D3DVIEWPORT9 viewport;
+ RECT scissorRect;
+
+ std::array<
+ D3D9ClipPlane,
+ caps::MaxClipPlanes> clipPlanes;
+
+ std::array<
+ std::array<DWORD, TextureStageStateCount>,
+ caps::TextureStageCount> textureStages;
+
+ D3D9ShaderConstantsVSSoftware vsConsts;
+ D3D9ShaderConstantsPS psConsts;
+
+ std::array<UINT, caps::MaxStreams> streamFreq;
+
+ std::array<Matrix4, caps::MaxTransforms> transforms;
+
+ D3DMATERIAL9 material = D3DMATERIAL9();
+
+ std::vector<std::optional<D3DLIGHT9>> lights;
+ std::array<DWORD, caps::MaxEnabledLights> enabledLightIndices;
+
+ bool IsLightEnabled(DWORD Index) {
+ const auto& indices = enabledLightIndices;
+ return std::find(indices.begin(), indices.end(), Index) != indices.end();
+ }
+ };
+
+ template <
+ DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType,
+ typename T>
+ HRESULT UpdateStateConstants(
+ D3D9CapturableState* pState,
+ UINT StartRegister,
+ const T* pConstantData,
+ UINT Count,
+ bool FloatEmu) {
+ auto UpdateHelper = [&] (auto& set) {
+ if constexpr (ConstantType == D3D9ConstantType::Float) {
+
+ if (!FloatEmu) {
+ size_t size = Count * sizeof(Vector4);
+
+ std::memcpy(set.fConsts[StartRegister].data, pConstantData, size);
+ }
+ else {
+ for (UINT i = 0; i < Count; i++)
+ set.fConsts[StartRegister + i] = replaceNaN(pConstantData + (i * 4));
+ }
+ }
+ else if constexpr (ConstantType == D3D9ConstantType::Int) {
+ size_t size = Count * sizeof(Vector4i);
+
+ std::memcpy(set.iConsts[StartRegister].data, pConstantData, size);
+ }
+ else {
+ for (uint32_t i = 0; i < Count; i++) {
+ const uint32_t constantIdx = StartRegister + i;
+ const uint32_t arrayIdx = constantIdx / 32;
+ const uint32_t bitIdx = constantIdx % 32;
+
+ const uint32_t bit = 1u << bitIdx;
+
+ set.bConsts[arrayIdx] &= ~bit;
+ if (pConstantData[i])
+ set.bConsts[arrayIdx] |= bit;
+ }
+ }
+
+ return D3D_OK;
+ };
+
+ return ProgramType == DxsoProgramTypes::VertexShader
+ ? UpdateHelper(pState->vsConsts)
+ : UpdateHelper(pState->psConsts);
+ }
+
+ struct Direct3DState9 : public D3D9CapturableState {
+
+ std::array<Com<D3D9Surface, false>, caps::MaxSimultaneousRenderTargets> renderTargets;
+ Com<D3D9Surface, false> depthStencil;
+
+ };
+
+
+ struct D3D9InputAssemblyState {
+ D3DPRIMITIVETYPE primitiveType = D3DPRIMITIVETYPE(0);
+ uint32_t streamsInstanced = 0;
+ uint32_t streamsUsed = 0;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.cpp
new file mode 100644
index 00000000..9cbf92f9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.cpp
@@ -0,0 +1,531 @@
+#include "d3d9_stateblock.h"
+
+#include "d3d9_device.h"
+#include "d3d9_vertex_declaration.h"
+#include "d3d9_buffer.h"
+#include "d3d9_shader.h"
+#include "d3d9_texture.h"
+
+#include "d3d9_util.h"
+
+namespace dxvk {
+
+ D3D9StateBlock::D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type)
+ : D3D9StateBlockBase(pDevice)
+ , m_deviceState (pDevice->GetRawState()) {
+ CaptureType(Type);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DStateBlock9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9StateBlock::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9StateBlock::Capture() {
+ if (m_captures.flags.test(D3D9CapturedStateFlag::VertexDecl))
+ SetVertexDeclaration(m_deviceState->vertexDecl.ptr());
+
+ ApplyOrCapture<D3D9StateFunction::Capture>();
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9StateBlock::Apply() {
+ m_applying = true;
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::VertexDecl) && m_state.vertexDecl != nullptr)
+ m_parent->SetVertexDeclaration(m_state.vertexDecl.ptr());
+
+ ApplyOrCapture<D3D9StateFunction::Apply>();
+ m_applying = false;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexDeclaration(D3D9VertexDecl* pDecl) {
+ m_state.vertexDecl = pDecl;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexDecl);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetIndices(D3D9IndexBuffer* pIndexData) {
+ m_state.indices = pIndexData;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Indices);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) {
+ m_state.renderStates[State] = Value;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
+ m_captures.renderStates.set(State, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStateSamplerState(
+ DWORD StateSampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value) {
+ m_state.samplerStates[StateSampler][Type] = Value;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
+ m_captures.samplers.set(StateSampler, true);
+ m_captures.samplerStates[StateSampler].set(Type, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStreamSource(
+ UINT StreamNumber,
+ D3D9VertexBuffer* pStreamData,
+ UINT OffsetInBytes,
+ UINT Stride) {
+ m_state.vertexBuffers[StreamNumber].vertexBuffer = pStreamData;
+
+ m_state.vertexBuffers[StreamNumber].offset = OffsetInBytes;
+ m_state.vertexBuffers[StreamNumber].stride = Stride;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexBuffers);
+ m_captures.vertexBuffers.set(StreamNumber, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStreamSourceFreq(UINT StreamNumber, UINT Setting) {
+ m_state.streamFreq[StreamNumber] = Setting;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::StreamFreq);
+ m_captures.streamFreq.set(StreamNumber, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture) {
+ TextureChangePrivate(m_state.textures[StateSampler], pTexture);
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Textures);
+ m_captures.textures.set(StateSampler, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexShader(D3D9VertexShader* pShader) {
+ m_state.vertexShader = pShader;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexShader);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetPixelShader(D3D9PixelShader* pShader) {
+ m_state.pixelShader = pShader;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::PixelShader);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetMaterial(const D3DMATERIAL9* pMaterial) {
+ m_state.material = *pMaterial;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Material);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) {
+ m_state.transforms[idx] = ConvertMatrix(pMatrix);
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
+ m_captures.transforms.set(idx, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetStateTextureStageState(
+ DWORD Stage,
+ D3D9TextureStageStateTypes Type,
+ DWORD Value) {
+ m_state.textureStages[Stage][Type] = Value;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::TextureStages);
+ m_captures.textureStages.set(Stage, true);
+ m_captures.textureStageStates[Stage].set(Type, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::MultiplyStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) {
+ m_state.transforms[idx] = m_state.transforms[idx] * ConvertMatrix(pMatrix);
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
+ m_captures.transforms.set(idx, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetViewport(const D3DVIEWPORT9* pViewport) {
+ m_state.viewport = *pViewport;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Viewport);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetScissorRect(const RECT* pRect) {
+ m_state.scissorRect = *pRect;
+
+ m_captures.flags.set(D3D9CapturedStateFlag::ScissorRect);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetClipPlane(DWORD Index, const float* pPlane) {
+ for (uint32_t i = 0; i < 4; i++)
+ m_state.clipPlanes[Index].coeff[i] = pPlane[i];
+
+ m_captures.flags.set(D3D9CapturedStateFlag::ClipPlanes);
+ m_captures.clipPlanes.set(Index, true);
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::VertexShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetPixelShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Float>(
+ StartRegister,
+ pConstantData,
+ Vector4fCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetPixelShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Int>(
+ StartRegister,
+ pConstantData,
+ Vector4iCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetPixelShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount) {
+ return SetShaderConstants<
+ DxsoProgramTypes::PixelShader,
+ D3D9ConstantType::Bool>(
+ StartRegister,
+ pConstantData,
+ BoolCount);
+ }
+
+
+ HRESULT D3D9StateBlock::SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
+ m_state.vsConsts.bConsts[idx] &= ~mask;
+ m_state.vsConsts.bConsts[idx] |= bits & mask;
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9StateBlock::SetPixelBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
+ m_state.psConsts.bConsts[idx] &= ~mask;
+ m_state.psConsts.bConsts[idx] |= bits & mask;
+ return D3D_OK;
+ }
+
+
+ void D3D9StateBlock::CapturePixelRenderStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
+
+ m_captures.renderStates.set(D3DRS_ZENABLE, true);
+ m_captures.renderStates.set(D3DRS_FILLMODE, true);
+ m_captures.renderStates.set(D3DRS_SHADEMODE, true);
+ m_captures.renderStates.set(D3DRS_ZWRITEENABLE, true);
+ m_captures.renderStates.set(D3DRS_ALPHATESTENABLE, true);
+ m_captures.renderStates.set(D3DRS_LASTPIXEL, true);
+ m_captures.renderStates.set(D3DRS_SRCBLEND, true);
+ m_captures.renderStates.set(D3DRS_DESTBLEND, true);
+ m_captures.renderStates.set(D3DRS_ZFUNC, true);
+ m_captures.renderStates.set(D3DRS_ALPHAREF, true);
+ m_captures.renderStates.set(D3DRS_ALPHAFUNC, true);
+ m_captures.renderStates.set(D3DRS_DITHERENABLE, true);
+ m_captures.renderStates.set(D3DRS_FOGSTART, true);
+ m_captures.renderStates.set(D3DRS_FOGEND, true);
+ m_captures.renderStates.set(D3DRS_FOGDENSITY, true);
+ m_captures.renderStates.set(D3DRS_ALPHABLENDENABLE, true);
+ m_captures.renderStates.set(D3DRS_DEPTHBIAS, true);
+ m_captures.renderStates.set(D3DRS_STENCILENABLE, true);
+ m_captures.renderStates.set(D3DRS_STENCILFAIL, true);
+ m_captures.renderStates.set(D3DRS_STENCILZFAIL, true);
+ m_captures.renderStates.set(D3DRS_STENCILPASS, true);
+ m_captures.renderStates.set(D3DRS_STENCILFUNC, true);
+ m_captures.renderStates.set(D3DRS_STENCILREF, true);
+ m_captures.renderStates.set(D3DRS_STENCILMASK, true);
+ m_captures.renderStates.set(D3DRS_STENCILWRITEMASK, true);
+ m_captures.renderStates.set(D3DRS_TEXTUREFACTOR, true);
+ m_captures.renderStates.set(D3DRS_WRAP0, true);
+ m_captures.renderStates.set(D3DRS_WRAP1, true);
+ m_captures.renderStates.set(D3DRS_WRAP2, true);
+ m_captures.renderStates.set(D3DRS_WRAP3, true);
+ m_captures.renderStates.set(D3DRS_WRAP4, true);
+ m_captures.renderStates.set(D3DRS_WRAP5, true);
+ m_captures.renderStates.set(D3DRS_WRAP6, true);
+ m_captures.renderStates.set(D3DRS_WRAP7, true);
+ m_captures.renderStates.set(D3DRS_WRAP8, true);
+ m_captures.renderStates.set(D3DRS_WRAP9, true);
+ m_captures.renderStates.set(D3DRS_WRAP10, true);
+ m_captures.renderStates.set(D3DRS_WRAP11, true);
+ m_captures.renderStates.set(D3DRS_WRAP12, true);
+ m_captures.renderStates.set(D3DRS_WRAP13, true);
+ m_captures.renderStates.set(D3DRS_WRAP14, true);
+ m_captures.renderStates.set(D3DRS_WRAP15, true);
+ m_captures.renderStates.set(D3DRS_COLORWRITEENABLE, true);
+ m_captures.renderStates.set(D3DRS_BLENDOP, true);
+ m_captures.renderStates.set(D3DRS_SCISSORTESTENABLE, true);
+ m_captures.renderStates.set(D3DRS_SLOPESCALEDEPTHBIAS, true);
+ m_captures.renderStates.set(D3DRS_ANTIALIASEDLINEENABLE, true);
+ m_captures.renderStates.set(D3DRS_TWOSIDEDSTENCILMODE, true);
+ m_captures.renderStates.set(D3DRS_CCW_STENCILFAIL, true);
+ m_captures.renderStates.set(D3DRS_CCW_STENCILZFAIL, true);
+ m_captures.renderStates.set(D3DRS_CCW_STENCILPASS, true);
+ m_captures.renderStates.set(D3DRS_CCW_STENCILFUNC, true);
+ m_captures.renderStates.set(D3DRS_COLORWRITEENABLE1, true);
+ m_captures.renderStates.set(D3DRS_COLORWRITEENABLE2, true);
+ m_captures.renderStates.set(D3DRS_COLORWRITEENABLE3, true);
+ m_captures.renderStates.set(D3DRS_BLENDFACTOR, true);
+ m_captures.renderStates.set(D3DRS_SRGBWRITEENABLE, true);
+ m_captures.renderStates.set(D3DRS_SEPARATEALPHABLENDENABLE, true);
+ m_captures.renderStates.set(D3DRS_SRCBLENDALPHA, true);
+ m_captures.renderStates.set(D3DRS_DESTBLENDALPHA, true);
+ m_captures.renderStates.set(D3DRS_BLENDOPALPHA, true);
+ }
+
+
+ void D3D9StateBlock::CapturePixelSamplerStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
+
+ for (uint32_t i = 0; i < 17; i++) {
+ m_captures.samplers.set(i, true);
+
+ m_captures.samplerStates[i].set(D3DSAMP_ADDRESSU, true);
+ m_captures.samplerStates[i].set(D3DSAMP_ADDRESSV, true);
+ m_captures.samplerStates[i].set(D3DSAMP_ADDRESSW, true);
+ m_captures.samplerStates[i].set(D3DSAMP_BORDERCOLOR, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MAGFILTER, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MINFILTER, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MIPFILTER, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MIPMAPLODBIAS, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MAXMIPLEVEL, true);
+ m_captures.samplerStates[i].set(D3DSAMP_MAXANISOTROPY, true);
+ m_captures.samplerStates[i].set(D3DSAMP_SRGBTEXTURE, true);
+ m_captures.samplerStates[i].set(D3DSAMP_ELEMENTINDEX, true);
+ }
+ }
+
+
+ void D3D9StateBlock::CapturePixelShaderStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::PixelShader);
+ m_captures.flags.set(D3D9CapturedStateFlag::PsConstants);
+
+ m_captures.psConsts.fConsts.setAll();
+ m_captures.psConsts.iConsts.setAll();
+ m_captures.psConsts.bConsts.setAll();
+ }
+
+
+ void D3D9StateBlock::CaptureVertexRenderStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
+
+ m_captures.renderStates.set(D3DRS_CULLMODE, true);
+ m_captures.renderStates.set(D3DRS_FOGENABLE, true);
+ m_captures.renderStates.set(D3DRS_FOGCOLOR, true);
+ m_captures.renderStates.set(D3DRS_FOGTABLEMODE, true);
+ m_captures.renderStates.set(D3DRS_FOGSTART, true);
+ m_captures.renderStates.set(D3DRS_FOGEND, true);
+ m_captures.renderStates.set(D3DRS_FOGDENSITY, true);
+ m_captures.renderStates.set(D3DRS_RANGEFOGENABLE, true);
+ m_captures.renderStates.set(D3DRS_AMBIENT, true);
+ m_captures.renderStates.set(D3DRS_COLORVERTEX, true);
+ m_captures.renderStates.set(D3DRS_FOGVERTEXMODE, true);
+ m_captures.renderStates.set(D3DRS_CLIPPING, true);
+ m_captures.renderStates.set(D3DRS_LIGHTING, true);
+ m_captures.renderStates.set(D3DRS_LOCALVIEWER, true);
+ m_captures.renderStates.set(D3DRS_EMISSIVEMATERIALSOURCE, true);
+ m_captures.renderStates.set(D3DRS_AMBIENTMATERIALSOURCE, true);
+ m_captures.renderStates.set(D3DRS_DIFFUSEMATERIALSOURCE, true);
+ m_captures.renderStates.set(D3DRS_SPECULARMATERIALSOURCE, true);
+ m_captures.renderStates.set(D3DRS_VERTEXBLEND, true);
+ m_captures.renderStates.set(D3DRS_CLIPPLANEENABLE, true);
+ m_captures.renderStates.set(D3DRS_POINTSIZE, true);
+ m_captures.renderStates.set(D3DRS_POINTSIZE_MIN, true);
+ m_captures.renderStates.set(D3DRS_POINTSPRITEENABLE, true);
+ m_captures.renderStates.set(D3DRS_POINTSCALEENABLE, true);
+ m_captures.renderStates.set(D3DRS_POINTSCALE_A, true);
+ m_captures.renderStates.set(D3DRS_POINTSCALE_B, true);
+ m_captures.renderStates.set(D3DRS_POINTSCALE_C, true);
+ m_captures.renderStates.set(D3DRS_MULTISAMPLEANTIALIAS, true);
+ m_captures.renderStates.set(D3DRS_MULTISAMPLEMASK, true);
+ m_captures.renderStates.set(D3DRS_PATCHEDGESTYLE, true);
+ m_captures.renderStates.set(D3DRS_POINTSIZE_MAX, true);
+ m_captures.renderStates.set(D3DRS_INDEXEDVERTEXBLENDENABLE, true);
+ m_captures.renderStates.set(D3DRS_TWEENFACTOR, true);
+ m_captures.renderStates.set(D3DRS_POSITIONDEGREE, true);
+ m_captures.renderStates.set(D3DRS_NORMALDEGREE, true);
+ m_captures.renderStates.set(D3DRS_MINTESSELLATIONLEVEL, true);
+ m_captures.renderStates.set(D3DRS_MAXTESSELLATIONLEVEL, true);
+ m_captures.renderStates.set(D3DRS_ADAPTIVETESS_X, true);
+ m_captures.renderStates.set(D3DRS_ADAPTIVETESS_Y, true);
+ m_captures.renderStates.set(D3DRS_ADAPTIVETESS_Z, true);
+ m_captures.renderStates.set(D3DRS_ADAPTIVETESS_W, true);
+ m_captures.renderStates.set(D3DRS_ENABLEADAPTIVETESSELLATION, true);
+ m_captures.renderStates.set(D3DRS_NORMALIZENORMALS, true);
+ m_captures.renderStates.set(D3DRS_SPECULARENABLE, true);
+ m_captures.renderStates.set(D3DRS_SHADEMODE, true);
+ }
+
+
+ void D3D9StateBlock::CaptureVertexSamplerStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
+
+ for (uint32_t i = 17; i < SamplerCount; i++) {
+ m_captures.samplers.set(i, true);
+ m_captures.samplerStates[i].set(D3DSAMP_DMAPOFFSET, true);
+ }
+ }
+
+
+ void D3D9StateBlock::CaptureVertexShaderStates() {
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexShader);
+ m_captures.flags.set(D3D9CapturedStateFlag::VsConstants);
+
+ for (uint32_t i = 0; i < m_parent->GetVertexConstantLayout().floatCount / 32; i++)
+ m_captures.vsConsts.fConsts.dword(i) = std::numeric_limits<uint32_t>::max();
+
+ for (uint32_t i = 0; i < m_parent->GetVertexConstantLayout().intCount / 32; i++)
+ m_captures.vsConsts.iConsts.dword(i) = std::numeric_limits<uint32_t>::max();
+
+ for (uint32_t i = 0; i < m_parent->GetVertexConstantLayout().bitmaskCount; i++)
+ m_captures.vsConsts.bConsts.dword(i) = std::numeric_limits<uint32_t>::max();
+ }
+
+
+ void D3D9StateBlock::CaptureType(D3D9StateBlockType Type) {
+ if (Type == D3D9StateBlockType::PixelState || Type == D3D9StateBlockType::All) {
+ CapturePixelRenderStates();
+ CapturePixelSamplerStates();
+ CapturePixelShaderStates();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::TextureStages);
+ m_captures.textureStages.setAll();
+ for (auto& stage : m_captures.textureStageStates)
+ stage.setAll();
+ }
+
+ if (Type == D3D9StateBlockType::VertexState || Type == D3D9StateBlockType::All) {
+ CaptureVertexRenderStates();
+ CaptureVertexSamplerStates();
+ CaptureVertexShaderStates();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexDecl);
+ m_captures.flags.set(D3D9CapturedStateFlag::StreamFreq);
+
+ for (uint32_t i = 0; i < caps::MaxStreams; i++)
+ m_captures.streamFreq.set(i, true);
+ }
+
+ if (Type == D3D9StateBlockType::All) {
+ m_captures.flags.set(D3D9CapturedStateFlag::Textures);
+ m_captures.textures.setAll();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::VertexBuffers);
+ m_captures.vertexBuffers.setAll();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Indices);
+ m_captures.flags.set(D3D9CapturedStateFlag::Viewport);
+ m_captures.flags.set(D3D9CapturedStateFlag::ScissorRect);
+
+ m_captures.flags.set(D3D9CapturedStateFlag::ClipPlanes);
+ m_captures.clipPlanes.setAll();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
+ m_captures.transforms.setAll();
+
+ m_captures.flags.set(D3D9CapturedStateFlag::Material);
+ }
+
+ if (Type != D3D9StateBlockType::None)
+ this->Capture();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.h
new file mode 100644
index 00000000..43a712ad
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_stateblock.h
@@ -0,0 +1,380 @@
+#pragma once
+
+#include "d3d9_device_child.h"
+#include "d3d9_device.h"
+#include "d3d9_state.h"
+
+#include "../util/util_bit.h"
+
+namespace dxvk {
+
+ enum class D3D9CapturedStateFlag : uint32_t {
+ VertexDecl,
+ Indices,
+ RenderStates,
+ SamplerStates,
+ VertexBuffers,
+ Textures,
+ VertexShader,
+ PixelShader,
+ Viewport,
+ ScissorRect,
+ ClipPlanes,
+ VsConstants,
+ PsConstants,
+ StreamFreq,
+ Transforms,
+ TextureStages,
+ Material
+ };
+
+ using D3D9CapturedStateFlags = Flags<D3D9CapturedStateFlag>;
+
+ struct D3D9StateCaptures {
+ D3D9CapturedStateFlags flags;
+
+ bit::bitset<RenderStateCount> renderStates;
+
+ bit::bitset<SamplerCount> samplers;
+ std::array<
+ bit::bitset<SamplerStateCount>,
+ SamplerCount> samplerStates;
+
+ bit::bitset<caps::MaxStreams> vertexBuffers;
+ bit::bitset<SamplerCount> textures;
+ bit::bitset<caps::MaxClipPlanes> clipPlanes;
+ bit::bitset<caps::MaxStreams> streamFreq;
+ bit::bitset<caps::MaxTransforms> transforms;
+ bit::bitset<caps::TextureStageCount> textureStages;
+ std::array<
+ bit::bitset<TextureStageStateCount>,
+ caps::TextureStageCount> textureStageStates;
+
+ struct {
+ bit::bitset<caps::MaxFloatConstantsSoftware> fConsts;
+ bit::bitset<caps::MaxOtherConstantsSoftware> iConsts;
+ bit::bitset<caps::MaxOtherConstantsSoftware> bConsts;
+ } vsConsts;
+
+ struct {
+ bit::bitset<caps::MaxFloatConstantsPS> fConsts;
+ bit::bitset<caps::MaxOtherConstants> iConsts;
+ bit::bitset<caps::MaxOtherConstants> bConsts;
+ } psConsts;
+ };
+
+ enum class D3D9StateBlockType :uint32_t {
+ None,
+ VertexState,
+ PixelState,
+ All
+ };
+
+ inline D3D9StateBlockType ConvertStateBlockType(D3DSTATEBLOCKTYPE type) {
+ switch (type) {
+ case D3DSBT_PIXELSTATE: return D3D9StateBlockType::PixelState;
+ case D3DSBT_VERTEXSTATE: return D3D9StateBlockType::VertexState;
+ default:
+ case D3DSBT_ALL: return D3D9StateBlockType::All;
+ }
+ }
+
+ using D3D9StateBlockBase = D3D9DeviceChild<IDirect3DStateBlock9>;
+ class D3D9StateBlock : public D3D9StateBlockBase {
+
+ public:
+
+ D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE Capture() final;
+ HRESULT STDMETHODCALLTYPE Apply() final;
+
+ HRESULT SetVertexDeclaration(D3D9VertexDecl* pDecl);
+
+ HRESULT SetIndices(D3D9IndexBuffer* pIndexData);
+
+ HRESULT SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
+
+ HRESULT SetStateSamplerState(
+ DWORD StateSampler,
+ D3DSAMPLERSTATETYPE Type,
+ DWORD Value);
+
+ HRESULT SetStreamSource(
+ UINT StreamNumber,
+ D3D9VertexBuffer* pStreamData,
+ UINT OffsetInBytes,
+ UINT Stride);
+
+ HRESULT SetStreamSourceFreq(UINT StreamNumber, UINT Setting);
+
+ HRESULT SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture);
+
+ HRESULT SetVertexShader(D3D9VertexShader* pShader);
+
+ HRESULT SetPixelShader(D3D9PixelShader* pShader);
+
+ HRESULT SetMaterial(const D3DMATERIAL9* pMaterial);
+
+ HRESULT SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix);
+
+ HRESULT SetStateTextureStageState(
+ DWORD Stage,
+ D3D9TextureStageStateTypes Type,
+ DWORD Value);
+
+ HRESULT MultiplyStateTransform(uint32_t idx, const D3DMATRIX* pMatrix);
+
+ HRESULT SetViewport(const D3DVIEWPORT9* pViewport);
+
+ HRESULT SetScissorRect(const RECT* pRect);
+
+ HRESULT SetClipPlane(DWORD Index, const float* pPlane);
+
+
+ HRESULT SetVertexShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT SetVertexShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT SetVertexShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount);
+
+
+ HRESULT SetPixelShaderConstantF(
+ UINT StartRegister,
+ const float* pConstantData,
+ UINT Vector4fCount);
+
+ HRESULT SetPixelShaderConstantI(
+ UINT StartRegister,
+ const int* pConstantData,
+ UINT Vector4iCount);
+
+ HRESULT SetPixelShaderConstantB(
+ UINT StartRegister,
+ const BOOL* pConstantData,
+ UINT BoolCount);
+
+ enum class D3D9StateFunction {
+ Apply,
+ Capture
+ };
+
+ template <typename Dst, typename Src>
+ void ApplyOrCapture(Dst* dst, const Src* src) {
+ if (m_captures.flags.test(D3D9CapturedStateFlag::StreamFreq)) {
+ for (uint32_t idx : bit::BitMask(m_captures.streamFreq.dword(0)))
+ dst->SetStreamSourceFreq(idx, src->streamFreq[idx]);
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::Indices))
+ dst->SetIndices(src->indices.ptr());
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::RenderStates)) {
+ for (uint32_t i = 0; i < m_captures.renderStates.dwordCount(); i++) {
+ for (uint32_t rs : bit::BitMask(m_captures.renderStates.dword(i))) {
+ uint32_t idx = i * 32 + rs;
+
+ dst->SetRenderState(D3DRENDERSTATETYPE(idx), src->renderStates[idx]);
+ }
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::SamplerStates)) {
+ for (uint32_t samplerIdx : bit::BitMask(m_captures.samplers.dword(0))) {
+ for (uint32_t stateIdx : bit::BitMask(m_captures.samplerStates[samplerIdx].dword(0)))
+ dst->SetStateSamplerState(samplerIdx, D3DSAMPLERSTATETYPE(stateIdx), src->samplerStates[samplerIdx][stateIdx]);
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::VertexBuffers)) {
+ for (uint32_t idx : bit::BitMask(m_captures.vertexBuffers.dword(0))) {
+ const auto& vbo = src->vertexBuffers[idx];
+ dst->SetStreamSource(
+ idx,
+ vbo.vertexBuffer.ptr(),
+ vbo.offset,
+ vbo.stride);
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::Material))
+ dst->SetMaterial(&src->material);
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::Textures)) {
+ for (uint32_t idx : bit::BitMask(m_captures.textures.dword(0)))
+ dst->SetStateTexture(idx, src->textures[idx]);
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::VertexShader))
+ dst->SetVertexShader(src->vertexShader.ptr());
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::PixelShader))
+ dst->SetPixelShader(src->pixelShader.ptr());
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::Transforms)) {
+ for (uint32_t i = 0; i < m_captures.transforms.dwordCount(); i++) {
+ for (uint32_t trans : bit::BitMask(m_captures.transforms.dword(i))) {
+ uint32_t idx = i * 32 + trans;
+
+ dst->SetStateTransform(idx, reinterpret_cast<const D3DMATRIX*>(&src->transforms[idx]));
+ }
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::TextureStages)) {
+ for (uint32_t stageIdx : bit::BitMask(m_captures.textureStages.dword(0))) {
+ for (uint32_t stateIdx : bit::BitMask(m_captures.textureStageStates[stageIdx].dword(0)))
+ dst->SetStateTextureStageState(stageIdx, D3D9TextureStageStateTypes(stateIdx), src->textureStages[stageIdx][stateIdx]);
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::Viewport))
+ dst->SetViewport(&src->viewport);
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::ScissorRect))
+ dst->SetScissorRect(&src->scissorRect);
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::ClipPlanes)) {
+ for (uint32_t idx : bit::BitMask(m_captures.clipPlanes.dword(0)))
+ dst->SetClipPlane(idx, src->clipPlanes[idx].coeff);
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::VsConstants)) {
+ for (uint32_t i = 0; i < m_captures.vsConsts.fConsts.dwordCount(); i++) {
+ for (uint32_t consts : bit::BitMask(m_captures.vsConsts.fConsts.dword(i))) {
+ uint32_t idx = i * 32 + consts;
+
+ dst->SetVertexShaderConstantF(idx, (float*)&src->vsConsts.fConsts[idx], 1);
+ }
+ }
+
+ for (uint32_t i = 0; i < m_captures.vsConsts.iConsts.dwordCount(); i++) {
+ for (uint32_t consts : bit::BitMask(m_captures.vsConsts.iConsts.dword(i))) {
+ uint32_t idx = i * 32 + consts;
+
+ dst->SetVertexShaderConstantI(idx, (int*)&src->vsConsts.iConsts[idx], 1);
+ }
+ }
+
+ if (m_captures.vsConsts.bConsts.any()) {
+ for (uint32_t i = 0; i < m_captures.vsConsts.bConsts.dwordCount(); i++)
+ dst->SetVertexBoolBitfield(i, m_captures.vsConsts.bConsts.dword(i), src->vsConsts.bConsts[i]);
+ }
+ }
+
+ if (m_captures.flags.test(D3D9CapturedStateFlag::PsConstants)) {
+ for (uint32_t i = 0; i < m_captures.psConsts.fConsts.dwordCount(); i++) {
+ for (uint32_t consts : bit::BitMask(m_captures.psConsts.fConsts.dword(i))) {
+ uint32_t idx = i * 32 + consts;
+
+ dst->SetPixelShaderConstantF(idx, (float*)&src->psConsts.fConsts[idx], 1);
+ }
+ }
+
+ for (uint32_t i = 0; i < m_captures.psConsts.iConsts.dwordCount(); i++) {
+ for (uint32_t consts : bit::BitMask(m_captures.psConsts.iConsts.dword(i))) {
+ uint32_t idx = i * 32 + consts;
+
+ dst->SetPixelShaderConstantI(idx, (int*)&src->psConsts.iConsts[idx], 1);
+ }
+ }
+
+ if (m_captures.psConsts.bConsts.any()) {
+ for (uint32_t i = 0; i < m_captures.psConsts.bConsts.dwordCount(); i++)
+ dst->SetPixelBoolBitfield(i, m_captures.psConsts.bConsts.dword(i), src->psConsts.bConsts[i]);
+ }
+ }
+ }
+
+ template <D3D9StateFunction Func>
+ void ApplyOrCapture() {
+ if constexpr (Func == D3D9StateFunction::Apply)
+ ApplyOrCapture(m_parent, &m_state);
+ else if constexpr (Func == D3D9StateFunction::Capture)
+ ApplyOrCapture(this, m_deviceState);
+ }
+
+ template <
+ DxsoProgramType ProgramType,
+ D3D9ConstantType ConstantType,
+ typename T>
+ HRESULT SetShaderConstants(
+ UINT StartRegister,
+ const T* pConstantData,
+ UINT Count) {
+ auto SetHelper = [&](auto& setCaptures) {
+ if constexpr (ProgramType == DxsoProgramTypes::VertexShader)
+ m_captures.flags.set(D3D9CapturedStateFlag::VsConstants);
+ else
+ m_captures.flags.set(D3D9CapturedStateFlag::PsConstants);
+
+ for (uint32_t i = 0; i < Count; i++) {
+ uint32_t reg = StartRegister + i;
+ if constexpr (ConstantType == D3D9ConstantType::Float)
+ setCaptures.fConsts.set(reg, true);
+ else if constexpr (ConstantType == D3D9ConstantType::Int)
+ setCaptures.iConsts.set(reg, true);
+ else if constexpr (ConstantType == D3D9ConstantType::Bool)
+ setCaptures.bConsts.set(reg, true);
+ }
+
+ UpdateStateConstants<
+ ProgramType,
+ ConstantType,
+ T>(
+ &m_state,
+ StartRegister,
+ pConstantData,
+ Count,
+ false);
+
+ return D3D_OK;
+ };
+
+ return ProgramType == DxsoProgramTypes::VertexShader
+ ? SetHelper(m_captures.vsConsts)
+ : SetHelper(m_captures.psConsts);
+ }
+
+ HRESULT SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
+ HRESULT SetPixelBoolBitfield (uint32_t idx, uint32_t mask, uint32_t bits);
+
+ inline bool IsApplying() {
+ return m_applying;
+ }
+
+ private:
+
+ void CapturePixelRenderStates();
+ void CapturePixelSamplerStates();
+ void CapturePixelShaderStates();
+
+ void CaptureVertexRenderStates();
+ void CaptureVertexSamplerStates();
+ void CaptureVertexShaderStates();
+
+ void CaptureType(D3D9StateBlockType State);
+
+ D3D9CapturableState m_state;
+ D3D9StateCaptures m_captures;
+
+ D3D9CapturableState* m_deviceState;
+
+ bool m_applying = false;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_subresource.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_subresource.h
new file mode 100644
index 00000000..8d047501
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_subresource.h
@@ -0,0 +1,149 @@
+#pragma once
+
+#include "d3d9_resource.h"
+#include "d3d9_common_texture.h"
+
+namespace dxvk {
+
+ template <typename... Type>
+ class D3D9Subresource : public D3D9Resource<Type...> {
+
+ public:
+
+ D3D9Subresource(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonTexture* pTexture,
+ UINT Face,
+ UINT MipLevel,
+ IDirect3DBaseTexture9* pBaseTexture,
+ IUnknown* pContainer)
+ : D3D9Resource<Type...>(pDevice),
+ m_container (pContainer),
+ m_baseTexture (pBaseTexture),
+ m_texture (pTexture),
+ m_face (Face),
+ m_mipLevel (MipLevel),
+ m_isSrgbCompatible (pTexture->IsSrgbCompatible()),
+ m_isNull (pTexture->IsNull()) {
+
+ }
+
+ ~D3D9Subresource() {
+ // We own the texture!
+ if (m_baseTexture == nullptr)
+ delete m_texture;
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() final {
+ if (m_baseTexture != nullptr)
+ return m_baseTexture->AddRef();
+
+ return D3D9Resource<Type...>::AddRef();
+ }
+
+ ULONG STDMETHODCALLTYPE Release() final {
+ if (m_baseTexture != nullptr)
+ return m_baseTexture->Release();
+
+ return D3D9Resource<Type...>::Release();
+ }
+
+ HRESULT STDMETHODCALLTYPE GetContainer(REFIID riid, void** ppContainer) final {
+ if (m_container != nullptr)
+ return m_container->QueryInterface(riid, ppContainer);
+
+ return this->GetDevice()->QueryInterface(riid, ppContainer);
+ }
+
+ void STDMETHODCALLTYPE PreLoad() {
+ m_texture->PreLoadSubresource(GetSubresource());
+ }
+
+ inline D3D9CommonTexture* GetCommonTexture() {
+ return m_texture;
+ }
+
+ inline UINT GetFace() const {
+ return m_face;
+ }
+
+ inline UINT GetMipLevel() const {
+ return m_mipLevel;
+ }
+
+ inline UINT GetSubresource() const {
+ return m_texture->CalcSubresource(m_face, m_mipLevel);
+ }
+
+ inline const Rc<DxvkImageView>& GetImageView(bool Srgb) {
+ Srgb &= m_isSrgbCompatible;
+ Rc<DxvkImageView>& view = m_sampleView.Pick(Srgb);
+
+ if (unlikely(view == nullptr && !IsNull()))
+ view = m_texture->CreateView(m_face, m_mipLevel, VK_IMAGE_USAGE_SAMPLED_BIT, Srgb);
+
+ return view;
+ }
+
+ inline const Rc<DxvkImageView>& GetRenderTargetView(bool Srgb) {
+ Srgb &= m_isSrgbCompatible;
+ Rc<DxvkImageView>& view = m_renderTargetView.Pick(Srgb);
+
+ if (unlikely(view == nullptr && !IsNull()))
+ view = m_texture->CreateView(m_face, m_mipLevel, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, Srgb);
+
+ return view;
+ }
+
+ inline VkImageLayout GetRenderTargetLayout() const {
+ return m_texture->DetermineRenderTargetLayout();
+ }
+
+ inline const Rc<DxvkImageView>& GetDepthStencilView() {
+ Rc<DxvkImageView>& view = m_depthStencilView;
+
+ if (unlikely(view == nullptr))
+ view = m_texture->CreateView(m_face, m_mipLevel, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, false);
+
+ return view;
+ }
+
+ inline VkImageLayout GetDepthStencilLayout(bool write, bool hazardous) const {
+ return m_texture->DetermineDepthStencilLayout(write, hazardous);
+ }
+
+ inline bool IsNull() {
+ return m_isNull;
+ }
+
+ inline IDirect3DBaseTexture9* GetBaseTexture() {
+ return m_baseTexture;
+ }
+
+ inline void Swap(D3D9Subresource* Other) {
+ // Only used for swap chain back buffers that don't
+ // have a container and all have identical properties
+ std::swap(m_texture, Other->m_texture);
+ std::swap(m_sampleView, Other->m_sampleView);
+ std::swap(m_renderTargetView, Other->m_renderTargetView);
+ }
+
+ protected:
+
+ IUnknown* m_container;
+ IDirect3DBaseTexture9* m_baseTexture;
+
+ D3D9CommonTexture* m_texture;
+
+ UINT m_face : 8;
+ UINT m_mipLevel : 16;
+ UINT m_isSrgbCompatible : 1;
+ UINT m_isNull : 1;
+
+ D3D9ColorView m_sampleView;
+ D3D9ColorView m_renderTargetView;
+ Rc<DxvkImageView> m_depthStencilView;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.cpp
new file mode 100644
index 00000000..6158675e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.cpp
@@ -0,0 +1,204 @@
+#include "d3d9_surface.h"
+#include "d3d9_texture.h"
+#include "d3d9_swapchain.h"
+
+#include "d3d9_device.h"
+
+namespace dxvk {
+
+ D3D9Surface::D3D9Surface(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc,
+ IUnknown* pContainer)
+ : D3D9SurfaceBase(
+ pDevice,
+ new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_SURFACE),
+ 0, 0,
+ nullptr,
+ pContainer) { }
+
+ D3D9Surface::D3D9Surface(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonTexture* pTexture,
+ UINT Face,
+ UINT MipLevel,
+ IDirect3DBaseTexture9* pBaseTexture)
+ : D3D9SurfaceBase(
+ pDevice,
+ pTexture,
+ Face, MipLevel,
+ pBaseTexture,
+ pBaseTexture) { }
+
+ void D3D9Surface::AddRefPrivate() {
+ if (m_baseTexture != nullptr) {
+ D3DRESOURCETYPE type = m_baseTexture->GetType();
+ if (type == D3DRTYPE_TEXTURE)
+ static_cast<D3D9Texture2D*> (m_baseTexture)->AddRefPrivate();
+ else //if (type == D3DRTYPE_CUBETEXTURE)
+ static_cast<D3D9TextureCube*>(m_baseTexture)->AddRefPrivate();
+
+ return;
+ }
+
+ D3D9SurfaceBase::AddRefPrivate();
+ }
+
+ void D3D9Surface::ReleasePrivate() {
+ if (m_baseTexture != nullptr) {
+ D3DRESOURCETYPE type = m_baseTexture->GetType();
+ if (type == D3DRTYPE_TEXTURE)
+ static_cast<D3D9Texture2D*> (m_baseTexture)->ReleasePrivate();
+ else //if (type == D3DRTYPE_CUBETEXTURE)
+ static_cast<D3D9TextureCube*>(m_baseTexture)->ReleasePrivate();
+
+ return;
+ }
+
+ D3D9SurfaceBase::ReleasePrivate();
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DSurface9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Surface::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Surface::GetType() {
+ return D3DRTYPE_SURFACE;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::GetDesc(D3DSURFACE_DESC *pDesc) {
+ if (pDesc == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto& desc = *(m_texture->Desc());
+
+ pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
+ pDesc->Type = D3DRTYPE_SURFACE;
+ pDesc->Usage = desc.Usage;
+ pDesc->Pool = desc.Pool;
+
+ pDesc->MultiSampleType = desc.MultiSample;
+ pDesc->MultiSampleQuality = desc.MultisampleQuality;
+ pDesc->Width = std::max(1u, desc.Width >> m_mipLevel);
+ pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
+
+ return D3D_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
+ if (unlikely(pLockedRect == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3DBOX box;
+ if (pRect != nullptr) {
+ box.Left = pRect->left;
+ box.Right = pRect->right;
+ box.Top = pRect->top;
+ box.Bottom = pRect->bottom;
+ box.Front = 0;
+ box.Back = 1;
+ }
+
+ D3DLOCKED_BOX lockedBox;
+
+ HRESULT hr = m_parent->LockImage(
+ m_texture,
+ m_face, m_mipLevel,
+ &lockedBox,
+ pRect != nullptr ? &box : nullptr,
+ Flags);
+
+ pLockedRect->pBits = lockedBox.pBits;
+ pLockedRect->Pitch = lockedBox.RowPitch;
+
+ return hr;
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::UnlockRect() {
+ return m_parent->UnlockImage(
+ m_texture,
+ m_face, m_mipLevel);
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::GetDC(HDC *phDC) {
+#ifndef DXVK_NATIVE
+ if (phDC == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ const D3D9_COMMON_TEXTURE_DESC& desc = *m_texture->Desc();
+
+ D3DLOCKED_RECT lockedRect;
+ HRESULT hr = LockRect(&lockedRect, nullptr, 0);
+ if (FAILED(hr))
+ return hr;
+
+ D3DKMT_CREATEDCFROMMEMORY createInfo;
+ // In...
+ createInfo.pMemory = lockedRect.pBits;
+ createInfo.Format = static_cast<D3DFORMAT>(desc.Format);
+ createInfo.Width = desc.Width;
+ createInfo.Height = desc.Height;
+ createInfo.Pitch = lockedRect.Pitch;
+ createInfo.hDeviceDc = CreateCompatibleDC(NULL);
+ createInfo.pColorTable = nullptr;
+
+ // Out...
+ createInfo.hBitmap = nullptr;
+ createInfo.hDc = nullptr;
+
+ D3DKMTCreateDCFromMemory(&createInfo);
+ DeleteDC(createInfo.hDeviceDc);
+
+ // These should now be set...
+ m_dcDesc.hDC = createInfo.hDc;
+ m_dcDesc.hBitmap = createInfo.hBitmap;
+
+ *phDC = m_dcDesc.hDC;
+ return D3D_OK;
+#else
+ if (phDC != nullptr)
+ *phDC = nullptr;
+
+ Logger::warn("D3D9Surface::GetDC: GDI interop not supported on native");
+ return D3DERR_INVALIDCALL;
+#endif
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Surface::ReleaseDC(HDC hDC) {
+#ifndef DXVK_NATIVE
+ if (m_dcDesc.hDC == nullptr || m_dcDesc.hDC != hDC)
+ return D3DERR_INVALIDCALL;
+
+ D3DKMTDestroyDCFromMemory(&m_dcDesc);
+
+ HRESULT hr = UnlockRect();
+ if (FAILED(hr))
+ return hr;
+
+ return D3D_OK;
+#else
+ Logger::warn("D3D9Surface::ReleaseDC: GDI interop not supported on native");
+ return D3DERR_INVALIDCALL;
+#endif
+ }
+
+
+ void D3D9Surface::ClearContainer() {
+ m_container = nullptr;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.h
new file mode 100644
index 00000000..10086cac
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_surface.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "d3d9_subresource.h"
+
+#include "d3d9_common_texture.h"
+
+#include "../util/util_gdi.h"
+
+#include <algorithm>
+
+namespace dxvk {
+
+ using D3D9GDIDesc = D3DKMT_DESTROYDCFROMMEMORY;
+
+ using D3D9SurfaceBase = D3D9Subresource<IDirect3DSurface9>;
+ class D3D9Surface final : public D3D9SurfaceBase {
+
+ public:
+
+ D3D9Surface(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc,
+ IUnknown* pContainer);
+
+ D3D9Surface(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonTexture* pTexture,
+ UINT Face,
+ UINT MipLevel,
+ IDirect3DBaseTexture9* pBaseTexture);
+
+ void AddRefPrivate();
+
+ void ReleasePrivate();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC *pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) final;
+
+ HRESULT STDMETHODCALLTYPE UnlockRect() final;
+
+ HRESULT STDMETHODCALLTYPE GetDC(HDC *phDC) final;
+
+ HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC) final;
+
+ inline VkExtent2D GetSurfaceExtent() const {
+ const auto* desc = m_texture->Desc();
+
+ return VkExtent2D {
+ std::max(1u, desc->Width >> GetMipLevel()),
+ std::max(1u, desc->Height >> GetMipLevel())
+ };
+ }
+
+ void ClearContainer();
+
+ private:
+
+ D3D9GDIDesc m_dcDesc;
+
+ };
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.cpp
new file mode 100644
index 00000000..673ac046
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.cpp
@@ -0,0 +1,1320 @@
+#include "d3d9_swapchain.h"
+#include "d3d9_surface.h"
+#include "d3d9_monitor.h"
+
+#include "d3d9_hud.h"
+
+namespace dxvk {
+
+#ifndef DXVK_NATIVE
+ struct D3D9WindowData {
+ bool unicode;
+ bool filter;
+ WNDPROC proc;
+ D3D9SwapChainEx* swapchain;
+ };
+
+
+ static dxvk::recursive_mutex g_windowProcMapMutex;
+ static std::unordered_map<HWND, D3D9WindowData> g_windowProcMap;
+
+
+ template <typename T, typename J, typename ... Args>
+ auto CallCharsetFunction(T unicode, J ascii, bool isUnicode, Args... args) {
+ return isUnicode
+ ? unicode(args...)
+ : ascii (args...);
+ }
+
+
+ class D3D9WindowMessageFilter {
+
+ public:
+
+ D3D9WindowMessageFilter(HWND window, bool filter = true)
+ : m_window(window) {
+ std::lock_guard lock(g_windowProcMapMutex);
+ auto it = g_windowProcMap.find(m_window);
+ m_filter = std::exchange(it->second.filter, filter);
+ }
+
+ ~D3D9WindowMessageFilter() {
+ std::lock_guard lock(g_windowProcMapMutex);
+ auto it = g_windowProcMap.find(m_window);
+ it->second.filter = m_filter;
+ }
+
+ D3D9WindowMessageFilter (const D3D9WindowMessageFilter&) = delete;
+ D3D9WindowMessageFilter& operator = (const D3D9WindowMessageFilter&) = delete;
+
+ private:
+
+ HWND m_window;
+ bool m_filter;
+
+ };
+
+
+ LRESULT CALLBACK D3D9WindowProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
+
+
+ void ResetWindowProc(HWND window) {
+ std::lock_guard lock(g_windowProcMapMutex);
+
+ auto it = g_windowProcMap.find(window);
+ if (it == g_windowProcMap.end())
+ return;
+
+ auto proc = reinterpret_cast<WNDPROC>(
+ CallCharsetFunction(
+ GetWindowLongPtrW, GetWindowLongPtrA, it->second.unicode,
+ window, GWLP_WNDPROC));
+
+
+ if (proc == D3D9WindowProc)
+ CallCharsetFunction(
+ SetWindowLongPtrW, SetWindowLongPtrA, it->second.unicode,
+ window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(it->second.proc));
+
+ g_windowProcMap.erase(window);
+ }
+
+
+ void HookWindowProc(HWND window, D3D9SwapChainEx* swapchain) {
+ std::lock_guard lock(g_windowProcMapMutex);
+
+ ResetWindowProc(window);
+
+ D3D9WindowData windowData;
+ windowData.unicode = IsWindowUnicode(window);
+ windowData.filter = false;
+ windowData.proc = reinterpret_cast<WNDPROC>(
+ CallCharsetFunction(
+ SetWindowLongPtrW, SetWindowLongPtrA, windowData.unicode,
+ window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(D3D9WindowProc)));
+ windowData.swapchain = swapchain;
+
+ g_windowProcMap[window] = std::move(windowData);
+ }
+
+
+ LRESULT CALLBACK D3D9WindowProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
+ if (message == WM_NCCALCSIZE && wparam == TRUE)
+ return 0;
+
+ D3D9WindowData windowData = {};
+
+ {
+ std::lock_guard lock(g_windowProcMapMutex);
+
+ auto it = g_windowProcMap.find(window);
+ if (it != g_windowProcMap.end())
+ windowData = it->second;
+ }
+
+ bool unicode = windowData.proc
+ ? windowData.unicode
+ : IsWindowUnicode(window);
+
+ if (!windowData.proc || windowData.filter)
+ return CallCharsetFunction(
+ DefWindowProcW, DefWindowProcA, unicode,
+ window, message, wparam, lparam);
+
+ if (message == WM_DESTROY)
+ ResetWindowProc(window);
+ else if (message == WM_ACTIVATEAPP) {
+ D3DDEVICE_CREATION_PARAMETERS create_parms;
+ windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms);
+
+ if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES)) {
+ if (wparam) {
+ // Heroes of Might and Magic V needs this to resume drawing after a focus loss
+ D3DPRESENT_PARAMETERS params;
+ RECT rect;
+
+ GetMonitorRect(GetDefaultMonitor(), &rect);
+ windowData.swapchain->GetPresentParameters(&params);
+ SetWindowPos(window, nullptr, rect.left, rect.top, params.BackBufferWidth, params.BackBufferHeight,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ else {
+ if (IsWindowVisible(window))
+ ShowWindow(window, SW_MINIMIZE);
+ }
+ }
+ }
+
+ return CallCharsetFunction(
+ CallWindowProcW, CallWindowProcA, unicode,
+ windowData.proc, window, message, wparam, lparam);
+ }
+#endif
+
+
+ static uint16_t MapGammaControlPoint(float x) {
+ if (x < 0.0f) x = 0.0f;
+ if (x > 1.0f) x = 1.0f;
+ return uint16_t(65535.0f * x);
+ }
+
+
+ struct D3D9PresentInfo {
+ float scale[2];
+ float offset[2];
+ };
+
+
+ static inline void ConvertDisplayMode(const D3DDISPLAYMODEEX& mode, wsi::WsiMode* wsiMode) {
+ wsiMode->width = mode.Width;
+ wsiMode->height = mode.Height;
+ wsiMode->refreshRate = wsi::WsiRational{ mode.RefreshRate, 1 };
+ wsiMode->bitsPerPixel = GetMonitorFormatBpp(EnumerateFormat(mode.Format));
+ wsiMode->interlaced = false;
+ }
+
+
+ static inline void ConvertDisplayMode(const wsi::WsiMode& devMode, D3DDISPLAYMODEEX* pMode) {
+ pMode->Size = sizeof(D3DDISPLAYMODEEX);
+ pMode->Width = devMode.width;
+ pMode->Height = devMode.height;
+ pMode->RefreshRate = devMode.refreshRate.numerator / devMode.refreshRate.denominator;
+ pMode->Format = D3DFMT_X8R8G8B8;
+ pMode->ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+ }
+
+
+ D3D9SwapChainEx::D3D9SwapChainEx(
+ D3D9DeviceEx* pDevice,
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode)
+ : D3D9SwapChainExBase(pDevice)
+ , m_device (pDevice->GetDXVKDevice())
+ , m_context (m_device->createContext())
+ , m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
+ , m_frameLatencySignal(new sync::Fence(m_frameId))
+ , m_dialog (pDevice->GetOptions()->enableDialogMode) {
+ this->NormalizePresentParameters(pPresentParams);
+ m_presentParams = *pPresentParams;
+ m_window = m_presentParams.hDeviceWindow;
+
+ UpdatePresentRegion(nullptr, nullptr);
+ if (!pDevice->GetOptions()->deferSurfaceCreation)
+ CreatePresenter();
+
+ CreateBackBuffers(m_presentParams.BackBufferCount);
+ CreateBlitter();
+ CreateHud();
+
+ InitRamp();
+
+ // Apply initial window mode and fullscreen state
+ if (!m_presentParams.Windowed && FAILED(EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode)))
+ throw DxvkError("D3D9: Failed to set initial fullscreen state");
+ }
+
+
+ D3D9SwapChainEx::~D3D9SwapChainEx() {
+ DestroyBackBuffers();
+#ifndef DXVK_NATIVE
+ ResetWindowProc(m_window);
+#endif
+
+ wsi::restoreDisplayMode(m_monitor);
+ NotifyDisplayRefreshRate(0.0);
+
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DSwapChain9)
+ || (GetParent()->IsExtended() && riid == __uuidof(IDirect3DSwapChain9Ex))) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9SwapChainEx::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::Present(
+ const RECT* pSourceRect,
+ const RECT* pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion,
+ DWORD dwFlags) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ uint32_t presentInterval = m_presentParams.PresentationInterval;
+
+ // This is not true directly in d3d9 to to timing differences that don't matter for us.
+ // For our purposes...
+ // D3DPRESENT_INTERVAL_DEFAULT (0) == D3DPRESENT_INTERVAL_ONE (1) which means VSYNC.
+ presentInterval = std::max(presentInterval, 1u);
+
+ if (presentInterval == D3DPRESENT_INTERVAL_IMMEDIATE || (dwFlags & D3DPRESENT_FORCEIMMEDIATE))
+ presentInterval = 0;
+
+ auto options = m_parent->GetOptions();
+
+ if (options->presentInterval >= 0)
+ presentInterval = options->presentInterval;
+
+ bool vsync = presentInterval != 0;
+
+ HWND window = m_presentParams.hDeviceWindow;
+ if (hDestWindowOverride != nullptr)
+ window = hDestWindowOverride;
+
+ bool recreate = false;
+ recreate |= m_presenter == nullptr;
+ recreate |= window != m_window;
+ recreate |= m_dialog != m_lastDialog;
+
+ m_window = window;
+
+ m_dirty |= vsync != m_vsync;
+ m_dirty |= UpdatePresentRegion(pSourceRect, pDestRect);
+ m_dirty |= recreate;
+ m_dirty |= m_presenter != nullptr &&
+ !m_presenter->hasSwapChain();
+
+ m_vsync = vsync;
+
+ m_lastDialog = m_dialog;
+
+ try {
+ if (recreate)
+ CreatePresenter();
+
+ if (std::exchange(m_dirty, false))
+ RecreateSwapChain(vsync);
+
+ // We aren't going to device loss simply because
+ // 99% of D3D9 games don't handle this properly and
+ // just end up crashing (like with alt-tab loss)
+ if (!m_presenter->hasSwapChain())
+ return D3D_OK;
+
+ PresentImage(presentInterval);
+ return D3D_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_DEVICEREMOVED;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetFrontBufferData(IDirect3DSurface9* pDestSurface) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ // This function can do absolutely everything!
+ // Copies the front buffer between formats with an implicit resolve.
+ // Oh, and the dest is systemmem...
+ // This is a slow function anyway, it waits for the copy to finish.
+ // so there's no reason to not just make and throwaway temp images.
+
+ // If extent of dst > src, then we blit to a subrect of the size
+ // of src onto a temp image of dst's extents,
+ // then copy buffer back to dst (given dst is subresource)
+
+ D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
+
+ if (unlikely(dst == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
+ D3D9CommonTexture* srcTexInfo = m_backBuffers.back()->GetCommonTexture();
+
+ if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM))
+ return D3DERR_INVALIDCALL;
+
+ Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
+ Rc<DxvkImage> srcImage = srcTexInfo->GetImage();
+
+ if (srcImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT) {
+ DxvkImageCreateInfo resolveInfo;
+ resolveInfo.type = VK_IMAGE_TYPE_2D;
+ resolveInfo.format = srcImage->info().format;
+ resolveInfo.flags = 0;
+ resolveInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ resolveInfo.extent = srcImage->info().extent;
+ resolveInfo.numLayers = 1;
+ resolveInfo.mipLevels = 1;
+ resolveInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT
+ | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ resolveInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+ | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ | VK_PIPELINE_STAGE_TRANSFER_BIT;
+ resolveInfo.access = VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ resolveInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ resolveInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ Rc<DxvkImage> resolvedSrc = m_device->createImage(
+ resolveInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ m_parent->EmitCs([
+ cDstImage = resolvedSrc,
+ cSrcImage = srcImage
+ ] (DxvkContext* ctx) {
+ VkImageSubresourceLayers resolveSubresource;
+ resolveSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ resolveSubresource.mipLevel = 0;
+ resolveSubresource.baseArrayLayer = 0;
+ resolveSubresource.layerCount = 1;
+
+ VkImageResolve resolveRegion;
+ resolveRegion.srcSubresource = resolveSubresource;
+ resolveRegion.srcOffset = VkOffset3D { 0, 0, 0 };
+ resolveRegion.dstSubresource = resolveSubresource;
+ resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 };
+ resolveRegion.extent = cSrcImage->info().extent;
+
+ ctx->resolveImage(
+ cDstImage, cSrcImage,
+ resolveRegion, VK_FORMAT_UNDEFINED);
+ });
+
+ srcImage = std::move(resolvedSrc);
+ }
+
+ D3D9Format srcFormat = srcTexInfo->Desc()->Format;
+ D3D9Format dstFormat = dstTexInfo->Desc()->Format;
+
+ bool similar = AreFormatsSimilar(srcFormat, dstFormat);
+
+ if (!similar || srcImage->info().extent != dstTexInfo->GetExtent()) {
+ DxvkImageCreateInfo blitCreateInfo;
+ blitCreateInfo.type = VK_IMAGE_TYPE_2D;
+ blitCreateInfo.format = dstTexInfo->GetFormatMapping().FormatColor;
+ blitCreateInfo.flags = 0;
+ blitCreateInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ blitCreateInfo.extent = dstTexInfo->GetExtent();
+ blitCreateInfo.numLayers = 1;
+ blitCreateInfo.mipLevels = 1;
+ blitCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT
+ | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ blitCreateInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+ | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ | VK_PIPELINE_STAGE_TRANSFER_BIT;
+ blitCreateInfo.access = VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ blitCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ blitCreateInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ Rc<DxvkImage> blittedSrc = m_device->createImage(
+ blitCreateInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(blittedSrc->info().format);
+ const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
+
+ const VkImageSubresource dstSubresource = dstTexInfo->GetSubresourceFromIndex(dstFormatInfo->aspectMask, 0);
+ const VkImageSubresource srcSubresource = srcTexInfo->GetSubresourceFromIndex(srcFormatInfo->aspectMask, 0);
+
+ VkImageSubresourceLayers dstSubresourceLayers = {
+ dstSubresource.aspectMask,
+ dstSubresource.mipLevel,
+ dstSubresource.arrayLayer, 1 };
+
+ VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+
+ VkExtent3D srcExtent = srcImage->mipLevelExtent(srcSubresource.mipLevel);
+
+ // Blit to a subrect of the src extents
+ VkImageBlit blitInfo;
+ blitInfo.dstSubresource = dstSubresourceLayers;
+ blitInfo.srcSubresource = srcSubresourceLayers;
+ blitInfo.dstOffsets[0] = VkOffset3D{ 0, 0, 0 };
+ blitInfo.dstOffsets[1] = VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
+ blitInfo.srcOffsets[0] = VkOffset3D{ 0, 0, 0 };
+ blitInfo.srcOffsets[1] = VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
+
+ m_parent->EmitCs([
+ cDstImage = blittedSrc,
+ cDstMap = dstTexInfo->GetMapping().Swizzle,
+ cSrcImage = srcImage,
+ cSrcMap = srcTexInfo->GetMapping().Swizzle,
+ cBlitInfo = blitInfo
+ ] (DxvkContext* ctx) {
+ ctx->blitImage(
+ cDstImage, cDstMap,
+ cSrcImage, cSrcMap,
+ cBlitInfo, VK_FILTER_NEAREST);
+ });
+
+ srcImage = std::move(blittedSrc);
+ }
+
+ const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format);
+ const VkImageSubresource srcSubresource = srcTexInfo->GetSubresourceFromIndex(srcFormatInfo->aspectMask, 0);
+ VkImageSubresourceLayers srcSubresourceLayers = {
+ srcSubresource.aspectMask,
+ srcSubresource.mipLevel,
+ srcSubresource.arrayLayer, 1 };
+ VkExtent3D srcExtent = srcImage->mipLevelExtent(srcSubresource.mipLevel);
+
+ m_parent->EmitCs([
+ cBuffer = dstBuffer,
+ cImage = srcImage,
+ cSubresources = srcSubresourceLayers,
+ cLevelExtent = srcExtent
+ ] (DxvkContext* ctx) {
+ ctx->copyImageToBuffer(cBuffer, 0, 4, 0,
+ cImage, cSubresources, VkOffset3D { 0, 0, 0 },
+ cLevelExtent);
+ });
+
+ dstTexInfo->SetWrittenByGPU(dst->GetSubresource(), true);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetBackBuffer(
+ UINT iBackBuffer,
+ D3DBACKBUFFER_TYPE Type,
+ IDirect3DSurface9** ppBackBuffer) {
+ // Could be doing a device reset...
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ if (unlikely(ppBackBuffer == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(iBackBuffer >= m_presentParams.BackBufferCount)) {
+ Logger::err(str::format("D3D9: GetBackBuffer: Invalid back buffer index: ", iBackBuffer));
+ return D3DERR_INVALIDCALL;
+ }
+
+ *ppBackBuffer = ref(m_backBuffers[iBackBuffer].ptr());
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetRasterStatus(D3DRASTER_STATUS* pRasterStatus) {
+ // We could use D3DKMTGetScanLine but Wine doesn't implement that.
+ // So... we lie here and make some stuff up
+ // enough that it makes games work.
+
+ // Assume there's 20 lines in a vBlank.
+ constexpr uint32_t vBlankLineCount = 20;
+
+ if (pRasterStatus == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ D3DDISPLAYMODEEX mode;
+ mode.Size = sizeof(mode);
+ if (FAILED(this->GetDisplayModeEx(&mode, nullptr)))
+ return D3DERR_INVALIDCALL;
+
+ uint32_t scanLineCount = mode.Height + vBlankLineCount;
+
+ auto nowUs = std::chrono::time_point_cast<std::chrono::microseconds>(
+ dxvk::high_resolution_clock::now())
+ .time_since_epoch();
+
+ auto frametimeUs = std::chrono::microseconds(1000000u / mode.RefreshRate);
+ auto scanLineUs = frametimeUs / scanLineCount;
+
+ pRasterStatus->ScanLine = (nowUs % frametimeUs) / scanLineUs;
+ pRasterStatus->InVBlank = pRasterStatus->ScanLine >= mode.Height;
+
+ if (pRasterStatus->InVBlank)
+ pRasterStatus->ScanLine = 0;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetDisplayMode(D3DDISPLAYMODE* pMode) {
+ if (pMode == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *pMode = D3DDISPLAYMODE();
+
+ D3DDISPLAYMODEEX mode;
+ mode.Size = sizeof(mode);
+ HRESULT hr = this->GetDisplayModeEx(&mode, nullptr);
+
+ if (FAILED(hr))
+ return hr;
+
+ pMode->Width = mode.Width;
+ pMode->Height = mode.Height;
+ pMode->Format = mode.Format;
+ pMode->RefreshRate = mode.RefreshRate;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetPresentParameters(D3DPRESENT_PARAMETERS* pPresentationParameters) {
+ if (pPresentationParameters == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *pPresentationParameters = m_presentParams;
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetLastPresentCount(UINT* pLastPresentCount) {
+ Logger::warn("D3D9SwapChainEx::GetLastPresentCount: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetPresentStats(D3DPRESENTSTATS* pPresentationStatistics) {
+ Logger::warn("D3D9SwapChainEx::GetPresentStats: Stub");
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9SwapChainEx::GetDisplayModeEx(D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) {
+ if (pMode == nullptr && pRotation == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ if (pRotation != nullptr)
+ *pRotation = D3DDISPLAYROTATION_IDENTITY;
+
+ if (pMode != nullptr) {
+ wsi::WsiMode devMode = { };
+
+ if (!wsi::getCurrentDisplayMode(GetDefaultMonitor(), &devMode)) {
+ Logger::err("D3D9SwapChainEx::GetDisplayModeEx: Failed to enum display settings");
+ return D3DERR_INVALIDCALL;
+ }
+
+ ConvertDisplayMode(devMode, pMode);
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9SwapChainEx::Reset(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ this->SynchronizePresent();
+ this->NormalizePresentParameters(pPresentParams);
+
+ m_dirty |= m_presentParams.BackBufferFormat != pPresentParams->BackBufferFormat
+ || m_presentParams.BackBufferCount != pPresentParams->BackBufferCount;
+
+ bool changeFullscreen = m_presentParams.Windowed != pPresentParams->Windowed;
+
+ if (pPresentParams->Windowed) {
+ if (changeFullscreen)
+ this->LeaveFullscreenMode();
+
+ wsi::resizeWindow(
+ m_window, &m_windowState,
+ pPresentParams->BackBufferWidth,
+ pPresentParams->BackBufferHeight);
+ }
+ else {
+ if (changeFullscreen) {
+ if (FAILED(this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode)))
+ return D3DERR_INVALIDCALL;
+ }
+
+#ifdef _WIN32
+ D3D9WindowMessageFilter filter(m_window);
+#endif
+
+ if (!changeFullscreen) {
+ if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode, false)))
+ return D3DERR_INVALIDCALL;
+ }
+ }
+
+ m_presentParams = *pPresentParams;
+
+ if (changeFullscreen)
+ SetGammaRamp(0, &m_ramp);
+
+ CreateBackBuffers(m_presentParams.BackBufferCount);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9SwapChainEx::WaitForVBlank() {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("D3D9SwapChainEx::WaitForVBlank: Stub");
+
+ return D3D_OK;
+ }
+
+ static bool validateGammaRamp(const WORD (&ramp)[256]) {
+ if (ramp[0] >= ramp[std::size(ramp) - 1]) {
+ Logger::err("validateGammaRamp: ramp inverted or flat");
+ return false;
+ }
+
+ for (size_t i = 1; i < std::size(ramp); i++) {
+ if (ramp[i] < ramp[i - 1]) {
+ Logger::err("validateGammaRamp: ramp not monotonically increasing");
+ return false;
+ }
+ if (ramp[i] - ramp[i - 1] >= UINT16_MAX / 2) {
+ Logger::err("validateGammaRamp: huuuge jump");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ void D3D9SwapChainEx::SetGammaRamp(
+ DWORD Flags,
+ const D3DGAMMARAMP* pRamp) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ if (unlikely(pRamp == nullptr))
+ return;
+
+ if (unlikely(!validateGammaRamp(pRamp->red)
+ && !validateGammaRamp(pRamp->blue)
+ && !validateGammaRamp(pRamp->green)))
+ return;
+
+ m_ramp = *pRamp;
+
+ bool isIdentity = true;
+
+ std::array<DxvkGammaCp, NumControlPoints> cp;
+
+ for (uint32_t i = 0; i < NumControlPoints; i++) {
+ uint16_t identity = MapGammaControlPoint(float(i) / float(NumControlPoints - 1));
+
+ cp[i].r = pRamp->red[i];
+ cp[i].g = pRamp->green[i];
+ cp[i].b = pRamp->blue[i];
+ cp[i].a = 0;
+
+ isIdentity &= cp[i].r == identity
+ && cp[i].g == identity
+ && cp[i].b == identity;
+ }
+
+ if (!isIdentity && !m_presentParams.Windowed)
+ m_blitter->setGammaRamp(NumControlPoints, cp.data());
+ else
+ m_blitter->setGammaRamp(0, nullptr);
+ }
+
+
+ void D3D9SwapChainEx::GetGammaRamp(D3DGAMMARAMP* pRamp) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ if (likely(pRamp != nullptr))
+ *pRamp = m_ramp;
+ }
+
+
+ void D3D9SwapChainEx::Invalidate(HWND hWindow) {
+ if (hWindow == nullptr)
+ hWindow = m_parent->GetWindow();
+
+ if (m_presentParams.hDeviceWindow == hWindow) {
+ m_presenter = nullptr;
+
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+ }
+ }
+
+
+ HRESULT D3D9SwapChainEx::SetDialogBoxMode(bool bEnableDialogs) {
+ D3D9DeviceLock lock = m_parent->LockDevice();
+
+ // https://docs.microsoft.com/en-us/windows/win32/api/d3d9/nf-d3d9-idirect3ddevice9-setdialogboxmode
+ // The MSDN documentation says this will error out under many weird conditions.
+ // However it doesn't appear to error at all in any of my tests of these
+ // cases described in the documentation.
+
+ m_dialog = bEnableDialogs;
+
+ return D3D_OK;
+ }
+
+
+ D3D9Surface* D3D9SwapChainEx::GetBackBuffer(UINT iBackBuffer) {
+ if (iBackBuffer >= m_presentParams.BackBufferCount)
+ return nullptr;
+
+ return m_backBuffers[iBackBuffer].ptr();
+ }
+
+
+ void D3D9SwapChainEx::NormalizePresentParameters(D3DPRESENT_PARAMETERS* pPresentParams) {
+ if (pPresentParams->hDeviceWindow == nullptr)
+ pPresentParams->hDeviceWindow = m_parent->GetWindow();
+
+ pPresentParams->BackBufferCount = std::max(pPresentParams->BackBufferCount, 1u);
+
+ const int32_t forcedMSAA = m_parent->GetOptions()->forceSwapchainMSAA;
+ if (forcedMSAA != -1) {
+ pPresentParams->MultiSampleType = D3DMULTISAMPLE_TYPE(forcedMSAA);
+ pPresentParams->MultiSampleQuality = 0;
+ }
+
+ if (pPresentParams->Windowed) {
+ GetWindowClientSize(pPresentParams->hDeviceWindow,
+ pPresentParams->BackBufferWidth ? nullptr : &pPresentParams->BackBufferWidth,
+ pPresentParams->BackBufferHeight ? nullptr : &pPresentParams->BackBufferHeight);
+ }
+ else {
+ GetMonitorClientSize(GetDefaultMonitor(),
+ pPresentParams->BackBufferWidth ? nullptr : &pPresentParams->BackBufferWidth,
+ pPresentParams->BackBufferHeight ? nullptr : &pPresentParams->BackBufferHeight);
+ }
+
+ if (pPresentParams->BackBufferFormat == D3DFMT_UNKNOWN)
+ pPresentParams->BackBufferFormat = D3DFMT_X8R8G8B8;
+
+ if (env::getEnvVar("DXVK_FORCE_WINDOWED") == "1")
+ pPresentParams->Windowed = TRUE;
+ }
+
+
+ void D3D9SwapChainEx::PresentImage(UINT SyncInterval) {
+ m_parent->Flush();
+
+ // Retrieve the image and image view to present
+ auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
+ auto swapImageView = m_backBuffers[0]->GetImageView(false);
+
+ // Bump our frame id.
+ ++m_frameId;
+
+ for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
+ SynchronizePresent();
+
+ // Presentation semaphores and WSI swap chain image
+ vk::PresenterInfo info = m_presenter->info();
+ vk::PresenterSync sync;
+
+ uint32_t imageIndex = 0;
+
+ VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
+
+ while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
+ RecreateSwapChain(m_vsync);
+
+ info = m_presenter->info();
+ status = m_presenter->acquireNextImage(sync, imageIndex);
+ }
+
+ m_context->beginRecording(
+ m_device->createCommandList());
+
+ VkRect2D srcRect = {
+ { int32_t(m_srcRect.left), int32_t(m_srcRect.top) },
+ { uint32_t(m_srcRect.right - m_srcRect.left), uint32_t(m_srcRect.bottom - m_srcRect.top) } };
+
+ VkRect2D dstRect = {
+ { int32_t(m_dstRect.left), int32_t(m_dstRect.top) },
+ { uint32_t(m_dstRect.right - m_dstRect.left), uint32_t(m_dstRect.bottom - m_dstRect.top) } };
+
+ m_blitter->presentImage(m_context.ptr(),
+ m_imageViews.at(imageIndex), dstRect,
+ swapImageView, srcRect);
+
+ if (m_hud != nullptr)
+ m_hud->render(m_context, info.format, info.imageExtent);
+
+ if (i + 1 >= SyncInterval)
+ m_context->signal(m_frameLatencySignal, m_frameId);
+
+ SubmitPresent(sync, i);
+ }
+
+ SyncFrameLatency();
+
+ // Rotate swap chain buffers so that the back
+ // buffer at index 0 becomes the front buffer.
+ for (uint32_t i = 1; i < m_backBuffers.size(); i++)
+ m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr());
+
+ m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+ }
+
+
+ void D3D9SwapChainEx::SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId) {
+ // Present from CS thread so that we don't
+ // have to synchronize with it first.
+ m_presentStatus.result = VK_NOT_READY;
+
+ m_parent->EmitCs([this,
+ cFrameId = FrameId,
+ cSync = Sync,
+ cHud = m_hud,
+ cCommandList = m_context->endRecording()
+ ] (DxvkContext* ctx) {
+ m_device->submitCommandList(cCommandList,
+ cSync.acquire, cSync.present);
+
+ if (cHud != nullptr && !cFrameId)
+ cHud->update();
+
+ m_device->presentImage(m_presenter, &m_presentStatus);
+ });
+
+ m_parent->FlushCsChunk();
+ }
+
+
+ void D3D9SwapChainEx::SynchronizePresent() {
+ // Recreate swap chain if the previous present call failed
+ VkResult status = m_device->waitForSubmission(&m_presentStatus);
+
+ if (status != VK_SUCCESS)
+ RecreateSwapChain(m_vsync);
+ }
+
+
+ void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
+ // Ensure that we can safely destroy the swap chain
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+
+ m_presentStatus.result = VK_SUCCESS;
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = GetPresentExtent();
+ presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
+ presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
+ presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = PickFullscreenMode();
+
+ if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS)
+ throw DxvkError("D3D9SwapChainEx: Failed to recreate swap chain");
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D9SwapChainEx::CreatePresenter() {
+ // Ensure that we can safely destroy the swap chain
+ m_device->waitForSubmission(&m_presentStatus);
+ m_device->waitForIdle();
+
+ m_presentStatus.result = VK_SUCCESS;
+
+ DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
+
+ vk::PresenterDevice presenterDevice;
+ presenterDevice.queueFamily = graphicsQueue.queueFamily;
+ presenterDevice.queue = graphicsQueue.queueHandle;
+ presenterDevice.adapter = m_device->adapter()->handle();
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = GetPresentExtent();
+ presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
+ presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
+ presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = PickFullscreenMode();
+
+ m_presenter = new vk::Presenter(m_window,
+ m_device->adapter()->vki(),
+ m_device->vkd(),
+ presenterDevice,
+ presenterDesc);
+
+ m_presenter->setFrameRateLimit(m_parent->GetOptions()->maxFrameRate);
+ m_presenter->setFrameRateLimiterRefreshRate(m_displayRefreshRate);
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D9SwapChainEx::CreateRenderTargetViews() {
+ vk::PresenterInfo info = m_presenter->info();
+
+ m_imageViews.clear();
+ m_imageViews.resize(info.imageCount);
+
+ DxvkImageCreateInfo imageInfo;
+ imageInfo.type = VK_IMAGE_TYPE_2D;
+ imageInfo.format = info.format.format;
+ imageInfo.flags = 0;
+ imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
+ imageInfo.numLayers = 1;
+ imageInfo.mipLevels = 1;
+ imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ imageInfo.stages = 0;
+ imageInfo.access = 0;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ imageInfo.shared = VK_TRUE;
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = info.format.format;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+
+ for (uint32_t i = 0; i < info.imageCount; i++) {
+ VkImage imageHandle = m_presenter->getImage(i).image;
+
+ Rc<DxvkImage> image = new DxvkImage(
+ m_device->vkd(), imageInfo, imageHandle);
+
+ m_imageViews[i] = new DxvkImageView(
+ m_device->vkd(), image, viewInfo);
+ }
+ }
+
+
+ void D3D9SwapChainEx::DestroyBackBuffers() {
+ for (auto& backBuffer : m_backBuffers)
+ backBuffer->ClearContainer();
+
+ m_backBuffers.clear();
+ }
+
+
+ void D3D9SwapChainEx::CreateBackBuffers(uint32_t NumBackBuffers) {
+ // Explicitly destroy current swap image before
+ // creating a new one to free up resources
+ DestroyBackBuffers();
+
+ int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1;
+ m_backBuffers.resize(NumBackBuffers + NumFrontBuffer);
+
+ // Create new back buffer
+ D3D9_COMMON_TEXTURE_DESC desc;
+ desc.Width = std::max(m_presentParams.BackBufferWidth, 1u);
+ desc.Height = std::max(m_presentParams.BackBufferHeight, 1u);
+ desc.Depth = 1;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = EnumerateFormat(m_presentParams.BackBufferFormat);
+ desc.MultiSample = m_presentParams.MultiSampleType;
+ desc.MultisampleQuality = m_presentParams.MultiSampleQuality;
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.Usage = D3DUSAGE_RENDERTARGET;
+ desc.Discard = FALSE;
+ desc.IsBackBuffer = TRUE;
+ desc.IsAttachmentOnly = FALSE;
+
+ for (uint32_t i = 0; i < m_backBuffers.size(); i++)
+ m_backBuffers[i] = new D3D9Surface(m_parent, &desc, this);
+
+ auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
+
+ // Initialize the image so that we can use it. Clearing
+ // to black prevents garbled output for the first frame.
+ VkImageSubresourceRange subresources;
+ subresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ subresources.baseMipLevel = 0;
+ subresources.levelCount = 1;
+ subresources.baseArrayLayer = 0;
+ subresources.layerCount = 1;
+
+ VkClearColorValue clearColor;
+ clearColor.float32[0] = 0.0f;
+ clearColor.float32[1] = 0.0f;
+ clearColor.float32[2] = 0.0f;
+ clearColor.float32[3] = 0.0f;
+
+ m_context->beginRecording(
+ m_device->createCommandList());
+
+ for (uint32_t i = 0; i < m_backBuffers.size(); i++) {
+ m_context->clearColorImage(
+ m_backBuffers[i]->GetCommonTexture()->GetImage(),
+ clearColor, subresources);
+ }
+
+ m_device->submitCommandList(
+ m_context->endRecording(),
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE);
+ }
+
+
+ void D3D9SwapChainEx::CreateBlitter() {
+ m_blitter = new DxvkSwapchainBlitter(m_device);
+ }
+
+
+ void D3D9SwapChainEx::CreateHud() {
+ m_hud = hud::Hud::createHud(m_device);
+
+ if (m_hud != nullptr) {
+ m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
+ m_hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent);
+ }
+ }
+
+
+ void D3D9SwapChainEx::InitRamp() {
+ for (uint32_t i = 0; i < NumControlPoints; i++) {
+ DWORD identity = DWORD(MapGammaControlPoint(float(i) / float(NumControlPoints - 1)));
+
+ m_ramp.red[i] = identity;
+ m_ramp.green[i] = identity;
+ m_ramp.blue[i] = identity;
+ }
+ }
+
+
+ void D3D9SwapChainEx::SyncFrameLatency() {
+ // Wait for the sync event so that we respect the maximum frame latency
+ m_frameLatencySignal->wait(m_frameId - GetActualFrameLatency());
+ }
+
+
+ uint32_t D3D9SwapChainEx::GetActualFrameLatency() {
+ uint32_t maxFrameLatency = m_parent->GetFrameLatency();
+
+ if (m_frameLatencyCap)
+ maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap);
+
+ maxFrameLatency = std::min(maxFrameLatency, m_presentParams.BackBufferCount + 1);
+ return maxFrameLatency;
+ }
+
+
+ uint32_t D3D9SwapChainEx::PickFormats(
+ D3D9Format Format,
+ VkSurfaceFormatKHR* pDstFormats) {
+ uint32_t n = 0;
+
+ switch (Format) {
+ default:
+ Logger::warn(str::format("D3D9SwapChainEx: Unexpected format: ", Format));
+
+ case D3D9Format::A8R8G8B8:
+ case D3D9Format::X8R8G8B8:
+ case D3D9Format::A8B8G8R8:
+ case D3D9Format::X8B8G8R8: {
+ pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+
+ case D3D9Format::A2R10G10B10:
+ case D3D9Format::A2B10G10R10: {
+ pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ } break;
+
+ case D3D9Format::X1R5G5B5:
+ case D3D9Format::A1R5G5B5: {
+ pDstFormats[n++] = { VK_FORMAT_B5G5R5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ }
+
+ case D3D9Format::R5G6B5: {
+ pDstFormats[n++] = { VK_FORMAT_B5G6R5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ pDstFormats[n++] = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ }
+ }
+
+ return n;
+ }
+
+
+ uint32_t D3D9SwapChainEx::PickPresentModes(
+ BOOL Vsync,
+ VkPresentModeKHR* pDstModes) {
+ uint32_t n = 0;
+
+ if (Vsync) {
+ if (m_parent->GetOptions()->tearFree == Tristate::False)
+ pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
+ pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
+ } else {
+ if (m_parent->GetOptions()->tearFree != Tristate::True)
+ pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
+ pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
+ }
+
+ return n;
+ }
+
+
+ uint32_t D3D9SwapChainEx::PickImageCount(
+ UINT Preferred) {
+ int32_t option = m_parent->GetOptions()->numBackBuffers;
+ return option > 0 ? uint32_t(option) : uint32_t(Preferred);
+ }
+
+
+ void D3D9SwapChainEx::NotifyDisplayRefreshRate(
+ double RefreshRate) {
+ m_displayRefreshRate = RefreshRate;
+
+ if (m_presenter != nullptr)
+ m_presenter->setFrameRateLimiterRefreshRate(RefreshRate);
+ }
+
+
+ HRESULT D3D9SwapChainEx::EnterFullscreenMode(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode, true))) {
+ Logger::err("D3D9: EnterFullscreenMode: Failed to change display mode");
+ return D3DERR_NOTAVAILABLE;
+ }
+
+#ifndef DXVK_NATIVE
+ // Testing shows we shouldn't hook WM_NCCALCSIZE but we shouldn't change
+ // windows style either.
+ //
+ // Some games restore window styles after we have changed it, so hooking is
+ // also required. Doing it will allow us to create fullscreen windows
+ // regardless of their style and it also appears to work on Windows.
+ HookWindowProc(m_window, this);
+
+ D3D9WindowMessageFilter filter(m_window);
+#endif
+
+ m_monitor = GetDefaultMonitor();
+
+ if (!wsi::enterFullscreenMode(m_monitor, m_window, &m_windowState, true)) {
+ Logger::err("D3D9: EnterFullscreenMode: Failed to enter fullscreen mode");
+ return D3DERR_NOTAVAILABLE;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9SwapChainEx::LeaveFullscreenMode() {
+ if (!wsi::restoreDisplayMode(m_monitor))
+ Logger::warn("D3D9: LeaveFullscreenMode: Failed to restore display mode");
+ NotifyDisplayRefreshRate(0.0);
+
+ m_monitor = nullptr;
+
+#ifndef DXVK_NATIVE
+ ResetWindowProc(m_window);
+#endif
+
+ if (!wsi::isWindow(m_window))
+ return D3D_OK;
+
+ if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) {
+ Logger::err("D3D9: LeaveFullscreenMode: Failed to exit fullscreen mode");
+ return D3DERR_NOTAVAILABLE;
+ }
+
+ return D3D_OK;
+ }
+
+
+ HRESULT D3D9SwapChainEx::ChangeDisplayMode(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ bool EnteringFullscreen) {
+ D3DDISPLAYMODEEX mode;
+
+ if (pFullscreenDisplayMode) {
+ mode = *pFullscreenDisplayMode;
+ } else {
+ mode.Width = pPresentParams->BackBufferWidth;
+ mode.Height = pPresentParams->BackBufferHeight;
+ mode.Format = pPresentParams->BackBufferFormat;
+ mode.RefreshRate = pPresentParams->FullScreen_RefreshRateInHz;
+ mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
+ mode.Size = sizeof(D3DDISPLAYMODEEX);
+ }
+
+ wsi::WsiMode wsiMode = { };
+ ConvertDisplayMode(mode, &wsiMode);
+
+ if (!wsi::setWindowMode(GetDefaultMonitor(), m_window, &wsiMode, EnteringFullscreen))
+ return D3DERR_NOTAVAILABLE;
+
+ return D3D_OK;
+ }
+
+
+ bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) {
+ if (pSourceRect == nullptr) {
+ m_srcRect.top = 0;
+ m_srcRect.left = 0;
+ m_srcRect.right = m_presentParams.BackBufferWidth;
+ m_srcRect.bottom = m_presentParams.BackBufferHeight;
+ }
+ else
+ m_srcRect = *pSourceRect;
+
+ RECT dstRect;
+ if (pDestRect == nullptr) {
+ // TODO: Should we hook WM_SIZE message for this?
+ UINT width, height;
+ GetWindowClientSize(m_window, &width, &height);
+
+ dstRect.top = 0;
+ dstRect.left = 0;
+ dstRect.right = LONG(width);
+ dstRect.bottom = LONG(height);
+ }
+ else
+ dstRect = *pDestRect;
+
+ bool recreate =
+ m_dstRect.left != dstRect.left
+ || m_dstRect.top != dstRect.top
+ || m_dstRect.right != dstRect.right
+ || m_dstRect.bottom != dstRect.bottom;
+
+ m_dstRect = dstRect;
+
+ return recreate;
+ }
+
+ VkExtent2D D3D9SwapChainEx::GetPresentExtent() {
+ return VkExtent2D {
+ std::max<uint32_t>(m_dstRect.right - m_dstRect.left, 1u),
+ std::max<uint32_t>(m_dstRect.bottom - m_dstRect.top, 1u) };
+ }
+
+
+ VkFullScreenExclusiveEXT D3D9SwapChainEx::PickFullscreenMode() {
+ return m_dialog
+ ? VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT
+ : VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT;
+ }
+
+
+ std::string D3D9SwapChainEx::GetApiName() {
+ return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9";
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.h
new file mode 100644
index 00000000..88953b2a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swapchain.h
@@ -0,0 +1,192 @@
+#pragma once
+
+#include "d3d9_device_child.h"
+#include "d3d9_device.h"
+#include "d3d9_format.h"
+
+#include "../dxvk/hud/dxvk_hud.h"
+
+#include "../dxvk/dxvk_swapchain_blitter.h"
+#include "../wsi/wsi_mode.h"
+#include "../wsi/wsi_window.h"
+#include "../wsi/wsi_monitor.h"
+
+#include "../util/sync/sync_signal.h"
+
+#include <vector>
+
+namespace dxvk {
+
+ class D3D9Surface;
+
+ using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
+ class D3D9SwapChainEx final : public D3D9SwapChainExBase {
+ static constexpr uint32_t NumControlPoints = 256;
+ public:
+
+ D3D9SwapChainEx(
+ D3D9DeviceEx* pDevice,
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ ~D3D9SwapChainEx();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE Present(
+ const RECT* pSourceRect,
+ const RECT* pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA* pDirtyRegion,
+ DWORD dwFlags);
+
+ HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
+
+ HRESULT STDMETHODCALLTYPE GetBackBuffer(
+ UINT iBackBuffer,
+ D3DBACKBUFFER_TYPE Type,
+ IDirect3DSurface9** ppBackBuffer);
+
+ HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS* pRasterStatus);
+
+ HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE* pMode);
+
+ HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS* pPresentationParameters);
+
+ HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT* pLastPresentCount);
+
+ HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS* pPresentationStatistics);
+
+ HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation);
+
+ HRESULT Reset(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ HRESULT WaitForVBlank();
+
+ void SetGammaRamp(
+ DWORD Flags,
+ const D3DGAMMARAMP* pRamp);
+
+ void GetGammaRamp(D3DGAMMARAMP* pRamp);
+
+ void Invalidate(HWND hWindow);
+
+ HRESULT SetDialogBoxMode(bool bEnableDialogs);
+
+ D3D9Surface* GetBackBuffer(UINT iBackBuffer);
+
+ const D3DPRESENT_PARAMETERS* GetPresentParams() const { return &m_presentParams; }
+
+ void SyncFrameLatency();
+
+ private:
+
+ enum BindingIds : uint32_t {
+ Image = 0,
+ Gamma = 1,
+ };
+
+ D3DPRESENT_PARAMETERS m_presentParams;
+ D3DGAMMARAMP m_ramp;
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkContext> m_context;
+ Rc<DxvkSwapchainBlitter> m_blitter;
+
+ Rc<vk::Presenter> m_presenter;
+
+ Rc<hud::Hud> m_hud;
+
+ std::vector<Com<D3D9Surface, false>> m_backBuffers;
+
+ RECT m_srcRect;
+ RECT m_dstRect;
+
+ DxvkSubmitStatus m_presentStatus;
+
+ std::vector<Rc<DxvkImageView>> m_imageViews;
+
+
+ uint64_t m_frameId = D3D9DeviceEx::MaxFrameLatency;
+ uint32_t m_frameLatencyCap = 0;
+ Rc<sync::Fence> m_frameLatencySignal;
+
+ bool m_dirty = true;
+ bool m_vsync = true;
+
+ bool m_dialog;
+ bool m_lastDialog = false;
+
+ HWND m_window = nullptr;
+ HMONITOR m_monitor = nullptr;
+
+ wsi::DxvkWindowState m_windowState;
+
+ double m_displayRefreshRate = 0.0;
+
+ void PresentImage(UINT PresentInterval);
+
+ void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);
+
+ void SynchronizePresent();
+
+ void RecreateSwapChain(
+ BOOL Vsync);
+
+ void CreatePresenter();
+
+ void CreateRenderTargetViews();
+
+ void DestroyBackBuffers();
+
+ void CreateBackBuffers(
+ uint32_t NumBackBuffers);
+
+ void CreateBlitter();
+
+ void CreateHud();
+
+ void InitRamp();
+
+ uint32_t GetActualFrameLatency();
+
+ uint32_t PickFormats(
+ D3D9Format Format,
+ VkSurfaceFormatKHR* pDstFormats);
+
+ uint32_t PickPresentModes(
+ BOOL Vsync,
+ VkPresentModeKHR* pDstModes);
+
+ uint32_t PickImageCount(
+ UINT Preferred);
+
+ void NormalizePresentParameters(D3DPRESENT_PARAMETERS* pPresentParams);
+
+ void NotifyDisplayRefreshRate(
+ double RefreshRate);
+
+ HRESULT EnterFullscreenMode(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
+
+ HRESULT LeaveFullscreenMode();
+
+ HRESULT ChangeDisplayMode(
+ D3DPRESENT_PARAMETERS* pPresentParams,
+ const D3DDISPLAYMODEEX* pFullscreenDisplayMode,
+ bool EnteringFullscreen);
+
+ bool UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect);
+
+ VkExtent2D GetPresentExtent();
+
+ VkFullScreenExclusiveEXT PickFullscreenMode();
+
+ std::string GetApiName();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.cpp
new file mode 100644
index 00000000..9b3b0270
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.cpp
@@ -0,0 +1,359 @@
+#include "d3d9_swvp_emu.h"
+
+#include "d3d9_device.h"
+#include "d3d9_vertex_declaration.h"
+
+#include "../spirv/spirv_module.h"
+
+namespace dxvk {
+
+ // Doesn't compare everything, only what we use in SWVP.
+
+ size_t D3D9VertexDeclHash::operator () (const D3D9VertexElements& key) const {
+ DxvkHashState hash;
+
+ std::hash<BYTE> bytehash;
+ std::hash<WORD> wordhash;
+
+ for (auto& element : key) {
+ hash.add(wordhash(element.Stream));
+ hash.add(wordhash(element.Offset));
+ hash.add(bytehash(element.Type));
+ hash.add(bytehash(element.Method));
+ hash.add(bytehash(element.Usage));
+ hash.add(bytehash(element.UsageIndex));
+ }
+
+ return hash;
+ }
+
+ bool D3D9VertexDeclEq::operator () (const D3D9VertexElements& a, const D3D9VertexElements& b) const {
+ if (a.size() != b.size())
+ return false;
+
+ bool equal = true;
+
+ for (uint32_t i = 0; i < a.size(); i++)
+ equal &= std::memcmp(&a[i], &b[i], sizeof(a[0])) == 0;
+
+ return equal;
+ }
+
+ enum class DecltypeClass {
+ Float, Byte, Short, Dec, Half
+ };
+
+ enum DecltypeFlags {
+ Signed = 1,
+ Normalize = 2,
+ ReverseRGB = 4
+ };
+
+ struct Decltype {
+ DecltypeClass Class;
+ uint32_t VectorCount;
+ uint32_t Flags;
+ };
+
+ Decltype ClassifyDecltype(D3DDECLTYPE Type) {
+ switch (Type) {
+ case D3DDECLTYPE_FLOAT1: return { DecltypeClass::Float, 1, DecltypeFlags::Signed };
+ case D3DDECLTYPE_FLOAT2: return { DecltypeClass::Float, 2, DecltypeFlags::Signed };
+ case D3DDECLTYPE_FLOAT3: return { DecltypeClass::Float, 3, DecltypeFlags::Signed };
+ case D3DDECLTYPE_FLOAT4: return { DecltypeClass::Float, 4, DecltypeFlags::Signed };
+ case D3DDECLTYPE_D3DCOLOR: return { DecltypeClass::Byte, 4, DecltypeFlags::Normalize | DecltypeFlags::ReverseRGB };
+ case D3DDECLTYPE_UBYTE4: return { DecltypeClass::Byte, 4, 0 };
+ case D3DDECLTYPE_SHORT2: return { DecltypeClass::Short, 2, DecltypeFlags::Signed };
+ case D3DDECLTYPE_SHORT4: return { DecltypeClass::Short, 4, DecltypeFlags::Signed };
+ case D3DDECLTYPE_UBYTE4N: return { DecltypeClass::Byte, 4, DecltypeFlags::Normalize };
+ case D3DDECLTYPE_SHORT2N: return { DecltypeClass::Short, 2, DecltypeFlags::Signed | DecltypeFlags::Normalize };
+ case D3DDECLTYPE_SHORT4N: return { DecltypeClass::Short, 4, DecltypeFlags::Signed | DecltypeFlags::Normalize };
+ case D3DDECLTYPE_USHORT2N: return { DecltypeClass::Short, 2, DecltypeFlags::Normalize };
+ case D3DDECLTYPE_USHORT4N: return { DecltypeClass::Short, 4, DecltypeFlags::Normalize };
+ case D3DDECLTYPE_UDEC3: return { DecltypeClass::Dec, 3, 0 };
+ case D3DDECLTYPE_DEC3N: return { DecltypeClass::Dec, 3, DecltypeFlags::Signed | DecltypeFlags::Normalize };
+ case D3DDECLTYPE_FLOAT16_2: return { DecltypeClass::Half, 2, DecltypeFlags::Signed };
+ case D3DDECLTYPE_FLOAT16_4: return { DecltypeClass::Half, 4, DecltypeFlags::Signed };
+ default: return { DecltypeClass::Float, 4, DecltypeFlags::Signed };
+ }
+ }
+
+ class D3D9SWVPEmulatorGenerator {
+
+ public:
+
+ D3D9SWVPEmulatorGenerator(const std::string& name)
+ : m_module(spvVersion(1, 3)) {
+ m_entryPointId = m_module.allocateId();
+
+ m_module.setDebugSource(
+ spv::SourceLanguageUnknown, 0,
+ m_module.addDebugString(name.c_str()),
+ nullptr);
+
+ m_module.setMemoryModel(
+ spv::AddressingModelLogical,
+ spv::MemoryModelGLSL450);
+
+ m_module.enableCapability(spv::CapabilityGeometry);
+
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeInputPoints);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeOutputPoints);
+ // This has to be > 0 for some reason even though
+ // we will never emit a vertex
+ m_module.setOutputVertices(m_entryPointId, 1);
+ m_module.setInvocations(m_entryPointId, 1);
+
+ m_module.functionBegin(m_module.defVoidType(), m_entryPointId, m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr), spv::FunctionControlMaskNone);
+ m_module.opLabel(m_module.allocateId());
+ }
+
+ void compile(const D3D9VertexDecl* pDecl) {
+ uint32_t uint_t = m_module.defIntType(32, false);
+ uint32_t float_t = m_module.defFloatType(32);
+ uint32_t vec4_t = m_module.defVectorType(float_t, 4);
+
+ uint32_t vec4_singular_array_t = m_module.defArrayType(vec4_t, m_module.constu32(1));
+
+ // Setup the buffer
+ uint32_t bufferSlot = getSWVPBufferSlot();
+
+ uint32_t arrayType = m_module.defRuntimeArrayTypeUnique(uint_t);
+ m_module.decorateArrayStride(arrayType, sizeof(uint32_t));
+
+ uint32_t buffer_t = m_module.defStructTypeUnique(1, &arrayType);
+ m_module.memberDecorateOffset(buffer_t, 0, 0);
+ m_module.decorate(buffer_t, spv::DecorationBufferBlock);
+
+ uint32_t buffer = m_module.newVar(m_module.defPointerType(buffer_t, spv::StorageClassUniform), spv::StorageClassUniform);
+ m_module.decorateDescriptorSet(buffer, 0);
+ m_module.decorateBinding(buffer, bufferSlot);
+
+ DxvkResourceSlot bufferRes;
+ bufferRes.slot = bufferSlot;
+ bufferRes.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ bufferRes.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ bufferRes.access = VK_ACCESS_SHADER_WRITE_BIT;
+ m_resourceSlots.push_back(bufferRes);
+
+ // Load our builtins
+ uint32_t primitiveIdPtr = m_module.newVar(m_module.defPointerType(uint_t, spv::StorageClassInput), spv::StorageClassInput);
+ m_module.decorateBuiltIn(primitiveIdPtr, spv::BuiltInPrimitiveId);
+ m_entryPointInterfaces.push_back(primitiveIdPtr);
+
+ uint32_t primitiveId = m_module.opLoad(uint_t, primitiveIdPtr);
+
+ // The size of any given vertex
+ uint32_t vertexSize = m_module.constu32(pDecl->GetSize() / sizeof(uint32_t));
+
+ //The offset of this vertex from the beginning of the buffer
+ uint32_t thisVertexOffset = m_module.opIMul(uint_t, vertexSize, primitiveId);
+
+
+ for (auto& element : pDecl->GetElements()) {
+ // Load the slot associated with this element
+ DxsoSemantic semantic = { DxsoUsage(element.Usage), element.UsageIndex };
+
+ uint32_t elementPtr;
+ uint32_t elementVar;
+
+ elementPtr = m_module.newVar(m_module.defPointerType(vec4_singular_array_t, spv::StorageClassInput), spv::StorageClassInput);
+ if ((semantic.usage == DxsoUsage::Position || semantic.usage == DxsoUsage::PositionT) && element.UsageIndex == 0) {
+ // Load from builtin
+ m_module.decorateBuiltIn(elementPtr, spv::BuiltInPosition);
+ }
+ else {
+ // Load from slot
+ uint32_t slotIdx = RegisterLinkerSlot(semantic);
+
+ m_module.decorateLocation(elementPtr, slotIdx);
+ m_interfaceSlots.inputSlots |= 1u << slotIdx;
+ }
+
+ uint32_t zero = m_module.constu32(0);
+ elementVar = m_module.opAccessChain(m_module.defPointerType(vec4_t, spv::StorageClassInput), elementPtr, 1, &zero);
+ elementVar = m_module.opLoad(vec4_t, elementVar);
+
+ m_entryPointInterfaces.push_back(elementPtr);
+
+ // The offset of this element from the beginning of any given vertex
+ uint32_t perVertexElementOffset = m_module.constu32(element.Offset / sizeof(uint32_t));
+
+ // The offset of this element from the beginning of the buffer for **THIS** vertex
+ uint32_t elementOffset = m_module.opIAdd(uint_t, thisVertexOffset, perVertexElementOffset);
+
+ // Write to the buffer at the element offset for each part of the vector.
+ Decltype elementInfo = ClassifyDecltype(D3DDECLTYPE(element.Type));
+
+ if (elementInfo.Class == DecltypeClass::Dec) {
+ // TODO!
+ Logger::warn("Encountered DEC3/UDEC3N class, ignoring...");
+ continue;
+ }
+
+ uint32_t vecn_t = m_module.defVectorType(float_t, elementInfo.VectorCount);
+ uint32_t componentSet;
+
+ // Modifiers...
+ if (elementInfo.Flags & DecltypeFlags::ReverseRGB) {
+ std::array<uint32_t, 4> indices = { 2, 1, 0, 3 };
+ componentSet = m_module.opVectorShuffle(vecn_t, elementVar, elementVar, elementInfo.VectorCount, indices.data());
+ }
+ else {
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+ componentSet = m_module.opVectorShuffle(vecn_t, elementVar, elementVar, elementInfo.VectorCount, indices.data());
+ }
+
+ if (elementInfo.Flags & DecltypeFlags::Normalize)
+ componentSet = m_module.opVectorTimesScalar(vecn_t, componentSet, m_module.constf32(255.0f));
+
+
+ bool isSigned = elementInfo.Flags & DecltypeFlags::Signed;
+
+ // Convert the component to the correct type/value.
+ switch (elementInfo.Class) {
+ case DecltypeClass::Float: break; // Do nothing!
+ case DecltypeClass::Byte: {
+ m_module.enableCapability(spv::CapabilityInt8);
+
+ uint32_t type = m_module.defIntType(8, isSigned);
+ type = m_module.defVectorType(type, elementInfo.VectorCount);
+
+ componentSet = isSigned
+ ? m_module.opConvertFtoS(type, componentSet)
+ : m_module.opConvertFtoU(type, componentSet);
+
+ break;
+ }
+ case DecltypeClass::Short: {
+ m_module.enableCapability(spv::CapabilityInt16);
+
+ uint32_t type = m_module.defIntType(16, isSigned);
+ type = m_module.defVectorType(type, elementInfo.VectorCount);
+
+ componentSet = isSigned
+ ? m_module.opConvertFtoS(type, componentSet)
+ : m_module.opConvertFtoU(type, componentSet);
+
+ break;
+ }
+ case DecltypeClass::Half: {
+ m_module.enableCapability(spv::CapabilityFloat16);
+
+ uint32_t type = m_module.defFloatType(16);
+ type = m_module.defVectorType(type, elementInfo.VectorCount);
+ componentSet = m_module.opFConvert(type, componentSet);
+
+ break;
+ }
+ case DecltypeClass::Dec: {
+ // TODO!
+ break;
+ }
+ }
+
+ // Bitcast to dwords before we write.
+ uint32_t dwordCount = GetDecltypeSize(D3DDECLTYPE(element.Type)) / sizeof(uint32_t);
+ uint32_t dwordVector = m_module.opBitcast(
+ m_module.defVectorType(uint_t, dwordCount),
+ componentSet);
+
+ // Finally write each dword to the buffer!
+ for (uint32_t i = 0; i < dwordCount; i++) {
+ std::array<uint32_t, 2> bufferIndices = { m_module.constu32(0), elementOffset };
+
+ uint32_t writeDest = m_module.opAccessChain(m_module.defPointerType(uint_t, spv::StorageClassUniform), buffer, bufferIndices.size(), bufferIndices.data());
+ uint32_t currentDword = m_module.opCompositeExtract(uint_t, dwordVector, 1, &i);
+
+ m_module.opStore(writeDest, currentDword);
+
+ elementOffset = m_module.opIAdd(uint_t, elementOffset, m_module.constu32(1));
+ }
+ }
+ }
+
+ Rc<DxvkShader> finalize() {
+ m_module.opReturn();
+ m_module.functionEnd();
+
+ m_module.addEntryPoint(m_entryPointId,
+ spv::ExecutionModelGeometry, "main",
+ m_entryPointInterfaces.size(),
+ m_entryPointInterfaces.data());
+ m_module.setDebugName(m_entryPointId, "main");
+
+ DxvkShaderConstData constData = { };
+
+ return new DxvkShader(
+ VK_SHADER_STAGE_GEOMETRY_BIT,
+ m_resourceSlots.size(),
+ m_resourceSlots.data(),
+ m_interfaceSlots,
+ m_module.compile(),
+ DxvkShaderOptions(),
+ std::move(constData));
+ }
+
+ private:
+
+ SpirvModule m_module;
+
+ std::vector<uint32_t> m_entryPointInterfaces;
+ uint32_t m_entryPointId = 0;
+
+ std::vector<DxvkResourceSlot> m_resourceSlots;
+ DxvkInterfaceSlots m_interfaceSlots;
+
+ };
+
+ Rc<DxvkShader> D3D9SWVPEmulator::GetShaderModule(D3D9DeviceEx* pDevice, const D3D9VertexDecl* pDecl) {
+ auto& elements = pDecl->GetElements();
+
+ // Use the shader's unique key for the lookup
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto entry = m_modules.find(elements);
+ if (entry != m_modules.end())
+ return entry->second;
+ }
+
+ Sha1Hash hash = Sha1Hash::compute(
+ elements.data(), elements.size() * sizeof(elements[0]));
+
+ DxvkShaderKey key = { VK_SHADER_STAGE_GEOMETRY_BIT , hash };
+ std::string name = str::format("SWVP_", key.toString());
+
+ // This shader has not been compiled yet, so we have to create a
+ // new module. This takes a while, so we won't lock the structure.
+ D3D9SWVPEmulatorGenerator generator(name);
+ generator.compile(pDecl);
+ Rc<DxvkShader> shader = generator.finalize();
+
+ shader->setShaderKey(key);
+ pDevice->GetDXVKDevice()->registerShader(shader);
+
+ const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
+
+ if (dumpPath.size() != 0) {
+ std::ofstream dumpStream(
+ str::format(dumpPath, "/", name, ".spv"),
+ std::ios_base::binary | std::ios_base::trunc);
+
+ shader->dump(dumpStream);
+ }
+
+ // Insert the new module into the lookup table. If another thread
+ // has compiled the same shader in the meantime, we should return
+ // that object instead and discard the newly created module.
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ auto status = m_modules.insert({ elements, shader });
+ if (!status.second)
+ return status.first->second;
+ }
+
+ return shader;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.h
new file mode 100644
index 00000000..91aae4c2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_swvp_emu.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <unordered_map>
+
+#include "d3d9_include.h"
+
+#include "../dxvk/dxvk_shader.h"
+
+namespace dxvk {
+
+ class D3D9VertexDecl;
+ class D3D9DeviceEx;
+
+ struct D3D9VertexDeclHash {
+ size_t operator () (const D3D9VertexElements& key) const;
+ };
+
+ struct D3D9VertexDeclEq {
+ bool operator () (const D3D9VertexElements& a, const D3D9VertexElements& b) const;
+ };
+
+ class D3D9SWVPEmulator {
+
+ public:
+
+ Rc<DxvkShader> GetShaderModule(D3D9DeviceEx* pDevice, const D3D9VertexDecl* pDecl);
+
+ private:
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ D3D9VertexElements, Rc<DxvkShader>,
+ D3D9VertexDeclHash, D3D9VertexDeclEq> m_modules;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.cpp
new file mode 100644
index 00000000..2ef86be3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.cpp
@@ -0,0 +1,248 @@
+#include "d3d9_texture.h"
+
+#include "d3d9_util.h"
+
+namespace dxvk {
+
+ // Direct3DTexture9
+
+ D3D9Texture2D::D3D9Texture2D(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc)
+ : D3D9Texture2DBase( pDevice, pDesc, D3DRTYPE_TEXTURE ) { }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DBaseTexture9)
+ || riid == __uuidof(IDirect3DTexture9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Texture2D::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Texture2D::GetType() {
+ return D3DRTYPE_TEXTURE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->GetDesc(pDesc);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel) {
+ InitReturnPtr(ppSurfaceLevel);
+
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ppSurfaceLevel == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppSurfaceLevel = ref(GetSubresource(Level));
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->LockRect(pLockedRect, pRect, Flags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::UnlockRect(UINT Level) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->UnlockRect();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture2D::AddDirtyRect(CONST RECT* pDirtyRect) {
+ if (pDirtyRect) {
+ D3DBOX box = { UINT(pDirtyRect->left), UINT(pDirtyRect->top), UINT(pDirtyRect->right), UINT(pDirtyRect->bottom), 0, 1 };
+ m_texture.AddDirtyBox(&box, 0);
+ } else {
+ m_texture.AddDirtyBox(nullptr, 0);
+ }
+ return D3D_OK;
+ }
+
+
+ // Direct3DVolumeTexture9
+
+
+ D3D9Texture3D::D3D9Texture3D(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc)
+ : D3D9Texture3DBase( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE ) { }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DBaseTexture9)
+ || riid == __uuidof(IDirect3DVolumeTexture9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Texture3D::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Texture3D::GetType() {
+ return D3DRTYPE_VOLUMETEXTURE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->GetDesc(pDesc);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::GetVolumeLevel(UINT Level, IDirect3DVolume9** ppVolumeLevel) {
+ InitReturnPtr(ppVolumeLevel);
+
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ppVolumeLevel == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppVolumeLevel = ref(GetSubresource(Level));
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->LockBox(pLockedBox, pBox, Flags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::UnlockBox(UINT Level) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->UnlockBox();
+ }
+
+ HRESULT STDMETHODCALLTYPE D3D9Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) {
+ m_texture.AddDirtyBox(pDirtyBox, 0);
+ return D3D_OK;
+ }
+
+
+ // Direct3DCubeTexture9
+
+
+ D3D9TextureCube::D3D9TextureCube(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc)
+ : D3D9TextureCubeBase( pDevice, pDesc, D3DRTYPE_CUBETEXTURE ) { }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DBaseTexture9)
+ || riid == __uuidof(IDirect3DCubeTexture9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9TextureCube::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE D3D9TextureCube::GetType() {
+ return D3DRTYPE_CUBETEXTURE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
+ if (unlikely(Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(Level)->GetDesc(pDesc);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface9** ppSurfaceLevel) {
+ InitReturnPtr(ppSurfaceLevel);
+
+ if (unlikely(Level >= m_texture.ExposedMipLevels() || Face >= D3DCUBEMAP_FACES(6)))
+ return D3DERR_INVALIDCALL;
+
+ if (unlikely(ppSurfaceLevel == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ *ppSurfaceLevel = ref(GetSubresource(m_texture.CalcSubresource(UINT(Face), Level)));
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::LockRect(D3DCUBEMAP_FACES Face, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
+ if (unlikely(Face > D3DCUBEMAP_FACE_NEGATIVE_Z || Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(m_texture.CalcSubresource(UINT(Face), Level))->LockRect(pLockedRect, pRect, Flags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) {
+ if (unlikely(Face > D3DCUBEMAP_FACE_NEGATIVE_Z || Level >= m_texture.ExposedMipLevels()))
+ return D3DERR_INVALIDCALL;
+
+ return GetSubresource(m_texture.CalcSubresource(UINT(Face), Level))->UnlockRect();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9TextureCube::AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect) {
+ if (pDirtyRect) {
+ D3DBOX box = { UINT(pDirtyRect->left), UINT(pDirtyRect->top), UINT(pDirtyRect->right), UINT(pDirtyRect->bottom), 0, 1 };
+ m_texture.AddDirtyBox(&box, Face);
+ } else {
+ m_texture.AddDirtyBox(nullptr, Face);
+ }
+ return D3D_OK;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.h
new file mode 100644
index 00000000..cfe6ecc2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_texture.h
@@ -0,0 +1,241 @@
+#pragma once
+
+#include "d3d9_device.h"
+#include "d3d9_surface.h"
+#include "d3d9_volume.h"
+#include "d3d9_util.h"
+
+#include <vector>
+#include <list>
+#include <mutex>
+#include <new>
+#include <type_traits>
+
+namespace dxvk {
+
+ template <typename SubresourceType, typename... Base>
+ class D3D9BaseTexture : public D3D9Resource<Base...> {
+
+ public:
+
+ using SubresourceData = std::aligned_storage_t<sizeof(SubresourceType), alignof(SubresourceType)>;
+
+ D3D9BaseTexture(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc,
+ D3DRESOURCETYPE ResourceType)
+ : D3D9Resource<Base...> ( pDevice )
+ , m_texture ( pDevice, pDesc, ResourceType )
+ , m_lod ( 0 ) {
+ const uint32_t arraySlices = m_texture.Desc()->ArraySize;
+ const uint32_t mipLevels = m_texture.Desc()->MipLevels;
+
+ m_subresources.resize(arraySlices * mipLevels);
+
+ for (uint32_t i = 0; i < arraySlices; i++) {
+ for (uint32_t j = 0; j < mipLevels; j++) {
+ const uint32_t subresource = m_texture.CalcSubresource(i, j);
+
+ SubresourceType* subObj = this->GetSubresource(subresource);
+
+ new (subObj) SubresourceType(
+ pDevice,
+ &m_texture,
+ i, j,
+ this);
+ }
+ }
+ }
+
+ ~D3D9BaseTexture() {
+ for (uint32_t i = 0; i < m_subresources.size(); i++) {
+ SubresourceType* subObj = this->GetSubresource(i);
+ subObj->~SubresourceType();
+ }
+ }
+
+ DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
+ DWORD oldLod = m_lod;
+ m_lod = LODNew;
+
+ m_texture.CreateSampleView(LODNew);
+ if (this->GetPrivateRefCount() > 0)
+ this->m_parent->MarkTextureBindingDirty(this);
+
+ return oldLod;
+ }
+
+ DWORD STDMETHODCALLTYPE GetLOD() final {
+ return m_lod;
+ }
+
+ DWORD STDMETHODCALLTYPE GetLevelCount() final {
+ return m_texture.ExposedMipLevels();
+ }
+
+ HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) final {
+ if (unlikely(FilterType == D3DTEXF_NONE))
+ return D3DERR_INVALIDCALL;
+
+ auto lock = this->m_parent->LockDevice();
+
+ m_texture.SetMipFilter(FilterType);
+ if (m_texture.IsAutomaticMip())
+ this->m_parent->MarkTextureMipsDirty(&m_texture);
+ return D3D_OK;
+ }
+
+ D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType() final {
+ return m_texture.GetMipFilter();
+ }
+
+ void STDMETHODCALLTYPE GenerateMipSubLevels() final {
+ if (!m_texture.NeedsMipGen())
+ return;
+
+ auto lock = this->m_parent->LockDevice();
+
+ this->m_parent->MarkTextureMipsUnDirty(&m_texture);
+ this->m_parent->EmitGenerateMips(&m_texture);
+ }
+
+ void STDMETHODCALLTYPE PreLoad() final {
+ m_texture.PreLoadAll();
+ }
+
+ D3D9CommonTexture* GetCommonTexture() {
+ return &m_texture;
+ }
+
+ SubresourceType* GetSubresource(UINT Subresource) {
+ return reinterpret_cast<SubresourceType*>(&m_subresources[Subresource]);
+ }
+
+ protected:
+
+ D3D9CommonTexture m_texture;
+
+ std::vector<SubresourceData> m_subresources;
+
+ DWORD m_lod;
+
+ };
+
+ using D3D9Texture2DBase = D3D9BaseTexture<D3D9Surface, IDirect3DTexture9>;
+ class D3D9Texture2D final : public D3D9Texture2DBase {
+
+ public:
+
+ D3D9Texture2D(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
+
+ HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel);
+
+ HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
+
+ HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level);
+
+ HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect);
+
+ };
+
+ using D3D9Texture3DBase = D3D9BaseTexture<D3D9Volume, IDirect3DVolumeTexture9>;
+ class D3D9Texture3D final : public D3D9Texture3DBase {
+
+ public:
+
+ D3D9Texture3D(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
+
+ HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume9** ppSurfaceLevel);
+
+ HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags);
+
+ HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level);
+
+ HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox);
+
+ };
+
+ using D3D9TextureCubeBase = D3D9BaseTexture<D3D9Surface, IDirect3DCubeTexture9>;
+ class D3D9TextureCube final : public D3D9TextureCubeBase {
+
+ public:
+
+ D3D9TextureCube(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
+
+ HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
+
+ HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface9** ppSurfaceLevel);
+
+ HRESULT STDMETHODCALLTYPE LockRect(D3DCUBEMAP_FACES Face, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
+
+ HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level);
+
+ HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect);
+
+ };
+
+ static_assert(sizeof(D3D9Texture2D) == sizeof(D3D9Texture3D) &&
+ sizeof(D3D9Texture2D) == sizeof(D3D9TextureCube));
+
+ inline D3D9CommonTexture* GetCommonTexture(IDirect3DBaseTexture9* ptr) {
+ if (ptr == nullptr)
+ return nullptr;
+
+ // We can avoid needing to get the type as m_texture has the same offset
+ // no matter the texture type.
+ // The compiler is not smart enough to eliminate the call to GetType as it is
+ // not marked const.
+ return static_cast<D3D9Texture2D*>(ptr)->GetCommonTexture();
+ }
+
+ inline D3D9CommonTexture* GetCommonTexture(D3D9Surface* ptr) {
+ if (ptr == nullptr)
+ return nullptr;
+
+ return ptr->GetCommonTexture();
+ }
+
+ inline D3D9CommonTexture* GetCommonTexture(IDirect3DSurface9* ptr) {
+ return GetCommonTexture(static_cast<D3D9Surface*>(ptr));
+ }
+
+ inline void TextureRefPrivate(IDirect3DBaseTexture9* tex, bool AddRef) {
+ if (tex == nullptr)
+ return;
+
+ // We can avoid needing to get the type as m_refCount has the same offset
+ // no matter the texture type.
+ // The compiler is not smart enough to eliminate the call to GetType as it is
+ // not marked const.
+ return CastRefPrivate<D3D9Texture2D>(tex, AddRef);
+ }
+
+ inline void TextureChangePrivate(IDirect3DBaseTexture9*& dst, IDirect3DBaseTexture9* src) {
+ TextureRefPrivate(dst, false);
+ TextureRefPrivate(src, true);
+ dst = src;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.cpp
new file mode 100644
index 00000000..91cf2637
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.cpp
@@ -0,0 +1,380 @@
+#include "d3d9_util.h"
+
+namespace dxvk {
+
+ HRESULT DecodeMultiSampleType(
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ VkSampleCountFlagBits* pCount) {
+ uint32_t sampleCount = std::max<uint32_t>(MultiSample, 1u);
+
+ // Check if this is a power of two...
+ if (sampleCount & (sampleCount - 1))
+ return D3DERR_INVALIDCALL;
+
+ if (MultiSample == D3DMULTISAMPLE_NONMASKABLE)
+ sampleCount = 1u << MultisampleQuality;
+
+ if (pCount != nullptr)
+ *pCount = VkSampleCountFlagBits(sampleCount);
+
+ return D3D_OK;
+ }
+
+
+ VkFormat GetPackedDepthStencilFormat(D3D9Format Format) {
+ switch (Format) {
+ case D3D9Format::D15S1:
+ return VK_FORMAT_D16_UNORM_S8_UINT; // This should never happen!
+
+ case D3D9Format::D16:
+ case D3D9Format::D16_LOCKABLE:
+ case D3D9Format::DF16:
+ return VK_FORMAT_D16_UNORM;
+
+ case D3D9Format::D24X8:
+ case D3D9Format::DF24:
+ return VK_FORMAT_X8_D24_UNORM_PACK32;
+
+ case D3D9Format::D24X4S4:
+ case D3D9Format::D24FS8:
+ case D3D9Format::D24S8:
+ case D3D9Format::INTZ:
+ return VK_FORMAT_D24_UNORM_S8_UINT;
+
+ case D3D9Format::D32:
+ case D3D9Format::D32_LOCKABLE:
+ case D3D9Format::D32F_LOCKABLE:
+ return VK_FORMAT_D32_SFLOAT;
+
+ case D3D9Format::S8_LOCKABLE:
+ return VK_FORMAT_S8_UINT;
+
+ default:
+ return VK_FORMAT_UNDEFINED;
+ }
+ }
+
+
+ VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage) {
+ VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+
+ if (Usage & D3DUSAGE_DEPTHSTENCIL)
+ features |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (Usage & D3DUSAGE_RENDERTARGET)
+ features |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+
+ return features;
+ }
+
+
+ VkImageUsageFlags GetImageUsageFlags(DWORD Usage) {
+ VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ if (Usage & D3DUSAGE_DEPTHSTENCIL)
+ usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (Usage & D3DUSAGE_RENDERTARGET)
+ usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ return usage;
+ }
+
+
+ uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count) {
+ switch (type) {
+ default:
+ case D3DPT_TRIANGLELIST: return count * 3;
+ case D3DPT_POINTLIST: return count;
+ case D3DPT_LINELIST: return count * 2;
+ case D3DPT_LINESTRIP: return count + 1;
+ case D3DPT_TRIANGLESTRIP: return count + 2;
+ case D3DPT_TRIANGLEFAN: return count + 2;
+ }
+ }
+
+
+ DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type) {
+ switch (type) {
+ default:
+ case D3DPT_TRIANGLELIST:
+ return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 };
+
+ case D3DPT_POINTLIST:
+ return { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 };
+
+ case D3DPT_LINELIST:
+ return { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 };
+
+ case D3DPT_LINESTRIP:
+ return { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_FALSE, 0 };
+
+ case D3DPT_TRIANGLESTRIP:
+ return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_FALSE, 0 };
+
+ case D3DPT_TRIANGLEFAN:
+ return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, VK_FALSE, 0 };
+ }
+ }
+
+
+ VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha) {
+ switch (BlendFactor) {
+ default:
+ case D3DBLEND_ZERO: return VK_BLEND_FACTOR_ZERO;
+ case D3DBLEND_ONE: return VK_BLEND_FACTOR_ONE;
+ case D3DBLEND_SRCCOLOR: return VK_BLEND_FACTOR_SRC_COLOR;
+ case D3DBLEND_INVSRCCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
+ case D3DBLEND_SRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
+ case D3DBLEND_INVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ case D3DBLEND_DESTALPHA: return VK_BLEND_FACTOR_DST_ALPHA;
+ case D3DBLEND_INVDESTALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
+ case D3DBLEND_DESTCOLOR: return VK_BLEND_FACTOR_DST_COLOR;
+ case D3DBLEND_INVDESTCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
+ case D3DBLEND_SRCALPHASAT: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
+ case D3DBLEND_BOTHSRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
+ case D3DBLEND_BOTHINVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ case D3DBLEND_BLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_CONSTANT_ALPHA : VK_BLEND_FACTOR_CONSTANT_COLOR;
+ case D3DBLEND_INVBLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA : VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
+ case D3DBLEND_SRCCOLOR2: return VK_BLEND_FACTOR_SRC1_COLOR;
+ case D3DBLEND_INVSRCCOLOR2: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
+ }
+ }
+
+
+ VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp) {
+ switch (BlendOp) {
+ default:
+ case D3DBLENDOP_ADD: return VK_BLEND_OP_ADD;
+ case D3DBLENDOP_SUBTRACT: return VK_BLEND_OP_SUBTRACT;
+ case D3DBLENDOP_REVSUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT;
+ case D3DBLENDOP_MIN: return VK_BLEND_OP_MIN;
+ case D3DBLENDOP_MAX: return VK_BLEND_OP_MAX;
+ }
+ }
+
+
+ VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter) {
+ switch (Filter) {
+ case D3DTEXF_NONE:
+ case D3DTEXF_POINT:
+ return VK_FILTER_NEAREST;
+ default:
+ return VK_FILTER_LINEAR;
+ }
+ }
+
+
+ D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter) {
+ D3D9MipFilter filter;
+ filter.MipsEnabled = Filter != D3DTEXF_NONE;
+
+ switch (Filter) {
+ case D3DTEXF_POINT:
+ case D3DTEXF_NONE:
+ filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
+ default:
+ filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_LINEAR; break;
+ }
+
+ return filter;
+ }
+
+
+ bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter) {
+ return Filter == D3DTEXF_ANISOTROPIC;
+ }
+
+
+ VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode) {
+ switch (Mode) {
+ default:
+ case D3DTADDRESS_WRAP:
+ return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ case D3DTADDRESS_MIRROR:
+ return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
+ case D3DTADDRESS_CLAMP:
+ return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ case D3DTADDRESS_BORDER:
+ return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+ case D3DTADDRESS_MIRRORONCE:
+ return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
+ }
+ }
+
+
+ VkCompareOp DecodeCompareOp(D3DCMPFUNC Func) {
+ switch (Func) {
+ default:
+ case D3DCMP_NEVER: return VK_COMPARE_OP_NEVER;
+ case D3DCMP_LESS: return VK_COMPARE_OP_LESS;
+ case D3DCMP_EQUAL: return VK_COMPARE_OP_EQUAL;
+ case D3DCMP_LESSEQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL;
+ case D3DCMP_GREATER: return VK_COMPARE_OP_GREATER;
+ case D3DCMP_NOTEQUAL: return VK_COMPARE_OP_NOT_EQUAL;
+ case D3DCMP_GREATEREQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL;
+ case D3DCMP_ALWAYS: return VK_COMPARE_OP_ALWAYS;
+ }
+ }
+
+
+ VkStencilOp DecodeStencilOp(D3DSTENCILOP Op) {
+ switch (Op) {
+ default:
+ case D3DSTENCILOP_KEEP: return VK_STENCIL_OP_KEEP;
+ case D3DSTENCILOP_ZERO: return VK_STENCIL_OP_ZERO;
+ case D3DSTENCILOP_REPLACE: return VK_STENCIL_OP_REPLACE;
+ case D3DSTENCILOP_INCRSAT: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
+ case D3DSTENCILOP_DECRSAT: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
+ case D3DSTENCILOP_INVERT: return VK_STENCIL_OP_INVERT;
+ case D3DSTENCILOP_INCR: return VK_STENCIL_OP_INCREMENT_AND_WRAP;
+ case D3DSTENCILOP_DECR: return VK_STENCIL_OP_DECREMENT_AND_WRAP;
+ }
+ }
+
+
+ VkCullModeFlags DecodeCullMode(D3DCULL Mode) {
+ switch (Mode) {
+ case D3DCULL_NONE: return VK_CULL_MODE_NONE;
+ case D3DCULL_CW: return VK_CULL_MODE_FRONT_BIT;
+ default:
+ case D3DCULL_CCW: return VK_CULL_MODE_BACK_BIT;
+ }
+ }
+
+
+ VkPolygonMode DecodeFillMode(D3DFILLMODE Mode) {
+ switch (Mode) {
+ case D3DFILL_POINT: return VK_POLYGON_MODE_POINT;
+ case D3DFILL_WIREFRAME: return VK_POLYGON_MODE_LINE;
+ default:
+ case D3DFILL_SOLID: return VK_POLYGON_MODE_FILL;
+ }
+ }
+
+
+ VkIndexType DecodeIndexType(D3D9Format Format) {
+ return Format == D3D9Format::INDEX16
+ ? VK_INDEX_TYPE_UINT16
+ : VK_INDEX_TYPE_UINT32;
+ }
+
+
+ VkFormat DecodeDecltype(D3DDECLTYPE Type) {
+ switch (Type) {
+ case D3DDECLTYPE_FLOAT1: return VK_FORMAT_R32_SFLOAT;
+ case D3DDECLTYPE_FLOAT2: return VK_FORMAT_R32G32_SFLOAT;
+ case D3DDECLTYPE_FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT;
+ case D3DDECLTYPE_FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT;
+ case D3DDECLTYPE_D3DCOLOR: return VK_FORMAT_B8G8R8A8_UNORM;
+ case D3DDECLTYPE_UBYTE4: return VK_FORMAT_R8G8B8A8_USCALED;
+ case D3DDECLTYPE_SHORT2: return VK_FORMAT_R16G16_SSCALED;
+ case D3DDECLTYPE_SHORT4: return VK_FORMAT_R16G16B16A16_SSCALED;
+ case D3DDECLTYPE_UBYTE4N: return VK_FORMAT_R8G8B8A8_UNORM;
+ case D3DDECLTYPE_SHORT2N: return VK_FORMAT_R16G16_SNORM;
+ case D3DDECLTYPE_SHORT4N: return VK_FORMAT_R16G16B16A16_SNORM;
+ case D3DDECLTYPE_USHORT2N: return VK_FORMAT_R16G16_UNORM;
+ case D3DDECLTYPE_USHORT4N: return VK_FORMAT_R16G16B16A16_UNORM;
+ case D3DDECLTYPE_UDEC3: return VK_FORMAT_A2B10G10R10_USCALED_PACK32;
+ case D3DDECLTYPE_FLOAT16_2: return VK_FORMAT_R16G16_SFLOAT;
+ case D3DDECLTYPE_FLOAT16_4: return VK_FORMAT_R16G16B16A16_SFLOAT;
+ case D3DDECLTYPE_DEC3N: return VK_FORMAT_A2B10G10R10_SNORM_PACK32;
+ case D3DDECLTYPE_UNUSED:
+ default: return VK_FORMAT_UNDEFINED;
+ }
+ }
+
+ void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent) {
+ offset.x = box.Left;
+ offset.y = box.Top;
+ offset.z = box.Front;
+
+ extent.width = box.Right - box.Left;
+ extent.height = box.Bottom - box.Top;
+ extent.depth = box.Back - box.Front;
+ }
+
+ void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent) {
+ offset.x = rect.left;
+ offset.y = rect.top;
+ offset.z = 0;
+
+ extent.width = rect.right - rect.left;
+ extent.height = rect.bottom - rect.top;
+ extent.depth = 1;
+ }
+
+ void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent) {
+ offset.x = rect.left;
+ offset.y = rect.top;
+
+ extent.width = rect.right - rect.left;
+ extent.height = rect.bottom - rect.top;
+ }
+
+ uint32_t GetDecltypeSize(D3DDECLTYPE Type) {
+ switch (Type) {
+ case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float);
+ case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float);
+ case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float);
+ case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float);
+ case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD);
+ case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE);
+ case D3DDECLTYPE_SHORT2: return 2 * sizeof(short);
+ case D3DDECLTYPE_SHORT4: return 4 * sizeof(short);
+ case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE);
+ case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short);
+ case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short);
+ case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short);
+ case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short);
+ case D3DDECLTYPE_UDEC3: return 4;
+ case D3DDECLTYPE_DEC3N: return 4;
+ case D3DDECLTYPE_FLOAT16_2: return 2 * 2;
+ case D3DDECLTYPE_FLOAT16_4: return 4 * 2;
+ default: return 0;
+ }
+ }
+
+
+ uint32_t GetDecltypeCount(D3DDECLTYPE Type) {
+ switch (Type) {
+ case D3DDECLTYPE_FLOAT1: return 1;
+ case D3DDECLTYPE_FLOAT2: return 2;
+ case D3DDECLTYPE_FLOAT3: return 3;
+ case D3DDECLTYPE_FLOAT4: return 4;
+ case D3DDECLTYPE_D3DCOLOR: return 4;
+ case D3DDECLTYPE_UBYTE4: return 4;
+ case D3DDECLTYPE_SHORT2: return 2;
+ case D3DDECLTYPE_SHORT4: return 4;
+ case D3DDECLTYPE_UBYTE4N: return 4;
+ case D3DDECLTYPE_SHORT2N: return 2;
+ case D3DDECLTYPE_SHORT4N: return 4;
+ case D3DDECLTYPE_USHORT2N: return 2;
+ case D3DDECLTYPE_USHORT4N: return 4;
+ case D3DDECLTYPE_UDEC3: return 3;
+ case D3DDECLTYPE_DEC3N: return 3;
+ case D3DDECLTYPE_FLOAT16_2: return 2;
+ case D3DDECLTYPE_FLOAT16_4: return 4;
+ default: return 0;
+ }
+ }
+
+
+ bool IsDepthFormat(D3D9Format Format) {
+ return Format == D3D9Format::D16_LOCKABLE
+ || Format == D3D9Format::D32
+ || Format == D3D9Format::D15S1
+ || Format == D3D9Format::D24S8
+ || Format == D3D9Format::D24X8
+ || Format == D3D9Format::D24X4S4
+ || Format == D3D9Format::D16
+ || Format == D3D9Format::D32F_LOCKABLE
+ || Format == D3D9Format::D24FS8
+ || Format == D3D9Format::D32_LOCKABLE
+ || Format == D3D9Format::DF16
+ || Format == D3D9Format::DF24
+ || Format == D3D9Format::INTZ;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.h
new file mode 100644
index 00000000..ced4f872
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_util.h
@@ -0,0 +1,295 @@
+#pragma once
+
+#include "d3d9_include.h"
+
+#include "d3d9_format.h"
+
+#include "../dxso/dxso_common.h"
+#include "../dxvk/dxvk_device.h"
+
+#include "../util/util_matrix.h"
+
+#include <d3dcommon.h>
+
+namespace dxvk {
+
+ struct D3D9ShaderMasks {
+ uint32_t samplerMask;
+ uint32_t rtMask;
+ };
+
+ static constexpr D3D9ShaderMasks FixedFunctionMask =
+ { 0b1111111, 0b1 };
+
+ struct D3D9MipFilter {
+ bool MipsEnabled;
+ VkSamplerMipmapMode MipFilter;
+ };
+
+ struct D3D9BlendState {
+ D3DBLEND Src;
+ D3DBLEND Dst;
+ D3DBLENDOP Op;
+ };
+
+ inline void FixupBlendState(D3D9BlendState& State) {
+ // Old DirectX 6 HW feature that still exists...
+ // Yuck!
+ if (unlikely(State.Src == D3DBLEND_BOTHSRCALPHA)) {
+ State.Src = D3DBLEND_SRCALPHA;
+ State.Dst = D3DBLEND_INVSRCALPHA;
+ }
+ else if (unlikely(State.Src == D3DBLEND_BOTHINVSRCALPHA)) {
+ State.Src = D3DBLEND_INVSRCALPHA;
+ State.Dst = D3DBLEND_SRCALPHA;
+ }
+ }
+
+ inline bool InvalidSampler(DWORD Sampler) {
+ if (Sampler > 15 && Sampler < D3DDMAPSAMPLER)
+ return true;
+
+ if (Sampler > D3DVERTEXTEXTURESAMPLER3)
+ return true;
+
+ return false;
+ }
+
+ inline DWORD RemapSamplerState(DWORD Sampler) {
+ if (Sampler >= D3DDMAPSAMPLER)
+ Sampler = 16 + (Sampler - D3DDMAPSAMPLER);
+
+ return Sampler;
+ }
+
+ inline std::pair<DxsoProgramType, DWORD> RemapStateSamplerShader(DWORD Sampler) {
+ if (Sampler >= 17)
+ return std::make_pair(DxsoProgramTypes::VertexShader, Sampler - 17);
+
+ return std::make_pair(DxsoProgramTypes::PixelShader, Sampler);
+ }
+
+ inline std::pair<DxsoProgramType, DWORD> RemapSamplerShader(DWORD Sampler) {
+ Sampler = RemapSamplerState(Sampler);
+
+ return RemapStateSamplerShader(Sampler);
+ }
+
+ template <typename T, typename J>
+ void CastRefPrivate(J* ptr, bool AddRef) {
+ if (ptr == nullptr)
+ return;
+
+ T* castedPtr = reinterpret_cast<T*>(ptr);
+ AddRef ? castedPtr->AddRefPrivate() : castedPtr->ReleasePrivate();
+ }
+
+ HRESULT DecodeMultiSampleType(
+ D3DMULTISAMPLE_TYPE MultiSample,
+ DWORD MultisampleQuality,
+ VkSampleCountFlagBits* pCount);
+
+ VkFormat GetPackedDepthStencilFormat(D3D9Format Format);
+
+ VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage);
+
+ VkImageUsageFlags GetImageUsageFlags(DWORD Usage);
+
+ inline void DecodeD3DCOLOR(D3DCOLOR color, float* rgba) {
+ // Encoded in D3DCOLOR as argb
+ rgba[3] = (float)((color & 0xff000000) >> 24) / 255.0f;
+ rgba[0] = (float)((color & 0x00ff0000) >> 16) / 255.0f;
+ rgba[1] = (float)((color & 0x0000ff00) >> 8) / 255.0f;
+ rgba[2] = (float)((color & 0x000000ff)) / 255.0f;
+ }
+
+ inline VkFormat PickSRGB(VkFormat format, VkFormat srgbFormat, bool srgb) {
+ return srgb ? srgbFormat : format;
+ }
+
+ inline VkShaderStageFlagBits GetShaderStage(DxsoProgramType ProgramType) {
+ switch (ProgramType) {
+ case DxsoProgramTypes::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
+ case DxsoProgramTypes::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
+ default: return VkShaderStageFlagBits(0);
+ }
+ }
+
+ inline uint32_t GetTransformIndex(D3DTRANSFORMSTATETYPE Type) {
+ if (Type == D3DTS_VIEW)
+ return 0;
+
+ if (Type == D3DTS_PROJECTION)
+ return 1;
+
+ if (Type >= D3DTS_TEXTURE0 && Type <= D3DTS_TEXTURE7)
+ return 2 + (Type - D3DTS_TEXTURE0);
+
+ return 10 + (Type - D3DTS_WORLD);
+ }
+
+ inline Matrix4 ConvertMatrix(const D3DMATRIX* Matrix) {
+ if (Matrix == nullptr) // Identity.
+ return Matrix4();
+
+ return Matrix4(Matrix->m);
+ }
+
+ uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count);
+
+ DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type);
+
+ VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha);
+
+ VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp);
+
+ VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter);
+
+ D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter);
+
+ bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter);
+
+ VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode);
+
+ VkCompareOp DecodeCompareOp(D3DCMPFUNC Func);
+
+ VkStencilOp DecodeStencilOp(D3DSTENCILOP Op);
+
+ VkCullModeFlags DecodeCullMode(D3DCULL Mode);
+
+ VkPolygonMode DecodeFillMode(D3DFILLMODE Mode);
+
+ VkIndexType DecodeIndexType(D3D9Format Format);
+
+ VkFormat DecodeDecltype(D3DDECLTYPE Type);
+
+ uint32_t GetDecltypeSize(D3DDECLTYPE Type);
+
+ uint32_t GetDecltypeCount(D3DDECLTYPE Type);
+
+ void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent);
+
+ void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent);
+
+ void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent);
+
+ inline float GetDepthBufferRValue(VkFormat Format) {
+ switch (Format) {
+ case VK_FORMAT_D16_UNORM_S8_UINT:
+ case VK_FORMAT_D16_UNORM:
+ return float(1 << 16);
+
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ return float(1 << 24);
+
+ default:
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ case VK_FORMAT_D32_SFLOAT:
+ return float(1 << 23);
+ }
+ }
+
+ template<typename T>
+ UINT CompactSparseList(T* pData, UINT Mask) {
+ uint32_t count = 0;
+
+ for (uint32_t id : bit::BitMask(Mask))
+ pData[count++] = pData[id];
+
+ return count;
+ }
+
+ bool IsDepthFormat(D3D9Format Format);
+
+ inline bool operator == (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
+ return a.X == b.X &&
+ a.Y == b.Y &&
+ a.Width == b.Width &&
+ a.Height == b.Height &&
+ a.MinZ == b.MinZ &&
+ a.MaxZ == b.MaxZ;
+ }
+
+ inline bool operator != (const D3DVIEWPORT9& a, const D3DVIEWPORT9& b) {
+ return !(a == b);
+ }
+
+ inline bool operator == (const RECT& a, const RECT& b) {
+ return a.left == b.left &&
+ a.right == b.right &&
+ a.top == b.top &&
+ a.bottom == b.bottom;
+ }
+
+ inline bool operator != (const RECT& a, const RECT& b) {
+ return !(a == b);
+ }
+
+ inline bool operator == (const POINT& a, const POINT& b) {
+ return a.x == b.x && a.y == b.y;
+ }
+
+ inline bool operator != (const POINT& a, const POINT& b) {
+ return !(a == b);
+ }
+
+ inline bool IsPoolManaged(D3DPOOL Pool) {
+ return Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_MANAGED_EX;
+ }
+
+ inline D3DRENDERSTATETYPE ColorWriteIndex(uint32_t i) {
+ return D3DRENDERSTATETYPE(i ? D3DRS_COLORWRITEENABLE1 + i - 1 : D3DRS_COLORWRITEENABLE);
+ }
+
+ inline bool AreFormatsSimilar(D3D9Format srcFormat, D3D9Format dstFormat) {
+ return (srcFormat == dstFormat)
+ || (srcFormat == D3D9Format::A8B8G8R8 && dstFormat == D3D9Format::X8B8G8R8)
+ || (srcFormat == D3D9Format::A8R8G8B8 && dstFormat == D3D9Format::X8R8G8B8)
+ || (srcFormat == D3D9Format::A1R5G5B5 && dstFormat == D3D9Format::X1R5G5B5)
+ || (srcFormat == D3D9Format::A4R4G4B4 && dstFormat == D3D9Format::X4R4G4B4);
+ }
+
+ inline bool IsBlitRegionInvalid(VkOffset3D offsets[2], VkExtent3D extent) {
+ // Only bother checking x, y as we don't have 3D blits.
+ return offsets[1].x < offsets[0].x ||
+ offsets[1].y < offsets[0].y ||
+ offsets[0].x < 0 ||
+ offsets[0].y < 0 ||
+ uint32_t(offsets[1].x) > extent.width ||
+ uint32_t(offsets[1].y) > extent.height;
+ }
+
+ enum D3D9TextureStageStateTypes : uint32_t
+ {
+ DXVK_TSS_COLOROP = 0,
+ DXVK_TSS_COLORARG1 = 1,
+ DXVK_TSS_COLORARG2 = 2,
+ DXVK_TSS_ALPHAOP = 3,
+ DXVK_TSS_ALPHAARG1 = 4,
+ DXVK_TSS_ALPHAARG2 = 5,
+ DXVK_TSS_BUMPENVMAT00 = 6,
+ DXVK_TSS_BUMPENVMAT01 = 7,
+ DXVK_TSS_BUMPENVMAT10 = 8,
+ DXVK_TSS_BUMPENVMAT11 = 9,
+ DXVK_TSS_TEXCOORDINDEX = 10,
+ DXVK_TSS_BUMPENVLSCALE = 21,
+ DXVK_TSS_BUMPENVLOFFSET = 22,
+ DXVK_TSS_TEXTURETRANSFORMFLAGS = 23,
+ DXVK_TSS_COLORARG0 = 25,
+ DXVK_TSS_ALPHAARG0 = 26,
+ DXVK_TSS_RESULTARG = 27,
+ DXVK_TSS_CONSTANT = 31,
+ DXVK_TSS_COUNT = 32
+ };
+
+ constexpr uint32_t DXVK_TSS_TCI_PASSTHRU = 0x00000000;
+ constexpr uint32_t DXVK_TSS_TCI_CAMERASPACENORMAL = 0x00010000;
+ constexpr uint32_t DXVK_TSS_TCI_CAMERASPACEPOSITION = 0x00020000;
+ constexpr uint32_t DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR = 0x00030000;
+ constexpr uint32_t DXVK_TSS_TCI_SPHEREMAP = 0x00040000;
+
+ inline D3D9TextureStageStateTypes RemapTextureStageStateType(D3DTEXTURESTAGESTATETYPE Type) {
+ return D3D9TextureStageStateTypes(Type - 1);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.cpp
new file mode 100644
index 00000000..9eb65d79
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.cpp
@@ -0,0 +1,234 @@
+#include "d3d9_vertex_declaration.h"
+#include "d3d9_util.h"
+
+#include <algorithm>
+#include <cstring>
+
+namespace dxvk {
+
+ D3D9VertexDecl::D3D9VertexDecl(
+ D3D9DeviceEx* pDevice,
+ DWORD FVF)
+ : D3D9VertexDeclBase(pDevice) {
+ this->SetFVF(FVF);
+ this->Classify();
+ }
+
+
+ D3D9VertexDecl::D3D9VertexDecl(
+ D3D9DeviceEx* pDevice,
+ const D3DVERTEXELEMENT9* pVertexElements,
+ uint32_t DeclCount)
+ : D3D9VertexDeclBase( pDevice )
+ , m_elements ( DeclCount )
+ , m_fvf ( 0 ) {
+ std::copy(pVertexElements, pVertexElements + DeclCount, m_elements.begin());
+ this->Classify();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9VertexDecl::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DVertexDeclaration9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9VertexDecl::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9VertexDecl::GetDeclaration(
+ D3DVERTEXELEMENT9* pElement,
+ UINT* pNumElements) {
+ if (pNumElements == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ *pNumElements = UINT(m_elements.size()) + 1u; // Account for D3DDECL_END
+
+ if (pElement == nullptr)
+ return D3D_OK;
+
+ // The native runtime ignores pNumElements here...
+ std::copy(m_elements.begin(), m_elements.end(), pElement);
+ pElement[m_elements.size()] = D3DDECL_END();
+
+ return D3D_OK;
+ }
+
+
+ void D3D9VertexDecl::SetFVF(DWORD FVF) {
+ m_fvf = FVF;
+
+ std::array<D3DVERTEXELEMENT9, 16> elements;
+ uint32_t elemCount = 0;
+ uint32_t texCount = 0;
+
+ uint32_t betas = 0;
+ uint8_t betaIdx = 0xFF;
+
+ switch (FVF & D3DFVF_POSITION_MASK) {
+ case D3DFVF_XYZ:
+ case D3DFVF_XYZB1:
+ case D3DFVF_XYZB2:
+ case D3DFVF_XYZB3:
+ case D3DFVF_XYZB4:
+ case D3DFVF_XYZB5:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
+ elements[elemCount].Usage = D3DDECLUSAGE_POSITION;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+
+ if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
+ break;
+
+ betas = (((FVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1) + 1;
+ if (FVF & D3DFVF_LASTBETA_D3DCOLOR)
+ betaIdx = D3DDECLTYPE_D3DCOLOR;
+ else if (FVF & D3DFVF_LASTBETA_UBYTE4)
+ betaIdx = D3DDECLTYPE_UBYTE4;
+ else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5)
+ betaIdx = D3DDECLTYPE_FLOAT1;
+
+ if (betaIdx != 0xFF)
+ betas--;
+
+ if (betas > 0) {
+ switch (betas) {
+ case 1: elements[elemCount].Type = D3DDECLTYPE_FLOAT1; break;
+ case 2: elements[elemCount].Type = D3DDECLTYPE_FLOAT2; break;
+ case 3: elements[elemCount].Type = D3DDECLTYPE_FLOAT3; break;
+ case 4: elements[elemCount].Type = D3DDECLTYPE_FLOAT4; break;
+ default: break;
+ }
+ elements[elemCount].Usage = D3DDECLUSAGE_BLENDWEIGHT;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ }
+
+ if (betaIdx != 0xFF) {
+ elements[elemCount].Type = betaIdx;
+ elements[elemCount].Usage = D3DDECLUSAGE_BLENDINDICES;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ }
+ break;
+
+ case D3DFVF_XYZW:
+ case D3DFVF_XYZRHW:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
+ elements[elemCount].Usage =
+ ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW)
+ ? D3DDECLUSAGE_POSITION
+ : D3DDECLUSAGE_POSITIONT;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ break;
+
+ default:
+ break;
+ }
+
+ if (FVF & D3DFVF_NORMAL) {
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
+ elements[elemCount].Usage = D3DDECLUSAGE_NORMAL;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ }
+ if (FVF & D3DFVF_PSIZE) {
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
+ elements[elemCount].Usage = D3DDECLUSAGE_PSIZE;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ }
+ if (FVF & D3DFVF_DIFFUSE) {
+ elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
+ elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
+ elements[elemCount].UsageIndex = 0;
+ elemCount++;
+ }
+ if (FVF & D3DFVF_SPECULAR) {
+ elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
+ elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
+ elements[elemCount].UsageIndex = 1;
+ elemCount++;
+ }
+
+ texCount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
+ texCount = std::min(texCount, 8u);
+
+ for (uint32_t i = 0; i < texCount; i++) {
+ switch ((FVF >> (16 + i * 2)) & 0x3) {
+ case D3DFVF_TEXTUREFORMAT1:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
+ break;
+
+ case D3DFVF_TEXTUREFORMAT2:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT2;
+ break;
+
+ case D3DFVF_TEXTUREFORMAT3:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
+ break;
+
+ case D3DFVF_TEXTUREFORMAT4:
+ elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
+ break;
+
+ default:
+ break;
+ }
+ elements[elemCount].Usage = D3DDECLUSAGE_TEXCOORD;
+ elements[elemCount].UsageIndex = i;
+ elemCount++;
+ }
+
+ for (uint32_t i = 0; i < elemCount; i++) {
+ elements[i].Stream = 0;
+ elements[i].Offset = (i == 0)
+ ? 0
+ : (elements[i - 1].Offset + GetDecltypeSize(D3DDECLTYPE(elements[i - 1].Type)));
+
+ elements[i].Method = D3DDECLMETHOD_DEFAULT;
+ }
+
+ m_elements.resize(elemCount);
+ std::copy(elements.begin(), elements.begin() + elemCount, m_elements.data());
+ }
+
+
+ void D3D9VertexDecl::Classify() {
+ for (const auto& element : m_elements) {
+ if (element.Stream == 0 && element.Type != D3DDECLTYPE_UNUSED)
+ m_size = std::max(m_size, element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
+
+ if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
+ m_flags.set(D3D9VertexDeclFlag::HasColor0);
+ else if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 1)
+ m_flags.set(D3D9VertexDeclFlag::HasColor1);
+ else if (element.Usage == D3DDECLUSAGE_POSITIONT)
+ m_flags.set(D3D9VertexDeclFlag::HasPositionT);
+ else if (element.Usage == D3DDECLUSAGE_PSIZE)
+ m_flags.set(D3D9VertexDeclFlag::HasPointSize);
+ else if (element.Usage == D3DDECLUSAGE_FOG)
+ m_flags.set(D3D9VertexDeclFlag::HasFog);
+ else if (element.Usage == D3DDECLUSAGE_BLENDWEIGHT)
+ m_flags.set(D3D9VertexDeclFlag::HasBlendWeight);
+ else if (element.Usage == D3DDECLUSAGE_BLENDINDICES)
+ m_flags.set(D3D9VertexDeclFlag::HasBlendIndices);
+
+ if (element.Usage == D3DDECLUSAGE_TEXCOORD)
+ m_texcoordMask |= GetDecltypeCount(D3DDECLTYPE(element.Type)) << (element.UsageIndex * 3);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.h
new file mode 100644
index 00000000..fe519f2d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_vertex_declaration.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "d3d9_device_child.h"
+#include "d3d9_util.h"
+
+#include <vector>
+
+namespace dxvk {
+
+ enum D3D9VertexDeclFlag {
+ HasColor0,
+ HasColor1,
+ HasPositionT,
+ HasPointSize,
+ HasFog,
+ HasBlendWeight,
+ HasBlendIndices
+ };
+ using D3D9VertexDeclFlags = Flags<D3D9VertexDeclFlag>;
+
+ using D3D9VertexDeclBase = D3D9DeviceChild<IDirect3DVertexDeclaration9>;
+ class D3D9VertexDecl final : public D3D9VertexDeclBase {
+
+ public:
+
+ D3D9VertexDecl(
+ D3D9DeviceEx* pDevice,
+ DWORD FVF);
+
+ D3D9VertexDecl(
+ D3D9DeviceEx* pDevice,
+ const D3DVERTEXELEMENT9* pVertexElements,
+ uint32_t DeclCount);
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDeclaration(
+ D3DVERTEXELEMENT9* pElement,
+ UINT* pNumElements);
+
+ inline DWORD GetFVF() {
+ return m_fvf;
+ }
+
+ void SetFVF(DWORD FVF);
+
+ const D3D9VertexElements& GetElements() const {
+ return m_elements;
+ }
+
+ UINT GetSize() const {
+ return m_size;
+ }
+
+ bool TestFlag(D3D9VertexDeclFlag flag) const {
+ return m_flags.test(flag);
+ }
+
+ uint32_t GetTexcoordMask() const {
+ return m_texcoordMask;
+ }
+
+ private:
+
+ void Classify();
+
+ D3D9VertexDeclFlags m_flags;
+
+ D3D9VertexElements m_elements;
+
+ DWORD m_fvf;
+
+ uint32_t m_texcoordMask = 0;
+
+ // The size of Stream 0. That's all we care about.
+ uint32_t m_size = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.cpp
new file mode 100644
index 00000000..399566f3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.cpp
@@ -0,0 +1,112 @@
+#include "d3d9_volume.h"
+
+#include "d3d9_device.h"
+#include "d3d9_texture.h"
+
+namespace dxvk {
+
+ D3D9Volume::D3D9Volume(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc)
+ : D3D9VolumeBase(
+ pDevice,
+ new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE ),
+ 0, 0,
+ nullptr,
+ nullptr) { }
+
+
+ D3D9Volume::D3D9Volume(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonTexture* pTexture,
+ UINT Face,
+ UINT MipLevel,
+ IDirect3DBaseTexture9* pContainer)
+ : D3D9VolumeBase(
+ pDevice,
+ pTexture,
+ Face, MipLevel,
+ pContainer,
+ pContainer) { }
+
+
+ void D3D9Volume::AddRefPrivate() {
+ // Can't have a swapchain container for a volume.
+ if (m_baseTexture != nullptr) {
+ static_cast<D3D9Texture3D*>(m_baseTexture)->AddRefPrivate();
+ return;
+ }
+
+ D3D9VolumeBase::AddRefPrivate();
+ }
+
+
+ void D3D9Volume::ReleasePrivate() {
+ // Can't have a swapchain container for a volume.
+ if (m_baseTexture != nullptr) {
+ static_cast<D3D9Texture3D*>(m_baseTexture)->ReleasePrivate();
+ return;
+ }
+
+ D3D9VolumeBase::ReleasePrivate();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Volume::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDirect3DResource9)
+ || riid == __uuidof(IDirect3DVolume9)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("D3D9Volume::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Volume::GetDesc(D3DVOLUME_DESC *pDesc) {
+ if (pDesc == nullptr)
+ return D3DERR_INVALIDCALL;
+
+ auto& desc = *(m_texture->Desc());
+
+ pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
+ pDesc->Type = D3DRTYPE_VOLUME;
+ pDesc->Usage = desc.Usage;
+ pDesc->Pool = desc.Pool;
+
+ pDesc->Width = std::max(1u, desc.Width >> m_mipLevel);
+ pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
+ pDesc->Depth = std::max(1u, desc.Depth >> m_mipLevel);
+
+ return D3D_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Volume::LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
+ if (unlikely(pLockedBox == nullptr))
+ return D3DERR_INVALIDCALL;
+
+ return m_parent->LockImage(
+ m_texture,
+ m_face, m_mipLevel,
+ pLockedBox,
+ pBox,
+ Flags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE D3D9Volume::UnlockBox() {
+ return m_parent->UnlockImage(
+ m_texture,
+ m_face, m_mipLevel);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.h
new file mode 100644
index 00000000..9c33a788
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_volume.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "d3d9_subresource.h"
+
+#include "d3d9_common_texture.h"
+
+namespace dxvk {
+
+ using D3D9VolumeBase = D3D9Subresource<IDirect3DVolume9>;
+ class D3D9Volume final : public D3D9VolumeBase {
+
+ public:
+
+ D3D9Volume(
+ D3D9DeviceEx* pDevice,
+ const D3D9_COMMON_TEXTURE_DESC* pDesc);
+
+ D3D9Volume(
+ D3D9DeviceEx* pDevice,
+ D3D9CommonTexture* pTexture,
+ UINT Face,
+ UINT MipLevel,
+ IDirect3DBaseTexture9* pContainer);
+
+ void AddRefPrivate();
+
+ void ReleasePrivate();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC *pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final;
+
+ HRESULT STDMETHODCALLTYPE UnlockBox() final;
+
+ };
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/meson.build b/src/libs/dxvk-native-1.9.2a/src/d3d9/meson.build
new file mode 100644
index 00000000..1086b857
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/meson.build
@@ -0,0 +1,54 @@
+d3d9_res = wrc_generator.process('version.rc')
+
+d3d9_shaders = files([
+ 'shaders/d3d9_convert_yuy2_uyvy.comp',
+ 'shaders/d3d9_convert_l6v5u5.comp',
+ 'shaders/d3d9_convert_x8l8v8u8.comp',
+ 'shaders/d3d9_convert_a2w10v10u10.comp',
+ 'shaders/d3d9_convert_nv12.comp',
+ 'shaders/d3d9_convert_yv12.comp'
+])
+
+d3d9_src = [
+ 'd3d9_main.cpp',
+ 'd3d9_interface.cpp',
+ 'd3d9_adapter.cpp',
+ 'd3d9_monitor.cpp',
+ 'd3d9_device.cpp',
+ 'd3d9_state.cpp',
+ 'd3d9_cursor.cpp',
+ 'd3d9_swapchain.cpp',
+ 'd3d9_format.cpp',
+ 'd3d9_common_texture.cpp',
+ 'd3d9_texture.cpp',
+ 'd3d9_surface.cpp',
+ 'd3d9_volume.cpp',
+ 'd3d9_common_buffer.cpp',
+ 'd3d9_buffer.cpp',
+ 'd3d9_shader.cpp',
+ 'd3d9_vertex_declaration.cpp',
+ 'd3d9_query.cpp',
+ 'd3d9_multithread.cpp',
+ 'd3d9_options.cpp',
+ 'd3d9_stateblock.cpp',
+ 'd3d9_sampler.cpp',
+ 'd3d9_util.cpp',
+ 'd3d9_initializer.cpp',
+ 'd3d9_fixed_function.cpp',
+ 'd3d9_names.cpp',
+ 'd3d9_swvp_emu.cpp',
+ 'd3d9_format_helpers.cpp',
+ 'd3d9_hud.cpp'
+]
+
+d3d9_dll = shared_library(so_prefix+'d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
+ name_prefix : '',
+ dependencies : [ dxso_dep, dxvk_dep, wsi_dep ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'd3d9'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+d3d9_dep = declare_dependency(
+ link_with : [ d3d9_dll ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_a2w10v10u10.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_a2w10v10u10.comp
new file mode 100644
index 00000000..2d489e3d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_a2w10v10u10.comp
@@ -0,0 +1,44 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uint offset = thread_id.x
+ + thread_id.y * u_info.extent.x;
+
+ uint value = texelFetch(src, int(offset)).r;
+
+ // Sign-extend magic!
+ int u10 = bitfieldExtract(int (value), 0, 10);
+ int v10 = bitfieldExtract(int (value), 10, 10);
+ int w10 = bitfieldExtract(int (value), 20, 10);
+ uint a2 = bitfieldExtract(uint(value), 30, 2);
+
+ vec4 color = vec4(
+ snormalize(u10, 10),
+ snormalize(v10, 10),
+ snormalize(w10, 10),
+ unormalize(a2, 2));
+
+ imageStore(dst, thread_id.xy, color);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_common.h b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_common.h
new file mode 100644
index 00000000..daca40e1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_common.h
@@ -0,0 +1,44 @@
+float unormalize(uint value, int bits) {
+ const int range = (1 << bits) - 1;
+
+ return float(value) / float(range);
+}
+
+float snormalize(int value, int bits) {
+ const int range = (1 << (bits - 1)) - 1;
+
+ // Min because, -32 and -31 map to -1.0f, and we
+ // divide by 31.
+ return max(float(value) / float(range), -1.0);
+}
+
+float unpackUnorm(uint p) {
+ return float(p) / 255.0;
+}
+
+vec2 unpackUnorm2x8(uint p) {
+ uvec2 value = uvec2(p & 0xFF, p >> 8);
+ return vec2(unpackUnorm(value.x), unpackUnorm(value.y));
+}
+
+mat3x4 g_yuv_to_rgb = {
+ { 298 / 256, 0, 409 / 256, 0.5 },
+ { 298 / 256, -100 / 256, -208 / 256, 0.5 },
+ { 298 / 256, 516 / 256, 0, 0.5 }
+};
+
+vec4 convertYUV(vec3 yuv) {
+ vec3 value = vec4(yuv, 1 / 255.0) * g_yuv_to_rgb;
+
+ return vec4(clamp(value, 0, 1), 1);
+}
+
+mat3x3 g_bt709_to_rgb = {
+ { 1.164, 0, 1.793 },
+ { 1.164, -0.213, -0.533 },
+ { 1.164, 2.112, 0 }
+};
+
+vec4 convertBT_709(vec3 cde) {
+ return vec4(clamp(cde * g_bt709_to_rgb, 0, 1), 1);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_l6v5u5.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_l6v5u5.comp
new file mode 100644
index 00000000..e7ee25a9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_l6v5u5.comp
@@ -0,0 +1,43 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uint offset = thread_id.x
+ + thread_id.y * u_info.extent.x;
+
+ uint value = texelFetch(src, int(offset)).r;
+
+ // Sign-extend magic!
+ int u5 = bitfieldExtract(int (value), 0, 5);
+ int v5 = bitfieldExtract(int (value), 5, 5);
+ uint l6 = bitfieldExtract(uint(value), 10, 6);
+
+ vec4 color = vec4(
+ snormalize(u5, 5),
+ snormalize(v5, 5),
+ unormalize(l6, 6),
+ 1.0f);
+
+ imageStore(dst, thread_id.xy, color);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_nv12.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_nv12.comp
new file mode 100644
index 00000000..70f7998d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_nv12.comp
@@ -0,0 +1,63 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+vec2 fetchUnorm2x8(usamplerBuffer source, uint offset) {
+ return unpackUnorm2x8(texelFetch(src, int(offset)).r);
+}
+
+// Format is:
+// YYYYYYYYYYYYYYY...
+// YYYYYYYYYYYYYYY...
+// UVUVUVUVUVUVUVU...
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uvec2 pitch = uvec2(u_info.extent.x, u_info.extent.y);
+
+ uint offset = thread_id.x
+ + thread_id.y * pitch.x;
+
+ // Fetch 2 luminance samples.
+ vec2 y = fetchUnorm2x8(src, offset) - (16 / 255.0);
+
+ // Go into the second plane to get the chroma data.
+ // UV data is subsampled as [2, 2]
+ // So we need to divide thread_id.y by 2.
+ // thread_id.x is already accounted for as we read uint16
+ offset = thread_id.x
+ + thread_id.y / 2 * pitch.x
+ + pitch.x * pitch.y;
+
+ vec2 uv = fetchUnorm2x8(src, offset) - (128 / 255.0);
+
+ // The NV12 format seems to use the BT.709 color space.
+ vec4 color0 = convertBT_709(vec3(y.x, uv.x, uv.y));
+ vec4 color1 = convertBT_709(vec3(y.y, uv.x, uv.y));
+
+ // We write as a macropixel of [2, 1]
+ // So write out 2 pixels in this run.
+ ivec2 writePos = thread_id.xy * ivec2(2, 1);
+
+ imageStore(dst, ivec2(writePos.x, writePos.y), color0);
+ imageStore(dst, ivec2(writePos.x + 1, writePos.y), color1);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_x8l8v8u8.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_x8l8v8u8.comp
new file mode 100644
index 00000000..a9257cb5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_x8l8v8u8.comp
@@ -0,0 +1,43 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uint offset = thread_id.x
+ + thread_id.y * u_info.extent.x;
+
+ uint value = texelFetch(src, int(offset)).r;
+
+ // Sign-extend magic!
+ int u8 = bitfieldExtract(int (value), 0, 8);
+ int v8 = bitfieldExtract(int (value), 8, 8);
+ uint l8 = bitfieldExtract(uint(value), 16, 8);
+
+ vec4 color = vec4(
+ snormalize(u8, 8),
+ snormalize(v8, 8),
+ unormalize(l8, 8),
+ 1.0f);
+
+ imageStore(dst, thread_id.xy, color);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp
new file mode 100644
index 00000000..8f38c9ba
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp
@@ -0,0 +1,53 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(constant_id = 1225) const bool s_is_uyvy = false;
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uint offset = thread_id.x
+ + thread_id.y * u_info.extent.x;
+
+ uint value = texelFetch(src, int(offset)).r;
+
+ vec4 data = unpackUnorm4x8(value);
+
+ // Flip around stuff for UYVY
+ if (s_is_uyvy)
+ data = data.yxwz;
+
+ float y0 = data.x - (16 / 255.0);
+ float u = data.y - (128 / 255.0);
+ float y1 = data.z - (16 / 255.0);
+ float v = data.w - (128 / 255.0);
+
+ vec4 color0 = convertYUV(vec3(y0, u, v));
+ vec4 color1 = convertYUV(vec3(y1, u, v));
+
+ // YUY2 has a macropixel of [2, 1]
+ // so we write 2 pixels in this run.
+ ivec2 writePos = thread_id.xy * ivec2(2, 1);
+
+ imageStore(dst, ivec2(writePos.x, writePos.y), color0);
+ imageStore(dst, ivec2(writePos.x + 1, writePos.y), color1);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yv12.comp b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yv12.comp
new file mode 100644
index 00000000..ad3822ab
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/shaders/d3d9_convert_yv12.comp
@@ -0,0 +1,58 @@
+#version 450
+#extension GL_GOOGLE_include_directive : enable
+
+#include "d3d9_convert_common.h"
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(binding = 1) uniform usamplerBuffer src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 extent;
+} u_info;
+
+// Format is:
+// YYYYYYYY...
+// VVVV...
+// UUUU...
+
+float fetchUnorm(usamplerBuffer source, uint offset) {
+ return unpackUnorm(texelFetch(src, int(offset)).r);
+}
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.extent))) {
+ uvec2 pitch = uvec2(u_info.extent.x, u_info.extent.y);
+
+ uint offset = thread_id.x
+ + thread_id.y * pitch.x;
+
+ // Fetch a Y, luminance sample.
+ float y = fetchUnorm(src, offset) - (16 / 255.0);
+
+ // Go into the second plane to get a V, chroma sample
+ offset = (thread_id.x / 2)
+ + (thread_id.y / 2) * (pitch.x / 2)
+ + pitch.x * pitch.y;
+
+ float v = fetchUnorm(src, offset) - (128 / 255.0);
+
+ // Go into the third plane to get a U, chroma sample
+ offset += (pitch.x / 2) * (pitch.y / 2);
+ float u = fetchUnorm(src, offset) - (128 / 255.0);
+
+ // TODO: Is this the right color space?
+ vec4 color = convertBT_709(vec3(y, u, v));
+
+ imageStore(dst, thread_id.xy, color);
+ }
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/version.rc b/src/libs/dxvk-native-1.9.2a/src/d3d9/version.rc
new file mode 100644
index 00000000..b4027eee
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/version.rc
@@ -0,0 +1,31 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "Direct3D 9 Runtime"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "D3D9.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "D3D9.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.cpp
new file mode 100644
index 00000000..4d59b8c8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.cpp
@@ -0,0 +1,103 @@
+#include "dxbc_analysis.h"
+
+namespace dxvk {
+
+ DxbcAnalyzer::DxbcAnalyzer(
+ const DxbcModuleInfo& moduleInfo,
+ const DxbcProgramInfo& programInfo,
+ const Rc<DxbcIsgn>& isgn,
+ const Rc<DxbcIsgn>& osgn,
+ const Rc<DxbcIsgn>& psgn,
+ DxbcAnalysisInfo& analysis)
+ : m_isgn (isgn),
+ m_osgn (osgn),
+ m_psgn (psgn),
+ m_analysis(&analysis) {
+ // Get number of clipping and culling planes from the
+ // input and output signatures. We will need this to
+ // declare the shader input and output interfaces.
+ m_analysis->clipCullIn = getClipCullInfo(m_isgn);
+ m_analysis->clipCullOut = getClipCullInfo(m_osgn);
+ }
+
+
+ DxbcAnalyzer::~DxbcAnalyzer() {
+
+ }
+
+
+ void DxbcAnalyzer::processInstruction(const DxbcShaderInstruction& ins) {
+ switch (ins.opClass) {
+ case DxbcInstClass::Atomic: {
+ const uint32_t operandId = ins.dstCount - 1;
+
+ if (ins.dst[operandId].type == DxbcOperandType::UnorderedAccessView) {
+ const uint32_t registerId = ins.dst[operandId].idx[0].offset;
+ m_analysis->uavInfos[registerId].accessAtomicOp = true;
+ m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ } break;
+
+ case DxbcInstClass::TextureSample:
+ case DxbcInstClass::TextureGather:
+ case DxbcInstClass::TextureQueryLod:
+ case DxbcInstClass::VectorDeriv: {
+ m_analysis->usesDerivatives = true;
+ } break;
+
+ case DxbcInstClass::ControlFlow: {
+ if (ins.op == DxbcOpcode::Discard)
+ m_analysis->usesKill = true;
+ } break;
+
+ case DxbcInstClass::BufferLoad: {
+ uint32_t operandId = ins.op == DxbcOpcode::LdStructured ? 2 : 1;
+
+ if (ins.src[operandId].type == DxbcOperandType::UnorderedAccessView) {
+ const uint32_t registerId = ins.src[operandId].idx[0].offset;
+ m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT;
+ }
+ } break;
+
+ case DxbcInstClass::BufferStore: {
+ if (ins.dst[0].type == DxbcOperandType::UnorderedAccessView) {
+ const uint32_t registerId = ins.dst[0].idx[0].offset;
+ m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
+ }
+ } break;
+
+ case DxbcInstClass::TypedUavLoad: {
+ const uint32_t registerId = ins.src[1].idx[0].offset;
+ m_analysis->uavInfos[registerId].accessTypedLoad = true;
+ m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_READ_BIT;
+ } break;
+
+ case DxbcInstClass::TypedUavStore: {
+ const uint32_t registerId = ins.dst[0].idx[0].offset;
+ m_analysis->uavInfos[registerId].accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
+ } break;
+
+ default:
+ return;
+ }
+ }
+
+
+ DxbcClipCullInfo DxbcAnalyzer::getClipCullInfo(const Rc<DxbcIsgn>& sgn) const {
+ DxbcClipCullInfo result;
+
+ if (sgn != nullptr) {
+ for (auto e = sgn->begin(); e != sgn->end(); e++) {
+ const uint32_t componentCount = e->componentMask.popCount();
+
+ if (e->systemValue == DxbcSystemValue::ClipDistance)
+ result.numClipPlanes += componentCount;
+ if (e->systemValue == DxbcSystemValue::CullDistance)
+ result.numCullPlanes += componentCount;
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.h
new file mode 100644
index 00000000..1c09cc9c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_analysis.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "dxbc_chunk_isgn.h"
+#include "dxbc_decoder.h"
+#include "dxbc_defs.h"
+#include "dxbc_names.h"
+#include "dxbc_modinfo.h"
+#include "dxbc_util.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Info about unordered access views
+ *
+ * Stores whether an UAV is accessed with typed
+ * read or atomic instructions. This information
+ * will be used to generate image types.
+ */
+ struct DxbcUavInfo {
+ bool accessTypedLoad = false;
+ bool accessAtomicOp = false;
+ VkAccessFlags accessFlags = 0;
+ };
+
+ /**
+ * \brief Counts cull and clip distances
+ */
+ struct DxbcClipCullInfo {
+ uint32_t numClipPlanes = 0;
+ uint32_t numCullPlanes = 0;
+ };
+
+ /**
+ * \brief Shader analysis info
+ */
+ struct DxbcAnalysisInfo {
+ std::array<DxbcUavInfo, 64> uavInfos;
+
+ DxbcClipCullInfo clipCullIn;
+ DxbcClipCullInfo clipCullOut;
+
+ bool usesDerivatives = false;
+ bool usesKill = false;
+ };
+
+ /**
+ * \brief DXBC shader analysis pass
+ *
+ * Collects information about the shader itself
+ * and the resources used by the shader, which
+ * will later be used by the actual compiler.
+ */
+ class DxbcAnalyzer {
+
+ public:
+
+ DxbcAnalyzer(
+ const DxbcModuleInfo& moduleInfo,
+ const DxbcProgramInfo& programInfo,
+ const Rc<DxbcIsgn>& isgn,
+ const Rc<DxbcIsgn>& osgn,
+ const Rc<DxbcIsgn>& psgn,
+ DxbcAnalysisInfo& analysis);
+
+ ~DxbcAnalyzer();
+
+ /**
+ * \brief Processes a single instruction
+ * \param [in] ins The instruction
+ */
+ void processInstruction(
+ const DxbcShaderInstruction& ins);
+
+ private:
+
+ Rc<DxbcIsgn> m_isgn;
+ Rc<DxbcIsgn> m_osgn;
+ Rc<DxbcIsgn> m_psgn;
+
+ DxbcAnalysisInfo* m_analysis = nullptr;
+
+ DxbcClipCullInfo getClipCullInfo(
+ const Rc<DxbcIsgn>& sgn) const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.cpp
new file mode 100644
index 00000000..ce6617bd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.cpp
@@ -0,0 +1,114 @@
+#include "dxbc_chunk_isgn.h"
+
+namespace dxvk {
+
+ DxbcIsgn::DxbcIsgn(DxbcReader reader, DxbcTag tag) {
+ uint32_t elementCount = reader.readu32();
+ reader.skip(sizeof(uint32_t));
+
+ std::array<DxbcScalarType, 4> componentTypes = {
+ DxbcScalarType::Uint32, DxbcScalarType::Uint32,
+ DxbcScalarType::Sint32, DxbcScalarType::Float32,
+ };
+
+ // https://github.com/DarkStarSword/3d-fixes/blob/master/dx11shaderanalyse.py#L101
+ bool hasStream = (tag == "ISG1") || (tag == "OSG1") || (tag == "PSG1") || (tag == "OSG5");
+ bool hasPrecision = (tag == "ISG1") || (tag == "OSG1") || (tag == "PSG1");
+
+ for (uint32_t i = 0; i < elementCount; i++) {
+ DxbcSgnEntry entry;
+ entry.streamId = hasStream ? reader.readu32() : 0;
+ entry.semanticName = reader.clone(reader.readu32()).readString();
+ entry.semanticIndex = reader.readu32();
+ entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
+ entry.componentType = componentTypes.at(reader.readu32());
+ entry.registerId = reader.readu32();
+ entry.componentMask = bit::extract(reader.readu32(), 0, 3);
+
+ if (hasPrecision)
+ reader.readu32();
+
+ m_entries.push_back(entry);
+ }
+ }
+
+
+ DxbcIsgn::~DxbcIsgn() {
+
+ }
+
+
+ const DxbcSgnEntry* DxbcIsgn::findByRegister(uint32_t registerId) const {
+ for (auto e = this->begin(); e != this->end(); e++) {
+ if (e->registerId == registerId)
+ return &(*e);
+ }
+
+ return nullptr;
+ }
+
+
+ const DxbcSgnEntry* DxbcIsgn::find(
+ const std::string& semanticName,
+ uint32_t semanticIndex,
+ uint32_t streamId) const {
+ for (auto e = this->begin(); e != this->end(); e++) {
+ if (e->semanticIndex == semanticIndex
+ && e->streamId == streamId
+ && compareSemanticNames(semanticName, e->semanticName))
+ return &(*e);
+ }
+
+ return nullptr;
+ }
+
+
+ DxbcRegMask DxbcIsgn::regMask(
+ uint32_t registerId) const {
+ DxbcRegMask mask;
+
+ for (auto e = this->begin(); e != this->end(); e++) {
+ if (e->registerId == registerId)
+ mask |= e->componentMask;
+ }
+
+ return mask;
+ }
+
+
+ uint32_t DxbcIsgn::maxRegisterCount() const {
+ uint32_t result = 0;
+ for (auto e = this->begin(); e != this->end(); e++)
+ result = std::max(result, e->registerId + 1);
+ return result;
+ }
+
+ void DxbcIsgn::printEntries() const {
+ for (auto entry = this->begin(); entry != this->end(); entry++) {
+ Logger::debug(str::format("SGN Entry:\n\t",
+ "semanticName: ", entry->semanticName, "\n\t",
+ "semanticIndex: ", entry->semanticIndex, "\n\t",
+ "registerId: ", entry->registerId, "\n\t",
+ "componentMask: ", entry->componentMask.maskString(), "\n\t",
+ "componentType: ", entry->componentType, "\n\t",
+ "systemValue: ", entry->systemValue, "\n\t",
+ "streamId: ", entry->streamId, "\n",
+ "\n"));
+ }
+ }
+
+
+ bool DxbcIsgn::compareSemanticNames(
+ const std::string& a, const std::string& b) const {
+ if (a.size() != b.size())
+ return false;
+
+ for (size_t i = 0; i < a.size(); i++) {
+ if (std::toupper(a[i]) != std::toupper(b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.h
new file mode 100644
index 00000000..030372f3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_isgn.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <cctype>
+
+#include "dxbc_common.h"
+#include "dxbc_decoder.h"
+#include "dxbc_enums.h"
+#include "dxbc_reader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Signature entry
+ *
+ * Stores the semantic name of an input or
+ * output and the corresponding register.
+ */
+ struct DxbcSgnEntry {
+ std::string semanticName;
+ uint32_t semanticIndex;
+ uint32_t registerId;
+ DxbcRegMask componentMask;
+ DxbcScalarType componentType;
+ DxbcSystemValue systemValue;
+ uint32_t streamId;
+ };
+
+ /**
+ * \brief Input/Output signature chunk
+ *
+ * Stores information about the input and
+ * output registers used by the shader stage.
+ */
+ class DxbcIsgn : public RcObject {
+
+ public:
+
+ DxbcIsgn(DxbcReader reader, DxbcTag tag);
+ ~DxbcIsgn();
+
+ auto begin() const { return m_entries.cbegin(); }
+ auto end () const { return m_entries.cend(); }
+
+ const DxbcSgnEntry* findByRegister(
+ uint32_t registerId) const;
+
+ const DxbcSgnEntry* find(
+ const std::string& semanticName,
+ uint32_t semanticIndex,
+ uint32_t streamIndex) const;
+
+ DxbcRegMask regMask(
+ uint32_t registerId) const;
+
+ uint32_t maxRegisterCount() const;
+
+ void printEntries() const;
+
+ private:
+
+ std::vector<DxbcSgnEntry> m_entries;
+
+ bool compareSemanticNames(
+ const std::string& a,
+ const std::string& b) const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.cpp
new file mode 100644
index 00000000..552329b8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.cpp
@@ -0,0 +1,24 @@
+#include "dxbc_chunk_shex.h"
+
+namespace dxvk {
+
+ DxbcShex::DxbcShex(DxbcReader reader) {
+ // The shader version and type are stored in a 32-bit unit,
+ // where the first byte contains the major and minor version
+ // numbers, and the high word contains the program type.
+ reader.skip(2);
+ auto pType = reader.readEnum<DxbcProgramType>();
+ m_programInfo = DxbcProgramInfo(pType);
+
+ // Read the actual shader code as an array of DWORDs.
+ auto codeLength = reader.readu32() - 2;
+ m_code.resize(codeLength);
+ reader.read(m_code.data(), codeLength * sizeof(uint32_t));
+ }
+
+
+ DxbcShex::~DxbcShex() {
+
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.h
new file mode 100644
index 00000000..8deecc86
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_chunk_shex.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "dxbc_common.h"
+#include "dxbc_decoder.h"
+#include "dxbc_reader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Shader code chunk
+ *
+ * Stores the DXBC shader code itself, as well
+ * as some meta info about the shader, i.e. what
+ * type of shader this is.
+ */
+ class DxbcShex : public RcObject {
+
+ public:
+
+ DxbcShex(DxbcReader reader);
+ ~DxbcShex();
+
+ DxbcProgramInfo programInfo() const {
+ return m_programInfo;
+ }
+
+ DxbcCodeSlice slice() const {
+ return DxbcCodeSlice(m_code.data(),
+ m_code.data() + m_code.size());
+ }
+
+ private:
+
+ DxbcProgramInfo m_programInfo;
+ std::vector<uint32_t> m_code;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.cpp
new file mode 100644
index 00000000..d150c585
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.cpp
@@ -0,0 +1,32 @@
+#include "dxbc_common.h"
+
+namespace dxvk {
+
+ VkShaderStageFlagBits DxbcProgramInfo::shaderStage() const {
+ switch (m_type) {
+ case DxbcProgramType::PixelShader : return VK_SHADER_STAGE_FRAGMENT_BIT;
+ case DxbcProgramType::VertexShader : return VK_SHADER_STAGE_VERTEX_BIT;
+ case DxbcProgramType::GeometryShader : return VK_SHADER_STAGE_GEOMETRY_BIT;
+ case DxbcProgramType::HullShader : return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+ case DxbcProgramType::DomainShader : return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+ case DxbcProgramType::ComputeShader : return VK_SHADER_STAGE_COMPUTE_BIT;
+ }
+
+ throw DxvkError("DxbcProgramInfo::shaderStage: Unsupported program type");
+ }
+
+
+ spv::ExecutionModel DxbcProgramInfo::executionModel() const {
+ switch (m_type) {
+ case DxbcProgramType::PixelShader : return spv::ExecutionModelFragment;
+ case DxbcProgramType::VertexShader : return spv::ExecutionModelVertex;
+ case DxbcProgramType::GeometryShader : return spv::ExecutionModelGeometry;
+ case DxbcProgramType::HullShader : return spv::ExecutionModelTessellationControl;
+ case DxbcProgramType::DomainShader : return spv::ExecutionModelTessellationEvaluation;
+ case DxbcProgramType::ComputeShader : return spv::ExecutionModelGLCompute;
+ }
+
+ throw DxvkError("DxbcProgramInfo::executionModel: Unsupported program type");
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.h
new file mode 100644
index 00000000..9c490d62
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_common.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "dxbc_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXBC Program type
+ *
+ * Defines the shader stage that a DXBC
+ * module has been compiled form.
+ */
+ enum class DxbcProgramType : uint16_t {
+ PixelShader = 0,
+ VertexShader = 1,
+ GeometryShader = 2,
+ HullShader = 3,
+ DomainShader = 4,
+ ComputeShader = 5,
+ };
+
+
+ /**
+ * \brief DXBC shader info
+ *
+ * Stores the shader program type.
+ */
+ class DxbcProgramInfo {
+
+ public:
+
+ DxbcProgramInfo() { }
+ DxbcProgramInfo(DxbcProgramType type)
+ : m_type(type) { }
+
+ /**
+ * \brief Program type
+ * \returns Program type
+ */
+ DxbcProgramType type() const {
+ return m_type;
+ }
+
+ /**
+ * \brief Vulkan shader stage
+ *
+ * The \c VkShaderStageFlagBits constant
+ * that corresponds to the program type.
+ * \returns Vulkan shaer stage
+ */
+ VkShaderStageFlagBits shaderStage() const;
+
+ /**
+ * \brief SPIR-V execution model
+ *
+ * The execution model that corresponds
+ * to the Vulkan shader stage.
+ * \returns SPIR-V execution model
+ */
+ spv::ExecutionModel executionModel() const;
+
+ private:
+
+ DxbcProgramType m_type = DxbcProgramType::PixelShader;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.cpp
new file mode 100644
index 00000000..f4f3951e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.cpp
@@ -0,0 +1,7905 @@
+#include "dxbc_compiler.h"
+
+namespace dxvk {
+
+ constexpr uint32_t Icb_BindingSlotId = 14;
+ constexpr uint32_t Icb_MaxBakedDwords = 16;
+
+ constexpr uint32_t PerVertex_Position = 0;
+ constexpr uint32_t PerVertex_CullDist = 1;
+ constexpr uint32_t PerVertex_ClipDist = 2;
+
+ DxbcCompiler::DxbcCompiler(
+ const std::string& fileName,
+ const DxbcModuleInfo& moduleInfo,
+ const DxbcProgramInfo& programInfo,
+ const Rc<DxbcIsgn>& isgn,
+ const Rc<DxbcIsgn>& osgn,
+ const Rc<DxbcIsgn>& psgn,
+ const DxbcAnalysisInfo& analysis)
+ : m_moduleInfo (moduleInfo),
+ m_programInfo(programInfo),
+ m_module (spvVersion(1, 3)),
+ m_isgn (isgn),
+ m_osgn (osgn),
+ m_psgn (psgn),
+ m_analysis (&analysis) {
+ // Declare an entry point ID. We'll need it during the
+ // initialization phase where the execution mode is set.
+ m_entryPointId = m_module.allocateId();
+
+ // Set the shader name so that we recognize it in renderdoc
+ m_module.setDebugSource(
+ spv::SourceLanguageUnknown, 0,
+ m_module.addDebugString(fileName.c_str()),
+ nullptr);
+
+ if (Logger::logLevel() <= LogLevel::Debug) {
+ if (m_isgn != nullptr) {
+ Logger::debug(str::format("Input Signature for - ", fileName.c_str(), "\n"));
+ m_isgn->printEntries();
+ }
+ if (m_osgn != nullptr) {
+ Logger::debug(str::format("Output Signature for - ", fileName.c_str(), "\n"));
+ m_osgn->printEntries();
+ }
+ if (m_psgn != nullptr) {
+ Logger::debug(str::format("Patch Constant Signature for - ", fileName.c_str(), "\n"));
+ m_psgn->printEntries();
+ }
+ }
+
+ // Set the memory model. This is the same for all shaders.
+ m_module.setMemoryModel(
+ spv::AddressingModelLogical,
+ spv::MemoryModelGLSL450);
+
+ // Make sure our interface registers are clear
+ for (uint32_t i = 0; i < DxbcMaxInterfaceRegs; i++) {
+ m_vRegs.at(i) = DxbcRegisterPointer { };
+ m_oRegs.at(i) = DxbcRegisterPointer { };
+ }
+
+ this->emitInit();
+ }
+
+
+ DxbcCompiler::~DxbcCompiler() {
+
+ }
+
+
+ void DxbcCompiler::processInstruction(const DxbcShaderInstruction& ins) {
+ switch (ins.opClass) {
+ case DxbcInstClass::Declaration:
+ return this->emitDcl(ins);
+
+ case DxbcInstClass::CustomData:
+ return this->emitCustomData(ins);
+
+ case DxbcInstClass::Atomic:
+ return this->emitAtomic(ins);
+
+ case DxbcInstClass::AtomicCounter:
+ return this->emitAtomicCounter(ins);
+
+ case DxbcInstClass::Barrier:
+ return this->emitBarrier(ins);
+
+ case DxbcInstClass::BitExtract:
+ return this->emitBitExtract(ins);
+
+ case DxbcInstClass::BitInsert:
+ return this->emitBitInsert(ins);
+
+ case DxbcInstClass::BitScan:
+ return this->emitBitScan(ins);
+
+ case DxbcInstClass::BufferQuery:
+ return this->emitBufferQuery(ins);
+
+ case DxbcInstClass::BufferLoad:
+ return this->emitBufferLoad(ins);
+
+ case DxbcInstClass::BufferStore:
+ return this->emitBufferStore(ins);
+
+ case DxbcInstClass::ConvertFloat16:
+ return this->emitConvertFloat16(ins);
+
+ case DxbcInstClass::ConvertFloat64:
+ return this->emitConvertFloat64(ins);
+
+ case DxbcInstClass::ControlFlow:
+ return this->emitControlFlow(ins);
+
+ case DxbcInstClass::GeometryEmit:
+ return this->emitGeometryEmit(ins);
+
+ case DxbcInstClass::HullShaderPhase:
+ return this->emitHullShaderPhase(ins);
+
+ case DxbcInstClass::HullShaderInstCnt:
+ return this->emitHullShaderInstCnt(ins);
+
+ case DxbcInstClass::Interpolate:
+ return this->emitInterpolate(ins);
+
+ case DxbcInstClass::NoOperation:
+ return;
+
+ case DxbcInstClass::TextureQuery:
+ return this->emitTextureQuery(ins);
+
+ case DxbcInstClass::TextureQueryLod:
+ return this->emitTextureQueryLod(ins);
+
+ case DxbcInstClass::TextureQueryMs:
+ return this->emitTextureQueryMs(ins);
+
+ case DxbcInstClass::TextureQueryMsPos:
+ return this->emitTextureQueryMsPos(ins);
+
+ case DxbcInstClass::TextureFetch:
+ return this->emitTextureFetch(ins);
+
+ case DxbcInstClass::TextureGather:
+ return this->emitTextureGather(ins);
+
+ case DxbcInstClass::TextureSample:
+ return this->emitTextureSample(ins);
+
+ case DxbcInstClass::TypedUavLoad:
+ return this->emitTypedUavLoad(ins);
+
+ case DxbcInstClass::TypedUavStore:
+ return this->emitTypedUavStore(ins);
+
+ case DxbcInstClass::VectorAlu:
+ return this->emitVectorAlu(ins);
+
+ case DxbcInstClass::VectorCmov:
+ return this->emitVectorCmov(ins);
+
+ case DxbcInstClass::VectorCmp:
+ return this->emitVectorCmp(ins);
+
+ case DxbcInstClass::VectorDeriv:
+ return this->emitVectorDeriv(ins);
+
+ case DxbcInstClass::VectorDot:
+ return this->emitVectorDot(ins);
+
+ case DxbcInstClass::VectorIdiv:
+ return this->emitVectorIdiv(ins);
+
+ case DxbcInstClass::VectorImul:
+ return this->emitVectorImul(ins);
+
+ case DxbcInstClass::VectorMsad:
+ return this->emitVectorMsad(ins);
+
+ case DxbcInstClass::VectorShift:
+ return this->emitVectorShift(ins);
+
+ case DxbcInstClass::VectorSinCos:
+ return this->emitVectorSinCos(ins);
+
+ default:
+ Logger::warn(
+ str::format("DxbcCompiler: Unhandled opcode class: ",
+ ins.op));
+ }
+ }
+
+
+ void DxbcCompiler::processXfbPassthrough() {
+ m_module.setExecutionMode (m_entryPointId, spv::ExecutionModeInputPoints);
+ m_module.setExecutionMode (m_entryPointId, spv::ExecutionModeOutputPoints);
+ m_module.setOutputVertices(m_entryPointId, 1);
+ m_module.setInvocations (m_entryPointId, 1);
+
+ for (auto e = m_isgn->begin(); e != m_isgn->end(); e++) {
+ emitDclInput(e->registerId, 1,
+ e->componentMask, DxbcSystemValue::None,
+ DxbcInterpolationMode::Undefined);
+ }
+
+ // Figure out which streams to enable
+ uint32_t streamMask = 0;
+
+ for (size_t i = 0; i < m_xfbVars.size(); i++)
+ streamMask |= 1u << m_xfbVars[i].streamId;
+
+ for (uint32_t streamId : bit::BitMask(streamMask)) {
+ emitXfbOutputSetup(streamId, true);
+ m_module.opEmitVertex(m_module.constu32(streamId));
+ }
+
+ // End the main function
+ emitFunctionEnd();
+ }
+
+
+ Rc<DxvkShader> DxbcCompiler::finalize() {
+ // Depending on the shader type, this will prepare
+ // input registers, call various shader functions
+ // and write back the output registers.
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::VertexShader: this->emitVsFinalize(); break;
+ case DxbcProgramType::HullShader: this->emitHsFinalize(); break;
+ case DxbcProgramType::DomainShader: this->emitDsFinalize(); break;
+ case DxbcProgramType::GeometryShader: this->emitGsFinalize(); break;
+ case DxbcProgramType::PixelShader: this->emitPsFinalize(); break;
+ case DxbcProgramType::ComputeShader: this->emitCsFinalize(); break;
+ }
+
+ // Emit float control mode if the extension is supported
+ this->emitFloatControl();
+
+ // Declare the entry point, we now have all the
+ // information we need, including the interfaces
+ m_module.addEntryPoint(m_entryPointId,
+ m_programInfo.executionModel(), "main",
+ m_entryPointInterfaces.size(),
+ m_entryPointInterfaces.data());
+ m_module.setDebugName(m_entryPointId, "main");
+
+ DxvkShaderOptions shaderOptions = { };
+
+ if (m_moduleInfo.xfb != nullptr) {
+ shaderOptions.rasterizedStream = m_moduleInfo.xfb->rasterizedStream;
+
+ for (uint32_t i = 0; i < 4; i++)
+ shaderOptions.xfbStrides[i] = m_moduleInfo.xfb->strides[i];
+ }
+
+ // Create the shader module object
+ return new DxvkShader(
+ m_programInfo.shaderStage(),
+ m_resourceSlots.size(),
+ m_resourceSlots.data(),
+ m_interfaceSlots,
+ m_module.compile(),
+ shaderOptions,
+ std::move(m_immConstData));
+ }
+
+
+ void DxbcCompiler::emitDcl(const DxbcShaderInstruction& ins) {
+ switch (ins.op) {
+ case DxbcOpcode::DclGlobalFlags:
+ return this->emitDclGlobalFlags(ins);
+
+ case DxbcOpcode::DclIndexRange:
+ return; // not needed for anything
+
+ case DxbcOpcode::DclTemps:
+ return this->emitDclTemps(ins);
+
+ case DxbcOpcode::DclIndexableTemp:
+ return this->emitDclIndexableTemp(ins);
+
+ case DxbcOpcode::DclInput:
+ case DxbcOpcode::DclInputSgv:
+ case DxbcOpcode::DclInputSiv:
+ case DxbcOpcode::DclInputPs:
+ case DxbcOpcode::DclInputPsSgv:
+ case DxbcOpcode::DclInputPsSiv:
+ case DxbcOpcode::DclOutput:
+ case DxbcOpcode::DclOutputSgv:
+ case DxbcOpcode::DclOutputSiv:
+ return this->emitDclInterfaceReg(ins);
+
+ case DxbcOpcode::DclConstantBuffer:
+ return this->emitDclConstantBuffer(ins);
+
+ case DxbcOpcode::DclSampler:
+ return this->emitDclSampler(ins);
+
+ case DxbcOpcode::DclStream:
+ return this->emitDclStream(ins);
+
+ case DxbcOpcode::DclUavTyped:
+ case DxbcOpcode::DclResource:
+ return this->emitDclResourceTyped(ins);
+
+ case DxbcOpcode::DclUavRaw:
+ case DxbcOpcode::DclResourceRaw:
+ case DxbcOpcode::DclUavStructured:
+ case DxbcOpcode::DclResourceStructured:
+ return this->emitDclResourceRawStructured(ins);
+
+ case DxbcOpcode::DclThreadGroupSharedMemoryRaw:
+ case DxbcOpcode::DclThreadGroupSharedMemoryStructured:
+ return this->emitDclThreadGroupSharedMemory(ins);
+
+ case DxbcOpcode::DclGsInputPrimitive:
+ return this->emitDclGsInputPrimitive(ins);
+
+ case DxbcOpcode::DclGsOutputPrimitiveTopology:
+ return this->emitDclGsOutputTopology(ins);
+
+ case DxbcOpcode::DclMaxOutputVertexCount:
+ return this->emitDclMaxOutputVertexCount(ins);
+
+ case DxbcOpcode::DclInputControlPointCount:
+ return this->emitDclInputControlPointCount(ins);
+
+ case DxbcOpcode::DclOutputControlPointCount:
+ return this->emitDclOutputControlPointCount(ins);
+
+ case DxbcOpcode::DclHsMaxTessFactor:
+ return this->emitDclHsMaxTessFactor(ins);
+
+ case DxbcOpcode::DclTessDomain:
+ return this->emitDclTessDomain(ins);
+
+ case DxbcOpcode::DclTessPartitioning:
+ return this->emitDclTessPartitioning(ins);
+
+ case DxbcOpcode::DclTessOutputPrimitive:
+ return this->emitDclTessOutputPrimitive(ins);
+
+ case DxbcOpcode::DclThreadGroup:
+ return this->emitDclThreadGroup(ins);
+
+ case DxbcOpcode::DclGsInstanceCount:
+ return this->emitDclGsInstanceCount(ins);
+
+ default:
+ Logger::warn(
+ str::format("DxbcCompiler: Unhandled opcode: ",
+ ins.op));
+ }
+ }
+
+
+ void DxbcCompiler::emitDclGlobalFlags(const DxbcShaderInstruction& ins) {
+ const DxbcGlobalFlags flags = ins.controls.globalFlags();
+
+ if (flags.test(DxbcGlobalFlag::RefactoringAllowed))
+ m_precise = false;
+
+ if (flags.test(DxbcGlobalFlag::EarlyFragmentTests))
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeEarlyFragmentTests);
+ }
+
+
+ void DxbcCompiler::emitDclTemps(const DxbcShaderInstruction& ins) {
+ // dcl_temps has one operand:
+ // (imm0) Number of temp registers
+
+ // Ignore this and declare temps on demand.
+ }
+
+
+ void DxbcCompiler::emitDclIndexableTemp(const DxbcShaderInstruction& ins) {
+ // dcl_indexable_temps has three operands:
+ // (imm0) Array register index (x#)
+ // (imm1) Number of vectors stored in the array
+ // (imm2) Component count of each individual vector
+ DxbcRegisterInfo info;
+ info.type.ctype = DxbcScalarType::Float32;
+ info.type.ccount = ins.imm[2].u32;
+ info.type.alength = ins.imm[1].u32;
+ info.sclass = spv::StorageClassPrivate;
+
+ const uint32_t regId = ins.imm[0].u32;
+
+ if (regId >= m_xRegs.size())
+ m_xRegs.resize(regId + 1);
+
+ m_xRegs.at(regId).ccount = info.type.ccount;
+ m_xRegs.at(regId).alength = info.type.alength;
+ m_xRegs.at(regId).varId = emitNewVariable(info);
+
+ m_module.setDebugName(m_xRegs.at(regId).varId,
+ str::format("x", regId).c_str());
+ }
+
+
+ void DxbcCompiler::emitDclInterfaceReg(const DxbcShaderInstruction& ins) {
+ switch (ins.dst[0].type) {
+ case DxbcOperandType::InputControlPoint:
+ if (m_programInfo.type() != DxbcProgramType::HullShader)
+ break;
+ /* fall through */
+
+ case DxbcOperandType::Input:
+ case DxbcOperandType::Output: {
+ // dcl_input and dcl_output instructions
+ // have the following operands:
+ // (dst0) The register to declare
+ // (imm0) The system value (optional)
+ uint32_t regDim = 0;
+ uint32_t regIdx = 0;
+
+ // In the vertex and fragment shader stage, the
+ // operand indices will have the following format:
+ // (0) Register index
+ //
+ // In other stages, the input and output registers
+ // may be declared as arrays of a fixed size:
+ // (0) Array length
+ // (1) Register index
+ if (ins.dst[0].idxDim == 2) {
+ regDim = ins.dst[0].idx[0].offset;
+ regIdx = ins.dst[0].idx[1].offset;
+ } else if (ins.dst[0].idxDim == 1) {
+ regIdx = ins.dst[0].idx[0].offset;
+ } else {
+ Logger::err(str::format(
+ "DxbcCompiler: ", ins.op,
+ ": Invalid index dimension"));
+ return;
+ }
+
+ // This declaration may map an output register to a system
+ // value. If that is the case, the system value type will
+ // be stored in the second operand.
+ const bool hasSv =
+ ins.op == DxbcOpcode::DclInputSgv
+ || ins.op == DxbcOpcode::DclInputSiv
+ || ins.op == DxbcOpcode::DclInputPsSgv
+ || ins.op == DxbcOpcode::DclInputPsSiv
+ || ins.op == DxbcOpcode::DclOutputSgv
+ || ins.op == DxbcOpcode::DclOutputSiv;
+
+ DxbcSystemValue sv = DxbcSystemValue::None;
+
+ if (hasSv)
+ sv = static_cast<DxbcSystemValue>(ins.imm[0].u32);
+
+ // In the pixel shader, inputs are declared with an
+ // interpolation mode that is part of the op token.
+ const bool hasInterpolationMode =
+ ins.op == DxbcOpcode::DclInputPs
+ || ins.op == DxbcOpcode::DclInputPsSiv;
+
+ DxbcInterpolationMode im = DxbcInterpolationMode::Undefined;
+
+ if (hasInterpolationMode)
+ im = ins.controls.interpolation();
+
+ // Declare the actual input/output variable
+ switch (ins.op) {
+ case DxbcOpcode::DclInput:
+ case DxbcOpcode::DclInputSgv:
+ case DxbcOpcode::DclInputSiv:
+ case DxbcOpcode::DclInputPs:
+ case DxbcOpcode::DclInputPsSgv:
+ case DxbcOpcode::DclInputPsSiv:
+ this->emitDclInput(regIdx, regDim, ins.dst[0].mask, sv, im);
+ break;
+
+ case DxbcOpcode::DclOutput:
+ case DxbcOpcode::DclOutputSgv:
+ case DxbcOpcode::DclOutputSiv:
+ this->emitDclOutput(regIdx, regDim, ins.dst[0].mask, sv, im);
+ break;
+
+ default:
+ Logger::err(str::format(
+ "DxbcCompiler: Unexpected opcode: ",
+ ins.op));
+ }
+ } break;
+
+ case DxbcOperandType::InputThreadId: {
+ m_cs.builtinGlobalInvocationId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 3, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInGlobalInvocationId,
+ "vThreadId");
+ } break;
+
+ case DxbcOperandType::InputThreadGroupId: {
+ m_cs.builtinWorkgroupId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 3, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInWorkgroupId,
+ "vThreadGroupId");
+ } break;
+
+ case DxbcOperandType::InputThreadIdInGroup: {
+ m_cs.builtinLocalInvocationId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 3, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInLocalInvocationId,
+ "vThreadIdInGroup");
+ } break;
+
+ case DxbcOperandType::InputThreadIndexInGroup: {
+ m_cs.builtinLocalInvocationIndex = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInLocalInvocationIndex,
+ "vThreadIndexInGroup");
+ } break;
+
+ case DxbcOperandType::InputCoverageMask: {
+ m_ps.builtinSampleMaskIn = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 1 },
+ spv::StorageClassInput },
+ spv::BuiltInSampleMask,
+ "vCoverage");
+ } break;
+
+ case DxbcOperandType::OutputCoverageMask: {
+ m_ps.builtinSampleMaskOut = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 1 },
+ spv::StorageClassOutput },
+ spv::BuiltInSampleMask,
+ "oMask");
+ } break;
+
+ case DxbcOperandType::OutputDepth: {
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeDepthReplacing);
+ m_ps.builtinDepth = emitNewBuiltinVariable({
+ { DxbcScalarType::Float32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInFragDepth,
+ "oDepth");
+ } break;
+
+ case DxbcOperandType::OutputStencilRef: {
+ m_module.enableExtension("SPV_EXT_shader_stencil_export");
+ m_module.enableCapability(spv::CapabilityStencilExportEXT);
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeStencilRefReplacingEXT);
+ m_ps.builtinStencilRef = emitNewBuiltinVariable({
+ { DxbcScalarType::Sint32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInFragStencilRefEXT,
+ "oStencilRef");
+ } break;
+
+ case DxbcOperandType::OutputDepthGe: {
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDepthReplacing);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDepthGreater);
+ m_ps.builtinDepth = emitNewBuiltinVariable({
+ { DxbcScalarType::Float32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInFragDepth,
+ "oDepthGe");
+ } break;
+
+ case DxbcOperandType::OutputDepthLe: {
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDepthReplacing);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDepthLess);
+ m_ps.builtinDepth = emitNewBuiltinVariable({
+ { DxbcScalarType::Float32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInFragDepth,
+ "oDepthLe");
+ } break;
+
+ case DxbcOperandType::InputPrimitiveId: {
+ m_primitiveIdIn = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInPrimitiveId,
+ "vPrim");
+ } break;
+
+ case DxbcOperandType::InputDomainPoint: {
+ m_ds.builtinTessCoord = emitNewBuiltinVariable({
+ { DxbcScalarType::Float32, 3, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInTessCoord,
+ "vDomain");
+ } break;
+
+ case DxbcOperandType::InputForkInstanceId:
+ case DxbcOperandType::InputJoinInstanceId: {
+ auto phase = this->getCurrentHsForkJoinPhase();
+
+ phase->instanceIdPtr = m_module.newVar(
+ m_module.defPointerType(
+ m_module.defIntType(32, 0),
+ spv::StorageClassFunction),
+ spv::StorageClassFunction);
+
+ m_module.opStore(phase->instanceIdPtr, phase->instanceId);
+ m_module.setDebugName(phase->instanceIdPtr,
+ ins.dst[0].type == DxbcOperandType::InputForkInstanceId
+ ? "vForkInstanceId" : "vJoinInstanceId");
+ } break;
+
+ case DxbcOperandType::OutputControlPointId: {
+ // This system value map to the invocation
+ // ID, which has been declared already.
+ } break;
+
+ case DxbcOperandType::InputPatchConstant:
+ case DxbcOperandType::OutputControlPoint: {
+ // These have been declared as global input and
+ // output arrays, so there's nothing left to do.
+ } break;
+
+ case DxbcOperandType::InputGsInstanceId: {
+ m_gs.builtinInvocationId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInInvocationId,
+ "vInstanceID");
+ } break;
+
+ default:
+ Logger::err(str::format(
+ "DxbcCompiler: Unsupported operand type declaration: ",
+ ins.dst[0].type));
+
+ }
+ }
+
+
+ void DxbcCompiler::emitDclInput(
+ uint32_t regIdx,
+ uint32_t regDim,
+ DxbcRegMask regMask,
+ DxbcSystemValue sv,
+ DxbcInterpolationMode im) {
+ // Avoid declaring the same variable multiple times.
+ // This may happen when multiple system values are
+ // mapped to different parts of the same register.
+ if (m_vRegs.at(regIdx).id == 0 && sv == DxbcSystemValue::None) {
+ const DxbcVectorType regType = getInputRegType(regIdx);
+
+ DxbcRegisterInfo info;
+ info.type.ctype = regType.ctype;
+ info.type.ccount = regType.ccount;
+ info.type.alength = regDim;
+ info.sclass = spv::StorageClassInput;
+
+ const uint32_t varId = emitNewVariable(info);
+
+ m_module.decorateLocation(varId, regIdx);
+ m_module.setDebugName(varId, str::format("v", regIdx).c_str());
+ m_entryPointInterfaces.push_back(varId);
+
+ m_vRegs.at(regIdx) = { regType, varId };
+
+ // Interpolation mode, used in pixel shaders
+ if (im == DxbcInterpolationMode::Constant)
+ m_module.decorate(varId, spv::DecorationFlat);
+
+ if (im == DxbcInterpolationMode::LinearCentroid
+ || im == DxbcInterpolationMode::LinearNoPerspectiveCentroid)
+ m_module.decorate(varId, spv::DecorationCentroid);
+
+ if (im == DxbcInterpolationMode::LinearNoPerspective
+ || im == DxbcInterpolationMode::LinearNoPerspectiveCentroid
+ || im == DxbcInterpolationMode::LinearNoPerspectiveSample)
+ m_module.decorate(varId, spv::DecorationNoPerspective);
+
+ if (im == DxbcInterpolationMode::LinearSample
+ || im == DxbcInterpolationMode::LinearNoPerspectiveSample) {
+ m_module.enableCapability(spv::CapabilitySampleRateShading);
+ m_module.decorate(varId, spv::DecorationSample);
+ }
+
+ // Declare the input slot as defined
+ m_interfaceSlots.inputSlots |= 1u << regIdx;
+ m_vArrayLength = std::max(m_vArrayLength, regIdx + 1);
+ } else if (sv != DxbcSystemValue::None) {
+ // Add a new system value mapping if needed
+ bool skipSv = sv == DxbcSystemValue::ClipDistance
+ || sv == DxbcSystemValue::CullDistance;
+
+ if (!skipSv)
+ m_vMappings.push_back({ regIdx, regMask, sv });
+ }
+ }
+
+
+ void DxbcCompiler::emitDclOutput(
+ uint32_t regIdx,
+ uint32_t regDim,
+ DxbcRegMask regMask,
+ DxbcSystemValue sv,
+ DxbcInterpolationMode im) {
+ // Add a new system value mapping if needed. Clip
+ // and cull distances are handled separately.
+ if (sv != DxbcSystemValue::None
+ && sv != DxbcSystemValue::ClipDistance
+ && sv != DxbcSystemValue::CullDistance)
+ m_oMappings.push_back({ regIdx, regMask, sv });
+
+ if (m_programInfo.type() == DxbcProgramType::HullShader) {
+ // Hull shaders don't use standard outputs
+ if (getCurrentHsForkJoinPhase() != nullptr)
+ m_hs.outputPerPatchMask |= 1 << regIdx;
+ } else if (m_oRegs.at(regIdx).id == 0) {
+ // Avoid declaring the same variable multiple times.
+ // This may happen when multiple system values are
+ // mapped to different parts of the same register.
+ const DxbcVectorType regType = getOutputRegType(regIdx);
+
+ DxbcRegisterInfo info;
+ info.type.ctype = regType.ctype;
+ info.type.ccount = regType.ccount;
+ info.type.alength = regDim;
+ info.sclass = spv::StorageClassOutput;
+
+ // In xfb mode, we set up the actual
+ // output vars when emitting a vertex
+ if (m_moduleInfo.xfb != nullptr)
+ info.sclass = spv::StorageClassPrivate;
+
+ // In geometry shaders, don't duplicate system value outputs
+ // to stay within device limits. The pixel shader will read
+ // all GS system value outputs as system value inputs.
+ if (m_programInfo.type() == DxbcProgramType::GeometryShader && sv != DxbcSystemValue::None)
+ info.sclass = spv::StorageClassPrivate;
+
+ const uint32_t varId = this->emitNewVariable(info);
+ m_module.setDebugName(varId, str::format("o", regIdx).c_str());
+
+ if (info.sclass == spv::StorageClassOutput) {
+ m_module.decorateLocation(varId, regIdx);
+ m_entryPointInterfaces.push_back(varId);
+
+ // Add index decoration for potential dual-source blending
+ if (m_programInfo.type() == DxbcProgramType::PixelShader)
+ m_module.decorateIndex(varId, 0);
+
+ // Declare vertex positions in all stages as invariant, even if
+ // this is not the last stage, to help with potential Z fighting.
+ if (sv == DxbcSystemValue::Position && m_moduleInfo.options.invariantPosition)
+ m_module.decorate(varId, spv::DecorationInvariant);
+ }
+
+ m_oRegs.at(regIdx) = { regType, varId };
+
+ // Declare the output slot as defined
+ m_interfaceSlots.outputSlots |= 1u << regIdx;
+ }
+ }
+
+
+ void DxbcCompiler::emitDclConstantBuffer(const DxbcShaderInstruction& ins) {
+ // dcl_constant_buffer has one operand with two indices:
+ // (0) Constant buffer register ID (cb#)
+ // (1) Number of constants in the buffer
+ const uint32_t bufferId = ins.dst[0].idx[0].offset;
+ const uint32_t elementCount = ins.dst[0].idx[1].offset;
+
+ bool asSsbo = m_moduleInfo.options.dynamicIndexedConstantBufferAsSsbo
+ && ins.controls.accessType() == DxbcConstantBufferAccessType::DynamicallyIndexed;
+
+ this->emitDclConstantBufferVar(bufferId, elementCount,
+ str::format("cb", bufferId).c_str(), asSsbo);
+ }
+
+
+ void DxbcCompiler::emitDclConstantBufferVar(
+ uint32_t regIdx,
+ uint32_t numConstants,
+ const char* name,
+ bool asSsbo) {
+ // Uniform buffer data is stored as a fixed-size array
+ // of 4x32-bit vectors. SPIR-V requires explicit strides.
+ const uint32_t arrayType = m_module.defArrayTypeUnique(
+ getVectorTypeId({ DxbcScalarType::Float32, 4 }),
+ m_module.constu32(numConstants));
+ m_module.decorateArrayStride(arrayType, 16);
+
+ // SPIR-V requires us to put that array into a
+ // struct and decorate that struct as a block.
+ const uint32_t structType = m_module.defStructTypeUnique(1, &arrayType);
+
+ m_module.decorate(structType, asSsbo
+ ? spv::DecorationBufferBlock
+ : spv::DecorationBlock);
+ m_module.memberDecorateOffset(structType, 0, 0);
+
+ m_module.setDebugName (structType, str::format(name, "_t").c_str());
+ m_module.setDebugMemberName (structType, 0, "m");
+
+ // Variable that we'll use to access the buffer
+ const uint32_t varId = m_module.newVar(
+ m_module.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.setDebugName(varId, name);
+
+ // Compute the DXVK binding slot index for the buffer.
+ // D3D11 needs to bind the actual buffers to this slot.
+ uint32_t bindingId = computeConstantBufferBinding(
+ m_programInfo.type(), regIdx);
+
+ m_module.decorateDescriptorSet(varId, 0);
+ m_module.decorateBinding(varId, bindingId);
+
+ if (asSsbo)
+ m_module.decorate(varId, spv::DecorationNonWritable);
+
+ // Declare a specialization constant which will
+ // store whether or not the resource is bound.
+ const uint32_t specConstId = m_module.specConstBool(true);
+ m_module.decorateSpecId(specConstId, bindingId);
+ m_module.setDebugName(specConstId,
+ str::format(name, "_bound").c_str());
+
+ DxbcConstantBuffer buf;
+ buf.varId = varId;
+ buf.size = numConstants;
+ m_constantBuffers.at(regIdx) = buf;
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = asSsbo
+ ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+ : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void DxbcCompiler::emitDclSampler(const DxbcShaderInstruction& ins) {
+ // dclSampler takes one operand:
+ // (dst0) The sampler register to declare
+ const uint32_t samplerId = ins.dst[0].idx[0].offset;
+
+ // The sampler type is opaque, but we still have to
+ // define a pointer and a variable in oder to use it
+ const uint32_t samplerType = m_module.defSamplerType();
+ const uint32_t samplerPtrType = m_module.defPointerType(
+ samplerType, spv::StorageClassUniformConstant);
+
+ // Define the sampler variable
+ const uint32_t varId = m_module.newVar(samplerPtrType,
+ spv::StorageClassUniformConstant);
+ m_module.setDebugName(varId,
+ str::format("s", samplerId).c_str());
+
+ m_samplers.at(samplerId).varId = varId;
+ m_samplers.at(samplerId).typeId = samplerType;
+
+ // Compute binding slot index for the sampler
+ uint32_t bindingId = computeSamplerBinding(
+ m_programInfo.type(), samplerId);
+
+ m_module.decorateDescriptorSet(varId, 0);
+ m_module.decorateBinding(varId, bindingId);
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_SAMPLER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = 0;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void DxbcCompiler::emitDclStream(const DxbcShaderInstruction& ins) {
+ if (ins.dst[0].idx[0].offset != 0 && m_moduleInfo.xfb == nullptr)
+ Logger::err("Dxbc: Multiple streams not supported");
+ }
+
+
+ void DxbcCompiler::emitDclResourceTyped(const DxbcShaderInstruction& ins) {
+ // dclResource takes two operands:
+ // (dst0) The resource register ID
+ // (imm0) The resource return type
+ const uint32_t registerId = ins.dst[0].idx[0].offset;
+
+ // We also handle unordered access views here
+ const bool isUav = ins.op == DxbcOpcode::DclUavTyped;
+
+ if (isUav) {
+ if (m_moduleInfo.options.useStorageImageReadWithoutFormat)
+ m_module.enableCapability(spv::CapabilityStorageImageReadWithoutFormat);
+ m_module.enableCapability(spv::CapabilityStorageImageWriteWithoutFormat);
+ }
+
+ // Defines the type of the resource (texture2D, ...)
+ const DxbcResourceDim resourceType = ins.controls.resourceDim();
+
+ // Defines the type of a read operation. DXBC has the ability
+ // to define four different types whereas SPIR-V only allows
+ // one, but in practice this should not be much of a problem.
+ auto xType = static_cast<DxbcResourceReturnType>(
+ bit::extract(ins.imm[0].u32, 0, 3));
+ auto yType = static_cast<DxbcResourceReturnType>(
+ bit::extract(ins.imm[0].u32, 4, 7));
+ auto zType = static_cast<DxbcResourceReturnType>(
+ bit::extract(ins.imm[0].u32, 8, 11));
+ auto wType = static_cast<DxbcResourceReturnType>(
+ bit::extract(ins.imm[0].u32, 12, 15));
+
+ if ((xType != yType) || (xType != zType) || (xType != wType))
+ Logger::warn("DxbcCompiler: dcl_resource: Ignoring resource return types");
+
+ // Declare the actual sampled type
+ const DxbcScalarType sampledType = [xType] {
+ switch (xType) {
+ // FIXME is this correct? There's no documentation about it
+ case DxbcResourceReturnType::Mixed: return DxbcScalarType::Uint32;
+ // FIXME do we have to manually clamp writes to SNORM/UNORM resources?
+ case DxbcResourceReturnType::Snorm: return DxbcScalarType::Float32;
+ case DxbcResourceReturnType::Unorm: return DxbcScalarType::Float32;
+ case DxbcResourceReturnType::Float: return DxbcScalarType::Float32;
+ case DxbcResourceReturnType::Sint: return DxbcScalarType::Sint32;
+ case DxbcResourceReturnType::Uint: return DxbcScalarType::Uint32;
+ default: throw DxvkError(str::format("DxbcCompiler: Invalid sampled type: ", xType));
+ }
+ }();
+
+ // Declare the resource type
+ const uint32_t sampledTypeId = getScalarTypeId(sampledType);
+ const DxbcImageInfo typeInfo = getResourceType(resourceType, isUav);
+
+ // Declare additional capabilities if necessary
+ switch (resourceType) {
+ case DxbcResourceDim::Buffer:
+ m_module.enableCapability(isUav
+ ? spv::CapabilityImageBuffer
+ : spv::CapabilitySampledBuffer);
+ break;
+
+ case DxbcResourceDim::Texture1D:
+ case DxbcResourceDim::Texture1DArr:
+ m_module.enableCapability(isUav
+ ? spv::CapabilityImage1D
+ : spv::CapabilitySampled1D);
+ break;
+
+ case DxbcResourceDim::TextureCubeArr:
+ m_module.enableCapability(
+ spv::CapabilitySampledCubeArray);
+ break;
+
+ default:
+ // No additional capabilities required
+ break;
+ }
+
+ // If the read-without-format capability is not set and this
+ // image is access via a typed load, or if atomic operations
+ // are used,, we must define the image format explicitly.
+ spv::ImageFormat imageFormat = spv::ImageFormatUnknown;
+
+ if (isUav) {
+ if ((m_analysis->uavInfos[registerId].accessAtomicOp)
+ || (m_analysis->uavInfos[registerId].accessTypedLoad
+ && !m_moduleInfo.options.useStorageImageReadWithoutFormat))
+ imageFormat = getScalarImageFormat(sampledType);
+ }
+
+ // We do not know whether the image is going to be used as
+ // a color image or a depth image yet, but we can pick the
+ // correct type when creating a sampled image object.
+ const uint32_t imageTypeId = m_module.defImageType(sampledTypeId,
+ typeInfo.dim, 0, typeInfo.array, typeInfo.ms, typeInfo.sampled,
+ imageFormat);
+
+ // We'll declare the texture variable with the color type
+ // and decide which one to use when the texture is sampled.
+ const uint32_t resourcePtrType = m_module.defPointerType(
+ imageTypeId, spv::StorageClassUniformConstant);
+
+ const uint32_t varId = m_module.newVar(resourcePtrType,
+ spv::StorageClassUniformConstant);
+
+ m_module.setDebugName(varId,
+ str::format(isUav ? "u" : "t", registerId).c_str());
+
+ // Compute the DXVK binding slot index for the resource.
+ // D3D11 needs to bind the actual resource to this slot.
+ uint32_t bindingId = isUav
+ ? computeUavBinding(m_programInfo.type(), registerId)
+ : computeSrvBinding(m_programInfo.type(), registerId);
+
+ m_module.decorateDescriptorSet(varId, 0);
+ m_module.decorateBinding(varId, bindingId);
+
+ if (ins.controls.uavFlags().test(DxbcUavFlag::GloballyCoherent))
+ m_module.decorate(varId, spv::DecorationCoherent);
+
+ // Declare a specialization constant which will
+ // store whether or not the resource is bound.
+ const uint32_t specConstId = m_module.specConstBool(true);
+ m_module.decorateSpecId(specConstId, bindingId);
+ m_module.setDebugName(specConstId,
+ str::format(isUav ? "u" : "t", registerId, "_bound").c_str());
+
+ if (isUav) {
+ DxbcUav uav;
+ uav.type = DxbcResourceType::Typed;
+ uav.imageInfo = typeInfo;
+ uav.varId = varId;
+ uav.ctrId = 0;
+ uav.specId = specConstId;
+ uav.sampledType = sampledType;
+ uav.sampledTypeId = sampledTypeId;
+ uav.imageTypeId = imageTypeId;
+ uav.structStride = 0;
+ uav.structAlign = 0;
+ m_uavs.at(registerId) = uav;
+ } else {
+ DxbcShaderResource res;
+ res.type = DxbcResourceType::Typed;
+ res.imageInfo = typeInfo;
+ res.varId = varId;
+ res.specId = specConstId;
+ res.sampledType = sampledType;
+ res.sampledTypeId = sampledTypeId;
+ res.imageTypeId = imageTypeId;
+ res.colorTypeId = imageTypeId;
+ res.depthTypeId = 0;
+ res.structStride = 0;
+ res.structAlign = 0;
+
+ if ((sampledType == DxbcScalarType::Float32)
+ && (resourceType == DxbcResourceDim::Texture2D
+ || resourceType == DxbcResourceDim::Texture2DArr
+ || resourceType == DxbcResourceDim::TextureCube
+ || resourceType == DxbcResourceDim::TextureCubeArr)) {
+ res.depthTypeId = m_module.defImageType(sampledTypeId,
+ typeInfo.dim, 1, typeInfo.array, typeInfo.ms, typeInfo.sampled,
+ spv::ImageFormatUnknown);
+ }
+
+ m_textures.at(registerId) = res;
+ }
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.view = typeInfo.vtype;
+
+ if (isUav) {
+ resource.type = resourceType == DxbcResourceDim::Buffer
+ ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
+ : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ resource.access = m_analysis->uavInfos[registerId].accessFlags;
+
+ if (!(resource.access & VK_ACCESS_SHADER_WRITE_BIT))
+ m_module.decorate(varId, spv::DecorationNonWritable);
+ if (!(resource.access & VK_ACCESS_SHADER_READ_BIT))
+ m_module.decorate(varId, spv::DecorationNonReadable);
+ } else {
+ resource.type = resourceType == DxbcResourceDim::Buffer
+ ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+ : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+ resource.access = VK_ACCESS_SHADER_READ_BIT;
+ }
+
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void DxbcCompiler::emitDclResourceRawStructured(const DxbcShaderInstruction& ins) {
+ // dcl_resource_raw and dcl_uav_raw take one argument:
+ // (dst0) The resource register ID
+ // dcl_resource_structured and dcl_uav_structured take two arguments:
+ // (dst0) The resource register ID
+ // (imm0) Structure stride, in bytes
+ const uint32_t registerId = ins.dst[0].idx[0].offset;
+
+ const bool isUav = ins.op == DxbcOpcode::DclUavRaw
+ || ins.op == DxbcOpcode::DclUavStructured;
+
+ const bool isStructured = ins.op == DxbcOpcode::DclUavStructured
+ || ins.op == DxbcOpcode::DclResourceStructured;
+
+ const DxbcScalarType sampledType = DxbcScalarType::Uint32;
+ const uint32_t sampledTypeId = getScalarTypeId(sampledType);
+
+ const DxbcImageInfo typeInfo = { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
+
+ // Declare the resource type
+ uint32_t resTypeId = 0;
+ uint32_t varId = 0;
+
+ // Write back resource info
+ DxbcResourceType resType = isStructured
+ ? DxbcResourceType::Structured
+ : DxbcResourceType::Raw;
+
+ uint32_t resStride = isStructured
+ ? ins.imm[0].u32
+ : 0;
+
+ uint32_t resAlign = isStructured
+ ? (resStride & -resStride)
+ : 16;
+
+ // Compute the DXVK binding slot index for the resource.
+ uint32_t bindingId = isUav
+ ? computeUavBinding(m_programInfo.type(), registerId)
+ : computeSrvBinding(m_programInfo.type(), registerId);
+
+ // Test whether we should use a raw SSBO for this resource
+ bool useRawSsbo = m_moduleInfo.options.minSsboAlignment <= resAlign;
+
+ if (useRawSsbo) {
+ uint32_t elemType = getScalarTypeId(DxbcScalarType::Uint32);
+ uint32_t arrayType = m_module.defRuntimeArrayTypeUnique(elemType);
+ uint32_t structType = m_module.defStructTypeUnique(1, &arrayType);
+ uint32_t ptrType = m_module.defPointerType(structType, spv::StorageClassUniform);
+
+ resTypeId = m_module.defPointerType(elemType, spv::StorageClassUniform);
+ varId = m_module.newVar(ptrType, spv::StorageClassUniform);
+
+ m_module.decorateArrayStride(arrayType, sizeof(uint32_t));
+ m_module.decorate(structType, spv::DecorationBufferBlock);
+ m_module.memberDecorateOffset(structType, 0, 0);
+
+ m_module.setDebugName(structType,
+ str::format(isUav ? "u" : "t", registerId, "_t").c_str());
+ m_module.setDebugMemberName(structType, 0, "m");
+ } else {
+ // Structured and raw buffers are represented as
+ // texel buffers consisting of 32-bit integers.
+ m_module.enableCapability(isUav
+ ? spv::CapabilityImageBuffer
+ : spv::CapabilitySampledBuffer);
+
+ resTypeId = m_module.defImageType(sampledTypeId,
+ typeInfo.dim, 0, typeInfo.array, typeInfo.ms, typeInfo.sampled,
+ spv::ImageFormatR32ui);
+
+ varId = m_module.newVar(
+ m_module.defPointerType(resTypeId, spv::StorageClassUniformConstant),
+ spv::StorageClassUniformConstant);
+ }
+
+ m_module.setDebugName(varId,
+ str::format(isUav ? "u" : "t", registerId).c_str());
+
+ m_module.decorateDescriptorSet(varId, 0);
+ m_module.decorateBinding(varId, bindingId);
+
+ if (ins.controls.uavFlags().test(DxbcUavFlag::GloballyCoherent))
+ m_module.decorate(varId, spv::DecorationCoherent);
+
+ // Declare a specialization constant which will
+ // store whether or not the resource is bound.
+ const uint32_t specConstId = m_module.specConstBool(true);
+ m_module.decorateSpecId(specConstId, bindingId);
+ m_module.setDebugName(specConstId,
+ str::format(isUav ? "u" : "t", registerId, "_bound").c_str());
+
+ if (isUav) {
+ DxbcUav uav;
+ uav.type = resType;
+ uav.imageInfo = typeInfo;
+ uav.varId = varId;
+ uav.ctrId = 0;
+ uav.specId = specConstId;
+ uav.sampledType = sampledType;
+ uav.sampledTypeId = sampledTypeId;
+ uav.imageTypeId = resTypeId;
+ uav.structStride = resStride;
+ uav.structAlign = resAlign;
+ m_uavs.at(registerId) = uav;
+ } else {
+ DxbcShaderResource res;
+ res.type = resType;
+ res.imageInfo = typeInfo;
+ res.varId = varId;
+ res.specId = specConstId;
+ res.sampledType = sampledType;
+ res.sampledTypeId = sampledTypeId;
+ res.imageTypeId = resTypeId;
+ res.colorTypeId = resTypeId;
+ res.depthTypeId = 0;
+ res.structStride = resStride;
+ res.structAlign = resAlign;
+ m_textures.at(registerId) = res;
+ }
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = useRawSsbo
+ ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+ : (isUav
+ ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
+ : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = isUav
+ ? m_analysis->uavInfos[registerId].accessFlags
+ : VK_ACCESS_SHADER_READ_BIT;
+
+ if (useRawSsbo || isUav) {
+ if (!(resource.access & VK_ACCESS_SHADER_WRITE_BIT))
+ m_module.decorate(varId, spv::DecorationNonWritable);
+ if (!(resource.access & VK_ACCESS_SHADER_READ_BIT))
+ m_module.decorate(varId, spv::DecorationNonReadable);
+ }
+
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void DxbcCompiler::emitDclThreadGroupSharedMemory(const DxbcShaderInstruction& ins) {
+ // dcl_tgsm_raw takes two arguments:
+ // (dst0) The resource register ID
+ // (imm0) Block size, in bytes
+ // dcl_tgsm_structured takes three arguments:
+ // (dst0) The resource register ID
+ // (imm0) Structure stride, in bytes
+ // (imm1) Structure count
+ const bool isStructured = ins.op == DxbcOpcode::DclThreadGroupSharedMemoryStructured;
+
+ const uint32_t regId = ins.dst[0].idx[0].offset;
+
+ if (regId >= m_gRegs.size())
+ m_gRegs.resize(regId + 1);
+
+ const uint32_t elementStride = isStructured ? ins.imm[0].u32 : 0;
+ const uint32_t elementCount = isStructured ? ins.imm[1].u32 : ins.imm[0].u32;
+
+ DxbcRegisterInfo varInfo;
+ varInfo.type.ctype = DxbcScalarType::Uint32;
+ varInfo.type.ccount = 1;
+ varInfo.type.alength = isStructured
+ ? elementCount * elementStride / 4
+ : elementCount / 4;
+ varInfo.sclass = spv::StorageClassWorkgroup;
+
+ m_gRegs[regId].type = isStructured
+ ? DxbcResourceType::Structured
+ : DxbcResourceType::Raw;
+ m_gRegs[regId].elementStride = elementStride;
+ m_gRegs[regId].elementCount = elementCount;
+ m_gRegs[regId].varId = emitNewVariable(varInfo);
+
+ m_module.setDebugName(m_gRegs[regId].varId,
+ str::format("g", regId).c_str());
+ }
+
+
+ void DxbcCompiler::emitDclGsInputPrimitive(const DxbcShaderInstruction& ins) {
+ // The input primitive type is stored within in the
+ // control bits of the opcode token. In SPIR-V, we
+ // have to define an execution mode.
+ const spv::ExecutionMode mode = [&] {
+ switch (ins.controls.primitive()) {
+ case DxbcPrimitive::Point: return spv::ExecutionModeInputPoints;
+ case DxbcPrimitive::Line: return spv::ExecutionModeInputLines;
+ case DxbcPrimitive::Triangle: return spv::ExecutionModeTriangles;
+ case DxbcPrimitive::LineAdj: return spv::ExecutionModeInputLinesAdjacency;
+ case DxbcPrimitive::TriangleAdj: return spv::ExecutionModeInputTrianglesAdjacency;
+ default: throw DxvkError("DxbcCompiler: Unsupported primitive type");
+ }
+ }();
+
+ m_gs.inputPrimitive = ins.controls.primitive();
+ m_module.setExecutionMode(m_entryPointId, mode);
+
+ const uint32_t vertexCount
+ = primitiveVertexCount(m_gs.inputPrimitive);
+
+ emitDclInputArray(vertexCount);
+ emitDclInputPerVertex(vertexCount, "gs_vertex_in");
+ }
+
+
+ void DxbcCompiler::emitDclGsOutputTopology(const DxbcShaderInstruction& ins) {
+ // The input primitive topology is stored within in the
+ // control bits of the opcode token. In SPIR-V, we have
+ // to define an execution mode.
+ const spv::ExecutionMode mode = [&] {
+ switch (ins.controls.primitiveTopology()) {
+ case DxbcPrimitiveTopology::PointList: return spv::ExecutionModeOutputPoints;
+ case DxbcPrimitiveTopology::LineStrip: return spv::ExecutionModeOutputLineStrip;
+ case DxbcPrimitiveTopology::TriangleStrip: return spv::ExecutionModeOutputTriangleStrip;
+ default: throw DxvkError("DxbcCompiler: Unsupported primitive topology");
+ }
+ }();
+
+ m_module.setExecutionMode(m_entryPointId, mode);
+ }
+
+
+ void DxbcCompiler::emitDclMaxOutputVertexCount(const DxbcShaderInstruction& ins) {
+ // dcl_max_output_vertex_count has one operand:
+ // (imm0) The maximum number of vertices
+ m_gs.outputVertexCount = ins.imm[0].u32;
+
+ m_module.setOutputVertices(m_entryPointId, m_gs.outputVertexCount);
+ }
+
+
+ void DxbcCompiler::emitDclInputControlPointCount(const DxbcShaderInstruction& ins) {
+ // dcl_input_control_points has the control point
+ // count embedded within the opcode token.
+ if (m_programInfo.type() == DxbcProgramType::HullShader) {
+ m_hs.vertexCountIn = ins.controls.controlPointCount();
+
+ emitDclInputArray(m_hs.vertexCountIn);
+ } else {
+ m_ds.vertexCountIn = ins.controls.controlPointCount();
+
+ m_ds.inputPerPatch = emitTessInterfacePerPatch (spv::StorageClassInput);
+ m_ds.inputPerVertex = emitTessInterfacePerVertex(spv::StorageClassInput, m_ds.vertexCountIn);
+ }
+ }
+
+
+ void DxbcCompiler::emitDclOutputControlPointCount(const DxbcShaderInstruction& ins) {
+ // dcl_output_control_points has the control point
+ // count embedded within the opcode token.
+ m_hs.vertexCountOut = ins.controls.controlPointCount();
+
+ m_hs.outputPerPatch = emitTessInterfacePerPatch(spv::StorageClassPrivate);
+ m_hs.outputPerVertex = emitTessInterfacePerVertex(spv::StorageClassOutput, m_hs.vertexCountOut);
+
+ m_module.setOutputVertices(m_entryPointId, m_hs.vertexCountOut);
+ }
+
+
+ void DxbcCompiler::emitDclHsMaxTessFactor(const DxbcShaderInstruction& ins) {
+ m_hs.maxTessFactor = ins.imm[0].f32;
+ }
+
+
+ void DxbcCompiler::emitDclTessDomain(const DxbcShaderInstruction& ins) {
+ const spv::ExecutionMode executionMode = [&] {
+ switch (ins.controls.tessDomain()) {
+ case DxbcTessDomain::Isolines: return spv::ExecutionModeIsolines;
+ case DxbcTessDomain::Triangles: return spv::ExecutionModeTriangles;
+ case DxbcTessDomain::Quads: return spv::ExecutionModeQuads;
+ default: throw DxvkError("Dxbc: Invalid tess domain");
+ }
+ }();
+
+ m_module.setExecutionMode(m_entryPointId, executionMode);
+ }
+
+
+ void DxbcCompiler::emitDclTessPartitioning(const DxbcShaderInstruction& ins) {
+ const spv::ExecutionMode executionMode = [&] {
+ switch (ins.controls.tessPartitioning()) {
+ case DxbcTessPartitioning::Pow2:
+ case DxbcTessPartitioning::Integer: return spv::ExecutionModeSpacingEqual;
+ case DxbcTessPartitioning::FractOdd: return spv::ExecutionModeSpacingFractionalOdd;
+ case DxbcTessPartitioning::FractEven: return spv::ExecutionModeSpacingFractionalEven;
+ default: throw DxvkError("Dxbc: Invalid tess partitioning");
+ }
+ }();
+
+ m_module.setExecutionMode(m_entryPointId, executionMode);
+ }
+
+
+ void DxbcCompiler::emitDclTessOutputPrimitive(const DxbcShaderInstruction& ins) {
+ switch (ins.controls.tessOutputPrimitive()) {
+ case DxbcTessOutputPrimitive::Point:
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModePointMode);
+ break;
+
+ case DxbcTessOutputPrimitive::Line:
+ break;
+
+ case DxbcTessOutputPrimitive::TriangleCw:
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeVertexOrderCw);
+ break;
+
+ case DxbcTessOutputPrimitive::TriangleCcw:
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeVertexOrderCcw);
+ break;
+
+ default:
+ throw DxvkError("Dxbc: Invalid tess output primitive");
+ }
+ }
+
+
+ void DxbcCompiler::emitDclThreadGroup(const DxbcShaderInstruction& ins) {
+ // dcl_thread_group has three operands:
+ // (imm0) Number of threads in X dimension
+ // (imm1) Number of threads in Y dimension
+ // (imm2) Number of threads in Z dimension
+ m_cs.workgroupSizeX = ins.imm[0].u32;
+ m_cs.workgroupSizeY = ins.imm[1].u32;
+ m_cs.workgroupSizeZ = ins.imm[2].u32;
+
+ m_module.setLocalSize(m_entryPointId,
+ ins.imm[0].u32, ins.imm[1].u32, ins.imm[2].u32);
+ }
+
+
+ void DxbcCompiler::emitDclGsInstanceCount(const DxbcShaderInstruction& ins) {
+ // dcl_gs_instance_count has one operand:
+ // (imm0) Number of geometry shader invocations
+ m_module.setInvocations(m_entryPointId, ins.imm[0].u32);
+ m_gs.invocationCount = ins.imm[0].u32;
+ }
+
+
+ uint32_t DxbcCompiler::emitDclUavCounter(uint32_t regId) {
+ // Declare a structure type which holds the UAV counter
+ if (m_uavCtrStructType == 0) {
+ const uint32_t t_u32 = m_module.defIntType(32, 0);
+ const uint32_t t_struct = m_module.defStructTypeUnique(1, &t_u32);
+
+ m_module.decorate(t_struct, spv::DecorationBufferBlock);
+ m_module.memberDecorateOffset(t_struct, 0, 0);
+
+ m_module.setDebugName (t_struct, "uav_meta");
+ m_module.setDebugMemberName(t_struct, 0, "ctr");
+
+ m_uavCtrStructType = t_struct;
+ m_uavCtrPointerType = m_module.defPointerType(
+ t_struct, spv::StorageClassUniform);
+ }
+
+ // Declare the buffer variable
+ const uint32_t varId = m_module.newVar(
+ m_uavCtrPointerType, spv::StorageClassUniform);
+
+ m_module.setDebugName(varId,
+ str::format("u", regId, "_meta").c_str());
+
+ uint32_t bindingId = computeUavCounterBinding(
+ m_programInfo.type(), regId);
+
+ m_module.decorateDescriptorSet(varId, 0);
+ m_module.decorateBinding(varId, bindingId);
+
+ // Declare the storage buffer binding
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT;
+ m_resourceSlots.push_back(resource);
+
+ return varId;
+ }
+
+
+ void DxbcCompiler::emitDclImmediateConstantBuffer(const DxbcShaderInstruction& ins) {
+ if (m_immConstBuf != 0)
+ throw DxvkError("DxbcCompiler: Immediate constant buffer already declared");
+
+ if ((ins.customDataSize & 0x3) != 0)
+ throw DxvkError("DxbcCompiler: Immediate constant buffer size not a multiple of four DWORDs");
+
+ if (ins.customDataSize <= Icb_MaxBakedDwords) {
+ this->emitDclImmediateConstantBufferBaked(
+ ins.customDataSize, ins.customData);
+ } else {
+ this->emitDclImmediateConstantBufferUbo(
+ ins.customDataSize, ins.customData);
+ }
+ }
+
+
+ void DxbcCompiler::emitDclImmediateConstantBufferBaked(
+ uint32_t dwordCount,
+ const uint32_t* dwordArray) {
+ // Declare individual vector constants as 4x32-bit vectors
+ std::array<uint32_t, 4096> vectorIds;
+
+ DxbcVectorType vecType;
+ vecType.ctype = DxbcScalarType::Uint32;
+ vecType.ccount = 4;
+
+ const uint32_t vectorTypeId = getVectorTypeId(vecType);
+ const uint32_t vectorCount = dwordCount / 4;
+
+ for (uint32_t i = 0; i < vectorCount; i++) {
+ std::array<uint32_t, 4> scalarIds = {
+ m_module.constu32(dwordArray[4 * i + 0]),
+ m_module.constu32(dwordArray[4 * i + 1]),
+ m_module.constu32(dwordArray[4 * i + 2]),
+ m_module.constu32(dwordArray[4 * i + 3]),
+ };
+
+ vectorIds.at(i) = m_module.constComposite(
+ vectorTypeId, scalarIds.size(), scalarIds.data());
+ }
+
+ // Declare the array that contains all the vectors
+ DxbcArrayType arrInfo;
+ arrInfo.ctype = DxbcScalarType::Uint32;
+ arrInfo.ccount = 4;
+ arrInfo.alength = vectorCount;
+
+ const uint32_t arrayTypeId = getArrayTypeId(arrInfo);
+ const uint32_t arrayId = m_module.constComposite(
+ arrayTypeId, vectorCount, vectorIds.data());
+
+ // Declare the variable that will hold the constant
+ // data and initialize it with the constant array.
+ const uint32_t pointerTypeId = m_module.defPointerType(
+ arrayTypeId, spv::StorageClassPrivate);
+
+ m_immConstBuf = m_module.newVarInit(
+ pointerTypeId, spv::StorageClassPrivate,
+ arrayId);
+ m_module.setDebugName(m_immConstBuf, "icb");
+ }
+
+
+ void DxbcCompiler::emitDclImmediateConstantBufferUbo(
+ uint32_t dwordCount,
+ const uint32_t* dwordArray) {
+ this->emitDclConstantBufferVar(Icb_BindingSlotId, dwordCount / 4, "icb",
+ m_moduleInfo.options.dynamicIndexedConstantBufferAsSsbo);
+ m_immConstData = DxvkShaderConstData(dwordCount, dwordArray);
+ }
+
+
+ void DxbcCompiler::emitCustomData(const DxbcShaderInstruction& ins) {
+ switch (ins.customDataType) {
+ case DxbcCustomDataClass::ImmConstBuf:
+ return emitDclImmediateConstantBuffer(ins);
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unsupported custom data block: ",
+ ins.customDataType));
+ }
+ }
+
+
+ void DxbcCompiler::emitVectorAlu(const DxbcShaderInstruction& ins) {
+ std::array<DxbcRegisterValue, DxbcMaxOperandCount> src;
+
+ for (uint32_t i = 0; i < ins.srcCount; i++)
+ src.at(i) = emitRegisterLoad(ins.src[i], ins.dst[0].mask);
+
+ DxbcRegisterValue dst;
+ dst.type.ctype = ins.dst[0].dataType;
+ dst.type.ccount = ins.dst[0].mask.popCount();
+
+ if (isDoubleType(ins.dst[0].dataType))
+ dst.type.ccount /= 2;
+
+ const uint32_t typeId = getVectorTypeId(dst.type);
+
+ switch (ins.op) {
+ /////////////////////
+ // Move instructions
+ case DxbcOpcode::Mov:
+ case DxbcOpcode::DMov:
+ dst.id = src.at(0).id;
+ break;
+
+ /////////////////////////////////////
+ // ALU operations on float32 numbers
+ case DxbcOpcode::Add:
+ case DxbcOpcode::DAdd:
+ dst.id = m_module.opFAdd(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Div:
+ case DxbcOpcode::DDiv:
+ dst.id = m_module.opFDiv(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Exp:
+ dst.id = m_module.opExp2(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Frc:
+ dst.id = m_module.opFract(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Log:
+ dst.id = m_module.opLog2(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Mad:
+ case DxbcOpcode::DFma:
+ dst.id = m_module.opFFma(typeId,
+ src.at(0).id, src.at(1).id, src.at(2).id);
+ break;
+
+ case DxbcOpcode::Max:
+ case DxbcOpcode::DMax:
+ dst.id = m_module.opNMax(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Min:
+ case DxbcOpcode::DMin:
+ dst.id = m_module.opNMin(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Mul:
+ case DxbcOpcode::DMul:
+ dst.id = m_module.opFMul(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Rcp:
+ dst.id = m_module.opFDiv(typeId,
+ emitBuildConstVecf32(
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ ins.dst[0].mask).id,
+ src.at(0).id);
+ break;
+
+ case DxbcOpcode::DRcp:
+ dst.id = m_module.opFDiv(typeId,
+ emitBuildConstVecf64(1.0, 1.0,
+ ins.dst[0].mask).id,
+ src.at(0).id);
+ break;
+
+ case DxbcOpcode::RoundNe:
+ dst.id = m_module.opRoundEven(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::RoundNi:
+ dst.id = m_module.opFloor(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::RoundPi:
+ dst.id = m_module.opCeil(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::RoundZ:
+ dst.id = m_module.opTrunc(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Rsq:
+ dst.id = m_module.opInverseSqrt(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Sqrt:
+ dst.id = m_module.opSqrt(
+ typeId, src.at(0).id);
+ break;
+
+ /////////////////////////////////////
+ // ALU operations on signed integers
+ case DxbcOpcode::IAdd:
+ dst.id = m_module.opIAdd(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::IMad:
+ case DxbcOpcode::UMad:
+ dst.id = m_module.opIAdd(typeId,
+ m_module.opIMul(typeId,
+ src.at(0).id, src.at(1).id),
+ src.at(2).id);
+ break;
+
+ case DxbcOpcode::IMax:
+ dst.id = m_module.opSMax(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::IMin:
+ dst.id = m_module.opSMin(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::INeg:
+ dst.id = m_module.opSNegate(
+ typeId, src.at(0).id);
+ break;
+
+ ///////////////////////////////////////
+ // ALU operations on unsigned integers
+ case DxbcOpcode::UMax:
+ dst.id = m_module.opUMax(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::UMin:
+ dst.id = m_module.opUMin(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ ///////////////////////////////////////
+ // Bit operations on unsigned integers
+ case DxbcOpcode::And:
+ dst.id = m_module.opBitwiseAnd(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Not:
+ dst.id = m_module.opNot(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::Or:
+ dst.id = m_module.opBitwiseOr(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Xor:
+ dst.id = m_module.opBitwiseXor(typeId,
+ src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::CountBits:
+ dst.id = m_module.opBitCount(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::BfRev:
+ dst.id = m_module.opBitReverse(
+ typeId, src.at(0).id);
+ break;
+
+ ///////////////////////////
+ // Conversion instructions
+ case DxbcOpcode::ItoF:
+ dst.id = m_module.opConvertStoF(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::UtoF:
+ dst.id = m_module.opConvertUtoF(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::FtoI:
+ dst.id = m_module.opConvertFtoS(
+ typeId, src.at(0).id);
+ break;
+
+ case DxbcOpcode::FtoU:
+ dst.id = m_module.opConvertFtoU(
+ typeId, src.at(0).id);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ if (ins.controls.precise() || m_precise)
+ m_module.decorate(dst.id, spv::DecorationNoContraction);
+
+ // Store computed value
+ dst = emitDstOperandModifiers(dst, ins.modifiers);
+ emitRegisterStore(ins.dst[0], dst);
+ }
+
+
+ void DxbcCompiler::emitVectorCmov(const DxbcShaderInstruction& ins) {
+ // movc and swapc have the following operands:
+ // (dst0) The first destination register
+ // (dst1) The second destination register (swapc only)
+ // (src0) The condition vector
+ // (src1) Vector to select from if the condition is not 0
+ // (src2) Vector to select from if the condition is 0
+ DxbcRegMask condMask = ins.dst[0].mask;
+
+ if (ins.dst[0].dataType == DxbcScalarType::Float64) {
+ condMask = DxbcRegMask(
+ condMask[0] && condMask[1],
+ condMask[2] && condMask[3],
+ false, false);
+ }
+
+ const DxbcRegisterValue condition = emitRegisterLoad(ins.src[0], condMask);
+ const DxbcRegisterValue selectTrue = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
+ const DxbcRegisterValue selectFalse = emitRegisterLoad(ins.src[2], ins.dst[0].mask);
+
+ uint32_t componentCount = condMask.popCount();
+
+ // We'll compare against a vector of zeroes to generate a
+ // boolean vector, which in turn will be used by OpSelect
+ uint32_t zeroType = m_module.defIntType(32, 0);
+ uint32_t boolType = m_module.defBoolType();
+
+ uint32_t zero = m_module.constu32(0);
+
+ if (componentCount > 1) {
+ zeroType = m_module.defVectorType(zeroType, componentCount);
+ boolType = m_module.defVectorType(boolType, componentCount);
+
+ const std::array<uint32_t, 4> zeroVec = { zero, zero, zero, zero };
+ zero = m_module.constComposite(zeroType, componentCount, zeroVec.data());
+ }
+
+ // In case of swapc, the second destination operand receives
+ // the output that a cmov instruction would normally get
+ const uint32_t trueIndex = ins.op == DxbcOpcode::Swapc ? 1 : 0;
+
+ for (uint32_t i = 0; i < ins.dstCount; i++) {
+ DxbcRegisterValue result;
+ result.type.ctype = ins.dst[i].dataType;
+ result.type.ccount = componentCount;
+ result.id = m_module.opSelect(
+ getVectorTypeId(result.type),
+ m_module.opINotEqual(boolType, condition.id, zero),
+ i == trueIndex ? selectTrue.id : selectFalse.id,
+ i != trueIndex ? selectTrue.id : selectFalse.id);
+
+ result = emitDstOperandModifiers(result, ins.modifiers);
+ emitRegisterStore(ins.dst[i], result);
+ }
+ }
+
+ void DxbcCompiler::emitVectorCmp(const DxbcShaderInstruction& ins) {
+ // Compare instructions have three operands:
+ // (dst0) The destination register
+ // (src0) The first vector to compare
+ // (src1) The second vector to compare
+ uint32_t componentCount = ins.dst[0].mask.popCount();
+
+ // For 64-bit operations, we'll return a 32-bit
+ // vector, so we have to adjust the read mask
+ DxbcRegMask srcMask = ins.dst[0].mask;
+
+ if (isDoubleType(ins.src[0].dataType)) {
+ srcMask = DxbcRegMask(
+ componentCount > 0, componentCount > 0,
+ componentCount > 1, componentCount > 1);
+ }
+
+ const std::array<DxbcRegisterValue, 2> src = {
+ emitRegisterLoad(ins.src[0], srcMask),
+ emitRegisterLoad(ins.src[1], srcMask),
+ };
+
+ // Condition, which is a boolean vector used
+ // to select between the ~0u and 0u vectors.
+ uint32_t condition = 0;
+ uint32_t conditionType = m_module.defBoolType();
+
+ if (componentCount > 1)
+ conditionType = m_module.defVectorType(conditionType, componentCount);
+
+ bool invert = false;
+
+ switch (ins.op) {
+ case DxbcOpcode::Ne:
+ case DxbcOpcode::DNe:
+ invert = true;
+ /* fall through */
+
+ case DxbcOpcode::Eq:
+ case DxbcOpcode::DEq:
+ condition = m_module.opFOrdEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Ge:
+ case DxbcOpcode::DGe:
+ condition = m_module.opFOrdGreaterThanEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::Lt:
+ case DxbcOpcode::DLt:
+ condition = m_module.opFOrdLessThan(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::IEq:
+ condition = m_module.opIEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::IGe:
+ condition = m_module.opSGreaterThanEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::ILt:
+ condition = m_module.opSLessThan(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::INe:
+ condition = m_module.opINotEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::UGe:
+ condition = m_module.opUGreaterThanEqual(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ case DxbcOpcode::ULt:
+ condition = m_module.opULessThan(
+ conditionType, src.at(0).id, src.at(1).id);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ // Generate constant vectors for selection
+ uint32_t sFalse = m_module.constu32( 0u);
+ uint32_t sTrue = m_module.constu32(~0u);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = componentCount;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (componentCount > 1) {
+ const std::array<uint32_t, 4> vFalse = { sFalse, sFalse, sFalse, sFalse };
+ const std::array<uint32_t, 4> vTrue = { sTrue, sTrue, sTrue, sTrue };
+
+ sFalse = m_module.constComposite(typeId, componentCount, vFalse.data());
+ sTrue = m_module.constComposite(typeId, componentCount, vTrue .data());
+ }
+
+ if (invert)
+ std::swap(sFalse, sTrue);
+
+ // Perform component-wise mask selection
+ // based on the condition evaluated above.
+ result.id = m_module.opSelect(
+ typeId, condition, sTrue, sFalse);
+
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitVectorDeriv(const DxbcShaderInstruction& ins) {
+ // Derivative instructions have two operands:
+ // (dst0) Destination register for the derivative
+ // (src0) The operand to compute the derivative of
+ DxbcRegisterValue value = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ switch (ins.op) {
+ case DxbcOpcode::DerivRtx:
+ value.id = m_module.opDpdx(typeId, value.id);
+ break;
+
+ case DxbcOpcode::DerivRty:
+ value.id = m_module.opDpdy(typeId, value.id);
+ break;
+
+ case DxbcOpcode::DerivRtxCoarse:
+ value.id = m_module.opDpdxCoarse(typeId, value.id);
+ break;
+
+ case DxbcOpcode::DerivRtyCoarse:
+ value.id = m_module.opDpdyCoarse(typeId, value.id);
+ break;
+
+ case DxbcOpcode::DerivRtxFine:
+ value.id = m_module.opDpdxFine(typeId, value.id);
+ break;
+
+ case DxbcOpcode::DerivRtyFine:
+ value.id = m_module.opDpdyFine(typeId, value.id);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ value = emitDstOperandModifiers(value, ins.modifiers);
+ emitRegisterStore(ins.dst[0], value);
+ }
+
+
+ void DxbcCompiler::emitVectorDot(const DxbcShaderInstruction& ins) {
+ const DxbcRegMask srcMask(true,
+ ins.op >= DxbcOpcode::Dp2,
+ ins.op >= DxbcOpcode::Dp3,
+ ins.op >= DxbcOpcode::Dp4);
+
+ const std::array<DxbcRegisterValue, 2> src = {
+ emitRegisterLoad(ins.src[0], srcMask),
+ emitRegisterLoad(ins.src[1], srcMask),
+ };
+
+ DxbcRegisterValue dst;
+ dst.type.ctype = ins.dst[0].dataType;
+ dst.type.ccount = 1;
+
+ dst.id = m_module.opDot(
+ getVectorTypeId(dst.type),
+ src.at(0).id,
+ src.at(1).id);
+
+ if (ins.controls.precise() || m_precise)
+ m_module.decorate(dst.id, spv::DecorationNoContraction);
+
+ dst = emitDstOperandModifiers(dst, ins.modifiers);
+ emitRegisterStore(ins.dst[0], dst);
+ }
+
+
+ void DxbcCompiler::emitVectorIdiv(const DxbcShaderInstruction& ins) {
+ // udiv has four operands:
+ // (dst0) Quotient destination register
+ // (dst1) Remainder destination register
+ // (src0) The first vector to compare
+ // (src1) The second vector to compare
+ if (ins.dst[0].type == DxbcOperandType::Null
+ && ins.dst[1].type == DxbcOperandType::Null)
+ return;
+
+ // FIXME support this if applications require it
+ if (ins.dst[0].type != DxbcOperandType::Null
+ && ins.dst[1].type != DxbcOperandType::Null
+ && ins.dst[0].mask != ins.dst[1].mask) {
+ Logger::warn("DxbcCompiler: Idiv with different destination masks not supported");
+ return;
+ }
+
+ // Load source operands as integers with the
+ // mask of one non-NULL destination operand
+ const DxbcRegMask srcMask =
+ ins.dst[0].type != DxbcOperandType::Null
+ ? ins.dst[0].mask
+ : ins.dst[1].mask;
+
+ const std::array<DxbcRegisterValue, 2> src = {
+ emitRegisterLoad(ins.src[0], srcMask),
+ emitRegisterLoad(ins.src[1], srcMask),
+ };
+
+ // Division by zero will return 0xffffffff for both results
+ auto bvecId = getVectorTypeId({ DxbcScalarType::Bool, srcMask.popCount() });
+
+ DxbcRegisterValue const0 = emitBuildConstVecu32( 0u, 0u, 0u, 0u, srcMask);
+ DxbcRegisterValue constff = emitBuildConstVecu32(~0u, ~0u, ~0u, ~0u, srcMask);
+
+ uint32_t cmpValue = m_module.opINotEqual(bvecId, src.at(1).id, const0.id);
+
+ // Compute results only if the destination
+ // operands are not NULL.
+ if (ins.dst[0].type != DxbcOperandType::Null) {
+ DxbcRegisterValue quotient;
+ quotient.type.ctype = ins.dst[0].dataType;
+ quotient.type.ccount = ins.dst[0].mask.popCount();
+
+ quotient.id = m_module.opUDiv(
+ getVectorTypeId(quotient.type),
+ src.at(0).id, src.at(1).id);
+
+ quotient.id = m_module.opSelect(
+ getVectorTypeId(quotient.type),
+ cmpValue, quotient.id, constff.id);
+
+ quotient = emitDstOperandModifiers(quotient, ins.modifiers);
+ emitRegisterStore(ins.dst[0], quotient);
+ }
+
+ if (ins.dst[1].type != DxbcOperandType::Null) {
+ DxbcRegisterValue remainder;
+ remainder.type.ctype = ins.dst[1].dataType;
+ remainder.type.ccount = ins.dst[1].mask.popCount();
+
+ remainder.id = m_module.opUMod(
+ getVectorTypeId(remainder.type),
+ src.at(0).id, src.at(1).id);
+
+ remainder.id = m_module.opSelect(
+ getVectorTypeId(remainder.type),
+ cmpValue, remainder.id, constff.id);
+
+ remainder = emitDstOperandModifiers(remainder, ins.modifiers);
+ emitRegisterStore(ins.dst[1], remainder);
+ }
+ }
+
+
+ void DxbcCompiler::emitVectorImul(const DxbcShaderInstruction& ins) {
+ // imul and umul have four operands:
+ // (dst0) High destination register
+ // (dst1) Low destination register
+ // (src0) The first vector to compare
+ // (src1) The second vector to compare
+ if (ins.dst[0].type == DxbcOperandType::Null) {
+ if (ins.dst[1].type == DxbcOperandType::Null)
+ return;
+
+ // If dst0 is NULL, this instruction behaves just
+ // like any other three-operand ALU instruction
+ const std::array<DxbcRegisterValue, 2> src = {
+ emitRegisterLoad(ins.src[0], ins.dst[1].mask),
+ emitRegisterLoad(ins.src[1], ins.dst[1].mask),
+ };
+
+ DxbcRegisterValue result;
+ result.type.ctype = ins.dst[1].dataType;
+ result.type.ccount = ins.dst[1].mask.popCount();
+ result.id = m_module.opIMul(
+ getVectorTypeId(result.type),
+ src.at(0).id, src.at(1).id);
+
+ result = emitDstOperandModifiers(result, ins.modifiers);
+ emitRegisterStore(ins.dst[1], result);
+ } else {
+ // TODO implement this
+ Logger::warn("DxbcCompiler: Extended Imul not yet supported");
+ }
+ }
+
+
+ void DxbcCompiler::emitVectorMsad(const DxbcShaderInstruction& ins) {
+ // msad has four operands:
+ // (dst0) Destination
+ // (src0) Reference (packed uint8)
+ // (src1) Source (packed uint8)
+ // (src2) Accumulator
+ DxbcRegisterValue refReg = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+ DxbcRegisterValue srcReg = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
+ DxbcRegisterValue result = emitRegisterLoad(ins.src[2], ins.dst[0].mask);
+
+ auto typeId = getVectorTypeId(result.type);
+ auto bvecId = getVectorTypeId({ DxbcScalarType::Bool, result.type.ccount });
+
+ for (uint32_t i = 0; i < 4; i++) {
+ auto shift = m_module.constu32(8 * i);
+ auto count = m_module.constu32(8);
+
+ auto ref = m_module.opBitFieldUExtract(typeId, refReg.id, shift, count);
+ auto src = m_module.opBitFieldUExtract(typeId, srcReg.id, shift, count);
+
+ auto zero = emitBuildConstVecu32(0, 0, 0, 0, ins.dst[0].mask);
+ auto mask = m_module.opINotEqual(bvecId, ref, zero.id);
+
+ auto diff = m_module.opSAbs(typeId, m_module.opISub(typeId, ref, src));
+ result.id = m_module.opSelect(typeId, mask, m_module.opIAdd(typeId, result.id, diff), result.id);
+ }
+
+ result = emitDstOperandModifiers(result, ins.modifiers);
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitVectorShift(const DxbcShaderInstruction& ins) {
+ // Shift operations have three operands:
+ // (dst0) The destination register
+ // (src0) The register to shift
+ // (src1) The shift amount (scalar)
+ DxbcRegisterValue shiftReg = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+ DxbcRegisterValue countReg = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
+
+ if (ins.src[1].type != DxbcOperandType::Imm32)
+ countReg = emitRegisterMaskBits(countReg, 0x1F);
+
+ if (countReg.type.ccount == 1)
+ countReg = emitRegisterExtend(countReg, shiftReg.type.ccount);
+
+ DxbcRegisterValue result;
+ result.type.ctype = ins.dst[0].dataType;
+ result.type.ccount = ins.dst[0].mask.popCount();
+
+ switch (ins.op) {
+ case DxbcOpcode::IShl:
+ result.id = m_module.opShiftLeftLogical(
+ getVectorTypeId(result.type),
+ shiftReg.id, countReg.id);
+ break;
+
+ case DxbcOpcode::IShr:
+ result.id = m_module.opShiftRightArithmetic(
+ getVectorTypeId(result.type),
+ shiftReg.id, countReg.id);
+ break;
+
+ case DxbcOpcode::UShr:
+ result.id = m_module.opShiftRightLogical(
+ getVectorTypeId(result.type),
+ shiftReg.id, countReg.id);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ result = emitDstOperandModifiers(result, ins.modifiers);
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitVectorSinCos(const DxbcShaderInstruction& ins) {
+ // sincos has three operands:
+ // (dst0) Destination register for sin(x)
+ // (dst1) Destination register for cos(x)
+ // (src0) Source operand x
+
+ // Load source operand as 32-bit float vector.
+ const DxbcRegisterValue srcValue = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, true, true, true));
+
+ // Either output may be DxbcOperandType::Null, in
+ // which case we don't have to generate any code.
+ if (ins.dst[0].type != DxbcOperandType::Null) {
+ const DxbcRegisterValue sinInput =
+ emitRegisterExtract(srcValue, ins.dst[0].mask);
+
+ DxbcRegisterValue sin;
+ sin.type = sinInput.type;
+ sin.id = m_module.opSin(
+ getVectorTypeId(sin.type),
+ sinInput.id);
+
+ emitRegisterStore(ins.dst[0], sin);
+ }
+
+ if (ins.dst[1].type != DxbcOperandType::Null) {
+ const DxbcRegisterValue cosInput =
+ emitRegisterExtract(srcValue, ins.dst[1].mask);
+
+ DxbcRegisterValue cos;
+ cos.type = cosInput.type;
+ cos.id = m_module.opCos(
+ getVectorTypeId(cos.type),
+ cosInput.id);
+
+ emitRegisterStore(ins.dst[1], cos);
+ }
+ }
+
+
+ void DxbcCompiler::emitGeometryEmit(const DxbcShaderInstruction& ins) {
+ // In xfb mode we might have multiple streams, so
+ // we have to figure out which stream to write to
+ uint32_t streamId = 0;
+ uint32_t streamVar = 0;
+
+ if (m_moduleInfo.xfb != nullptr) {
+ streamId = ins.dstCount > 0 ? ins.dst[0].idx[0].offset : 0;
+ streamVar = m_module.constu32(streamId);
+ }
+
+ // Checking the negation is easier for EmitThenCut/EmitThenCutStream
+ bool doEmit = ins.op != DxbcOpcode::Cut && ins.op != DxbcOpcode::CutStream;
+ bool doCut = ins.op != DxbcOpcode::Emit && ins.op != DxbcOpcode::EmitStream;
+
+ if (doEmit) {
+ if (m_perVertexOut)
+ emitOutputSetup();
+ emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances);
+ emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances);
+ emitXfbOutputSetup(streamId, false);
+ m_module.opEmitVertex(streamVar);
+ }
+
+ if (doCut)
+ m_module.opEndPrimitive(streamVar);
+ }
+
+
+ void DxbcCompiler::emitAtomic(const DxbcShaderInstruction& ins) {
+ // atomic_* operations have the following operands:
+ // (dst0) Destination u# or g# register
+ // (src0) Index into the texture or buffer
+ // (src1) The source value for the operation
+ // (src2) Second source operand (optional)
+ // imm_atomic_* operations have the following operands:
+ // (dst0) Register that receives the result
+ // (dst1) Destination u# or g# register
+ // (srcX) As above
+ const DxbcBufferInfo bufferInfo = getBufferInfo(ins.dst[ins.dstCount - 1]);
+
+ bool isImm = ins.dstCount == 2;
+ bool isUav = ins.dst[ins.dstCount - 1].type == DxbcOperandType::UnorderedAccessView;
+
+ bool isSsbo = m_moduleInfo.options.minSsboAlignment <= bufferInfo.align
+ && bufferInfo.type != DxbcResourceType::Typed
+ && isUav;
+
+ // Perform atomic operations on UAVs only if the UAV
+ // is bound and if there is nothing else stopping us.
+ DxbcConditional cond;
+
+ if (isUav) {
+ uint32_t writeTest = emitUavWriteTest(bufferInfo);
+
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+ }
+
+ // Retrieve destination pointer for the atomic operation>
+ const DxbcRegisterPointer pointer = emitGetAtomicPointer(
+ ins.dst[ins.dstCount - 1], ins.src[0]);
+
+ // Load source values
+ std::array<DxbcRegisterValue, 2> src;
+
+ for (uint32_t i = 1; i < ins.srcCount; i++) {
+ src[i - 1] = emitRegisterBitcast(
+ emitRegisterLoad(ins.src[i], DxbcRegMask(true, false, false, false)),
+ pointer.type.ctype);
+ }
+
+ // Define memory scope and semantics based on the operands
+ uint32_t scope = 0;
+ uint32_t semantics = 0;
+
+ if (isUav) {
+ scope = spv::ScopeDevice;
+ semantics = spv::MemorySemanticsAcquireReleaseMask;
+
+ semantics |= isSsbo
+ ? spv::MemorySemanticsUniformMemoryMask
+ : spv::MemorySemanticsImageMemoryMask;
+ } else {
+ scope = spv::ScopeWorkgroup;
+ semantics = spv::MemorySemanticsWorkgroupMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask;
+ }
+
+ const uint32_t scopeId = m_module.constu32(scope);
+ const uint32_t semanticsId = m_module.constu32(semantics);
+
+ // Perform the atomic operation on the given pointer
+ DxbcRegisterValue value;
+ value.type = pointer.type;
+ value.id = 0;
+
+ // The result type, which is a scalar integer
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ switch (ins.op) {
+ case DxbcOpcode::AtomicCmpStore:
+ case DxbcOpcode::ImmAtomicCmpExch:
+ value.id = m_module.opAtomicCompareExchange(
+ typeId, pointer.id, scopeId, semanticsId,
+ m_module.constu32(spv::MemorySemanticsMaskNone),
+ src[1].id, src[0].id);
+ break;
+
+ case DxbcOpcode::ImmAtomicExch:
+ value.id = m_module.opAtomicExchange(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicIAdd:
+ case DxbcOpcode::ImmAtomicIAdd:
+ value.id = m_module.opAtomicIAdd(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicAnd:
+ case DxbcOpcode::ImmAtomicAnd:
+ value.id = m_module.opAtomicAnd(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicOr:
+ case DxbcOpcode::ImmAtomicOr:
+ value.id = m_module.opAtomicOr(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicXor:
+ case DxbcOpcode::ImmAtomicXor:
+ value.id = m_module.opAtomicXor(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicIMin:
+ case DxbcOpcode::ImmAtomicIMin:
+ value.id = m_module.opAtomicSMin(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicIMax:
+ case DxbcOpcode::ImmAtomicIMax:
+ value.id = m_module.opAtomicSMax(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicUMin:
+ case DxbcOpcode::ImmAtomicUMin:
+ value.id = m_module.opAtomicUMin(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ case DxbcOpcode::AtomicUMax:
+ case DxbcOpcode::ImmAtomicUMax:
+ value.id = m_module.opAtomicUMax(typeId,
+ pointer.id, scopeId, semanticsId,
+ src[0].id);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ // Write back the result to the destination
+ // register if this is an imm_atomic_* opcode.
+ if (isImm)
+ emitRegisterStore(ins.dst[0], value);
+
+ // End conditional block
+ if (isUav) {
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ }
+ }
+
+
+ void DxbcCompiler::emitAtomicCounter(const DxbcShaderInstruction& ins) {
+ // imm_atomic_alloc and imm_atomic_consume have the following operands:
+ // (dst0) The register that will hold the old counter value
+ // (dst1) The UAV whose counter is going to be modified
+ const DxbcBufferInfo bufferInfo = getBufferInfo(ins.dst[1]);
+
+ const uint32_t registerId = ins.dst[1].idx[0].offset;
+
+ if (m_uavs.at(registerId).ctrId == 0)
+ m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
+
+ // Only perform the operation if the UAV is bound
+ uint32_t writeTest = emitUavWriteTest(bufferInfo);
+
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+
+ // Only use subgroup ops on compute to avoid having to
+ // deal with helper invocations or hardware limitations
+ bool useSubgroupOps = m_moduleInfo.options.useSubgroupOpsForAtomicCounters
+ && m_programInfo.type() == DxbcProgramType::ComputeShader;
+
+ // In case we have subgroup ops enabled, we need to
+ // count the number of active lanes, the lane index,
+ // and we need to perform the atomic op conditionally
+ uint32_t laneCount = 0;
+ uint32_t laneIndex = 0;
+
+ DxbcConditional elect;
+
+ if (useSubgroupOps) {
+ m_module.enableCapability(spv::CapabilityGroupNonUniform);
+ m_module.enableCapability(spv::CapabilityGroupNonUniformBallot);
+
+ uint32_t ballot = m_module.opGroupNonUniformBallot(
+ getVectorTypeId({ DxbcScalarType::Uint32, 4 }),
+ m_module.constu32(spv::ScopeSubgroup),
+ m_module.constBool(true));
+
+ laneCount = m_module.opGroupNonUniformBallotBitCount(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ m_module.constu32(spv::ScopeSubgroup),
+ spv::GroupOperationReduce, ballot);
+
+ laneIndex = m_module.opGroupNonUniformBallotBitCount(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ m_module.constu32(spv::ScopeSubgroup),
+ spv::GroupOperationExclusiveScan, ballot);
+
+ // Elect one lane to perform the atomic op
+ uint32_t election = m_module.opGroupNonUniformElect(
+ m_module.defBoolType(),
+ m_module.constu32(spv::ScopeSubgroup));
+
+ elect.labelIf = m_module.allocateId();
+ elect.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(elect.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(election, elect.labelIf, elect.labelEnd);
+
+ m_module.opLabel(elect.labelIf);
+ } else {
+ // We're going to use this for the increment
+ laneCount = m_module.constu32(1);
+ }
+
+ // Get a pointer to the atomic counter in question
+ DxbcRegisterInfo ptrType;
+ ptrType.type.ctype = DxbcScalarType::Uint32;
+ ptrType.type.ccount = 1;
+ ptrType.type.alength = 0;
+ ptrType.sclass = spv::StorageClassUniform;
+
+ uint32_t zeroId = m_module.consti32(0);
+ uint32_t ptrId = m_module.opAccessChain(
+ getPointerTypeId(ptrType),
+ m_uavs.at(registerId).ctrId,
+ 1, &zeroId);
+
+ // Define memory scope and semantics based on the operands
+ uint32_t scope = spv::ScopeDevice;
+ uint32_t semantics = spv::MemorySemanticsUniformMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask;
+
+ uint32_t scopeId = m_module.constu32(scope);
+ uint32_t semanticsId = m_module.constu32(semantics);
+
+ // Compute the result value
+ DxbcRegisterValue value;
+ value.type.ctype = DxbcScalarType::Uint32;
+ value.type.ccount = 1;
+
+ uint32_t typeId = getVectorTypeId(value.type);
+
+ switch (ins.op) {
+ case DxbcOpcode::ImmAtomicAlloc:
+ value.id = m_module.opAtomicIAdd(typeId, ptrId,
+ scopeId, semanticsId, laneCount);
+ break;
+
+ case DxbcOpcode::ImmAtomicConsume:
+ value.id = m_module.opAtomicISub(typeId, ptrId,
+ scopeId, semanticsId, laneCount);
+ value.id = m_module.opISub(typeId, value.id, laneCount);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ // If we're using subgroup ops, we have to broadcast
+ // the result of the atomic op and compute the index
+ if (useSubgroupOps) {
+ m_module.opBranch(elect.labelEnd);
+ m_module.opLabel (elect.labelEnd);
+
+ uint32_t undef = m_module.constUndef(typeId);
+
+ std::array<SpirvPhiLabel, 2> phiLabels = {{
+ { value.id, elect.labelIf },
+ { undef, cond.labelIf },
+ }};
+
+ value.id = m_module.opPhi(typeId,
+ phiLabels.size(), phiLabels.data());
+ value.id = m_module.opGroupNonUniformBroadcastFirst(typeId,
+ m_module.constu32(spv::ScopeSubgroup), value.id);
+ value.id = m_module.opIAdd(typeId, value.id, laneIndex);
+ }
+
+ // Store the result
+ emitRegisterStore(ins.dst[0], value);
+
+ // End conditional block
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ }
+
+
+ void DxbcCompiler::emitBarrier(const DxbcShaderInstruction& ins) {
+ // sync takes no operands. Instead, the synchronization
+ // scope is defined by the operand control bits.
+ const DxbcSyncFlags flags = ins.controls.syncFlags();
+
+ uint32_t executionScope = spv::ScopeInvocation;
+ uint32_t memoryScope = spv::ScopeInvocation;
+ uint32_t memorySemantics = 0;
+
+ if (flags.test(DxbcSyncFlag::ThreadsInGroup))
+ executionScope = spv::ScopeWorkgroup;
+
+ if (flags.test(DxbcSyncFlag::ThreadGroupSharedMemory)) {
+ memoryScope = spv::ScopeWorkgroup;
+ memorySemantics |= spv::MemorySemanticsWorkgroupMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask;
+ }
+
+ if (flags.test(DxbcSyncFlag::UavMemoryGroup)) {
+ memoryScope = spv::ScopeWorkgroup;
+ memorySemantics |= spv::MemorySemanticsImageMemoryMask
+ | spv::MemorySemanticsUniformMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask;
+ }
+
+ if (flags.test(DxbcSyncFlag::UavMemoryGlobal)) {
+ memoryScope = spv::ScopeDevice;
+ memorySemantics |= spv::MemorySemanticsImageMemoryMask
+ | spv::MemorySemanticsUniformMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask;
+ }
+
+ if (executionScope != spv::ScopeInvocation) {
+ m_module.opControlBarrier(
+ m_module.constu32(executionScope),
+ m_module.constu32(memoryScope),
+ m_module.constu32(memorySemantics));
+ } else if (memoryScope != spv::ScopeInvocation) {
+ m_module.opMemoryBarrier(
+ m_module.constu32(memoryScope),
+ m_module.constu32(memorySemantics));
+ } else {
+ Logger::warn("DxbcCompiler: sync instruction has no effect");
+ }
+ }
+
+
+ void DxbcCompiler::emitBitExtract(const DxbcShaderInstruction& ins) {
+ // ibfe and ubfe take the following arguments:
+ // (dst0) The destination register
+ // (src0) Number of bits to extact
+ // (src1) Offset of the bits to extract
+ // (src2) Register to extract bits from
+ const bool isSigned = ins.op == DxbcOpcode::IBfe;
+
+ DxbcRegisterValue bitCnt = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+ DxbcRegisterValue bitOfs = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
+
+ if (ins.src[0].type != DxbcOperandType::Imm32)
+ bitCnt = emitRegisterMaskBits(bitCnt, 0x1F);
+
+ if (ins.src[1].type != DxbcOperandType::Imm32)
+ bitOfs = emitRegisterMaskBits(bitOfs, 0x1F);
+
+ const DxbcRegisterValue src = emitRegisterLoad(ins.src[2], ins.dst[0].mask);
+
+ const uint32_t componentCount = src.type.ccount;
+ std::array<uint32_t, 4> componentIds = {{ 0, 0, 0, 0 }};
+
+ for (uint32_t i = 0; i < componentCount; i++) {
+ const DxbcRegisterValue currBitCnt = emitRegisterExtract(bitCnt, DxbcRegMask::select(i));
+ const DxbcRegisterValue currBitOfs = emitRegisterExtract(bitOfs, DxbcRegMask::select(i));
+ const DxbcRegisterValue currSrc = emitRegisterExtract(src, DxbcRegMask::select(i));
+
+ const uint32_t typeId = getVectorTypeId(currSrc.type);
+
+ componentIds[i] = isSigned
+ ? m_module.opBitFieldSExtract(typeId, currSrc.id, currBitOfs.id, currBitCnt.id)
+ : m_module.opBitFieldUExtract(typeId, currSrc.id, currBitOfs.id, currBitCnt.id);
+ }
+
+ DxbcRegisterValue result;
+ result.type = src.type;
+ result.id = componentCount > 1
+ ? m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ componentCount, componentIds.data())
+ : componentIds[0];
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitBitInsert(const DxbcShaderInstruction& ins) {
+ // ibfe and ubfe take the following arguments:
+ // (dst0) The destination register
+ // (src0) Number of bits to extact
+ // (src1) Offset of the bits to extract
+ // (src2) Register to take bits from
+ // (src3) Register to replace bits in
+ DxbcRegisterValue bitCnt = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+ DxbcRegisterValue bitOfs = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
+
+ if (ins.src[0].type != DxbcOperandType::Imm32)
+ bitCnt = emitRegisterMaskBits(bitCnt, 0x1F);
+
+ if (ins.src[1].type != DxbcOperandType::Imm32)
+ bitOfs = emitRegisterMaskBits(bitOfs, 0x1F);
+
+ const DxbcRegisterValue insert = emitRegisterLoad(ins.src[2], ins.dst[0].mask);
+ const DxbcRegisterValue base = emitRegisterLoad(ins.src[3], ins.dst[0].mask);
+
+ const uint32_t componentCount = base.type.ccount;
+ std::array<uint32_t, 4> componentIds = {{ 0, 0, 0, 0 }};
+
+ for (uint32_t i = 0; i < componentCount; i++) {
+ const DxbcRegisterValue currBitCnt = emitRegisterExtract(bitCnt, DxbcRegMask::select(i));
+ const DxbcRegisterValue currBitOfs = emitRegisterExtract(bitOfs, DxbcRegMask::select(i));
+ const DxbcRegisterValue currInsert = emitRegisterExtract(insert, DxbcRegMask::select(i));
+ const DxbcRegisterValue currBase = emitRegisterExtract(base, DxbcRegMask::select(i));
+
+ componentIds[i] = m_module.opBitFieldInsert(
+ getVectorTypeId(currBase.type),
+ currBase.id, currInsert.id,
+ currBitOfs.id, currBitCnt.id);
+ }
+
+ DxbcRegisterValue result;
+ result.type = base.type;
+ result.id = componentCount > 1
+ ? m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ componentCount, componentIds.data())
+ : componentIds[0];
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitBitScan(const DxbcShaderInstruction& ins) {
+ // firstbit(lo|hi|shi) have two operands:
+ // (dst0) The destination operant
+ // (src0) Source operand to scan
+ DxbcRegisterValue src = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+
+ DxbcRegisterValue dst;
+ dst.type.ctype = ins.dst[0].dataType;
+ dst.type.ccount = ins.dst[0].mask.popCount();
+
+ // Result type, should be an unsigned integer
+ const uint32_t typeId = getVectorTypeId(dst.type);
+
+ switch (ins.op) {
+ case DxbcOpcode::FirstBitLo: dst.id = m_module.opFindILsb(typeId, src.id); break;
+ case DxbcOpcode::FirstBitHi: dst.id = m_module.opFindUMsb(typeId, src.id); break;
+ case DxbcOpcode::FirstBitShi: dst.id = m_module.opFindSMsb(typeId, src.id); break;
+ default: Logger::warn(str::format("DxbcCompiler: Unhandled instruction: ", ins.op)); return;
+ }
+
+ // The 'Hi' variants are counted from the MSB in DXBC
+ // rather than the LSB, so we have to invert the number
+ if (ins.op == DxbcOpcode::FirstBitHi || ins.op == DxbcOpcode::FirstBitShi) {
+ uint32_t boolTypeId = m_module.defBoolType();
+
+ if (dst.type.ccount > 1)
+ boolTypeId = m_module.defVectorType(boolTypeId, dst.type.ccount);
+
+ DxbcRegisterValue const31 = emitBuildConstVecu32(31u, 31u, 31u, 31u, ins.dst[0].mask);
+ DxbcRegisterValue constff = emitBuildConstVecu32(~0u, ~0u, ~0u, ~0u, ins.dst[0].mask);
+
+ dst.id = m_module.opSelect(typeId,
+ m_module.opINotEqual(boolTypeId, dst.id, constff.id),
+ m_module.opISub(typeId, const31.id, dst.id),
+ constff.id);
+ }
+
+ // No modifiers are supported
+ emitRegisterStore(ins.dst[0], dst);
+ }
+
+
+ void DxbcCompiler::emitBufferQuery(const DxbcShaderInstruction& ins) {
+ // bufinfo takes two arguments
+ // (dst0) The destination register
+ // (src0) The buffer register to query
+ const DxbcBufferInfo bufferInfo = getBufferInfo(ins.src[0]);
+
+ bool isSsbo = m_moduleInfo.options.minSsboAlignment <= bufferInfo.align
+ && bufferInfo.type != DxbcResourceType::Typed;
+
+ // We'll store this as a scalar unsigned integer
+ DxbcRegisterValue result = isSsbo
+ ? emitQueryBufferSize(ins.src[0])
+ : emitQueryTexelBufferSize(ins.src[0]);
+
+ uint32_t typeId = getVectorTypeId(result.type);
+
+ // Adjust returned size if this is a raw or structured
+ // buffer, as emitQueryTexelBufferSize only returns the
+ // number of typed elements in the buffer.
+ if (bufferInfo.type == DxbcResourceType::Raw) {
+ result.id = m_module.opIMul(typeId,
+ result.id, m_module.constu32(4));
+ } else if (bufferInfo.type == DxbcResourceType::Structured) {
+ result.id = m_module.opUDiv(typeId, result.id,
+ m_module.constu32(bufferInfo.stride / 4));
+ }
+
+ // Store the result. The scalar will be extended to a
+ // vector if the write mask consists of more than one
+ // component, which is the desired behaviour.
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitBufferLoad(const DxbcShaderInstruction& ins) {
+ // ld_raw takes three arguments:
+ // (dst0) Destination register
+ // (src0) Byte offset
+ // (src1) Source register
+ // ld_structured takes four arguments:
+ // (dst0) Destination register
+ // (src0) Structure index
+ // (src1) Byte offset
+ // (src2) Source register
+ const bool isStructured = ins.op == DxbcOpcode::LdStructured;
+
+ // Source register. The exact way we access
+ // the data depends on the register type.
+ const DxbcRegister& dstReg = ins.dst[0];
+ const DxbcRegister& srcReg = isStructured ? ins.src[2] : ins.src[1];
+
+ // Retrieve common info about the buffer
+ const DxbcBufferInfo bufferInfo = getBufferInfo(srcReg);
+
+ // Compute element index
+ const DxbcRegisterValue elementIndex = isStructured
+ ? emitCalcBufferIndexStructured(
+ emitRegisterLoad(ins.src[0], DxbcRegMask(true, false, false, false)),
+ emitRegisterLoad(ins.src[1], DxbcRegMask(true, false, false, false)),
+ bufferInfo.stride)
+ : emitCalcBufferIndexRaw(
+ emitRegisterLoad(ins.src[0], DxbcRegMask(true, false, false, false)));
+
+ emitRegisterStore(dstReg,
+ emitRawBufferLoad(srcReg, elementIndex, dstReg.mask));
+ }
+
+
+ void DxbcCompiler::emitBufferStore(const DxbcShaderInstruction& ins) {
+ // store_raw takes three arguments:
+ // (dst0) Destination register
+ // (src0) Byte offset
+ // (src1) Source register
+ // store_structured takes four arguments:
+ // (dst0) Destination register
+ // (src0) Structure index
+ // (src1) Byte offset
+ // (src2) Source register
+ const bool isStructured = ins.op == DxbcOpcode::StoreStructured;
+
+ // Source register. The exact way we access
+ // the data depends on the register type.
+ const DxbcRegister& dstReg = ins.dst[0];
+ const DxbcRegister& srcReg = isStructured ? ins.src[2] : ins.src[1];
+
+ // Retrieve common info about the buffer
+ const DxbcBufferInfo bufferInfo = getBufferInfo(dstReg);
+
+ // Compute element index
+ const DxbcRegisterValue elementIndex = isStructured
+ ? emitCalcBufferIndexStructured(
+ emitRegisterLoad(ins.src[0], DxbcRegMask(true, false, false, false)),
+ emitRegisterLoad(ins.src[1], DxbcRegMask(true, false, false, false)),
+ bufferInfo.stride)
+ : emitCalcBufferIndexRaw(
+ emitRegisterLoad(ins.src[0], DxbcRegMask(true, false, false, false)));
+
+ emitRawBufferStore(dstReg, elementIndex,
+ emitRegisterLoad(srcReg, dstReg.mask));
+ }
+
+
+ void DxbcCompiler::emitConvertFloat16(const DxbcShaderInstruction& ins) {
+ // f32tof16 takes two operands:
+ // (dst0) Destination register as a uint32 vector
+ // (src0) Source register as a float32 vector
+ // f16tof32 takes two operands:
+ // (dst0) Destination register as a float32 vector
+ // (src0) Source register as a uint32 vector
+ const DxbcRegisterValue src = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
+
+ // We handle both packing and unpacking here
+ const bool isPack = ins.op == DxbcOpcode::F32toF16;
+
+ // The conversion instructions do not map very well to the
+ // SPIR-V pack instructions, which operate on 2D vectors.
+ std::array<uint32_t, 4> scalarIds = {{ 0, 0, 0, 0 }};
+
+ const uint32_t componentCount = src.type.ccount;
+
+ // These types are used in both pack and unpack operations
+ const uint32_t t_u32 = getVectorTypeId({ DxbcScalarType::Uint32, 1 });
+ const uint32_t t_f32 = getVectorTypeId({ DxbcScalarType::Float32, 1 });
+ const uint32_t t_f32v2 = getVectorTypeId({ DxbcScalarType::Float32, 2 });
+
+ // Constant zero-bit pattern, used for packing
+ const uint32_t zerof32 = isPack ? m_module.constf32(0.0f) : 0;
+
+ for (uint32_t i = 0; i < componentCount; i++) {
+ const DxbcRegisterValue componentValue
+ = emitRegisterExtract(src, DxbcRegMask::select(i));
+
+ if (isPack) { // f32tof16
+ const std::array<uint32_t, 2> packIds =
+ {{ componentValue.id, zerof32 }};
+
+ scalarIds[i] = m_module.opPackHalf2x16(t_u32,
+ m_module.opCompositeConstruct(t_f32v2, packIds.size(), packIds.data()));
+ } else { // f16tof32
+ const uint32_t zeroIndex = 0;
+
+ scalarIds[i] = m_module.opCompositeExtract(t_f32,
+ m_module.opUnpackHalf2x16(t_f32v2, componentValue.id),
+ 1, &zeroIndex);
+ }
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = ins.dst[0].dataType;
+ result.type.ccount = componentCount;
+
+ uint32_t typeId = getVectorTypeId(result.type);
+ result.id = componentCount > 1
+ ? m_module.opCompositeConstruct(typeId,
+ componentCount, scalarIds.data())
+ : scalarIds[0];
+
+ if (isPack) {
+ // Some drivers return infinity if the input value is above a certain
+ // threshold, but D3D wants us to return infinity only if the input is
+ // actually infinite. Fix this up to return the maximum representable
+ // 16-bit floating point number instead, but preserve input infinity.
+ uint32_t t_bvec = getVectorTypeId({ DxbcScalarType::Bool, componentCount });
+ uint32_t f16Infinity = m_module.constuReplicant(0x7C00, componentCount);
+ uint32_t f16Unsigned = m_module.constuReplicant(0x7FFF, componentCount);
+
+ uint32_t isInputInf = m_module.opIsInf(t_bvec, src.id);
+ uint32_t isValueInf = m_module.opIEqual(t_bvec, f16Infinity,
+ m_module.opBitwiseAnd(typeId, result.id, f16Unsigned));
+
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ m_module.opLogicalAnd(t_bvec, isValueInf, m_module.opLogicalNot(t_bvec, isInputInf)),
+ m_module.opISub(typeId, result.id, m_module.constuReplicant(1, componentCount)),
+ result.id);
+ }
+
+ // Store result in the destination register
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitConvertFloat64(const DxbcShaderInstruction& ins) {
+ // ftod and dtof take the following operands:
+ // (dst0) Destination operand
+ // (src0) Number to convert
+ uint32_t dstBits = ins.dst[0].mask.popCount();
+
+ DxbcRegMask srcMask = isDoubleType(ins.dst[0].dataType)
+ ? DxbcRegMask(dstBits >= 2, dstBits >= 4, false, false)
+ : DxbcRegMask(dstBits >= 1, dstBits >= 1, dstBits >= 2, dstBits >= 2);
+
+ // Perform actual conversion, destination modifiers are not applied
+ DxbcRegisterValue val = emitRegisterLoad(ins.src[0], srcMask);
+
+ DxbcRegisterValue result;
+ result.type.ctype = ins.dst[0].dataType;
+ result.type.ccount = val.type.ccount;
+
+ switch (ins.op) {
+ case DxbcOpcode::DtoF:
+ case DxbcOpcode::FtoD:
+ result.id = m_module.opFConvert(
+ getVectorTypeId(result.type), val.id);
+ break;
+
+ case DxbcOpcode::DtoI:
+ result.id = m_module.opConvertFtoS(
+ getVectorTypeId(result.type), val.id);
+ break;
+
+ case DxbcOpcode::DtoU:
+ result.id = m_module.opConvertFtoU(
+ getVectorTypeId(result.type), val.id);
+ break;
+
+ case DxbcOpcode::ItoD:
+ result.id = m_module.opConvertStoF(
+ getVectorTypeId(result.type), val.id);
+ break;
+
+ case DxbcOpcode::UtoD:
+ result.id = m_module.opConvertUtoF(
+ getVectorTypeId(result.type), val.id);
+ break;
+
+ default:
+ Logger::warn(str::format("DxbcCompiler: Unhandled instruction: ", ins.op));
+ return;
+ }
+
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitHullShaderInstCnt(const DxbcShaderInstruction& ins) {
+ this->getCurrentHsForkJoinPhase()->instanceCount = ins.imm[0].u32;
+ }
+
+
+ void DxbcCompiler::emitHullShaderPhase(const DxbcShaderInstruction& ins) {
+ switch (ins.op) {
+ case DxbcOpcode::HsDecls: {
+ if (m_hs.currPhaseType != DxbcCompilerHsPhase::None)
+ Logger::err("DXBC: HsDecls not the first phase in hull shader");
+
+ m_hs.currPhaseType = DxbcCompilerHsPhase::Decl;
+ } break;
+
+ case DxbcOpcode::HsControlPointPhase: {
+ m_hs.cpPhase = this->emitNewHullShaderControlPointPhase();
+
+ m_hs.currPhaseType = DxbcCompilerHsPhase::ControlPoint;
+ m_hs.currPhaseId = 0;
+
+ m_module.setDebugName(m_hs.cpPhase.functionId, "hs_control_point");
+ } break;
+
+ case DxbcOpcode::HsForkPhase: {
+ auto phase = this->emitNewHullShaderForkJoinPhase();
+ m_hs.forkPhases.push_back(phase);
+
+ m_hs.currPhaseType = DxbcCompilerHsPhase::Fork;
+ m_hs.currPhaseId = m_hs.forkPhases.size() - 1;
+
+ m_module.setDebugName(phase.functionId,
+ str::format("hs_fork_", m_hs.currPhaseId).c_str());
+ } break;
+
+ case DxbcOpcode::HsJoinPhase: {
+ auto phase = this->emitNewHullShaderForkJoinPhase();
+ m_hs.joinPhases.push_back(phase);
+
+ m_hs.currPhaseType = DxbcCompilerHsPhase::Join;
+ m_hs.currPhaseId = m_hs.joinPhases.size() - 1;
+
+ m_module.setDebugName(phase.functionId,
+ str::format("hs_join_", m_hs.currPhaseId).c_str());
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ }
+ }
+
+
+ void DxbcCompiler::emitInterpolate(const DxbcShaderInstruction& ins) {
+ m_module.enableCapability(spv::CapabilityInterpolationFunction);
+
+ // The SPIR-V instructions operate on input variable pointers,
+ // which are all declared as four-component float vectors.
+ uint32_t registerId = ins.src[0].idx[0].offset;
+
+ DxbcRegisterValue result;
+ result.type = getInputRegType(registerId);
+
+ switch (ins.op) {
+ case DxbcOpcode::EvalCentroid: {
+ result.id = m_module.opInterpolateAtCentroid(
+ getVectorTypeId(result.type),
+ m_vRegs.at(registerId).id);
+ } break;
+
+ case DxbcOpcode::EvalSampleIndex: {
+ const DxbcRegisterValue sampleIndex = emitRegisterLoad(
+ ins.src[1], DxbcRegMask(true, false, false, false));
+
+ result.id = m_module.opInterpolateAtSample(
+ getVectorTypeId(result.type),
+ m_vRegs.at(registerId).id,
+ sampleIndex.id);
+ } break;
+
+ case DxbcOpcode::EvalSnapped: {
+ const DxbcRegisterValue offset = emitRegisterLoad(
+ ins.src[1], DxbcRegMask(true, true, false, false));
+
+ result.id = m_module.opInterpolateAtOffset(
+ getVectorTypeId(result.type),
+ m_vRegs.at(registerId).id,
+ offset.id);
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ result = emitRegisterSwizzle(result,
+ ins.src[0].swizzle, ins.dst[0].mask);
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitTextureQuery(const DxbcShaderInstruction& ins) {
+ // resinfo has three operands:
+ // (dst0) The destination register
+ // (src0) Resource LOD to query
+ // (src1) Resource to query
+ const DxbcBufferInfo resourceInfo = getBufferInfo(ins.src[1]);
+ const DxbcResinfoType resinfoType = ins.controls.resinfoType();
+
+ // Read the exact LOD for the image query
+ const DxbcRegisterValue mipLod = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ const DxbcScalarType returnType = resinfoType == DxbcResinfoType::Uint
+ ? DxbcScalarType::Uint32 : DxbcScalarType::Float32;
+
+ // Query the size of the selected mip level, as well as the
+ // total number of mip levels. We will have to combine the
+ // result into a four-component vector later.
+ DxbcRegisterValue imageSize = emitQueryTextureSize(ins.src[1], mipLod);
+ DxbcRegisterValue imageLevels = emitQueryTextureLods(ins.src[1]);
+
+ // Convert intermediates to the requested type
+ if (returnType == DxbcScalarType::Float32) {
+ imageSize.type.ctype = DxbcScalarType::Float32;
+ imageSize.id = m_module.opConvertUtoF(
+ getVectorTypeId(imageSize.type),
+ imageSize.id);
+
+ imageLevels.type.ctype = DxbcScalarType::Float32;
+ imageLevels.id = m_module.opConvertUtoF(
+ getVectorTypeId(imageLevels.type),
+ imageLevels.id);
+ }
+
+ // If the selected return type is rcpFloat, we need
+ // to compute the reciprocal of the image dimensions,
+ // but not the array size, so we need to separate it.
+ const uint32_t imageCoordDim = imageSize.type.ccount;
+
+ DxbcRegisterValue imageLayers;
+ imageLayers.type = imageSize.type;
+ imageLayers.id = 0;
+
+ if (resinfoType == DxbcResinfoType::RcpFloat && resourceInfo.image.array) {
+ imageLayers = emitRegisterExtract(imageSize, DxbcRegMask::select(imageCoordDim - 1));
+ imageSize = emitRegisterExtract(imageSize, DxbcRegMask::firstN(imageCoordDim - 1));
+ }
+
+ if (resinfoType == DxbcResinfoType::RcpFloat) {
+ imageSize.id = m_module.opFDiv(
+ getVectorTypeId(imageSize.type),
+ emitBuildConstVecf32(1.0f, 1.0f, 1.0f, 1.0f,
+ DxbcRegMask::firstN(imageSize.type.ccount)).id,
+ imageSize.id);
+ }
+
+ // Concatenate result vectors and scalars to form a
+ // 4D vector. Unused components will be set to zero.
+ std::array<uint32_t, 4> vectorIds = { imageSize.id, 0, 0, 0 };
+ uint32_t numVectorIds = 1;
+
+ if (imageLayers.id != 0)
+ vectorIds[numVectorIds++] = imageLayers.id;
+
+ if (imageCoordDim < 3) {
+ const uint32_t zero = returnType == DxbcScalarType::Uint32
+ ? m_module.constu32(0)
+ : m_module.constf32(0.0f);
+
+ for (uint32_t i = imageCoordDim; i < 3; i++)
+ vectorIds[numVectorIds++] = zero;
+ }
+
+ vectorIds[numVectorIds++] = imageLevels.id;
+
+ // Create the actual result vector
+ DxbcRegisterValue result;
+ result.type.ctype = returnType;
+ result.type.ccount = 4;
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ numVectorIds, vectorIds.data());
+
+ // Swizzle components using the resource swizzle
+ // and the destination operand's write mask
+ result = emitRegisterSwizzle(result,
+ ins.src[1].swizzle, ins.dst[0].mask);
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitTextureQueryLod(const DxbcShaderInstruction& ins) {
+ // All sample instructions have at least these operands:
+ // (dst0) The destination register
+ // (src0) Texture coordinates
+ // (src1) The texture itself
+ // (src2) The sampler object
+ const DxbcRegister& texCoordReg = ins.src[0];
+ const DxbcRegister& textureReg = ins.src[1];
+ const DxbcRegister& samplerReg = ins.src[2];
+
+ // Texture and sampler register IDs
+ const auto& texture = m_textures.at(textureReg.idx[0].offset);
+ const auto& sampler = m_samplers.at(samplerReg.idx[0].offset);
+
+ // Load texture coordinates
+ const DxbcRegisterValue coord = emitRegisterLoad(texCoordReg,
+ DxbcRegMask::firstN(getTexLayerDim(texture.imageInfo)));
+
+ // Query the LOD. The result is a two-dimensional float32
+ // vector containing the mip level and virtual LOD numbers.
+ const uint32_t sampledImageId = emitLoadSampledImage(texture, sampler, false);
+ const uint32_t queriedLodId = m_module.opImageQueryLod(
+ getVectorTypeId({ DxbcScalarType::Float32, 2 }),
+ sampledImageId, coord.id);
+
+ // Build the result array vector by filling up
+ // the remaining two components with zeroes.
+ const uint32_t zero = m_module.constf32(0.0f);
+ const std::array<uint32_t, 3> resultIds
+ = {{ queriedLodId, zero, zero }};
+
+ DxbcRegisterValue result;
+ result.type = DxbcVectorType { DxbcScalarType::Float32, 4 };
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ resultIds.size(), resultIds.data());
+
+ result = emitRegisterSwizzle(result, ins.src[1].swizzle, ins.dst[0].mask);
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitTextureQueryMs(const DxbcShaderInstruction& ins) {
+ // sampleinfo has two operands:
+ // (dst0) The destination register
+ // (src0) Resource to query
+ DxbcRegisterValue sampleCount = emitQueryTextureSamples(ins.src[0]);
+
+ if (ins.controls.returnType() != DxbcInstructionReturnType::Uint) {
+ sampleCount.type = { DxbcScalarType::Float32, 1 };
+ sampleCount.id = m_module.opConvertUtoF(
+ getVectorTypeId(sampleCount.type),
+ sampleCount.id);
+ }
+
+ emitRegisterStore(ins.dst[0], sampleCount);
+ }
+
+
+ void DxbcCompiler::emitTextureQueryMsPos(const DxbcShaderInstruction& ins) {
+ // samplepos has three operands:
+ // (dst0) The destination register
+ // (src0) Resource to query
+ // (src1) Sample index
+ if (m_samplePositions == 0)
+ m_samplePositions = emitSamplePosArray();
+
+ // The lookup index is qual to the sample count plus the
+ // sample index, or 0 if the resource cannot be queried.
+ DxbcRegisterValue sampleCount = emitQueryTextureSamples(ins.src[0]);
+ DxbcRegisterValue sampleIndex = emitRegisterLoad(
+ ins.src[1], DxbcRegMask(true, false, false, false));
+
+ uint32_t lookupIndex = m_module.opIAdd(
+ getVectorTypeId(sampleCount.type),
+ sampleCount.id, sampleIndex.id);
+
+ // Validate the parameters
+ uint32_t sampleCountValid = m_module.opULessThanEqual(
+ m_module.defBoolType(),
+ sampleCount.id,
+ m_module.constu32(16));
+
+ uint32_t sampleIndexValid = m_module.opULessThan(
+ m_module.defBoolType(),
+ sampleIndex.id,
+ sampleCount.id);
+
+ // If the lookup cannot be performed, set the lookup
+ // index to zero, which will return a zero vector.
+ lookupIndex = m_module.opSelect(
+ getVectorTypeId(sampleCount.type),
+ m_module.opLogicalAnd(
+ m_module.defBoolType(),
+ sampleCountValid,
+ sampleIndexValid),
+ lookupIndex,
+ m_module.constu32(0));
+
+ // Load sample pos vector and write the masked
+ // components to the destination register.
+ DxbcRegisterPointer samplePos;
+ samplePos.type.ctype = DxbcScalarType::Float32;
+ samplePos.type.ccount = 2;
+ samplePos.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(samplePos.type),
+ spv::StorageClassPrivate),
+ m_samplePositions, 1, &lookupIndex);
+
+ // Expand to vec4 by appending zeroes
+ DxbcRegisterValue result = emitValueLoad(samplePos);
+
+ DxbcRegisterValue zero;
+ zero.type.ctype = DxbcScalarType::Float32;
+ zero.type.ccount = 2;
+ zero.id = m_module.constvec2f32(0.0f, 0.0f);
+
+ result = emitRegisterConcat(result, zero);
+
+ emitRegisterStore(ins.dst[0],
+ emitRegisterSwizzle(result,
+ ins.src[0].swizzle,
+ ins.dst[0].mask));
+ }
+
+
+ void DxbcCompiler::emitTextureFetch(const DxbcShaderInstruction& ins) {
+ // ld has three operands:
+ // (dst0) The destination register
+ // (src0) Source address
+ // (src1) Source texture
+ // ld2dms has four operands:
+ // (dst0) The destination register
+ // (src0) Source address
+ // (src1) Source texture
+ // (src2) Sample number
+ const auto& texture = m_textures.at(ins.src[1].idx[0].offset);
+ const uint32_t imageLayerDim = getTexLayerDim(texture.imageInfo);
+
+ // Load the texture coordinates. The last component
+ // contains the LOD if the resource is an image.
+ const DxbcRegisterValue address = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, true, true, true));
+
+ // Additional image operands. This will store
+ // the LOD and the address offset if present.
+ SpirvImageOperands imageOperands;
+
+ if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) {
+ const std::array<uint32_t, 3> offsetIds = {
+ imageLayerDim >= 1 ? m_module.consti32(ins.sampleControls.u) : 0,
+ imageLayerDim >= 2 ? m_module.consti32(ins.sampleControls.v) : 0,
+ imageLayerDim >= 3 ? m_module.consti32(ins.sampleControls.w) : 0,
+ };
+
+ imageOperands.flags |= spv::ImageOperandsConstOffsetMask;
+ imageOperands.sConstOffset = m_module.constComposite(
+ getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }),
+ imageLayerDim, offsetIds.data());
+ }
+
+ // The LOD is not present when reading from
+ // a buffer or from a multisample texture.
+ if (texture.imageInfo.dim != spv::DimBuffer && texture.imageInfo.ms == 0) {
+ DxbcRegisterValue imageLod;
+
+ if (ins.op != DxbcOpcode::LdMs) {
+ imageLod = emitRegisterExtract(
+ address, DxbcRegMask(false, false, false, true));
+ } else {
+ // If we force-disabled MSAA, fetch from LOD 0
+ imageLod.type = { DxbcScalarType::Uint32, 1 };
+ imageLod.id = m_module.constu32(0);
+ }
+
+ imageOperands.flags |= spv::ImageOperandsLodMask;
+ imageOperands.sLod = imageLod.id;
+ }
+
+ // The ld2ms instruction has a sample index, but we
+ // are only allowed to set it for multisample views
+ if (ins.op == DxbcOpcode::LdMs && texture.imageInfo.ms == 1) {
+ DxbcRegisterValue sampleId = emitRegisterLoad(
+ ins.src[2], DxbcRegMask(true, false, false, false));
+
+ imageOperands.flags |= spv::ImageOperandsSampleMask;
+ imageOperands.sSampleId = sampleId.id;
+ }
+
+ // Extract coordinates from address
+ const DxbcRegisterValue coord = emitCalcTexCoord(address, texture.imageInfo);
+
+ // Reading a typed image or buffer view
+ // always returns a four-component vector.
+ const uint32_t imageId = m_module.opLoad(texture.imageTypeId, texture.varId);
+
+ DxbcRegisterValue result;
+ result.type.ctype = texture.sampledType;
+ result.type.ccount = 4;
+ result.id = m_module.opImageFetch(
+ getVectorTypeId(result.type), imageId,
+ coord.id, imageOperands);
+
+ // Swizzle components using the texture swizzle
+ // and the destination operand's write mask
+ result = emitRegisterSwizzle(result,
+ ins.src[1].swizzle, ins.dst[0].mask);
+
+ // If the texture is not bound, return zeroes
+ DxbcRegisterValue bound;
+ bound.type = { DxbcScalarType::Bool, 1 };
+ bound.id = texture.specId;
+
+ DxbcRegisterValue mergedResult;
+ mergedResult.type = result.type;
+ mergedResult.id = m_module.opSelect(getVectorTypeId(mergedResult.type),
+ emitBuildVector(bound, result.type.ccount).id, result.id,
+ emitBuildZeroVector(result.type).id);
+
+ emitRegisterStore(ins.dst[0], mergedResult);
+ }
+
+
+ void DxbcCompiler::emitTextureGather(const DxbcShaderInstruction& ins) {
+ // Gather4 takes the following operands:
+ // (dst0) The destination register
+ // (src0) Texture coordinates
+ // (src1) The texture itself
+ // (src2) The sampler, with a component selector
+ // Gather4C takes the following additional operand:
+ // (src3) The depth reference value
+ // The Gather4Po variants take an additional operand
+ // which defines an extended constant offset.
+ // TODO reduce code duplication by moving some common code
+ // in both sample() and gather() into separate methods
+ const bool isExtendedGather = ins.op == DxbcOpcode::Gather4Po
+ || ins.op == DxbcOpcode::Gather4PoC;
+
+ const DxbcRegister& texCoordReg = ins.src[0];
+ const DxbcRegister& textureReg = ins.src[1 + isExtendedGather];
+ const DxbcRegister& samplerReg = ins.src[2 + isExtendedGather];
+
+ // Texture and sampler register IDs
+ const auto& texture = m_textures.at(textureReg.idx[0].offset);
+ const auto& sampler = m_samplers.at(samplerReg.idx[0].offset);
+
+ // Image type, which stores the image dimensions etc.
+ const uint32_t imageLayerDim = getTexLayerDim(texture.imageInfo);
+
+ // Load the texture coordinates. SPIR-V allows these
+ // to be float4 even if not all components are used.
+ DxbcRegisterValue coord = emitLoadTexCoord(texCoordReg, texture.imageInfo);
+
+ // Load reference value for depth-compare operations
+ const bool isDepthCompare = ins.op == DxbcOpcode::Gather4C
+ || ins.op == DxbcOpcode::Gather4PoC;
+
+ const DxbcRegisterValue referenceValue = isDepthCompare
+ ? emitRegisterLoad(ins.src[3 + isExtendedGather],
+ DxbcRegMask(true, false, false, false))
+ : DxbcRegisterValue();
+
+ // Accumulate additional image operands.
+ SpirvImageOperands imageOperands;
+
+ if (isExtendedGather) {
+ m_module.enableCapability(spv::CapabilityImageGatherExtended);
+
+ DxbcRegisterValue gatherOffset = emitRegisterLoad(
+ ins.src[1], DxbcRegMask::firstN(imageLayerDim));
+
+ imageOperands.flags |= spv::ImageOperandsOffsetMask;
+ imageOperands.gOffset = gatherOffset.id;
+ } else if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) {
+ const std::array<uint32_t, 3> offsetIds = {
+ imageLayerDim >= 1 ? m_module.consti32(ins.sampleControls.u) : 0,
+ imageLayerDim >= 2 ? m_module.consti32(ins.sampleControls.v) : 0,
+ imageLayerDim >= 3 ? m_module.consti32(ins.sampleControls.w) : 0,
+ };
+
+ imageOperands.flags |= spv::ImageOperandsConstOffsetMask;
+ imageOperands.sConstOffset = m_module.constComposite(
+ getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }),
+ imageLayerDim, offsetIds.data());
+ }
+
+ // Gathering texels always returns a four-component
+ // vector, even for the depth-compare variants.
+ uint32_t sampledImageId = emitLoadSampledImage(texture, sampler, isDepthCompare);
+
+ DxbcRegisterValue result;
+ result.type.ctype = texture.sampledType;
+ result.type.ccount = 4;
+
+ switch (ins.op) {
+ // Simple image gather operation
+ case DxbcOpcode::Gather4:
+ case DxbcOpcode::Gather4Po: {
+ result.id = m_module.opImageGather(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ m_module.consti32(samplerReg.swizzle[0]),
+ imageOperands);
+ } break;
+
+ // Depth-compare operation
+ case DxbcOpcode::Gather4C:
+ case DxbcOpcode::Gather4PoC: {
+ result.id = m_module.opImageDrefGather(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ referenceValue.id, imageOperands);
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ // Swizzle components using the texture swizzle
+ // and the destination operand's write mask
+ result = emitRegisterSwizzle(result,
+ textureReg.swizzle, ins.dst[0].mask);
+
+ DxbcRegisterValue bound;
+ bound.type = { DxbcScalarType::Bool, 1 };
+ bound.id = texture.specId;
+
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ emitBuildVector(bound, result.type.ccount).id, result.id,
+ emitBuildZeroVector(result.type).id);
+
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitTextureSample(const DxbcShaderInstruction& ins) {
+ // All sample instructions have at least these operands:
+ // (dst0) The destination register
+ // (src0) Texture coordinates
+ // (src1) The texture itself
+ // (src2) The sampler object
+ const DxbcRegister& texCoordReg = ins.src[0];
+ const DxbcRegister& textureReg = ins.src[1];
+ const DxbcRegister& samplerReg = ins.src[2];
+
+ // Texture and sampler register IDs
+ const auto& texture = m_textures.at(textureReg.idx[0].offset);
+ const auto& sampler = m_samplers.at(samplerReg.idx[0].offset);
+ const uint32_t imageLayerDim = getTexLayerDim(texture.imageInfo);
+
+ // Load the texture coordinates. SPIR-V allows these
+ // to be float4 even if not all components are used.
+ DxbcRegisterValue coord = emitLoadTexCoord(texCoordReg, texture.imageInfo);
+
+ // Load reference value for depth-compare operations
+ const bool isDepthCompare = ins.op == DxbcOpcode::SampleC
+ || ins.op == DxbcOpcode::SampleClz;
+
+ const DxbcRegisterValue referenceValue = isDepthCompare
+ ? emitRegisterLoad(ins.src[3], DxbcRegMask(true, false, false, false))
+ : DxbcRegisterValue();
+
+ // Load explicit gradients for sample operations that require them
+ const bool hasExplicitGradients = ins.op == DxbcOpcode::SampleD;
+
+ const DxbcRegisterValue explicitGradientX = hasExplicitGradients
+ ? emitRegisterLoad(ins.src[3], DxbcRegMask::firstN(imageLayerDim))
+ : DxbcRegisterValue();
+
+ const DxbcRegisterValue explicitGradientY = hasExplicitGradients
+ ? emitRegisterLoad(ins.src[4], DxbcRegMask::firstN(imageLayerDim))
+ : DxbcRegisterValue();
+
+ // LOD for certain sample operations
+ const bool hasLod = ins.op == DxbcOpcode::SampleL
+ || ins.op == DxbcOpcode::SampleB;
+
+ const DxbcRegisterValue lod = hasLod
+ ? emitRegisterLoad(ins.src[3], DxbcRegMask(true, false, false, false))
+ : DxbcRegisterValue();
+
+ // Accumulate additional image operands. These are
+ // not part of the actual operand token in SPIR-V.
+ SpirvImageOperands imageOperands;
+
+ if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) {
+ const std::array<uint32_t, 3> offsetIds = {
+ imageLayerDim >= 1 ? m_module.consti32(ins.sampleControls.u) : 0,
+ imageLayerDim >= 2 ? m_module.consti32(ins.sampleControls.v) : 0,
+ imageLayerDim >= 3 ? m_module.consti32(ins.sampleControls.w) : 0,
+ };
+
+ imageOperands.flags |= spv::ImageOperandsConstOffsetMask;
+ imageOperands.sConstOffset = m_module.constComposite(
+ getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }),
+ imageLayerDim, offsetIds.data());
+ }
+
+ // Combine the texture and the sampler into a sampled image
+ uint32_t sampledImageId = emitLoadSampledImage(texture, sampler, isDepthCompare);
+
+ // Sampling an image always returns a four-component
+ // vector, whereas depth-compare ops return a scalar.
+ DxbcRegisterValue result;
+ result.type.ctype = texture.sampledType;
+ result.type.ccount = isDepthCompare ? 1 : 4;
+
+ switch (ins.op) {
+ // Simple image sample operation
+ case DxbcOpcode::Sample: {
+ result.id = m_module.opImageSampleImplicitLod(
+ getVectorTypeId(result.type),
+ sampledImageId, coord.id,
+ imageOperands);
+ } break;
+
+ // Depth-compare operation
+ case DxbcOpcode::SampleC: {
+ result.id = m_module.opImageSampleDrefImplicitLod(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ referenceValue.id, imageOperands);
+ } break;
+
+ // Depth-compare operation on mip level zero
+ case DxbcOpcode::SampleClz: {
+ imageOperands.flags |= spv::ImageOperandsLodMask;
+ imageOperands.sLod = m_module.constf32(0.0f);
+
+ result.id = m_module.opImageSampleDrefExplicitLod(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ referenceValue.id, imageOperands);
+ } break;
+
+ // Sample operation with explicit gradients
+ case DxbcOpcode::SampleD: {
+ imageOperands.flags |= spv::ImageOperandsGradMask;
+ imageOperands.sGradX = explicitGradientX.id;
+ imageOperands.sGradY = explicitGradientY.id;
+
+ result.id = m_module.opImageSampleExplicitLod(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ imageOperands);
+ } break;
+
+ // Sample operation with explicit LOD
+ case DxbcOpcode::SampleL: {
+ imageOperands.flags |= spv::ImageOperandsLodMask;
+ imageOperands.sLod = lod.id;
+
+ result.id = m_module.opImageSampleExplicitLod(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ imageOperands);
+ } break;
+
+ // Sample operation with LOD bias
+ case DxbcOpcode::SampleB: {
+ imageOperands.flags |= spv::ImageOperandsBiasMask;
+ imageOperands.sLodBias = lod.id;
+
+ result.id = m_module.opImageSampleImplicitLod(
+ getVectorTypeId(result.type), sampledImageId, coord.id,
+ imageOperands);
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ return;
+ }
+
+ // Swizzle components using the texture swizzle
+ // and the destination operand's write mask
+ if (result.type.ccount != 1) {
+ result = emitRegisterSwizzle(result,
+ textureReg.swizzle, ins.dst[0].mask);
+ }
+
+ DxbcRegisterValue bound;
+ bound.type = { DxbcScalarType::Bool, 1 };
+ bound.id = texture.specId;
+
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ emitBuildVector(bound, result.type.ccount).id, result.id,
+ emitBuildZeroVector(result.type).id);
+
+ emitRegisterStore(ins.dst[0], result);
+ }
+
+
+ void DxbcCompiler::emitTypedUavLoad(const DxbcShaderInstruction& ins) {
+ // load_uav_typed has three operands:
+ // (dst0) The destination register
+ // (src0) The texture or buffer coordinates
+ // (src1) The UAV to load from
+ const uint32_t registerId = ins.src[1].idx[0].offset;
+ const DxbcUav uavInfo = m_uavs.at(registerId);
+
+ // Load texture coordinates
+ DxbcRegisterValue texCoord = emitLoadTexCoord(
+ ins.src[0], uavInfo.imageInfo);
+
+ // Load source value from the UAV
+ DxbcRegisterValue uavValue;
+ uavValue.type.ctype = uavInfo.sampledType;
+ uavValue.type.ccount = 4;
+ uavValue.id = m_module.opImageRead(
+ getVectorTypeId(uavValue.type),
+ m_module.opLoad(uavInfo.imageTypeId, uavInfo.varId),
+ texCoord.id, SpirvImageOperands());
+
+ // Apply component swizzle and mask
+ uavValue = emitRegisterSwizzle(uavValue,
+ ins.src[1].swizzle, ins.dst[0].mask);
+
+ emitRegisterStore(ins.dst[0], uavValue);
+ }
+
+
+ void DxbcCompiler::emitTypedUavStore(const DxbcShaderInstruction& ins) {
+ // store_uav_typed has three operands:
+ // (dst0) The destination UAV
+ // (src0) The texture or buffer coordinates
+ // (src1) The value to store
+ const DxbcBufferInfo uavInfo = getBufferInfo(ins.dst[0]);
+
+ // Execute write op only if the UAV is bound
+ uint32_t writeTest = emitUavWriteTest(uavInfo);
+
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge (cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+
+ // Load texture coordinates
+ DxbcRegisterValue texCoord = emitLoadTexCoord(ins.src[0], uavInfo.image);
+
+ // Load the value that will be written to the image. We'll
+ // have to cast it to the component type of the image.
+ const DxbcRegisterValue texValue = emitRegisterBitcast(
+ emitRegisterLoad(ins.src[1], DxbcRegMask(true, true, true, true)),
+ uavInfo.stype);
+
+ // Write the given value to the image
+ m_module.opImageWrite(
+ m_module.opLoad(uavInfo.typeId, uavInfo.varId),
+ texCoord.id, texValue.id, SpirvImageOperands());
+
+ // End conditional block
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ }
+
+
+ void DxbcCompiler::emitControlFlowIf(const DxbcShaderInstruction& ins) {
+ // Load the first component of the condition
+ // operand and perform a zero test on it.
+ const DxbcRegisterValue condition = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ // Declare the 'if' block. We do not know if there
+ // will be an 'else' block or not, so we'll assume
+ // that there is one and leave it empty otherwise.
+ DxbcCfgBlock block;
+ block.type = DxbcCfgBlockType::If;
+ block.b_if.ztestId = emitRegisterZeroTest(condition, ins.controls.zeroTest()).id;
+ block.b_if.labelIf = m_module.allocateId();
+ block.b_if.labelElse = 0;
+ block.b_if.labelEnd = m_module.allocateId();
+ block.b_if.headerPtr = m_module.getInsertionPtr();
+ m_controlFlowBlocks.push_back(block);
+
+ // We'll insert the branch instruction when closing
+ // the block, since we don't know whether or not an
+ // else block is needed right now.
+ m_module.opLabel(block.b_if.labelIf);
+ }
+
+
+ void DxbcCompiler::emitControlFlowElse(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::If
+ || m_controlFlowBlocks.back().b_if.labelElse != 0)
+ throw DxvkError("DxbcCompiler: 'Else' without 'If' found");
+
+ // Set the 'Else' flag so that we do
+ // not insert a dummy block on 'EndIf'
+ DxbcCfgBlock& block = m_controlFlowBlocks.back();
+ block.b_if.labelElse = m_module.allocateId();
+
+ // Close the 'If' block by branching to
+ // the merge block we declared earlier
+ m_module.opBranch(block.b_if.labelEnd);
+ m_module.opLabel (block.b_if.labelElse);
+ }
+
+
+ void DxbcCompiler::emitControlFlowEndIf(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::If)
+ throw DxvkError("DxbcCompiler: 'EndIf' without 'If' found");
+
+ // Remove the block from the stack, it's closed
+ DxbcCfgBlock block = m_controlFlowBlocks.back();
+ m_controlFlowBlocks.pop_back();
+
+ // Write out the 'if' header
+ m_module.beginInsertion(block.b_if.headerPtr);
+
+ m_module.opSelectionMerge(
+ block.b_if.labelEnd,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ block.b_if.ztestId,
+ block.b_if.labelIf,
+ block.b_if.labelElse != 0
+ ? block.b_if.labelElse
+ : block.b_if.labelEnd);
+
+ m_module.endInsertion();
+
+ // End the active 'if' or 'else' block
+ m_module.opBranch(block.b_if.labelEnd);
+ m_module.opLabel (block.b_if.labelEnd);
+ }
+
+
+ void DxbcCompiler::emitControlFlowSwitch(const DxbcShaderInstruction& ins) {
+ // Load the selector as a scalar unsigned integer
+ const DxbcRegisterValue selector = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ // Declare switch block. We cannot insert the switch
+ // instruction itself yet because the number of case
+ // statements and blocks is unknown at this point.
+ DxbcCfgBlock block;
+ block.type = DxbcCfgBlockType::Switch;
+ block.b_switch.insertPtr = m_module.getInsertionPtr();
+ block.b_switch.selectorId = selector.id;
+ block.b_switch.labelBreak = m_module.allocateId();
+ block.b_switch.labelCase = m_module.allocateId();
+ block.b_switch.labelDefault = 0;
+ block.b_switch.labelCases = nullptr;
+ m_controlFlowBlocks.push_back(block);
+
+ // Define the first 'case' label
+ m_module.opLabel(block.b_switch.labelCase);
+ }
+
+
+ void DxbcCompiler::emitControlFlowCase(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::Switch)
+ throw DxvkError("DxbcCompiler: 'Case' without 'Switch' found");
+
+ // The source operand must be a 32-bit immediate.
+ if (ins.src[0].type != DxbcOperandType::Imm32)
+ throw DxvkError("DxbcCompiler: Invalid operand type for 'Case'");
+
+ // Use the last label allocated for 'case'. The block starting
+ // with that label is guaranteed to be empty unless a previous
+ // 'case' block was not properly closed in the DXBC shader.
+ DxbcCfgBlockSwitch* block = &m_controlFlowBlocks.back().b_switch;
+
+ DxbcSwitchLabel label;
+ label.desc.literal = ins.src[0].imm.u32_1;
+ label.desc.labelId = block->labelCase;
+ label.next = block->labelCases;
+ block->labelCases = new DxbcSwitchLabel(label);
+ }
+
+
+ void DxbcCompiler::emitControlFlowDefault(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::Switch)
+ throw DxvkError("DxbcCompiler: 'Default' without 'Switch' found");
+
+ // Set the last label allocated for 'case' as the default label.
+ m_controlFlowBlocks.back().b_switch.labelDefault
+ = m_controlFlowBlocks.back().b_switch.labelCase;
+ }
+
+
+ void DxbcCompiler::emitControlFlowEndSwitch(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::Switch)
+ throw DxvkError("DxbcCompiler: 'EndSwitch' without 'Switch' found");
+
+ // Remove the block from the stack, it's closed
+ DxbcCfgBlock block = m_controlFlowBlocks.back();
+ m_controlFlowBlocks.pop_back();
+
+ // If no 'default' label was specified, use the last allocated
+ // 'case' label. This is guaranteed to be an empty block unless
+ // a previous 'case' block was not closed properly.
+ if (block.b_switch.labelDefault == 0)
+ block.b_switch.labelDefault = block.b_switch.labelCase;
+
+ // Close the current 'case' block
+ m_module.opBranch(block.b_switch.labelBreak);
+ m_module.opLabel (block.b_switch.labelBreak);
+
+ // Insert the 'switch' statement. For that, we need to
+ // gather all the literal-label pairs for the construct.
+ m_module.beginInsertion(block.b_switch.insertPtr);
+ m_module.opSelectionMerge(
+ block.b_switch.labelBreak,
+ spv::SelectionControlMaskNone);
+
+ // We'll restore the original order of the case labels here
+ std::vector<SpirvSwitchCaseLabel> jumpTargets;
+ for (auto i = block.b_switch.labelCases; i != nullptr; i = i->next)
+ jumpTargets.insert(jumpTargets.begin(), i->desc);
+
+ m_module.opSwitch(
+ block.b_switch.selectorId,
+ block.b_switch.labelDefault,
+ jumpTargets.size(),
+ jumpTargets.data());
+ m_module.endInsertion();
+
+ // Destroy the list of case labels
+ // FIXME we're leaking memory if compilation fails.
+ DxbcSwitchLabel* caseLabel = block.b_switch.labelCases;
+
+ while (caseLabel != nullptr)
+ delete std::exchange(caseLabel, caseLabel->next);
+ }
+
+
+ void DxbcCompiler::emitControlFlowLoop(const DxbcShaderInstruction& ins) {
+ // Declare the 'loop' block
+ DxbcCfgBlock block;
+ block.type = DxbcCfgBlockType::Loop;
+ block.b_loop.labelHeader = m_module.allocateId();
+ block.b_loop.labelBegin = m_module.allocateId();
+ block.b_loop.labelContinue = m_module.allocateId();
+ block.b_loop.labelBreak = m_module.allocateId();
+ m_controlFlowBlocks.push_back(block);
+
+ m_module.opBranch(block.b_loop.labelHeader);
+ m_module.opLabel (block.b_loop.labelHeader);
+
+ m_module.opLoopMerge(
+ block.b_loop.labelBreak,
+ block.b_loop.labelContinue,
+ spv::LoopControlMaskNone);
+
+ m_module.opBranch(block.b_loop.labelBegin);
+ m_module.opLabel (block.b_loop.labelBegin);
+ }
+
+
+ void DxbcCompiler::emitControlFlowEndLoop(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxbcCfgBlockType::Loop)
+ throw DxvkError("DxbcCompiler: 'EndLoop' without 'Loop' found");
+
+ // Remove the block from the stack, it's closed
+ const DxbcCfgBlock block = m_controlFlowBlocks.back();
+ m_controlFlowBlocks.pop_back();
+
+ // Declare the continue block
+ m_module.opBranch(block.b_loop.labelContinue);
+ m_module.opLabel (block.b_loop.labelContinue);
+
+ // Declare the merge block
+ m_module.opBranch(block.b_loop.labelHeader);
+ m_module.opLabel (block.b_loop.labelBreak);
+ }
+
+
+ void DxbcCompiler::emitControlFlowBreak(const DxbcShaderInstruction& ins) {
+ const bool isBreak = ins.op == DxbcOpcode::Break;
+
+ DxbcCfgBlock* cfgBlock = isBreak
+ ? cfgFindBlock({ DxbcCfgBlockType::Loop, DxbcCfgBlockType::Switch })
+ : cfgFindBlock({ DxbcCfgBlockType::Loop });
+
+ if (cfgBlock == nullptr)
+ throw DxvkError("DxbcCompiler: 'Break' or 'Continue' outside 'Loop' or 'Switch' found");
+
+ if (cfgBlock->type == DxbcCfgBlockType::Loop) {
+ m_module.opBranch(isBreak
+ ? cfgBlock->b_loop.labelBreak
+ : cfgBlock->b_loop.labelContinue);
+ } else /* if (cfgBlock->type == DxbcCfgBlockType::Switch) */ {
+ m_module.opBranch(cfgBlock->b_switch.labelBreak);
+ }
+
+ // Subsequent instructions assume that there is an open block
+ const uint32_t labelId = m_module.allocateId();
+ m_module.opLabel(labelId);
+
+ // If this is on the same level as a switch-case construct,
+ // rather than being nested inside an 'if' statement, close
+ // the current 'case' block.
+ if (m_controlFlowBlocks.back().type == DxbcCfgBlockType::Switch)
+ cfgBlock->b_switch.labelCase = labelId;
+ }
+
+
+ void DxbcCompiler::emitControlFlowBreakc(const DxbcShaderInstruction& ins) {
+ const bool isBreak = ins.op == DxbcOpcode::Breakc;
+
+ DxbcCfgBlock* cfgBlock = isBreak
+ ? cfgFindBlock({ DxbcCfgBlockType::Loop, DxbcCfgBlockType::Switch })
+ : cfgFindBlock({ DxbcCfgBlockType::Loop });
+
+ if (cfgBlock == nullptr)
+ throw DxvkError("DxbcCompiler: 'Breakc' or 'Continuec' outside 'Loop' or 'Switch' found");
+
+ // Perform zero test on the first component of the condition
+ const DxbcRegisterValue condition = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
+ condition, ins.controls.zeroTest());
+
+ // We basically have to wrap this into an 'if' block
+ const uint32_t breakBlock = m_module.allocateId();
+ const uint32_t mergeBlock = m_module.allocateId();
+
+ m_module.opSelectionMerge(mergeBlock,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ zeroTest.id, breakBlock, mergeBlock);
+
+ m_module.opLabel(breakBlock);
+
+ if (cfgBlock->type == DxbcCfgBlockType::Loop) {
+ m_module.opBranch(isBreak
+ ? cfgBlock->b_loop.labelBreak
+ : cfgBlock->b_loop.labelContinue);
+ } else /* if (cfgBlock->type == DxbcCfgBlockType::Switch) */ {
+ m_module.opBranch(cfgBlock->b_switch.labelBreak);
+ }
+
+ m_module.opLabel(mergeBlock);
+ }
+
+
+ void DxbcCompiler::emitControlFlowRet(const DxbcShaderInstruction& ins) {
+ if (m_controlFlowBlocks.size() != 0) {
+ uint32_t labelId = m_module.allocateId();
+
+ m_module.opReturn();
+ m_module.opLabel(labelId);
+
+ // return can be used in place of break to terminate a case block
+ if (m_controlFlowBlocks.back().type == DxbcCfgBlockType::Switch)
+ m_controlFlowBlocks.back().b_switch.labelCase = labelId;
+ } else {
+ // Last instruction in the current function
+ this->emitFunctionEnd();
+ }
+ }
+
+
+ void DxbcCompiler::emitControlFlowRetc(const DxbcShaderInstruction& ins) {
+ // Perform zero test on the first component of the condition
+ const DxbcRegisterValue condition = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
+ condition, ins.controls.zeroTest());
+
+ // We basically have to wrap this into an 'if' block
+ const uint32_t returnLabel = m_module.allocateId();
+ const uint32_t continueLabel = m_module.allocateId();
+
+ m_module.opSelectionMerge(continueLabel,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ zeroTest.id, returnLabel, continueLabel);
+
+ m_module.opLabel(returnLabel);
+ m_module.opReturn();
+
+ m_module.opLabel(continueLabel);
+ }
+
+
+ void DxbcCompiler::emitControlFlowDiscard(const DxbcShaderInstruction& ins) {
+ // Discard actually has an operand that determines
+ // whether or not the fragment should be discarded
+ const DxbcRegisterValue condition = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
+ condition, ins.controls.zeroTest());
+
+ if (m_ps.killState == 0) {
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(zeroTest.id, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+
+ if (m_moduleInfo.options.useDemoteToHelperInvocation) {
+ m_module.opDemoteToHelperInvocation();
+ m_module.opBranch(cond.labelEnd);
+ } else {
+ // OpKill terminates the block
+ m_module.opKill();
+ }
+
+ m_module.opLabel(cond.labelEnd);
+ } else {
+ uint32_t typeId = m_module.defBoolType();
+
+ uint32_t killState = m_module.opLoad (typeId, m_ps.killState);
+ killState = m_module.opLogicalOr(typeId, killState, zeroTest.id);
+ m_module.opStore(m_ps.killState, killState);
+
+ if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) {
+ uint32_t ballot = m_module.opGroupNonUniformBallot(
+ getVectorTypeId({ DxbcScalarType::Uint32, 4 }),
+ m_module.constu32(spv::ScopeSubgroup),
+ killState);
+
+ uint32_t laneId = m_module.opLoad(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ m_ps.builtinLaneId);
+
+ uint32_t laneIdPart = m_module.opShiftRightLogical(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ laneId, m_module.constu32(5));
+
+ uint32_t laneMask = m_module.opVectorExtractDynamic(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ ballot, laneIdPart);
+
+ uint32_t laneIdQuad = m_module.opBitwiseAnd(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ laneId, m_module.constu32(0x1c));
+
+ laneMask = m_module.opShiftRightLogical(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ laneMask, laneIdQuad);
+
+ laneMask = m_module.opBitwiseAnd(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ laneMask, m_module.constu32(0xf));
+
+ uint32_t killSubgroup = m_module.opIEqual(
+ m_module.defBoolType(),
+ laneMask, m_module.constu32(0xf));
+
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(killSubgroup, cond.labelIf, cond.labelEnd);
+
+ // OpKill terminates the block
+ m_module.opLabel(cond.labelIf);
+ m_module.opKill();
+
+ m_module.opLabel(cond.labelEnd);
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitControlFlowLabel(const DxbcShaderInstruction& ins) {
+ uint32_t functionNr = ins.dst[0].idx[0].offset;
+ uint32_t functionId = getFunctionId(functionNr);
+
+ this->emitFunctionBegin(
+ functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+
+ m_module.opLabel(m_module.allocateId());
+ m_module.setDebugName(functionId, str::format("label", functionNr).c_str());
+
+ m_insideFunction = true;
+ }
+
+
+ void DxbcCompiler::emitControlFlowCall(const DxbcShaderInstruction& ins) {
+ uint32_t functionNr = ins.src[0].idx[0].offset;
+ uint32_t functionId = getFunctionId(functionNr);
+
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ functionId, 0, nullptr);
+ }
+
+
+ void DxbcCompiler::emitControlFlowCallc(const DxbcShaderInstruction& ins) {
+ uint32_t functionNr = ins.src[1].idx[0].offset;
+ uint32_t functionId = getFunctionId(functionNr);
+
+ // Perform zero test on the first component of the condition
+ const DxbcRegisterValue condition = emitRegisterLoad(
+ ins.src[0], DxbcRegMask(true, false, false, false));
+
+ const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
+ condition, ins.controls.zeroTest());
+
+ // We basically have to wrap this into an 'if' block
+ const uint32_t callLabel = m_module.allocateId();
+ const uint32_t skipLabel = m_module.allocateId();
+
+ m_module.opSelectionMerge(skipLabel,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ zeroTest.id, callLabel, skipLabel);
+
+ m_module.opLabel(callLabel);
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ functionId, 0, nullptr);
+
+ m_module.opBranch(skipLabel);
+ m_module.opLabel(skipLabel);
+ }
+
+
+ void DxbcCompiler::emitControlFlow(const DxbcShaderInstruction& ins) {
+ switch (ins.op) {
+ case DxbcOpcode::If:
+ return this->emitControlFlowIf(ins);
+
+ case DxbcOpcode::Else:
+ return this->emitControlFlowElse(ins);
+
+ case DxbcOpcode::EndIf:
+ return this->emitControlFlowEndIf(ins);
+
+ case DxbcOpcode::Switch:
+ return this->emitControlFlowSwitch(ins);
+
+ case DxbcOpcode::Case:
+ return this->emitControlFlowCase(ins);
+
+ case DxbcOpcode::Default:
+ return this->emitControlFlowDefault(ins);
+
+ case DxbcOpcode::EndSwitch:
+ return this->emitControlFlowEndSwitch(ins);
+
+ case DxbcOpcode::Loop:
+ return this->emitControlFlowLoop(ins);
+
+ case DxbcOpcode::EndLoop:
+ return this->emitControlFlowEndLoop(ins);
+
+ case DxbcOpcode::Break:
+ case DxbcOpcode::Continue:
+ return this->emitControlFlowBreak(ins);
+
+ case DxbcOpcode::Breakc:
+ case DxbcOpcode::Continuec:
+ return this->emitControlFlowBreakc(ins);
+
+ case DxbcOpcode::Ret:
+ return this->emitControlFlowRet(ins);
+
+ case DxbcOpcode::Retc:
+ return this->emitControlFlowRetc(ins);
+
+ case DxbcOpcode::Discard:
+ return this->emitControlFlowDiscard(ins);
+
+ case DxbcOpcode::Label:
+ return this->emitControlFlowLabel(ins);
+
+ case DxbcOpcode::Call:
+ return this->emitControlFlowCall(ins);
+
+ case DxbcOpcode::Callc:
+ return this->emitControlFlowCallc(ins);
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled instruction: ",
+ ins.op));
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildConstVecf32(
+ float x,
+ float y,
+ float z,
+ float w,
+ const DxbcRegMask& writeMask) {
+ // TODO refactor these functions into one single template
+ std::array<uint32_t, 4> ids = { 0, 0, 0, 0 };
+ uint32_t componentIndex = 0;
+
+ if (writeMask[0]) ids[componentIndex++] = m_module.constf32(x);
+ if (writeMask[1]) ids[componentIndex++] = m_module.constf32(y);
+ if (writeMask[2]) ids[componentIndex++] = m_module.constf32(z);
+ if (writeMask[3]) ids[componentIndex++] = m_module.constf32(w);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Float32;
+ result.type.ccount = componentIndex;
+ result.id = componentIndex > 1
+ ? m_module.constComposite(
+ getVectorTypeId(result.type),
+ componentIndex, ids.data())
+ : ids[0];
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildConstVecu32(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z,
+ uint32_t w,
+ const DxbcRegMask& writeMask) {
+ std::array<uint32_t, 4> ids = { 0, 0, 0, 0 };
+ uint32_t componentIndex = 0;
+
+ if (writeMask[0]) ids[componentIndex++] = m_module.constu32(x);
+ if (writeMask[1]) ids[componentIndex++] = m_module.constu32(y);
+ if (writeMask[2]) ids[componentIndex++] = m_module.constu32(z);
+ if (writeMask[3]) ids[componentIndex++] = m_module.constu32(w);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = componentIndex;
+ result.id = componentIndex > 1
+ ? m_module.constComposite(
+ getVectorTypeId(result.type),
+ componentIndex, ids.data())
+ : ids[0];
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildConstVeci32(
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ int32_t w,
+ const DxbcRegMask& writeMask) {
+ std::array<uint32_t, 4> ids = { 0, 0, 0, 0 };
+ uint32_t componentIndex = 0;
+
+ if (writeMask[0]) ids[componentIndex++] = m_module.consti32(x);
+ if (writeMask[1]) ids[componentIndex++] = m_module.consti32(y);
+ if (writeMask[2]) ids[componentIndex++] = m_module.consti32(z);
+ if (writeMask[3]) ids[componentIndex++] = m_module.consti32(w);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Sint32;
+ result.type.ccount = componentIndex;
+ result.id = componentIndex > 1
+ ? m_module.constComposite(
+ getVectorTypeId(result.type),
+ componentIndex, ids.data())
+ : ids[0];
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildConstVecf64(
+ double xy,
+ double zw,
+ const DxbcRegMask& writeMask) {
+ std::array<uint32_t, 2> ids = { 0, 0 };
+ uint32_t componentIndex = 0;
+
+ if (writeMask[0] && writeMask[1]) ids[componentIndex++] = m_module.constf64(xy);
+ if (writeMask[2] && writeMask[3]) ids[componentIndex++] = m_module.constf64(zw);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Float64;
+ result.type.ccount = componentIndex;
+ result.id = componentIndex > 1
+ ? m_module.constComposite(
+ getVectorTypeId(result.type),
+ componentIndex, ids.data())
+ : ids[0];
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildVector(
+ DxbcRegisterValue scalar,
+ uint32_t count) {
+ if (count == 1)
+ return scalar;
+
+ std::array<uint32_t, 4> scalarIds =
+ { scalar.id, scalar.id, scalar.id, scalar.id };
+
+ DxbcRegisterValue result;
+ result.type.ctype = scalar.type.ctype;
+ result.type.ccount = count;
+ result.id = m_module.constComposite(
+ getVectorTypeId(result.type),
+ count, scalarIds.data());
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitBuildZeroVector(
+ DxbcVectorType type) {
+ DxbcRegisterValue result;
+ result.type.ctype = type.ctype;
+ result.type.ccount = 1;
+
+ switch (type.ctype) {
+ case DxbcScalarType::Float32: result.id = m_module.constf32(0.0f); break;
+ case DxbcScalarType::Uint32: result.id = m_module.constu32(0u); break;
+ case DxbcScalarType::Sint32: result.id = m_module.consti32(0); break;
+ default: throw DxvkError("DxbcCompiler: Invalid scalar type");
+ }
+
+ return emitBuildVector(result, type.ccount);
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterBitcast(
+ DxbcRegisterValue srcValue,
+ DxbcScalarType dstType) {
+ DxbcScalarType srcType = srcValue.type.ctype;
+
+ if (srcType == dstType)
+ return srcValue;
+
+ DxbcRegisterValue result;
+ result.type.ctype = dstType;
+ result.type.ccount = srcValue.type.ccount;
+
+ if (isDoubleType(srcType)) result.type.ccount *= 2;
+ if (isDoubleType(dstType)) result.type.ccount /= 2;
+
+ result.id = m_module.opBitcast(
+ getVectorTypeId(result.type),
+ srcValue.id);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterSwizzle(
+ DxbcRegisterValue value,
+ DxbcRegSwizzle swizzle,
+ DxbcRegMask writeMask) {
+ if (value.type.ccount == 1)
+ return emitRegisterExtend(value, writeMask.popCount());
+
+ std::array<uint32_t, 4> indices;
+
+ uint32_t dstIndex = 0;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (writeMask[i])
+ indices[dstIndex++] = swizzle[i];
+ }
+
+ // If the swizzle combined with the mask can be reduced
+ // to a no-op, we don't need to insert any instructions.
+ bool isIdentitySwizzle = dstIndex == value.type.ccount;
+
+ for (uint32_t i = 0; i < dstIndex && isIdentitySwizzle; i++)
+ isIdentitySwizzle &= indices[i] == i;
+
+ if (isIdentitySwizzle)
+ return value;
+
+ // Use OpCompositeExtract if the resulting vector contains
+ // only one component, and OpVectorShuffle if it is a vector.
+ DxbcRegisterValue result;
+ result.type.ctype = value.type.ctype;
+ result.type.ccount = dstIndex;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (dstIndex == 1) {
+ result.id = m_module.opCompositeExtract(
+ typeId, value.id, 1, indices.data());
+ } else {
+ result.id = m_module.opVectorShuffle(
+ typeId, value.id, value.id,
+ dstIndex, indices.data());
+ }
+
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterExtract(
+ DxbcRegisterValue value,
+ DxbcRegMask mask) {
+ return emitRegisterSwizzle(value,
+ DxbcRegSwizzle(0, 1, 2, 3), mask);
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterInsert(
+ DxbcRegisterValue dstValue,
+ DxbcRegisterValue srcValue,
+ DxbcRegMask srcMask) {
+ DxbcRegisterValue result;
+ result.type = dstValue.type;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (srcMask.popCount() == 0) {
+ // Nothing to do if the insertion mask is empty
+ result.id = dstValue.id;
+ } else if (dstValue.type.ccount == 1) {
+ // Both values are scalar, so the first component
+ // of the write mask decides which one to take.
+ result.id = srcMask[0] ? srcValue.id : dstValue.id;
+ } else if (srcValue.type.ccount == 1) {
+ // The source value is scalar. Since OpVectorShuffle
+ // requires both arguments to be vectors, we have to
+ // use OpCompositeInsert to modify the vector instead.
+ const uint32_t componentId = srcMask.firstSet();
+
+ result.id = m_module.opCompositeInsert(typeId,
+ srcValue.id, dstValue.id, 1, &componentId);
+ } else {
+ // Both arguments are vectors. We can determine which
+ // components to take from which vector and use the
+ // OpVectorShuffle instruction.
+ std::array<uint32_t, 4> components;
+ uint32_t srcComponentId = dstValue.type.ccount;
+
+ for (uint32_t i = 0; i < dstValue.type.ccount; i++)
+ components.at(i) = srcMask[i] ? srcComponentId++ : i;
+
+ result.id = m_module.opVectorShuffle(
+ typeId, dstValue.id, srcValue.id,
+ dstValue.type.ccount, components.data());
+ }
+
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterConcat(
+ DxbcRegisterValue value1,
+ DxbcRegisterValue value2) {
+ std::array<uint32_t, 2> ids =
+ {{ value1.id, value2.id }};
+
+ DxbcRegisterValue result;
+ result.type.ctype = value1.type.ctype;
+ result.type.ccount = value1.type.ccount + value2.type.ccount;
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ ids.size(), ids.data());
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterExtend(
+ DxbcRegisterValue value,
+ uint32_t size) {
+ if (size == 1)
+ return value;
+
+ std::array<uint32_t, 4> ids = {{
+ value.id, value.id,
+ value.id, value.id,
+ }};
+
+ DxbcRegisterValue result;
+ result.type.ctype = value.type.ctype;
+ result.type.ccount = size;
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ size, ids.data());
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterAbsolute(
+ DxbcRegisterValue value) {
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ switch (value.type.ctype) {
+ case DxbcScalarType::Float32: value.id = m_module.opFAbs(typeId, value.id); break;
+ case DxbcScalarType::Float64: value.id = m_module.opFAbs(typeId, value.id); break;
+ case DxbcScalarType::Sint32: value.id = m_module.opSAbs(typeId, value.id); break;
+ case DxbcScalarType::Sint64: value.id = m_module.opSAbs(typeId, value.id); break;
+ default: Logger::warn("DxbcCompiler: Cannot get absolute value for given type");
+ }
+
+ return value;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterNegate(
+ DxbcRegisterValue value) {
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ switch (value.type.ctype) {
+ case DxbcScalarType::Float32: value.id = m_module.opFNegate(typeId, value.id); break;
+ case DxbcScalarType::Float64: value.id = m_module.opFNegate(typeId, value.id); break;
+ case DxbcScalarType::Sint32: value.id = m_module.opSNegate(typeId, value.id); break;
+ case DxbcScalarType::Sint64: value.id = m_module.opSNegate(typeId, value.id); break;
+ default: Logger::warn("DxbcCompiler: Cannot negate given type");
+ }
+
+ return value;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterZeroTest(
+ DxbcRegisterValue value,
+ DxbcZeroTest test) {
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Bool;
+ result.type.ccount = 1;
+
+ const uint32_t zeroId = m_module.constu32(0u);
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ result.id = test == DxbcZeroTest::TestZ
+ ? m_module.opIEqual (typeId, value.id, zeroId)
+ : m_module.opINotEqual(typeId, value.id, zeroId);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterMaskBits(
+ DxbcRegisterValue value,
+ uint32_t mask) {
+ DxbcRegisterValue maskVector = emitBuildConstVecu32(
+ mask, mask, mask, mask, DxbcRegMask::firstN(value.type.ccount));
+
+ DxbcRegisterValue result;
+ result.type = value.type;
+ result.id = m_module.opBitwiseAnd(
+ getVectorTypeId(result.type),
+ value.id, maskVector.id);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitSrcOperandModifiers(
+ DxbcRegisterValue value,
+ DxbcRegModifiers modifiers) {
+ if (modifiers.test(DxbcRegModifier::Abs))
+ value = emitRegisterAbsolute(value);
+
+ if (modifiers.test(DxbcRegModifier::Neg))
+ value = emitRegisterNegate(value);
+ return value;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitDstOperandModifiers(
+ DxbcRegisterValue value,
+ DxbcOpModifiers modifiers) {
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ if (modifiers.saturate) {
+ DxbcRegMask mask;
+ DxbcRegisterValue vec0, vec1;
+
+ if (value.type.ctype == DxbcScalarType::Float32) {
+ mask = DxbcRegMask::firstN(value.type.ccount);
+ vec0 = emitBuildConstVecf32(0.0f, 0.0f, 0.0f, 0.0f, mask);
+ vec1 = emitBuildConstVecf32(1.0f, 1.0f, 1.0f, 1.0f, mask);
+ } else if (value.type.ctype == DxbcScalarType::Float64) {
+ mask = DxbcRegMask::firstN(value.type.ccount * 2);
+ vec0 = emitBuildConstVecf64(0.0, 0.0, mask);
+ vec1 = emitBuildConstVecf64(1.0, 1.0, mask);
+ }
+
+ if (mask)
+ value.id = m_module.opNClamp(typeId, value.id, vec0.id, vec1.id);
+ }
+
+ return value;
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitArrayAccess(
+ DxbcRegisterPointer pointer,
+ spv::StorageClass sclass,
+ uint32_t index) {
+ uint32_t ptrTypeId = m_module.defPointerType(
+ getVectorTypeId(pointer.type), sclass);
+
+ DxbcRegisterPointer result;
+ result.type = pointer.type;
+ result.id = m_module.opAccessChain(
+ ptrTypeId, pointer.id, 1, &index);
+ return result;
+ }
+
+
+ uint32_t DxbcCompiler::emitLoadSampledImage(
+ const DxbcShaderResource& textureResource,
+ const DxbcSampler& samplerResource,
+ bool isDepthCompare) {
+ const uint32_t sampledImageType = isDepthCompare
+ ? m_module.defSampledImageType(textureResource.depthTypeId)
+ : m_module.defSampledImageType(textureResource.colorTypeId);
+
+ return m_module.opSampledImage(sampledImageType,
+ m_module.opLoad(textureResource.imageTypeId, textureResource.varId),
+ m_module.opLoad(samplerResource.typeId, samplerResource.varId));
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetTempPtr(
+ const DxbcRegister& operand) {
+ // r# regs are indexed as follows:
+ // (0) register index (immediate)
+ uint32_t regIdx = operand.idx[0].offset;
+
+ if (regIdx >= m_rRegs.size())
+ m_rRegs.resize(regIdx + 1, 0u);
+
+ if (!m_rRegs.at(regIdx)) {
+ DxbcRegisterInfo info;
+ info.type.ctype = DxbcScalarType::Float32;
+ info.type.ccount = 4;
+ info.type.alength = 0;
+ info.sclass = spv::StorageClassPrivate;
+
+ uint32_t varId = emitNewVariable(info);
+ m_rRegs.at(regIdx) = varId;
+
+ m_module.setDebugName(varId,
+ str::format("r", regIdx).c_str());
+ }
+
+ DxbcRegisterPointer result;
+ result.type.ctype = DxbcScalarType::Float32;
+ result.type.ccount = 4;
+ result.id = m_rRegs.at(regIdx);
+ return result;
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetIndexableTempPtr(
+ const DxbcRegister& operand) {
+ return getIndexableTempPtr(operand, emitIndexLoad(operand.idx[1]));
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetInputPtr(
+ const DxbcRegister& operand) {
+ // In the vertex and pixel stages,
+ // v# regs are indexed as follows:
+ // (0) register index (relative)
+ //
+ // In the tessellation and geometry
+ // stages, the index has two dimensions:
+ // (0) vertex index (relative)
+ // (1) register index (relative)
+ DxbcRegisterPointer result;
+ result.type.ctype = DxbcScalarType::Float32;
+ result.type.ccount = 4;
+
+ std::array<uint32_t, 2> indices = {{ 0, 0 }};
+
+ for (uint32_t i = 0; i < operand.idxDim; i++)
+ indices.at(i) = emitIndexLoad(operand.idx[i]).id;
+
+ // Pick the input array depending on
+ // the program type and operand type
+ struct InputArray {
+ uint32_t id;
+ spv::StorageClass sclass;
+ };
+
+ const InputArray array = [&] () -> InputArray {
+ switch (operand.type) {
+ case DxbcOperandType::InputControlPoint:
+ return m_programInfo.type() == DxbcProgramType::HullShader
+ ? InputArray { m_vArray, spv::StorageClassPrivate }
+ : InputArray { m_ds.inputPerVertex, spv::StorageClassInput };
+ case DxbcOperandType::InputPatchConstant:
+ return m_programInfo.type() == DxbcProgramType::HullShader
+ ? InputArray { m_hs.outputPerPatch, spv::StorageClassPrivate }
+ : InputArray { m_ds.inputPerPatch, spv::StorageClassInput };
+ case DxbcOperandType::OutputControlPoint:
+ return InputArray { m_hs.outputPerVertex, spv::StorageClassOutput };
+ default:
+ return { m_vArray, spv::StorageClassPrivate };
+ }
+ }();
+
+ DxbcRegisterInfo info;
+ info.type.ctype = result.type.ctype;
+ info.type.ccount = result.type.ccount;
+ info.type.alength = 0;
+ info.sclass = array.sclass;
+
+ result.id = m_module.opAccessChain(
+ getPointerTypeId(info), array.id,
+ operand.idxDim, indices.data());
+
+ return result;
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetOutputPtr(
+ const DxbcRegister& operand) {
+ if (m_programInfo.type() == DxbcProgramType::HullShader) {
+ // Hull shaders are special in that they have two sets of
+ // output registers, one for per-patch values and one for
+ // per-vertex values.
+ DxbcRegisterPointer result;
+ result.type.ctype = DxbcScalarType::Float32;
+ result.type.ccount = 4;
+
+ uint32_t registerId = emitIndexLoad(operand.idx[0]).id;
+
+ if (m_hs.currPhaseType == DxbcCompilerHsPhase::ControlPoint) {
+ std::array<uint32_t, 2> indices = {{
+ m_module.opLoad(m_module.defIntType(32, 0), m_hs.builtinInvocationId),
+ registerId,
+ }};
+
+ uint32_t ptrTypeId = m_module.defPointerType(
+ getVectorTypeId(result.type),
+ spv::StorageClassOutput);
+
+ result.id = m_module.opAccessChain(
+ ptrTypeId, m_hs.outputPerVertex,
+ indices.size(), indices.data());
+ } else {
+ uint32_t ptrTypeId = m_module.defPointerType(
+ getVectorTypeId(result.type),
+ spv::StorageClassPrivate);
+
+ result.id = m_module.opAccessChain(
+ ptrTypeId, m_hs.outputPerPatch,
+ 1, &registerId);
+ }
+
+ return result;
+ } else {
+ // Regular shaders have their output
+ // registers set up at declaration time
+ return m_oRegs.at(operand.idx[0].offset);
+ }
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetImmConstBufPtr(
+ const DxbcRegister& operand) {
+ const DxbcRegisterValue constId
+ = emitIndexLoad(operand.idx[0]);
+
+ if (m_immConstBuf != 0) {
+ DxbcRegisterInfo ptrInfo;
+ ptrInfo.type.ctype = DxbcScalarType::Uint32;
+ ptrInfo.type.ccount = 4;
+ ptrInfo.type.alength = 0;
+ ptrInfo.sclass = spv::StorageClassPrivate;
+
+ DxbcRegisterPointer result;
+ result.type.ctype = ptrInfo.type.ctype;
+ result.type.ccount = ptrInfo.type.ccount;
+ result.id = m_module.opAccessChain(
+ getPointerTypeId(ptrInfo),
+ m_immConstBuf, 1, &constId.id);
+ return result;
+ } else if (m_constantBuffers.at(Icb_BindingSlotId).varId != 0) {
+ const std::array<uint32_t, 2> indices =
+ {{ m_module.consti32(0), constId.id }};
+
+ DxbcRegisterInfo ptrInfo;
+ ptrInfo.type.ctype = DxbcScalarType::Float32;
+ ptrInfo.type.ccount = 4;
+ ptrInfo.type.alength = 0;
+ ptrInfo.sclass = spv::StorageClassUniform;
+
+ DxbcRegisterPointer result;
+ result.type.ctype = ptrInfo.type.ctype;
+ result.type.ccount = ptrInfo.type.ccount;
+ result.id = m_module.opAccessChain(
+ getPointerTypeId(ptrInfo),
+ m_constantBuffers.at(Icb_BindingSlotId).varId,
+ indices.size(), indices.data());
+ return result;
+ } else {
+ throw DxvkError("DxbcCompiler: Immediate constant buffer not defined");
+ }
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetOperandPtr(
+ const DxbcRegister& operand) {
+ switch (operand.type) {
+ case DxbcOperandType::Temp:
+ return emitGetTempPtr(operand);
+
+ case DxbcOperandType::IndexableTemp:
+ return emitGetIndexableTempPtr(operand);
+
+ case DxbcOperandType::Input:
+ case DxbcOperandType::InputControlPoint:
+ case DxbcOperandType::InputPatchConstant:
+ case DxbcOperandType::OutputControlPoint:
+ return emitGetInputPtr(operand);
+
+ case DxbcOperandType::Output:
+ return emitGetOutputPtr(operand);
+
+ case DxbcOperandType::ImmediateConstantBuffer:
+ return emitGetImmConstBufPtr(operand);
+
+ case DxbcOperandType::InputThreadId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 3 },
+ m_cs.builtinGlobalInvocationId };
+
+ case DxbcOperandType::InputThreadGroupId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 3 },
+ m_cs.builtinWorkgroupId };
+
+ case DxbcOperandType::InputThreadIdInGroup:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 3 },
+ m_cs.builtinLocalInvocationId };
+
+ case DxbcOperandType::InputThreadIndexInGroup:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 1 },
+ m_cs.builtinLocalInvocationIndex };
+
+ case DxbcOperandType::InputCoverageMask: {
+ const std::array<uint32_t, 1> indices
+ = {{ m_module.constu32(0) }};
+
+ DxbcRegisterPointer result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(result.type),
+ spv::StorageClassInput),
+ m_ps.builtinSampleMaskIn,
+ indices.size(), indices.data());
+ return result;
+ }
+
+ case DxbcOperandType::OutputCoverageMask: {
+ const std::array<uint32_t, 1> indices
+ = {{ m_module.constu32(0) }};
+
+ DxbcRegisterPointer result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(result.type),
+ spv::StorageClassOutput),
+ m_ps.builtinSampleMaskOut,
+ indices.size(), indices.data());
+ return result;
+ }
+
+ case DxbcOperandType::OutputDepth:
+ case DxbcOperandType::OutputDepthGe:
+ case DxbcOperandType::OutputDepthLe:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Float32, 1 },
+ m_ps.builtinDepth };
+
+ case DxbcOperandType::OutputStencilRef:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Sint32, 1 },
+ m_ps.builtinStencilRef };
+
+ case DxbcOperandType::InputPrimitiveId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 1 },
+ m_primitiveIdIn };
+
+ case DxbcOperandType::InputDomainPoint:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Float32, 3 },
+ m_ds.builtinTessCoord };
+
+ case DxbcOperandType::OutputControlPointId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 1 },
+ m_hs.builtinInvocationId };
+
+ case DxbcOperandType::InputForkInstanceId:
+ case DxbcOperandType::InputJoinInstanceId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 1 },
+ getCurrentHsForkJoinPhase()->instanceIdPtr };
+
+ case DxbcOperandType::InputGsInstanceId:
+ return DxbcRegisterPointer {
+ { DxbcScalarType::Uint32, 1 },
+ m_gs.builtinInvocationId };
+
+ default:
+ throw DxvkError(str::format(
+ "DxbcCompiler: Unhandled operand type: ",
+ operand.type));
+ }
+ }
+
+
+ DxbcRegisterPointer DxbcCompiler::emitGetAtomicPointer(
+ const DxbcRegister& operand,
+ const DxbcRegister& address) {
+ // Query information about the resource itself
+ const uint32_t registerId = operand.idx[0].offset;
+ const DxbcBufferInfo resourceInfo = getBufferInfo(operand);
+
+ // For UAVs and shared memory, different methods
+ // of obtaining the final pointer are used.
+ bool isTgsm = operand.type == DxbcOperandType::ThreadGroupSharedMemory;
+ bool isSsbo = m_moduleInfo.options.minSsboAlignment <= resourceInfo.align
+ && resourceInfo.type != DxbcResourceType::Typed
+ && !isTgsm;
+
+ // Compute the actual address into the resource
+ const DxbcRegisterValue addressValue = [&] {
+ switch (resourceInfo.type) {
+ case DxbcResourceType::Raw:
+ return emitCalcBufferIndexRaw(emitRegisterLoad(
+ address, DxbcRegMask(true, false, false, false)));
+
+ case DxbcResourceType::Structured: {
+ const DxbcRegisterValue addressComponents = emitRegisterLoad(
+ address, DxbcRegMask(true, true, false, false));
+
+ return emitCalcBufferIndexStructured(
+ emitRegisterExtract(addressComponents, DxbcRegMask(true, false, false, false)),
+ emitRegisterExtract(addressComponents, DxbcRegMask(false, true, false, false)),
+ resourceInfo.stride);
+ };
+
+ case DxbcResourceType::Typed: {
+ if (isTgsm)
+ throw DxvkError("DxbcCompiler: TGSM cannot be typed");
+
+ return emitLoadTexCoord(address,
+ m_uavs.at(registerId).imageInfo);
+ }
+
+ default:
+ throw DxvkError("DxbcCompiler: Unhandled resource type");
+ }
+ }();
+
+ // Compute the actual pointer
+ DxbcRegisterPointer result;
+ result.type.ctype = resourceInfo.stype;
+ result.type.ccount = 1;
+
+ if (isTgsm) {
+ result.id = m_module.opAccessChain(resourceInfo.typeId,
+ resourceInfo.varId, 1, &addressValue.id);
+ } else if (isSsbo) {
+ uint32_t indices[2] = { m_module.constu32(0), addressValue.id };
+ result.id = m_module.opAccessChain(resourceInfo.typeId,
+ resourceInfo.varId, 2, indices);
+ } else {
+ result.id = m_module.opImageTexelPointer(
+ m_module.defPointerType(getVectorTypeId(result.type), spv::StorageClassImage),
+ resourceInfo.varId, addressValue.id, m_module.constu32(0));
+ }
+
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRawBufferLoad(
+ const DxbcRegister& operand,
+ DxbcRegisterValue elementIndex,
+ DxbcRegMask writeMask) {
+ const DxbcBufferInfo bufferInfo = getBufferInfo(operand);
+
+ // Shared memory is the only type of buffer that
+ // is not accessed through a texel buffer view
+ bool isTgsm = operand.type == DxbcOperandType::ThreadGroupSharedMemory;
+ bool isSsbo = m_moduleInfo.options.minSsboAlignment <= bufferInfo.align
+ && !isTgsm;
+
+ // Common types and IDs used while loading the data
+ uint32_t bufferId = isTgsm || isSsbo ? 0 : m_module.opLoad(bufferInfo.typeId, bufferInfo.varId);
+
+ uint32_t vectorTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 4 });
+ uint32_t scalarTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 1 });
+
+ // Since all data is represented as a sequence of 32-bit
+ // integers, we have to load each component individually.
+ std::array<uint32_t, 4> ccomps = { 0, 0, 0, 0 };
+ std::array<uint32_t, 4> scomps = { 0, 0, 0, 0 };
+ uint32_t scount = 0;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ uint32_t sindex = operand.swizzle[i];
+
+ if (!writeMask[i])
+ continue;
+
+ if (ccomps[sindex] == 0) {
+ uint32_t elementIndexAdjusted = m_module.opIAdd(
+ getVectorTypeId(elementIndex.type), elementIndex.id,
+ m_module.consti32(sindex));
+
+ // Load requested component from the buffer
+ uint32_t zero = 0;
+
+ if (isTgsm) {
+ ccomps[sindex] = m_module.opLoad(scalarTypeId,
+ m_module.opAccessChain(bufferInfo.typeId,
+ bufferInfo.varId, 1, &elementIndexAdjusted));
+ } else if (isSsbo) {
+ uint32_t indices[2] = { m_module.constu32(0), elementIndexAdjusted };
+ ccomps[sindex] = m_module.opLoad(scalarTypeId,
+ m_module.opAccessChain(bufferInfo.typeId,
+ bufferInfo.varId, 2, indices));
+ } else if (operand.type == DxbcOperandType::Resource) {
+ ccomps[sindex] = m_module.opCompositeExtract(scalarTypeId,
+ m_module.opImageFetch(vectorTypeId,
+ bufferId, elementIndexAdjusted,
+ SpirvImageOperands()), 1, &zero);
+ } else if (operand.type == DxbcOperandType::UnorderedAccessView) {
+ ccomps[sindex] = m_module.opCompositeExtract(scalarTypeId,
+ m_module.opImageRead(vectorTypeId,
+ bufferId, elementIndexAdjusted,
+ SpirvImageOperands()), 1, &zero);
+ } else {
+ throw DxvkError("DxbcCompiler: Invalid operand type for strucured/raw load");
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < 4; i++) {
+ uint32_t sindex = operand.swizzle[i];
+
+ if (writeMask[i])
+ scomps[scount++] = ccomps[sindex];
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = scount;
+ result.id = scomps[0];
+
+ if (scount > 1) {
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ scount, scomps.data());
+ }
+
+ return result;
+ }
+
+
+ void DxbcCompiler::emitRawBufferStore(
+ const DxbcRegister& operand,
+ DxbcRegisterValue elementIndex,
+ DxbcRegisterValue value) {
+ const DxbcBufferInfo bufferInfo = getBufferInfo(operand);
+
+ // Cast source value to the expected data type
+ value = emitRegisterBitcast(value, DxbcScalarType::Uint32);
+
+ // Thread Group Shared Memory is not accessed through a texel buffer view
+ bool isTgsm = operand.type == DxbcOperandType::ThreadGroupSharedMemory;
+ bool isSsbo = m_moduleInfo.options.minSsboAlignment <= bufferInfo.align
+ && !isTgsm;
+
+ // Perform UAV writes only if the UAV is bound and if there
+ // is nothing else preventing us from writing to it.
+ DxbcConditional cond;
+
+ if (!isTgsm) {
+ uint32_t writeTest = emitUavWriteTest(bufferInfo);
+
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(writeTest, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+ }
+
+ // Perform the actual write operation
+ uint32_t bufferId = isTgsm || isSsbo ? 0 : m_module.opLoad(bufferInfo.typeId, bufferInfo.varId);
+
+ uint32_t scalarTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 1 });
+ uint32_t vectorTypeId = getVectorTypeId({ DxbcScalarType::Uint32, 4 });
+
+ uint32_t srcComponentIndex = 0;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (operand.mask[i]) {
+ uint32_t srcComponentId = value.type.ccount > 1
+ ? m_module.opCompositeExtract(scalarTypeId,
+ value.id, 1, &srcComponentIndex)
+ : value.id;
+
+ // Add the component offset to the element index
+ uint32_t elementIndexAdjusted = i != 0
+ ? m_module.opIAdd(getVectorTypeId(elementIndex.type),
+ elementIndex.id, m_module.consti32(i))
+ : elementIndex.id;
+
+ if (isTgsm) {
+ m_module.opStore(
+ m_module.opAccessChain(bufferInfo.typeId,
+ bufferInfo.varId, 1, &elementIndexAdjusted),
+ srcComponentId);
+ } else if (isSsbo) {
+ uint32_t indices[2] = { m_module.constu32(0), elementIndexAdjusted };
+ m_module.opStore(
+ m_module.opAccessChain(bufferInfo.typeId,
+ bufferInfo.varId, 2, indices),
+ srcComponentId);
+ } else if (operand.type == DxbcOperandType::UnorderedAccessView) {
+ const std::array<uint32_t, 4> srcVectorIds = {
+ srcComponentId, srcComponentId,
+ srcComponentId, srcComponentId,
+ };
+
+ m_module.opImageWrite(
+ bufferId, elementIndexAdjusted,
+ m_module.opCompositeConstruct(vectorTypeId,
+ 4, srcVectorIds.data()),
+ SpirvImageOperands());
+ } else {
+ throw DxvkError("DxbcCompiler: Invalid operand type for strucured/raw store");
+ }
+
+ // Write next component
+ srcComponentIndex += 1;
+ }
+ }
+
+ // Make sure that shared memory stores are made visible in
+ // case the game does not synchronize invocations properly
+ if (isTgsm && m_moduleInfo.options.forceTgsmBarriers) {
+ m_module.opMemoryBarrier(
+ m_module.constu32(spv::ScopeWorkgroup),
+ m_module.constu32(spv::MemorySemanticsWorkgroupMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask));
+ }
+
+ // End conditional block
+ if (!isTgsm) {
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitQueryBufferSize(
+ const DxbcRegister& resource) {
+ const DxbcBufferInfo bufferInfo = getBufferInfo(resource);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opArrayLength(
+ getVectorTypeId(result.type),
+ bufferInfo.varId, 0);
+
+ // Report a size of 0 if resource is not bound
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ bufferInfo.specId, result.id, m_module.constu32(0));
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitQueryTexelBufferSize(
+ const DxbcRegister& resource) {
+ // Load the texel buffer object. This cannot be used with
+ // constant buffers or any other type of resource.
+ const DxbcBufferInfo bufferInfo = getBufferInfo(resource);
+
+ const uint32_t bufferId = m_module.opLoad(
+ bufferInfo.typeId, bufferInfo.varId);
+
+ // We'll store this as a scalar unsigned integer
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opImageQuerySize(
+ getVectorTypeId(result.type), bufferId);
+
+ // Report a size of 0 if resource is not bound
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ bufferInfo.specId, result.id, m_module.constu32(0));
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitQueryTextureLods(
+ const DxbcRegister& resource) {
+ const DxbcBufferInfo info = getBufferInfo(resource);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+
+ if (info.image.sampled == 1) {
+ result.id = m_module.opImageQueryLevels(
+ getVectorTypeId(result.type),
+ m_module.opLoad(info.typeId, info.varId));
+ } else {
+ // Report one LOD in case of UAVs
+ result.id = m_module.constu32(1);
+ }
+
+ // Report zero LODs for unbound images
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ info.specId, result.id, m_module.constu32(0));
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitQueryTextureSamples(
+ const DxbcRegister& resource) {
+ if (resource.type == DxbcOperandType::Rasterizer) {
+ // SPIR-V has no gl_NumSamples equivalent, so we have
+ // to work around it using a specialization constant
+ if (!m_ps.specRsSampleCount) {
+ m_ps.specRsSampleCount = emitNewSpecConstant(
+ DxvkSpecConstantId::RasterizerSampleCount,
+ DxbcScalarType::Uint32, 1,
+ "RasterizerSampleCount");
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_ps.specRsSampleCount;
+ return result;
+ } else {
+ DxbcBufferInfo info = getBufferInfo(resource);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+
+ if (info.image.ms) {
+ result.id = m_module.opImageQuerySamples(
+ getVectorTypeId(result.type),
+ m_module.opLoad(info.typeId, info.varId));
+ } else {
+ // OpImageQuerySamples requires MSAA images
+ result.id = m_module.constu32(1);
+ }
+
+ // Report a sample count of 0 for unbound images
+ result.id = m_module.opSelect(getVectorTypeId(result.type),
+ info.specId, result.id, m_module.constu32(0));
+ return result;
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitQueryTextureSize(
+ const DxbcRegister& resource,
+ DxbcRegisterValue lod) {
+ const DxbcBufferInfo info = getBufferInfo(resource);
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = getTexSizeDim(info.image);
+
+ if (info.image.ms == 0 && info.image.sampled == 1) {
+ result.id = m_module.opImageQuerySizeLod(
+ getVectorTypeId(result.type),
+ m_module.opLoad(info.typeId, info.varId),
+ lod.id);
+ } else {
+ result.id = m_module.opImageQuerySize(
+ getVectorTypeId(result.type),
+ m_module.opLoad(info.typeId, info.varId));
+ }
+
+ // Report a size of zero for unbound textures
+ uint32_t zero = m_module.constu32(0);
+ uint32_t cond = info.specId;
+
+ if (result.type.ccount > 1) {
+ std::array<uint32_t, 4> zeroes = {{ zero, zero, zero, zero }};
+ std::array<uint32_t, 4> conds = {{ cond, cond, cond, cond }};
+
+ zero = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ result.type.ccount, zeroes.data());
+
+ cond = m_module.opCompositeConstruct(
+ m_module.defVectorType(m_module.defBoolType(), result.type.ccount),
+ result.type.ccount, conds.data());
+ }
+
+ result.id = m_module.opSelect(
+ getVectorTypeId(result.type),
+ cond, result.id, zero);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitCalcBufferIndexStructured(
+ DxbcRegisterValue structId,
+ DxbcRegisterValue structOffset,
+ uint32_t structStride) {
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Sint32;
+ result.type.ccount = 1;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ uint32_t offset = m_moduleInfo.options.useSdivForBufferIndex
+ ? m_module.opSDiv (typeId, structOffset.id, m_module.consti32(4))
+ : m_module.opShiftRightLogical(typeId, structOffset.id, m_module.consti32(2));
+
+ result.id = m_module.opIAdd(typeId,
+ m_module.opIMul(typeId, structId.id, m_module.consti32(structStride / 4)),
+ offset);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitCalcBufferIndexRaw(
+ DxbcRegisterValue byteOffset) {
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Sint32;
+ result.type.ccount = 1;
+
+ uint32_t typeId = getVectorTypeId(result.type);
+
+ result.id = m_moduleInfo.options.useSdivForBufferIndex
+ ? m_module.opSDiv (typeId, byteOffset.id, m_module.consti32(4))
+ : m_module.opShiftRightLogical(typeId, byteOffset.id, m_module.consti32(2));
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitCalcTexCoord(
+ DxbcRegisterValue coordVector,
+ const DxbcImageInfo& imageInfo) {
+ const uint32_t dim = getTexCoordDim(imageInfo);
+
+ if (dim != coordVector.type.ccount) {
+ coordVector = emitRegisterExtract(
+ coordVector, DxbcRegMask::firstN(dim));
+ }
+
+ return coordVector;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitLoadTexCoord(
+ const DxbcRegister& coordReg,
+ const DxbcImageInfo& imageInfo) {
+ return emitCalcTexCoord(emitRegisterLoad(coordReg,
+ DxbcRegMask(true, true, true, true)), imageInfo);
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitIndexLoad(
+ DxbcRegIndex index) {
+ if (index.relReg != nullptr) {
+ DxbcRegisterValue result = emitRegisterLoad(
+ *index.relReg, DxbcRegMask(true, false, false, false));
+
+ if (index.offset != 0) {
+ result.id = m_module.opIAdd(
+ getVectorTypeId(result.type), result.id,
+ m_module.consti32(index.offset));
+ }
+
+ return result;
+ } else {
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Sint32;
+ result.type.ccount = 1;
+ result.id = m_module.consti32(index.offset);
+ return result;
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitValueLoad(
+ DxbcRegisterPointer ptr) {
+ DxbcRegisterValue result;
+ result.type = ptr.type;
+ result.id = m_module.opLoad(
+ getVectorTypeId(result.type),
+ ptr.id);
+ return result;
+ }
+
+
+ void DxbcCompiler::emitValueStore(
+ DxbcRegisterPointer ptr,
+ DxbcRegisterValue value,
+ DxbcRegMask writeMask) {
+ // If the component types are not compatible,
+ // we need to bit-cast the source variable.
+ if (value.type.ctype != ptr.type.ctype)
+ value = emitRegisterBitcast(value, ptr.type.ctype);
+
+ // If the source value consists of only one component,
+ // it is stored in all components of the destination.
+ if (value.type.ccount == 1)
+ value = emitRegisterExtend(value, writeMask.popCount());
+
+ if (ptr.type.ccount == writeMask.popCount()) {
+ // Simple case: We write to the entire register
+ m_module.opStore(ptr.id, value.id);
+ } else {
+ // We only write to part of the destination
+ // register, so we need to load and modify it
+ DxbcRegisterValue tmp = emitValueLoad(ptr);
+ tmp = emitRegisterInsert(tmp, value, writeMask);
+
+ m_module.opStore(ptr.id, tmp.id);
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterLoadRaw(
+ const DxbcRegister& reg) {
+ return emitValueLoad(emitGetOperandPtr(reg));
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitConstantBufferLoad(
+ const DxbcRegister& reg,
+ DxbcRegMask writeMask) {
+ // Constant buffers take a two-dimensional index:
+ // (0) register index (immediate)
+ // (1) constant offset (relative)
+ DxbcRegisterInfo info;
+ info.type.ctype = DxbcScalarType::Float32;
+ info.type.ccount = 4;
+ info.type.alength = 0;
+ info.sclass = spv::StorageClassUniform;
+
+ uint32_t regId = reg.idx[0].offset;
+ DxbcRegisterValue constId = emitIndexLoad(reg.idx[1]);
+
+ uint32_t ptrTypeId = getPointerTypeId(info);
+
+ const std::array<uint32_t, 2> indices =
+ {{ m_module.consti32(0), constId.id }};
+
+ DxbcRegisterPointer ptr;
+ ptr.type.ctype = info.type.ctype;
+ ptr.type.ccount = info.type.ccount;
+ ptr.id = m_module.opAccessChain(ptrTypeId,
+ m_constantBuffers.at(regId).varId,
+ indices.size(), indices.data());
+
+ // Load individual components from buffer
+ std::array<uint32_t, 4> ccomps = { 0, 0, 0, 0 };
+ std::array<uint32_t, 4> scomps = { 0, 0, 0, 0 };
+ uint32_t scount = 0;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ uint32_t sindex = reg.swizzle[i];
+
+ if (!writeMask[i] || ccomps[sindex])
+ continue;
+
+ uint32_t componentId = m_module.constu32(sindex);
+ uint32_t componentPtr = m_module.opAccessChain(
+ m_module.defPointerType(
+ getScalarTypeId(DxbcScalarType::Float32),
+ spv::StorageClassUniform),
+ ptr.id, 1, &componentId);
+
+ ccomps[sindex] = m_module.opLoad(
+ getScalarTypeId(DxbcScalarType::Float32),
+ componentPtr);
+ }
+
+ for (uint32_t i = 0; i < 4; i++) {
+ uint32_t sindex = reg.swizzle[i];
+
+ if (writeMask[i])
+ scomps[scount++] = ccomps[sindex];
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Float32;
+ result.type.ccount = scount;
+ result.id = scomps[0];
+
+ if (scount > 1) {
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ scount, scomps.data());
+ }
+
+ // Apply any post-processing that might be necessary
+ result = emitRegisterBitcast(result, reg.dataType);
+ result = emitSrcOperandModifiers(result, reg.modifiers);
+ return result;
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitRegisterLoad(
+ const DxbcRegister& reg,
+ DxbcRegMask writeMask) {
+ if (reg.type == DxbcOperandType::Imm32
+ || reg.type == DxbcOperandType::Imm64) {
+ DxbcRegisterValue result;
+
+ if (reg.componentCount == DxbcComponentCount::Component1) {
+ // Create one single u32 constant
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.constu32(reg.imm.u32_1);
+
+ result = emitRegisterExtend(result, writeMask.popCount());
+ } else if (reg.componentCount == DxbcComponentCount::Component4) {
+ // Create a u32 vector with as many components as needed
+ std::array<uint32_t, 4> indices = { };
+ uint32_t indexId = 0;
+
+ for (uint32_t i = 0; i < indices.size(); i++) {
+ if (writeMask[i]) {
+ indices.at(indexId++) =
+ m_module.constu32(reg.imm.u32_4[i]);
+ }
+ }
+
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = writeMask.popCount();
+ result.id = indices.at(0);
+
+ if (indexId > 1) {
+ result.id = m_module.constComposite(
+ getVectorTypeId(result.type),
+ result.type.ccount, indices.data());
+ }
+
+ } else {
+ // Something went horribly wrong in the decoder or the shader is broken
+ throw DxvkError("DxbcCompiler: Invalid component count for immediate operand");
+ }
+
+ // Cast constants to the requested type
+ return emitRegisterBitcast(result, reg.dataType);
+ } else if (reg.type == DxbcOperandType::ConstantBuffer) {
+ return emitConstantBufferLoad(reg, writeMask);
+ } else {
+ // Load operand from the operand pointer
+ DxbcRegisterValue result = emitRegisterLoadRaw(reg);
+
+ // Apply operand swizzle to the operand value
+ result = emitRegisterSwizzle(result, reg.swizzle, writeMask);
+
+ // Cast it to the requested type. We need to do
+ // this after the swizzling for 64-bit types.
+ result = emitRegisterBitcast(result, reg.dataType);
+
+ // Apply operand modifiers
+ result = emitSrcOperandModifiers(result, reg.modifiers);
+ return result;
+ }
+ }
+
+
+ void DxbcCompiler::emitRegisterStore(
+ const DxbcRegister& reg,
+ DxbcRegisterValue value) {
+ if (reg.type == DxbcOperandType::IndexableTemp) {
+ DxbcRegisterValue vectorId = emitIndexLoad(reg.idx[1]);
+ uint32_t boundsCheck = m_module.opULessThan(
+ m_module.defBoolType(), vectorId.id,
+ m_module.constu32(m_xRegs.at(reg.idx[0].offset).alength));
+
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(boundsCheck, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+ emitValueStore(getIndexableTempPtr(reg, vectorId), value, reg.mask);
+
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ } else {
+ emitValueStore(emitGetOperandPtr(reg), value, reg.mask);
+ }
+ }
+
+
+ uint32_t DxbcCompiler::emitNewSpecConstant(
+ DxvkSpecConstantId specId,
+ DxbcScalarType type,
+ uint32_t value,
+ const char* name) {
+ uint32_t id = m_module.specConst32(
+ getScalarTypeId(type), value);
+
+ m_module.decorateSpecId(id, uint32_t(specId));
+ m_module.setDebugName(id, name);
+ return id;
+ }
+
+
+ void DxbcCompiler::emitInputSetup() {
+ m_module.setLateConst(m_vArrayLengthId, &m_vArrayLength);
+
+ // Copy all defined v# registers into the input array
+ const uint32_t vecTypeId = m_module.defVectorType(m_module.defFloatType(32), 4);
+ const uint32_t ptrTypeId = m_module.defPointerType(vecTypeId, spv::StorageClassPrivate);
+
+ for (uint32_t i = 0; i < m_vRegs.size(); i++) {
+ if (m_vRegs.at(i).id != 0) {
+ const uint32_t registerId = m_module.consti32(i);
+
+ DxbcRegisterPointer srcPtr = m_vRegs.at(i);
+ DxbcRegisterValue srcValue = emitRegisterBitcast(
+ emitValueLoad(srcPtr), DxbcScalarType::Float32);
+
+ DxbcRegisterPointer dstPtr;
+ dstPtr.type = { DxbcScalarType::Float32, 4 };
+ dstPtr.id = m_module.opAccessChain(
+ ptrTypeId, m_vArray, 1, &registerId);
+
+ emitValueStore(dstPtr, srcValue, DxbcRegMask::firstN(srcValue.type.ccount));
+ }
+ }
+
+ // Copy all system value registers into the array,
+ // preserving any previously written contents.
+ for (const DxbcSvMapping& map : m_vMappings) {
+ const uint32_t registerId = m_module.consti32(map.regId);
+
+ const DxbcRegisterValue value = [&] {
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::VertexShader: return emitVsSystemValueLoad(map.sv, map.regMask);
+ case DxbcProgramType::PixelShader: return emitPsSystemValueLoad(map.sv, map.regMask);
+ default: throw DxvkError(str::format("DxbcCompiler: Unexpected stage: ", m_programInfo.type()));
+ }
+ }();
+
+ DxbcRegisterPointer inputReg;
+ inputReg.type.ctype = DxbcScalarType::Float32;
+ inputReg.type.ccount = 4;
+ inputReg.id = m_module.opAccessChain(
+ ptrTypeId, m_vArray, 1, &registerId);
+ emitValueStore(inputReg, value, map.regMask);
+ }
+ }
+
+
+ void DxbcCompiler::emitInputSetup(uint32_t vertexCount) {
+ m_module.setLateConst(m_vArrayLengthId, &m_vArrayLength);
+
+ // Copy all defined v# registers into the input array. Note
+ // that the outer index of the array is the vertex index.
+ const uint32_t vecTypeId = m_module.defVectorType(m_module.defFloatType(32), 4);
+ const uint32_t dstPtrTypeId = m_module.defPointerType(vecTypeId, spv::StorageClassPrivate);
+
+ for (uint32_t i = 0; i < m_vRegs.size(); i++) {
+ if (m_vRegs.at(i).id != 0) {
+ const uint32_t registerId = m_module.consti32(i);
+
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ std::array<uint32_t, 2> indices
+ = {{ m_module.consti32(v), registerId }};
+
+ DxbcRegisterPointer srcPtr;
+ srcPtr.type = m_vRegs.at(i).type;
+ srcPtr.id = m_module.opAccessChain(
+ m_module.defPointerType(getVectorTypeId(srcPtr.type), spv::StorageClassInput),
+ m_vRegs.at(i).id, 1, indices.data());
+
+ DxbcRegisterValue srcValue = emitRegisterBitcast(
+ emitValueLoad(srcPtr), DxbcScalarType::Float32);
+
+ DxbcRegisterPointer dstPtr;
+ dstPtr.type = { DxbcScalarType::Float32, 4 };
+ dstPtr.id = m_module.opAccessChain(
+ dstPtrTypeId, m_vArray, 2, indices.data());
+
+ emitValueStore(dstPtr, srcValue, DxbcRegMask::firstN(srcValue.type.ccount));
+ }
+ }
+ }
+
+ // Copy all system value registers into the array,
+ // preserving any previously written contents.
+ for (const DxbcSvMapping& map : m_vMappings) {
+ const uint32_t registerId = m_module.consti32(map.regId);
+
+ for (uint32_t v = 0; v < vertexCount; v++) {
+ const DxbcRegisterValue value = [&] {
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::GeometryShader: return emitGsSystemValueLoad(map.sv, map.regMask, v);
+ default: throw DxvkError(str::format("DxbcCompiler: Unexpected stage: ", m_programInfo.type()));
+ }
+ }();
+
+ std::array<uint32_t, 2> indices = {
+ m_module.consti32(v), registerId,
+ };
+
+ DxbcRegisterPointer inputReg;
+ inputReg.type.ctype = DxbcScalarType::Float32;
+ inputReg.type.ccount = 4;
+ inputReg.id = m_module.opAccessChain(dstPtrTypeId,
+ m_vArray, indices.size(), indices.data());
+ emitValueStore(inputReg, value, map.regMask);
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitOutputSetup() {
+ for (const DxbcSvMapping& svMapping : m_oMappings) {
+ DxbcRegisterPointer outputReg = m_oRegs.at(svMapping.regId);
+
+ if (m_programInfo.type() == DxbcProgramType::HullShader) {
+ uint32_t registerIndex = m_module.constu32(svMapping.regId);
+
+ outputReg.type = { DxbcScalarType::Float32, 4 };
+ outputReg.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(outputReg.type),
+ spv::StorageClassPrivate),
+ m_hs.outputPerPatch,
+ 1, &registerIndex);
+ }
+
+ auto sv = svMapping.sv;
+ auto mask = svMapping.regMask;
+ auto value = emitValueLoad(outputReg);
+
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::VertexShader: emitVsSystemValueStore(sv, mask, value); break;
+ case DxbcProgramType::GeometryShader: emitGsSystemValueStore(sv, mask, value); break;
+ case DxbcProgramType::HullShader: emitHsSystemValueStore(sv, mask, value); break;
+ case DxbcProgramType::DomainShader: emitDsSystemValueStore(sv, mask, value); break;
+ case DxbcProgramType::PixelShader: emitPsSystemValueStore(sv, mask, value); break;
+ case DxbcProgramType::ComputeShader: break;
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitOutputMapping() {
+ // For pixel shaders, we need to swizzle the
+ // output vectors using some spec constants.
+ for (uint32_t i = 0; i < m_oRegs.size(); i++) {
+ if (m_oRegs[i].id == 0 || m_oRegs[i].type.ccount < 2)
+ continue;
+
+ DxbcRegisterValue vector = emitValueLoad(m_oRegs[i]);
+
+ uint32_t specTypeId = getScalarTypeId(DxbcScalarType::Uint32);
+ uint32_t compTypeId = getScalarTypeId(vector.type.ctype);
+
+ uint32_t specId = m_module.specConst32(specTypeId, 0x3210);
+ m_module.decorateSpecId(specId, uint32_t(DxvkSpecConstantId::ColorComponentMappings) + i);
+ m_module.setDebugName(specId, str::format("omap", i).c_str());
+
+ std::array<uint32_t, 4> scalars;
+ for (uint32_t c = 0; c < vector.type.ccount; c++) {
+ scalars[c] = m_module.opVectorExtractDynamic(compTypeId, vector.id,
+ m_module.opBitFieldUExtract(specTypeId, specId,
+ m_module.constu32(4 * c), m_module.constu32(4)));
+ }
+
+ uint32_t typeId = getVectorTypeId(vector.type);
+ vector.id = m_module.opCompositeConstruct(typeId, vector.type.ccount, scalars.data());
+
+ // Replace NaN by zero if requested
+ if (m_moduleInfo.options.enableRtOutputNanFixup && vector.type.ctype == DxbcScalarType::Float32) {
+ uint32_t boolType = m_module.defBoolType();
+
+ if (vector.type.ccount > 1)
+ boolType = m_module.defVectorType(boolType, vector.type.ccount);
+
+ uint32_t zero = emitBuildConstVecf32(0.0f, 0.0f, 0.0f, 0.0f,
+ DxbcRegMask((1u << vector.type.ccount) - 1)).id;
+ uint32_t isNan = m_module.opIsNan(boolType, vector.id);
+ vector.id = m_module.opSelect(typeId, isNan, zero, vector.id);
+ }
+
+ emitValueStore(m_oRegs[i], vector,
+ DxbcRegMask::firstN(vector.type.ccount));
+ }
+ }
+
+
+ void DxbcCompiler::emitOutputDepthClamp() {
+ // HACK: Some drivers do not clamp FragDepth to [minDepth..maxDepth]
+ // before writing to the depth attachment, but we do not have acccess
+ // to those. Clamp to [0..1] instead.
+ if (m_ps.builtinDepth) {
+ DxbcRegisterPointer ptr;
+ ptr.type = { DxbcScalarType::Float32, 1 };
+ ptr.id = m_ps.builtinDepth;
+
+ DxbcRegisterValue value = emitValueLoad(ptr);
+
+ value.id = m_module.opFClamp(
+ getVectorTypeId(ptr.type),
+ value.id,
+ m_module.constf32(0.0f),
+ m_module.constf32(1.0f));
+
+ emitValueStore(ptr, value,
+ DxbcRegMask::firstN(1));
+ }
+ }
+
+
+ void DxbcCompiler::emitInitWorkgroupMemory() {
+ bool hasTgsm = false;
+
+ for (uint32_t i = 0; i < m_gRegs.size(); i++) {
+ if (!m_gRegs[i].varId)
+ continue;
+
+ if (!m_cs.builtinLocalInvocationIndex) {
+ m_cs.builtinLocalInvocationIndex = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInLocalInvocationIndex,
+ "vThreadIndexInGroup");
+ }
+
+ uint32_t intTypeId = getScalarTypeId(DxbcScalarType::Uint32);
+ uint32_t ptrTypeId = m_module.defPointerType(
+ intTypeId, spv::StorageClassWorkgroup);
+
+ uint32_t numElements = m_gRegs[i].type == DxbcResourceType::Structured
+ ? m_gRegs[i].elementCount * m_gRegs[i].elementStride / 4
+ : m_gRegs[i].elementCount / 4;
+
+ uint32_t numThreads = m_cs.workgroupSizeX *
+ m_cs.workgroupSizeY * m_cs.workgroupSizeZ;
+
+ uint32_t numElementsPerThread = numElements / numThreads;
+ uint32_t numElementsRemaining = numElements % numThreads;
+
+ uint32_t threadId = m_module.opLoad(
+ intTypeId, m_cs.builtinLocalInvocationIndex);
+
+ uint32_t strideId = m_module.constu32(numElementsPerThread);
+ uint32_t zeroId = m_module.constu32(0);
+
+ for (uint32_t e = 0; e < numElementsPerThread; e++) {
+ uint32_t ofsId = m_module.opIAdd(intTypeId,
+ m_module.opIMul(intTypeId, strideId, threadId),
+ m_module.constu32(e));
+
+ uint32_t ptrId = m_module.opAccessChain(
+ ptrTypeId, m_gRegs[i].varId, 1, &ofsId);
+
+ m_module.opStore(ptrId, zeroId);
+ }
+
+ if (numElementsRemaining) {
+ uint32_t condition = m_module.opULessThan(
+ m_module.defBoolType(), threadId,
+ m_module.constu32(numElementsRemaining));
+
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(condition, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+
+ uint32_t ofsId = m_module.opIAdd(intTypeId,
+ m_module.constu32(numThreads * numElementsPerThread),
+ threadId);
+
+ uint32_t ptrId = m_module.opAccessChain(
+ ptrTypeId, m_gRegs[i].varId, 1, &ofsId);
+
+ m_module.opStore(ptrId, zeroId);
+
+ m_module.opBranch(cond.labelEnd);
+ m_module.opLabel (cond.labelEnd);
+ }
+
+ hasTgsm = true;
+ }
+
+ if (hasTgsm) {
+ m_module.opControlBarrier(
+ m_module.constu32(spv::ScopeInvocation),
+ m_module.constu32(spv::ScopeWorkgroup),
+ m_module.constu32(spv::MemorySemanticsWorkgroupMemoryMask
+ | spv::MemorySemanticsAcquireReleaseMask));
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitVsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask) {
+ switch (sv) {
+ case DxbcSystemValue::VertexId: {
+ const uint32_t typeId = getScalarTypeId(DxbcScalarType::Uint32);
+
+ if (m_vs.builtinVertexId == 0) {
+ m_vs.builtinVertexId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInVertexIndex,
+ "vs_vertex_index");
+ }
+
+ if (m_vs.builtinBaseVertex == 0) {
+ m_vs.builtinBaseVertex = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInBaseVertex,
+ "vs_base_vertex");
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opISub(typeId,
+ m_module.opLoad(typeId, m_vs.builtinVertexId),
+ m_module.opLoad(typeId, m_vs.builtinBaseVertex));
+ return result;
+ } break;
+
+ case DxbcSystemValue::InstanceId: {
+ const uint32_t typeId = getScalarTypeId(DxbcScalarType::Uint32);
+
+ if (m_vs.builtinInstanceId == 0) {
+ m_vs.builtinInstanceId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInInstanceIndex,
+ "vs_instance_index");
+ }
+
+ if (m_vs.builtinBaseInstance == 0) {
+ m_vs.builtinBaseInstance = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInBaseInstance,
+ "vs_base_instance");
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opISub(typeId,
+ m_module.opLoad(typeId, m_vs.builtinInstanceId),
+ m_module.opLoad(typeId, m_vs.builtinBaseInstance));
+ return result;
+ } break;
+
+ default:
+ throw DxvkError(str::format(
+ "DxbcCompiler: Unhandled VS SV input: ", sv));
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitGsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ uint32_t vertexId) {
+ switch (sv) {
+ case DxbcSystemValue::Position: {
+ const std::array<uint32_t, 2> indices = {
+ m_module.consti32(vertexId),
+ m_module.consti32(PerVertex_Position),
+ };
+
+ DxbcRegisterPointer ptrIn;
+ ptrIn.type.ctype = DxbcScalarType::Float32;
+ ptrIn.type.ccount = 4;
+
+ ptrIn.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(ptrIn.type),
+ spv::StorageClassInput),
+ m_perVertexIn,
+ indices.size(),
+ indices.data());
+
+ return emitRegisterExtract(
+ emitValueLoad(ptrIn), mask);
+ } break;
+
+ default:
+ throw DxvkError(str::format(
+ "DxbcCompiler: Unhandled GS SV input: ", sv));
+ }
+ }
+
+
+ DxbcRegisterValue DxbcCompiler::emitPsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask) {
+ switch (sv) {
+ case DxbcSystemValue::Position: {
+ if (m_ps.builtinFragCoord == 0) {
+ m_ps.builtinFragCoord = emitNewBuiltinVariable({
+ { DxbcScalarType::Float32, 4, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInFragCoord,
+ "ps_frag_coord");
+ }
+
+ DxbcRegisterPointer ptrIn;
+ ptrIn.type = { DxbcScalarType::Float32, 4 };
+ ptrIn.id = m_ps.builtinFragCoord;
+
+ // The X, Y and Z components of the SV_POSITION semantic
+ // are identical to Vulkan's FragCoord builtin, but we
+ // need to compute the reciprocal of the W component.
+ DxbcRegisterValue fragCoord = emitValueLoad(ptrIn);
+
+ uint32_t componentIndex = 3;
+ uint32_t t_f32 = m_module.defFloatType(32);
+ uint32_t v_wComp = m_module.opCompositeExtract(t_f32, fragCoord.id, 1, &componentIndex);
+ v_wComp = m_module.opFDiv(t_f32, m_module.constf32(1.0f), v_wComp);
+
+ fragCoord.id = m_module.opCompositeInsert(
+ getVectorTypeId(fragCoord.type),
+ v_wComp, fragCoord.id,
+ 1, &componentIndex);
+
+ return emitRegisterExtract(fragCoord, mask);
+ } break;
+
+ case DxbcSystemValue::IsFrontFace: {
+ if (m_ps.builtinIsFrontFace == 0) {
+ m_ps.builtinIsFrontFace = emitNewBuiltinVariable({
+ { DxbcScalarType::Bool, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInFrontFacing,
+ "ps_is_front_face");
+ }
+
+ DxbcRegisterValue result;
+ result.type.ctype = DxbcScalarType::Uint32;
+ result.type.ccount = 1;
+ result.id = m_module.opSelect(
+ getVectorTypeId(result.type),
+ m_module.opLoad(
+ m_module.defBoolType(),
+ m_ps.builtinIsFrontFace),
+ m_module.constu32(0xFFFFFFFF),
+ m_module.constu32(0x00000000));
+ return result;
+ } break;
+
+ case DxbcSystemValue::PrimitiveId: {
+ if (m_primitiveIdIn == 0) {
+ m_module.enableCapability(spv::CapabilityGeometry);
+
+ m_primitiveIdIn = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInPrimitiveId,
+ "ps_primitive_id");
+ }
+
+ DxbcRegisterPointer ptrIn;
+ ptrIn.type = { DxbcScalarType::Uint32, 1 };
+ ptrIn.id = m_primitiveIdIn;
+
+ return emitValueLoad(ptrIn);
+ } break;
+
+ case DxbcSystemValue::SampleIndex: {
+ if (m_ps.builtinSampleId == 0) {
+ m_module.enableCapability(spv::CapabilitySampleRateShading);
+
+ m_ps.builtinSampleId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInSampleId,
+ "ps_sample_id");
+ }
+
+ DxbcRegisterPointer ptrIn;
+ ptrIn.type.ctype = DxbcScalarType::Uint32;
+ ptrIn.type.ccount = 1;
+ ptrIn.id = m_ps.builtinSampleId;
+
+ return emitValueLoad(ptrIn);
+ } break;
+
+ case DxbcSystemValue::RenderTargetId: {
+ if (m_ps.builtinLayer == 0) {
+ m_module.enableCapability(spv::CapabilityGeometry);
+
+ m_ps.builtinLayer = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInLayer,
+ "v_layer");
+ }
+
+ DxbcRegisterPointer ptr;
+ ptr.type.ctype = DxbcScalarType::Uint32;
+ ptr.type.ccount = 1;
+ ptr.id = m_ps.builtinLayer;
+
+ return emitValueLoad(ptr);
+ } break;
+
+ case DxbcSystemValue::ViewportId: {
+ if (m_ps.builtinViewportId == 0) {
+ m_module.enableCapability(spv::CapabilityMultiViewport);
+
+ m_ps.builtinViewportId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInViewportIndex,
+ "v_viewport");
+ }
+
+ DxbcRegisterPointer ptr;
+ ptr.type.ctype = DxbcScalarType::Uint32;
+ ptr.type.ccount = 1;
+ ptr.id = m_ps.builtinViewportId;
+
+ return emitValueLoad(ptr);
+ } break;
+
+ default:
+ throw DxvkError(str::format(
+ "DxbcCompiler: Unhandled PS SV input: ", sv));
+ }
+ }
+
+
+ void DxbcCompiler::emitVsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value) {
+ switch (sv) {
+ case DxbcSystemValue::Position: {
+ const uint32_t memberId = m_module.consti32(PerVertex_Position);
+
+ DxbcRegisterPointer ptr;
+ ptr.type.ctype = DxbcScalarType::Float32;
+ ptr.type.ccount = 4;
+
+ ptr.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(ptr.type),
+ spv::StorageClassOutput),
+ m_perVertexOut, 1, &memberId);
+
+ emitValueStore(ptr, value, mask);
+ } break;
+
+ case DxbcSystemValue::RenderTargetId: {
+ if (m_programInfo.type() != DxbcProgramType::GeometryShader)
+ enableShaderViewportIndexLayer();
+
+ if (m_gs.builtinLayer == 0) {
+ m_module.enableCapability(spv::CapabilityGeometry);
+
+ m_gs.builtinLayer = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInLayer,
+ "o_layer");
+ }
+
+ DxbcRegisterPointer ptr;
+ ptr.type = { DxbcScalarType::Uint32, 1 };
+ ptr.id = m_gs.builtinLayer;
+
+ emitValueStore(
+ ptr, emitRegisterExtract(value, mask),
+ DxbcRegMask(true, false, false, false));
+ } break;
+
+ case DxbcSystemValue::ViewportId: {
+ if (m_programInfo.type() != DxbcProgramType::GeometryShader)
+ enableShaderViewportIndexLayer();
+
+ if (m_gs.builtinViewportId == 0) {
+ m_module.enableCapability(spv::CapabilityMultiViewport);
+
+ m_gs.builtinViewportId = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInViewportIndex,
+ "o_viewport");
+ }
+
+ DxbcRegisterPointer ptr;
+ ptr.type = { DxbcScalarType::Uint32, 1};
+ ptr.id = m_gs.builtinViewportId;
+
+ emitValueStore(
+ ptr, emitRegisterExtract(value, mask),
+ DxbcRegMask(true, false, false, false));
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled VS SV output: ", sv));
+ }
+ }
+
+
+ void DxbcCompiler::emitHsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value) {
+ if (sv >= DxbcSystemValue::FinalQuadUeq0EdgeTessFactor
+ && sv <= DxbcSystemValue::FinalLineDensityTessFactor) {
+ struct TessFactor {
+ uint32_t array = 0;
+ uint32_t index = 0;
+ };
+
+ static const std::array<TessFactor, 12> s_tessFactors = {{
+ { m_hs.builtinTessLevelOuter, 0 }, // FinalQuadUeq0EdgeTessFactor
+ { m_hs.builtinTessLevelOuter, 1 }, // FinalQuadVeq0EdgeTessFactor
+ { m_hs.builtinTessLevelOuter, 2 }, // FinalQuadUeq1EdgeTessFactor
+ { m_hs.builtinTessLevelOuter, 3 }, // FinalQuadVeq1EdgeTessFactor
+ { m_hs.builtinTessLevelInner, 0 }, // FinalQuadUInsideTessFactor
+ { m_hs.builtinTessLevelInner, 1 }, // FinalQuadVInsideTessFactor
+ { m_hs.builtinTessLevelOuter, 0 }, // FinalTriUeq0EdgeTessFactor
+ { m_hs.builtinTessLevelOuter, 1 }, // FinalTriVeq0EdgeTessFactor
+ { m_hs.builtinTessLevelOuter, 2 }, // FinalTriWeq0EdgeTessFactor
+ { m_hs.builtinTessLevelInner, 0 }, // FinalTriInsideTessFactor
+ { m_hs.builtinTessLevelOuter, 0 }, // FinalLineDensityTessFactor
+ { m_hs.builtinTessLevelOuter, 1 }, // FinalLineDetailTessFactor
+ }};
+
+ const TessFactor tessFactor = s_tessFactors.at(uint32_t(sv)
+ - uint32_t(DxbcSystemValue::FinalQuadUeq0EdgeTessFactor));
+
+ const uint32_t tessFactorArrayIndex
+ = m_module.constu32(tessFactor.index);
+
+ // Apply global tess factor limit
+ float maxTessFactor = m_hs.maxTessFactor;
+
+ if (m_moduleInfo.tess != nullptr) {
+ if (m_moduleInfo.tess->maxTessFactor < maxTessFactor)
+ maxTessFactor = m_moduleInfo.tess->maxTessFactor;
+ }
+
+ DxbcRegisterValue tessValue = emitRegisterExtract(value, mask);
+ tessValue.id = m_module.opFClamp(getVectorTypeId(tessValue.type),
+ tessValue.id, m_module.constf32(0.0f),
+ m_module.constf32(maxTessFactor));
+
+ DxbcRegisterPointer ptr;
+ ptr.type.ctype = DxbcScalarType::Float32;
+ ptr.type.ccount = 1;
+ ptr.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(ptr.type),
+ spv::StorageClassOutput),
+ tessFactor.array, 1,
+ &tessFactorArrayIndex);
+
+ emitValueStore(ptr, tessValue,
+ DxbcRegMask(true, false, false, false));
+ } else {
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled HS SV output: ", sv));
+ }
+ }
+
+
+ void DxbcCompiler::emitGsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value) {
+ switch (sv) {
+ case DxbcSystemValue::Position:
+ case DxbcSystemValue::CullDistance:
+ case DxbcSystemValue::ClipDistance:
+ case DxbcSystemValue::RenderTargetId:
+ case DxbcSystemValue::ViewportId:
+ emitVsSystemValueStore(sv, mask, value);
+ break;
+
+ case DxbcSystemValue::PrimitiveId: {
+ if (m_primitiveIdOut == 0) {
+ m_primitiveIdOut = emitNewBuiltinVariable({
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassOutput },
+ spv::BuiltInPrimitiveId,
+ "gs_primitive_id");
+ }
+
+ DxbcRegisterPointer ptr;
+ ptr.type = { DxbcScalarType::Uint32, 1};
+ ptr.id = m_primitiveIdOut;
+
+ emitValueStore(
+ ptr, emitRegisterExtract(value, mask),
+ DxbcRegMask(true, false, false, false));
+ } break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled GS SV output: ", sv));
+ }
+ }
+
+
+ void DxbcCompiler::emitPsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value) {
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled PS SV output: ", sv));
+ }
+
+
+ void DxbcCompiler::emitDsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value) {
+ switch (sv) {
+ case DxbcSystemValue::Position:
+ case DxbcSystemValue::CullDistance:
+ case DxbcSystemValue::ClipDistance:
+ case DxbcSystemValue::RenderTargetId:
+ case DxbcSystemValue::ViewportId:
+ emitVsSystemValueStore(sv, mask, value);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcCompiler: Unhandled DS SV output: ", sv));
+ }
+ }
+
+
+ void DxbcCompiler::emitClipCullStore(
+ DxbcSystemValue sv,
+ uint32_t dstArray) {
+ uint32_t offset = 0;
+
+ if (dstArray == 0)
+ return;
+
+ for (auto e = m_osgn->begin(); e != m_osgn->end(); e++) {
+ if (e->systemValue == sv) {
+ DxbcRegisterPointer srcPtr = m_oRegs.at(e->registerId);
+ DxbcRegisterValue srcValue = emitValueLoad(srcPtr);
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (e->componentMask[i]) {
+ uint32_t offsetId = m_module.consti32(offset++);
+
+ DxbcRegisterValue component = emitRegisterExtract(
+ srcValue, DxbcRegMask::select(i));
+
+ DxbcRegisterPointer dstPtr;
+ dstPtr.type = { DxbcScalarType::Float32, 1 };
+ dstPtr.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(dstPtr.type),
+ spv::StorageClassOutput),
+ dstArray, 1, &offsetId);
+
+ emitValueStore(dstPtr, component,
+ DxbcRegMask(true, false, false, false));
+ }
+ }
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitClipCullLoad(
+ DxbcSystemValue sv,
+ uint32_t srcArray) {
+ uint32_t offset = 0;
+
+ if (srcArray == 0)
+ return;
+
+ for (auto e = m_isgn->begin(); e != m_isgn->end(); e++) {
+ if (e->systemValue == sv) {
+ // Load individual components from the source array
+ uint32_t componentIndex = 0;
+ std::array<uint32_t, 4> componentIds = {{ 0, 0, 0, 0 }};
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (e->componentMask[i]) {
+ uint32_t offsetId = m_module.consti32(offset++);
+
+ DxbcRegisterPointer srcPtr;
+ srcPtr.type = { DxbcScalarType::Float32, 1 };
+ srcPtr.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(srcPtr.type),
+ spv::StorageClassInput),
+ srcArray, 1, &offsetId);
+
+ componentIds[componentIndex++]
+ = emitValueLoad(srcPtr).id;
+ }
+ }
+
+ // Put everything into one vector
+ DxbcRegisterValue dstValue;
+ dstValue.type = { DxbcScalarType::Float32, componentIndex };
+ dstValue.id = componentIds[0];
+
+ if (componentIndex > 1) {
+ dstValue.id = m_module.opCompositeConstruct(
+ getVectorTypeId(dstValue.type),
+ componentIndex, componentIds.data());
+ }
+
+ // Store vector to the input array
+ uint32_t registerId = m_module.consti32(e->registerId);
+
+ DxbcRegisterPointer dstInput;
+ dstInput.type = { DxbcScalarType::Float32, 4 };
+ dstInput.id = m_module.opAccessChain(
+ m_module.defPointerType(
+ getVectorTypeId(dstInput.type),
+ spv::StorageClassPrivate),
+ m_vArray, 1, &registerId);
+
+ emitValueStore(dstInput, dstValue, e->componentMask);
+ }
+ }
+ }
+
+
+ uint32_t DxbcCompiler::emitUavWriteTest(const DxbcBufferInfo& uav) {
+ uint32_t typeId = m_module.defBoolType();
+ uint32_t testId = uav.specId;
+
+ if (m_ps.killState != 0) {
+ uint32_t killState = m_module.opLoad(typeId, m_ps.killState);
+
+ testId = m_module.opLogicalAnd(typeId, testId,
+ m_module.opLogicalNot(typeId, killState));
+ }
+
+ return testId;
+ }
+
+
+ void DxbcCompiler::emitInit() {
+ // Set up common capabilities for all shaders
+ m_module.enableCapability(spv::CapabilityShader);
+ m_module.enableCapability(spv::CapabilityImageQuery);
+
+ // Initialize the shader module with capabilities
+ // etc. Each shader type has its own peculiarities.
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::VertexShader: emitVsInit(); break;
+ case DxbcProgramType::HullShader: emitHsInit(); break;
+ case DxbcProgramType::DomainShader: emitDsInit(); break;
+ case DxbcProgramType::GeometryShader: emitGsInit(); break;
+ case DxbcProgramType::PixelShader: emitPsInit(); break;
+ case DxbcProgramType::ComputeShader: emitCsInit(); break;
+ }
+ }
+
+
+ void DxbcCompiler::emitFunctionBegin(
+ uint32_t entryPoint,
+ uint32_t returnType,
+ uint32_t funcType) {
+ this->emitFunctionEnd();
+
+ m_module.functionBegin(
+ returnType, entryPoint, funcType,
+ spv::FunctionControlMaskNone);
+
+ m_insideFunction = true;
+ }
+
+
+ void DxbcCompiler::emitFunctionEnd() {
+ if (m_insideFunction) {
+ m_module.opReturn();
+ m_module.functionEnd();
+ }
+
+ m_insideFunction = false;
+ }
+
+
+ void DxbcCompiler::emitFunctionLabel() {
+ m_module.opLabel(m_module.allocateId());
+ }
+
+
+ void DxbcCompiler::emitMainFunctionBegin() {
+ this->emitFunctionBegin(
+ m_entryPointId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxbcCompiler::emitVsInit() {
+ m_module.enableCapability(spv::CapabilityClipDistance);
+ m_module.enableCapability(spv::CapabilityCullDistance);
+ m_module.enableCapability(spv::CapabilityDrawParameters);
+
+ // Declare the per-vertex output block. This is where
+ // the vertex shader will write the vertex position.
+ const uint32_t perVertexStruct = this->getPerVertexBlockId();
+ const uint32_t perVertexPointer = m_module.defPointerType(
+ perVertexStruct, spv::StorageClassOutput);
+
+ m_perVertexOut = m_module.newVar(
+ perVertexPointer, spv::StorageClassOutput);
+ m_entryPointInterfaces.push_back(m_perVertexOut);
+ m_module.setDebugName(m_perVertexOut, "vs_vertex_out");
+
+ // Standard input array
+ emitDclInputArray(0);
+
+ // Cull/clip distances as outputs
+ m_clipDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numClipPlanes,
+ spv::BuiltInClipDistance,
+ spv::StorageClassOutput);
+
+ m_cullDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numCullPlanes,
+ spv::BuiltInCullDistance,
+ spv::StorageClassOutput);
+
+ // Main function of the vertex shader
+ m_vs.functionId = m_module.allocateId();
+ m_module.setDebugName(m_vs.functionId, "vs_main");
+
+ this->emitFunctionBegin(
+ m_vs.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxbcCompiler::emitHsInit() {
+ m_module.enableCapability(spv::CapabilityTessellation);
+ m_module.enableCapability(spv::CapabilityClipDistance);
+ m_module.enableCapability(spv::CapabilityCullDistance);
+
+ m_hs.builtinInvocationId = emitNewBuiltinVariable(
+ DxbcRegisterInfo {
+ { DxbcScalarType::Uint32, 1, 0 },
+ spv::StorageClassInput },
+ spv::BuiltInInvocationId,
+ "vOutputControlPointId");
+
+ m_hs.builtinTessLevelOuter = emitBuiltinTessLevelOuter(spv::StorageClassOutput);
+ m_hs.builtinTessLevelInner = emitBuiltinTessLevelInner(spv::StorageClassOutput);
+ }
+
+
+ void DxbcCompiler::emitDsInit() {
+ m_module.enableCapability(spv::CapabilityTessellation);
+ m_module.enableCapability(spv::CapabilityClipDistance);
+ m_module.enableCapability(spv::CapabilityCullDistance);
+
+ m_ds.builtinTessLevelOuter = emitBuiltinTessLevelOuter(spv::StorageClassInput);
+ m_ds.builtinTessLevelInner = emitBuiltinTessLevelInner(spv::StorageClassInput);
+
+ // Declare the per-vertex output block
+ const uint32_t perVertexStruct = this->getPerVertexBlockId();
+ const uint32_t perVertexPointer = m_module.defPointerType(
+ perVertexStruct, spv::StorageClassOutput);
+
+ // Cull/clip distances as outputs
+ m_clipDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numClipPlanes,
+ spv::BuiltInClipDistance,
+ spv::StorageClassOutput);
+
+ m_cullDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numCullPlanes,
+ spv::BuiltInCullDistance,
+ spv::StorageClassOutput);
+
+ m_perVertexOut = m_module.newVar(
+ perVertexPointer, spv::StorageClassOutput);
+ m_entryPointInterfaces.push_back(m_perVertexOut);
+ m_module.setDebugName(m_perVertexOut, "ds_vertex_out");
+
+ // Main function of the domain shader
+ m_ds.functionId = m_module.allocateId();
+ m_module.setDebugName(m_ds.functionId, "ds_main");
+
+ this->emitFunctionBegin(
+ m_ds.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxbcCompiler::emitGsInit() {
+ m_module.enableCapability(spv::CapabilityGeometry);
+ m_module.enableCapability(spv::CapabilityClipDistance);
+ m_module.enableCapability(spv::CapabilityCullDistance);
+
+ // Enable capabilities for xfb mode if necessary
+ if (m_moduleInfo.xfb != nullptr) {
+ m_module.enableCapability(spv::CapabilityGeometryStreams);
+ m_module.enableCapability(spv::CapabilityTransformFeedback);
+
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeXfb);
+ }
+
+ // Declare the per-vertex output block. Outputs are not
+ // declared as arrays, instead they will be flushed when
+ // calling EmitVertex.
+ if (!m_moduleInfo.xfb || m_moduleInfo.xfb->rasterizedStream >= 0) {
+ const uint32_t perVertexStruct = this->getPerVertexBlockId();
+ const uint32_t perVertexPointer = m_module.defPointerType(
+ perVertexStruct, spv::StorageClassOutput);
+
+ m_perVertexOut = m_module.newVar(
+ perVertexPointer, spv::StorageClassOutput);
+ m_entryPointInterfaces.push_back(m_perVertexOut);
+ m_module.setDebugName(m_perVertexOut, "gs_vertex_out");
+ }
+
+ // Cull/clip distances as outputs
+ m_clipDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numClipPlanes,
+ spv::BuiltInClipDistance,
+ spv::StorageClassOutput);
+
+ m_cullDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullOut.numCullPlanes,
+ spv::BuiltInCullDistance,
+ spv::StorageClassOutput);
+
+ // Emit Xfb variables if necessary
+ if (m_moduleInfo.xfb != nullptr)
+ emitXfbOutputDeclarations();
+
+ // Main function of the vertex shader
+ m_gs.functionId = m_module.allocateId();
+ m_module.setDebugName(m_gs.functionId, "gs_main");
+
+ this->emitFunctionBegin(
+ m_gs.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxbcCompiler::emitPsInit() {
+ m_module.enableCapability(spv::CapabilityDerivativeControl);
+
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeOriginUpperLeft);
+
+ // Standard input array
+ emitDclInputArray(0);
+
+ // Cull/clip distances as inputs
+ m_clipDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullIn.numClipPlanes,
+ spv::BuiltInClipDistance,
+ spv::StorageClassInput);
+
+ m_cullDistances = emitDclClipCullDistanceArray(
+ m_analysis->clipCullIn.numCullPlanes,
+ spv::BuiltInCullDistance,
+ spv::StorageClassInput);
+
+ // Main function of the pixel shader
+ m_ps.functionId = m_module.allocateId();
+ m_module.setDebugName(m_ps.functionId, "ps_main");
+
+ this->emitFunctionBegin(
+ m_ps.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+
+ if (m_analysis->usesKill && m_moduleInfo.options.useDemoteToHelperInvocation) {
+ // This extension basically implements D3D-style discard
+ m_module.enableExtension("SPV_EXT_demote_to_helper_invocation");
+ m_module.enableCapability(spv::CapabilityDemoteToHelperInvocationEXT);
+ } else if (m_analysis->usesKill && m_analysis->usesDerivatives) {
+ // We may have to defer kill operations to the end of
+ // the shader in order to keep derivatives correct.
+ m_ps.killState = m_module.newVarInit(
+ m_module.defPointerType(m_module.defBoolType(), spv::StorageClassPrivate),
+ spv::StorageClassPrivate, m_module.constBool(false));
+
+ m_module.setDebugName(m_ps.killState, "ps_kill");
+
+ if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) {
+ m_module.enableCapability(spv::CapabilityGroupNonUniform);
+ m_module.enableCapability(spv::CapabilityGroupNonUniformBallot);
+
+ DxbcRegisterInfo laneId;
+ laneId.type = { DxbcScalarType::Uint32, 1, 0 };
+ laneId.sclass = spv::StorageClassInput;
+
+ m_ps.builtinLaneId = emitNewBuiltinVariable(
+ laneId, spv::BuiltInSubgroupLocalInvocationId,
+ "fLaneId");
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitCsInit() {
+ // Main function of the compute shader
+ m_cs.functionId = m_module.allocateId();
+ m_module.setDebugName(m_cs.functionId, "cs_main");
+
+ this->emitFunctionBegin(
+ m_cs.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxbcCompiler::emitVsFinalize() {
+ this->emitMainFunctionBegin();
+ this->emitInputSetup();
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_vs.functionId, 0, nullptr);
+ this->emitOutputSetup();
+ this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances);
+ this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances);
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitHsFinalize() {
+ if (m_hs.cpPhase.functionId == 0)
+ m_hs.cpPhase = this->emitNewHullShaderPassthroughPhase();
+
+ // Control point phase
+ this->emitMainFunctionBegin();
+ this->emitInputSetup(m_hs.vertexCountIn);
+ this->emitHsControlPointPhase(m_hs.cpPhase);
+ this->emitHsPhaseBarrier();
+
+ // Fork-join phases and output setup
+ this->emitHsInvocationBlockBegin(1);
+
+ for (const auto& phase : m_hs.forkPhases)
+ this->emitHsForkJoinPhase(phase);
+
+ for (const auto& phase : m_hs.joinPhases)
+ this->emitHsForkJoinPhase(phase);
+
+ this->emitOutputSetup();
+ this->emitHsOutputSetup();
+ this->emitHsInvocationBlockEnd();
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitDsFinalize() {
+ this->emitMainFunctionBegin();
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_ds.functionId, 0, nullptr);
+ this->emitOutputSetup();
+ this->emitClipCullStore(DxbcSystemValue::ClipDistance, m_clipDistances);
+ this->emitClipCullStore(DxbcSystemValue::CullDistance, m_cullDistances);
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitGsFinalize() {
+ if (!m_gs.invocationCount)
+ m_module.setInvocations(m_entryPointId, 1);
+
+ this->emitMainFunctionBegin();
+ this->emitInputSetup(
+ primitiveVertexCount(m_gs.inputPrimitive));
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_gs.functionId, 0, nullptr);
+ // No output setup at this point as that was
+ // already done during the EmitVertex step
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitPsFinalize() {
+ this->emitMainFunctionBegin();
+ this->emitInputSetup();
+ this->emitClipCullLoad(DxbcSystemValue::ClipDistance, m_clipDistances);
+ this->emitClipCullLoad(DxbcSystemValue::CullDistance, m_cullDistances);
+
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_ps.functionId, 0, nullptr);
+
+ if (m_ps.killState != 0) {
+ DxbcConditional cond;
+ cond.labelIf = m_module.allocateId();
+ cond.labelEnd = m_module.allocateId();
+
+ uint32_t killTest = m_module.opLoad(m_module.defBoolType(), m_ps.killState);
+
+ m_module.opSelectionMerge(cond.labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(killTest, cond.labelIf, cond.labelEnd);
+
+ m_module.opLabel(cond.labelIf);
+ m_module.opKill();
+
+ m_module.opLabel(cond.labelEnd);
+ }
+
+ this->emitOutputSetup();
+ this->emitOutputMapping();
+
+ if (m_moduleInfo.options.useDepthClipWorkaround)
+ this->emitOutputDepthClamp();
+
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitCsFinalize() {
+ this->emitMainFunctionBegin();
+
+ if (m_moduleInfo.options.zeroInitWorkgroupMemory)
+ this->emitInitWorkgroupMemory();
+
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_cs.functionId, 0, nullptr);
+
+ this->emitFunctionEnd();
+ }
+
+
+ void DxbcCompiler::emitXfbOutputDeclarations() {
+ for (uint32_t i = 0; i < m_moduleInfo.xfb->entryCount; i++) {
+ const DxbcXfbEntry* xfbEntry = m_moduleInfo.xfb->entries + i;
+ const DxbcSgnEntry* sigEntry = m_osgn->find(
+ xfbEntry->semanticName,
+ xfbEntry->semanticIndex,
+ xfbEntry->streamId);
+
+ if (sigEntry == nullptr)
+ continue;
+
+ DxbcRegisterInfo varInfo;
+ varInfo.type.ctype = DxbcScalarType::Float32;
+ varInfo.type.ccount = xfbEntry->componentCount;
+ varInfo.type.alength = 0;
+ varInfo.sclass = spv::StorageClassOutput;
+
+ uint32_t dstComponentMask = (1 << xfbEntry->componentCount) - 1;
+ uint32_t srcComponentMask = dstComponentMask
+ << sigEntry->componentMask.firstSet()
+ << xfbEntry->componentIndex;
+
+ DxbcXfbVar xfbVar;
+ xfbVar.varId = emitNewVariable(varInfo);
+ xfbVar.streamId = xfbEntry->streamId;
+ xfbVar.outputId = sigEntry->registerId;
+ xfbVar.srcMask = DxbcRegMask(srcComponentMask);
+ xfbVar.dstMask = DxbcRegMask(dstComponentMask);
+ m_xfbVars.push_back(xfbVar);
+
+ m_entryPointInterfaces.push_back(xfbVar.varId);
+ m_module.setDebugName(xfbVar.varId,
+ str::format("xfb", i).c_str());
+
+ m_module.decorateXfb(xfbVar.varId,
+ xfbEntry->streamId, xfbEntry->bufferId, xfbEntry->offset,
+ m_moduleInfo.xfb->strides[xfbEntry->bufferId]);
+ }
+
+ // TODO Compact location/component assignment
+ for (uint32_t i = 0; i < m_xfbVars.size(); i++) {
+ m_xfbVars[i].location = i;
+ m_xfbVars[i].component = 0;
+ }
+
+ for (uint32_t i = 0; i < m_xfbVars.size(); i++) {
+ const DxbcXfbVar* var = &m_xfbVars[i];
+
+ m_module.decorateLocation (var->varId, var->location);
+ m_module.decorateComponent(var->varId, var->component);
+ }
+ }
+
+
+ void DxbcCompiler::emitXfbOutputSetup(
+ uint32_t streamId,
+ bool passthrough) {
+ for (size_t i = 0; i < m_xfbVars.size(); i++) {
+ if (m_xfbVars[i].streamId == streamId) {
+ DxbcRegisterPointer srcPtr = passthrough
+ ? m_vRegs[m_xfbVars[i].outputId]
+ : m_oRegs[m_xfbVars[i].outputId];
+
+ if (passthrough) {
+ srcPtr = emitArrayAccess(srcPtr,
+ spv::StorageClassInput,
+ m_module.constu32(0));
+ }
+
+ DxbcRegisterPointer dstPtr;
+ dstPtr.type.ctype = DxbcScalarType::Float32;
+ dstPtr.type.ccount = m_xfbVars[i].dstMask.popCount();
+ dstPtr.id = m_xfbVars[i].varId;
+
+ DxbcRegisterValue value = emitRegisterExtract(
+ emitValueLoad(srcPtr), m_xfbVars[i].srcMask);
+ emitValueStore(dstPtr, value, m_xfbVars[i].dstMask);
+ }
+ }
+ }
+
+
+ void DxbcCompiler::emitHsControlPointPhase(
+ const DxbcCompilerHsControlPointPhase& phase) {
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ phase.functionId, 0, nullptr);
+ }
+
+
+ void DxbcCompiler::emitHsForkJoinPhase(
+ const DxbcCompilerHsForkJoinPhase& phase) {
+ for (uint32_t i = 0; i < phase.instanceCount; i++) {
+ uint32_t invocationId = m_module.constu32(i);
+
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ phase.functionId, 1,
+ &invocationId);
+ }
+ }
+
+
+ void DxbcCompiler::emitDclInputArray(uint32_t vertexCount) {
+ DxbcVectorType info;
+ info.ctype = DxbcScalarType::Float32;
+ info.ccount = 4;
+
+ // Define the array type. This will be two-dimensional
+ // in some shaders, with the outer index representing
+ // the vertex ID within an invocation.
+ m_vArrayLength = m_isgn != nullptr ? std::max(1u, m_isgn->maxRegisterCount()) : 1;
+ m_vArrayLengthId = m_module.lateConst32(getScalarTypeId(DxbcScalarType::Uint32));
+
+ uint32_t vectorTypeId = getVectorTypeId(info);
+ uint32_t arrayTypeId = m_module.defArrayType(vectorTypeId, m_vArrayLengthId);
+
+ if (vertexCount != 0) {
+ arrayTypeId = m_module.defArrayType(
+ arrayTypeId, m_module.constu32(vertexCount));
+ }
+
+ // Define the actual variable. Note that this is private
+ // because we will copy input registers and some system
+ // variables to the array during the setup phase.
+ const uint32_t ptrTypeId = m_module.defPointerType(
+ arrayTypeId, spv::StorageClassPrivate);
+
+ const uint32_t varId = m_module.newVar(
+ ptrTypeId, spv::StorageClassPrivate);
+
+ m_module.setDebugName(varId, "shader_in");
+ m_vArray = varId;
+ }
+
+
+ void DxbcCompiler::emitDclInputPerVertex(
+ uint32_t vertexCount,
+ const char* varName) {
+ uint32_t typeId = getPerVertexBlockId();
+
+ if (vertexCount != 0) {
+ typeId = m_module.defArrayType(typeId,
+ m_module.constu32(vertexCount));
+ }
+
+ const uint32_t ptrTypeId = m_module.defPointerType(
+ typeId, spv::StorageClassInput);
+
+ m_perVertexIn = m_module.newVar(
+ ptrTypeId, spv::StorageClassInput);
+ m_module.setDebugName(m_perVertexIn, varName);
+
+ m_entryPointInterfaces.push_back(m_perVertexIn);
+ }
+
+
+ uint32_t DxbcCompiler::emitDclClipCullDistanceArray(
+ uint32_t length,
+ spv::BuiltIn builtIn,
+ spv::StorageClass storageClass) {
+ if (length == 0)
+ return 0;
+
+ uint32_t t_f32 = m_module.defFloatType(32);
+ uint32_t t_arr = m_module.defArrayType(t_f32, m_module.constu32(length));
+ uint32_t t_ptr = m_module.defPointerType(t_arr, storageClass);
+ uint32_t varId = m_module.newVar(t_ptr, storageClass);
+
+ m_module.decorateBuiltIn(varId, builtIn);
+ m_module.setDebugName(varId,
+ builtIn == spv::BuiltInClipDistance
+ ? "clip_distances"
+ : "cull_distances");
+
+ m_entryPointInterfaces.push_back(varId);
+ return varId;
+ }
+
+
+ DxbcCompilerHsControlPointPhase DxbcCompiler::emitNewHullShaderControlPointPhase() {
+ uint32_t funTypeId = m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr);
+
+ uint32_t funId = m_module.allocateId();
+
+ this->emitFunctionBegin(funId,
+ m_module.defVoidType(),
+ funTypeId);
+ this->emitFunctionLabel();
+
+ DxbcCompilerHsControlPointPhase result;
+ result.functionId = funId;
+ return result;
+ }
+
+
+ DxbcCompilerHsControlPointPhase DxbcCompiler::emitNewHullShaderPassthroughPhase() {
+ uint32_t funTypeId = m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr);
+
+ // Begin passthrough function
+ uint32_t funId = m_module.allocateId();
+ m_module.setDebugName(funId, "hs_passthrough");
+
+ this->emitFunctionBegin(funId,
+ m_module.defVoidType(),
+ funTypeId);
+ this->emitFunctionLabel();
+
+ // We'll basically copy each input variable to the corresponding
+ // output, using the shader's invocation ID as the array index.
+ const uint32_t invocationId = m_module.opLoad(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ m_hs.builtinInvocationId);
+
+ for (auto i = m_isgn->begin(); i != m_isgn->end(); i++) {
+ this->emitDclInput(
+ i->registerId, m_hs.vertexCountIn,
+ i->componentMask,
+ DxbcSystemValue::None,
+ DxbcInterpolationMode::Undefined);
+
+ // Vector type index
+ const std::array<uint32_t, 2> dstIndices
+ = {{ invocationId, m_module.constu32(i->registerId) }};
+
+ DxbcRegisterPointer srcPtr;
+ srcPtr.type = m_vRegs.at(i->registerId).type;
+ srcPtr.id = m_module.opAccessChain(
+ m_module.defPointerType(getVectorTypeId(srcPtr.type), spv::StorageClassInput),
+ m_vRegs.at(i->registerId).id, 1, &invocationId);
+
+ DxbcRegisterValue srcValue = emitRegisterBitcast(
+ emitValueLoad(srcPtr), DxbcScalarType::Float32);
+
+ DxbcRegisterPointer dstPtr;
+ dstPtr.type = { DxbcScalarType::Float32, 4 };
+ dstPtr.id = m_module.opAccessChain(
+ m_module.defPointerType(getVectorTypeId(dstPtr.type), spv::StorageClassOutput),
+ m_hs.outputPerVertex, dstIndices.size(), dstIndices.data());
+
+ emitValueStore(dstPtr, srcValue, DxbcRegMask::firstN(srcValue.type.ccount));
+ }
+
+ // End function
+ this->emitFunctionEnd();
+
+ DxbcCompilerHsControlPointPhase result;
+ result.functionId = funId;
+ return result;
+ }
+
+
+ DxbcCompilerHsForkJoinPhase DxbcCompiler::emitNewHullShaderForkJoinPhase() {
+ uint32_t argTypeId = m_module.defIntType(32, 0);
+ uint32_t funTypeId = m_module.defFunctionType(
+ m_module.defVoidType(), 1, &argTypeId);
+
+ uint32_t funId = m_module.allocateId();
+
+ this->emitFunctionBegin(funId,
+ m_module.defVoidType(),
+ funTypeId);
+
+ uint32_t argId = m_module.functionParameter(argTypeId);
+ this->emitFunctionLabel();
+
+ DxbcCompilerHsForkJoinPhase result;
+ result.functionId = funId;
+ result.instanceId = argId;
+ return result;
+ }
+
+
+ void DxbcCompiler::emitHsPhaseBarrier() {
+ uint32_t exeScopeId = m_module.constu32(spv::ScopeWorkgroup);
+ uint32_t memScopeId = m_module.constu32(spv::ScopeInvocation);
+ uint32_t semanticId = m_module.constu32(spv::MemorySemanticsMaskNone);
+
+ m_module.opControlBarrier(exeScopeId, memScopeId, semanticId);
+ }
+
+
+ void DxbcCompiler::emitHsInvocationBlockBegin(uint32_t count) {
+ uint32_t invocationId = m_module.opLoad(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ m_hs.builtinInvocationId);
+
+ uint32_t condition = m_module.opULessThan(
+ m_module.defBoolType(), invocationId,
+ m_module.constu32(count));
+
+ m_hs.invocationBlockBegin = m_module.allocateId();
+ m_hs.invocationBlockEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(
+ m_hs.invocationBlockEnd,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ condition,
+ m_hs.invocationBlockBegin,
+ m_hs.invocationBlockEnd);
+
+ m_module.opLabel(
+ m_hs.invocationBlockBegin);
+ }
+
+
+ void DxbcCompiler::emitHsInvocationBlockEnd() {
+ m_module.opBranch (m_hs.invocationBlockEnd);
+ m_module.opLabel (m_hs.invocationBlockEnd);
+
+ m_hs.invocationBlockBegin = 0;
+ m_hs.invocationBlockEnd = 0;
+ }
+
+
+ void DxbcCompiler::emitHsOutputSetup() {
+ uint32_t outputPerPatch = emitTessInterfacePerPatch(spv::StorageClassOutput);
+
+ if (!outputPerPatch)
+ return;
+
+ uint32_t vecType = getVectorTypeId({ DxbcScalarType::Float32, 4 });
+
+ uint32_t srcPtrType = m_module.defPointerType(vecType, spv::StorageClassPrivate);
+ uint32_t dstPtrType = m_module.defPointerType(vecType, spv::StorageClassOutput);
+
+ for (uint32_t i = 0; i < 32; i++) {
+ if (m_hs.outputPerPatchMask & (1 << i)) {
+ uint32_t index = m_module.constu32(i);
+
+ uint32_t srcPtr = m_module.opAccessChain(srcPtrType, m_hs.outputPerPatch, 1, &index);
+ uint32_t dstPtr = m_module.opAccessChain(dstPtrType, outputPerPatch, 1, &index);
+
+ m_module.opStore(dstPtr, m_module.opLoad(vecType, srcPtr));
+ }
+ }
+ }
+
+
+ uint32_t DxbcCompiler::emitTessInterfacePerPatch(spv::StorageClass storageClass) {
+ const char* name = "vPatch";
+
+ if (storageClass == spv::StorageClassPrivate)
+ name = "rPatch";
+ if (storageClass == spv::StorageClassOutput)
+ name = "oPatch";
+
+ uint32_t arrLen = m_psgn != nullptr ? m_psgn->maxRegisterCount() : 0;
+
+ if (!arrLen)
+ return 0;
+
+ uint32_t vecType = m_module.defVectorType (m_module.defFloatType(32), 4);
+ uint32_t arrType = m_module.defArrayType (vecType, m_module.constu32(arrLen));
+ uint32_t ptrType = m_module.defPointerType(arrType, storageClass);
+ uint32_t varId = m_module.newVar (ptrType, storageClass);
+
+ m_module.setDebugName (varId, name);
+
+ if (storageClass != spv::StorageClassPrivate) {
+ m_module.decorate (varId, spv::DecorationPatch);
+ m_module.decorateLocation (varId, 0);
+
+ m_entryPointInterfaces.push_back(varId);
+ }
+
+ return varId;
+ }
+
+
+ uint32_t DxbcCompiler::emitTessInterfacePerVertex(spv::StorageClass storageClass, uint32_t vertexCount) {
+ const bool isInput = storageClass == spv::StorageClassInput;
+
+ uint32_t arrLen = isInput
+ ? (m_isgn != nullptr ? m_isgn->maxRegisterCount() : 0)
+ : (m_osgn != nullptr ? m_osgn->maxRegisterCount() : 0);
+
+ if (!arrLen)
+ return 0;
+
+ uint32_t locIdx = m_psgn != nullptr
+ ? m_psgn->maxRegisterCount()
+ : 0;
+
+ uint32_t vecType = m_module.defVectorType (m_module.defFloatType(32), 4);
+ uint32_t arrTypeInner = m_module.defArrayType (vecType, m_module.constu32(arrLen));
+ uint32_t arrTypeOuter = m_module.defArrayType (arrTypeInner, m_module.constu32(vertexCount));
+ uint32_t ptrType = m_module.defPointerType(arrTypeOuter, storageClass);
+ uint32_t varId = m_module.newVar (ptrType, storageClass);
+
+ m_module.setDebugName (varId, isInput ? "vVertex" : "oVertex");
+ m_module.decorateLocation (varId, locIdx);
+
+ if (storageClass != spv::StorageClassPrivate)
+ m_entryPointInterfaces.push_back(varId);
+ return varId;
+ }
+
+
+ uint32_t DxbcCompiler::emitSamplePosArray() {
+ const std::array<uint32_t, 32> samplePosVectors = {{
+ // Invalid sample count / unbound resource
+ m_module.constvec2f32( 0.0f, 0.0f),
+ // VK_SAMPLE_COUNT_1_BIT
+ m_module.constvec2f32( 0.0f, 0.0f),
+ // VK_SAMPLE_COUNT_2_BIT
+ m_module.constvec2f32( 0.25f, 0.25f),
+ m_module.constvec2f32(-0.25f,-0.25f),
+ // VK_SAMPLE_COUNT_4_BIT
+ m_module.constvec2f32(-0.125f,-0.375f),
+ m_module.constvec2f32( 0.375f,-0.125f),
+ m_module.constvec2f32(-0.375f, 0.125f),
+ m_module.constvec2f32( 0.125f, 0.375f),
+ // VK_SAMPLE_COUNT_8_BIT
+ m_module.constvec2f32( 0.0625f,-0.1875f),
+ m_module.constvec2f32(-0.0625f, 0.1875f),
+ m_module.constvec2f32( 0.3125f, 0.0625f),
+ m_module.constvec2f32(-0.1875f,-0.3125f),
+ m_module.constvec2f32(-0.3125f, 0.3125f),
+ m_module.constvec2f32(-0.4375f,-0.0625f),
+ m_module.constvec2f32( 0.1875f, 0.4375f),
+ m_module.constvec2f32( 0.4375f,-0.4375f),
+ // VK_SAMPLE_COUNT_16_BIT
+ m_module.constvec2f32( 0.0625f, 0.0625f),
+ m_module.constvec2f32(-0.0625f,-0.1875f),
+ m_module.constvec2f32(-0.1875f, 0.1250f),
+ m_module.constvec2f32( 0.2500f,-0.0625f),
+ m_module.constvec2f32(-0.3125f,-0.1250f),
+ m_module.constvec2f32( 0.1250f, 0.3125f),
+ m_module.constvec2f32( 0.3125f, 0.1875f),
+ m_module.constvec2f32( 0.1875f,-0.3125f),
+ m_module.constvec2f32(-0.1250f, 0.3750f),
+ m_module.constvec2f32( 0.0000f,-0.4375f),
+ m_module.constvec2f32(-0.2500f,-0.3750f),
+ m_module.constvec2f32(-0.3750f, 0.2500f),
+ m_module.constvec2f32(-0.5000f, 0.0000f),
+ m_module.constvec2f32( 0.4375f,-0.2500f),
+ m_module.constvec2f32( 0.3750f, 0.4375f),
+ m_module.constvec2f32(-0.4375f,-0.5000f),
+ }};
+
+ uint32_t arrayTypeId = getArrayTypeId({
+ DxbcScalarType::Float32, 2,
+ static_cast<uint32_t>(samplePosVectors.size()) });
+
+ uint32_t samplePosArray = m_module.constComposite(
+ arrayTypeId,
+ samplePosVectors.size(),
+ samplePosVectors.data());
+
+ uint32_t varId = m_module.newVarInit(
+ m_module.defPointerType(arrayTypeId, spv::StorageClassPrivate),
+ spv::StorageClassPrivate, samplePosArray);
+
+ m_module.setDebugName(varId, "g_sample_pos");
+ return varId;
+ }
+
+
+ void DxbcCompiler::emitFloatControl() {
+ DxbcFloatControlFlags flags = m_moduleInfo.options.floatControl;
+
+ if (flags.isClear())
+ return;
+
+ const uint32_t width32 = 32;
+ const uint32_t width64 = 64;
+
+ m_module.enableExtension("SPV_KHR_float_controls");
+
+ if (flags.test(DxbcFloatControlFlag::DenormFlushToZero32)) {
+ m_module.enableCapability(spv::CapabilityDenormFlushToZero);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDenormFlushToZero, 1, &width32);
+ }
+
+ if (flags.test(DxbcFloatControlFlag::PreserveNan32)) {
+ m_module.enableCapability(spv::CapabilitySignedZeroInfNanPreserve);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeSignedZeroInfNanPreserve, 1, &width32);
+ }
+
+ if (m_module.hasCapability(spv::CapabilityFloat64)) {
+ if (flags.test(DxbcFloatControlFlag::DenormPreserve64)) {
+ m_module.enableCapability(spv::CapabilityDenormPreserve);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeDenormPreserve, 1, &width64);
+ }
+
+ if (flags.test(DxbcFloatControlFlag::PreserveNan64)) {
+ m_module.enableCapability(spv::CapabilitySignedZeroInfNanPreserve);
+ m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeSignedZeroInfNanPreserve, 1, &width64);
+ }
+ }
+ }
+
+
+ uint32_t DxbcCompiler::emitNewVariable(const DxbcRegisterInfo& info) {
+ const uint32_t ptrTypeId = this->getPointerTypeId(info);
+ return m_module.newVar(ptrTypeId, info.sclass);
+ }
+
+
+ uint32_t DxbcCompiler::emitNewBuiltinVariable(
+ const DxbcRegisterInfo& info,
+ spv::BuiltIn builtIn,
+ const char* name) {
+ const uint32_t varId = emitNewVariable(info);
+
+ m_module.setDebugName(varId, name);
+ m_module.decorateBuiltIn(varId, builtIn);
+
+ if (m_programInfo.type() == DxbcProgramType::PixelShader
+ && info.type.ctype != DxbcScalarType::Float32
+ && info.type.ctype != DxbcScalarType::Bool
+ && info.sclass == spv::StorageClassInput)
+ m_module.decorate(varId, spv::DecorationFlat);
+
+ m_entryPointInterfaces.push_back(varId);
+ return varId;
+ }
+
+
+ uint32_t DxbcCompiler::emitBuiltinTessLevelOuter(spv::StorageClass storageClass) {
+ uint32_t id = emitNewBuiltinVariable(
+ DxbcRegisterInfo {
+ { DxbcScalarType::Float32, 0, 4 },
+ storageClass },
+ spv::BuiltInTessLevelOuter,
+ "bTessLevelOuter");
+
+ m_module.decorate(id, spv::DecorationPatch);
+ return id;
+ }
+
+
+ uint32_t DxbcCompiler::emitBuiltinTessLevelInner(spv::StorageClass storageClass) {
+ uint32_t id = emitNewBuiltinVariable(
+ DxbcRegisterInfo {
+ { DxbcScalarType::Float32, 0, 2 },
+ storageClass },
+ spv::BuiltInTessLevelInner,
+ "bTessLevelInner");
+
+ m_module.decorate(id, spv::DecorationPatch);
+ return id;
+ }
+
+
+ void DxbcCompiler::enableShaderViewportIndexLayer() {
+ if (!m_extensions.shaderViewportIndexLayer) {
+ m_extensions.shaderViewportIndexLayer = true;
+
+ m_module.enableExtension("SPV_EXT_shader_viewport_index_layer");
+ m_module.enableCapability(spv::CapabilityShaderViewportIndexLayerEXT);
+ }
+ }
+
+
+ DxbcCfgBlock* DxbcCompiler::cfgFindBlock(
+ const std::initializer_list<DxbcCfgBlockType>& types) {
+ for (auto cur = m_controlFlowBlocks.rbegin();
+ cur != m_controlFlowBlocks.rend(); cur++) {
+ for (auto type : types) {
+ if (cur->type == type)
+ return &(*cur);
+ }
+ }
+
+ return nullptr;
+ }
+
+
+ DxbcBufferInfo DxbcCompiler::getBufferInfo(const DxbcRegister& reg) {
+ const uint32_t registerId = reg.idx[0].offset;
+
+ switch (reg.type) {
+ case DxbcOperandType::Resource: {
+ const auto& texture = m_textures.at(registerId);
+
+ DxbcBufferInfo result;
+ result.image = texture.imageInfo;
+ result.stype = texture.sampledType;
+ result.type = texture.type;
+ result.typeId = texture.imageTypeId;
+ result.varId = texture.varId;
+ result.specId = texture.specId;
+ result.stride = texture.structStride;
+ result.align = texture.structAlign;
+ return result;
+ } break;
+
+ case DxbcOperandType::UnorderedAccessView: {
+ const auto& uav = m_uavs.at(registerId);
+
+ DxbcBufferInfo result;
+ result.image = uav.imageInfo;
+ result.stype = uav.sampledType;
+ result.type = uav.type;
+ result.typeId = uav.imageTypeId;
+ result.varId = uav.varId;
+ result.specId = uav.specId;
+ result.stride = uav.structStride;
+ result.align = uav.structAlign;
+ return result;
+ } break;
+
+ case DxbcOperandType::ThreadGroupSharedMemory: {
+ DxbcBufferInfo result;
+ result.image = { spv::DimBuffer, 0, 0, 0 };
+ result.stype = DxbcScalarType::Uint32;
+ result.type = m_gRegs.at(registerId).type;
+ result.typeId = m_module.defPointerType(
+ getScalarTypeId(DxbcScalarType::Uint32),
+ spv::StorageClassWorkgroup);
+ result.varId = m_gRegs.at(registerId).varId;
+ result.specId = 0;
+ result.stride = m_gRegs.at(registerId).elementStride;
+ result.align = 0;
+ return result;
+ } break;
+
+ default:
+ throw DxvkError(str::format("DxbcCompiler: Invalid operand type for buffer: ", reg.type));
+ }
+ }
+
+
+ uint32_t DxbcCompiler::getTexSizeDim(const DxbcImageInfo& imageType) const {
+ switch (imageType.dim) {
+ case spv::DimBuffer: return 1 + imageType.array;
+ case spv::Dim1D: return 1 + imageType.array;
+ case spv::Dim2D: return 2 + imageType.array;
+ case spv::Dim3D: return 3 + imageType.array;
+ case spv::DimCube: return 2 + imageType.array;
+ default: throw DxvkError("DxbcCompiler: getTexLayerDim: Unsupported image dimension");
+ }
+ }
+
+
+ uint32_t DxbcCompiler::getTexLayerDim(const DxbcImageInfo& imageType) const {
+ switch (imageType.dim) {
+ case spv::DimBuffer: return 1;
+ case spv::Dim1D: return 1;
+ case spv::Dim2D: return 2;
+ case spv::Dim3D: return 3;
+ case spv::DimCube: return 3;
+ default: throw DxvkError("DxbcCompiler: getTexLayerDim: Unsupported image dimension");
+ }
+ }
+
+
+ uint32_t DxbcCompiler::getTexCoordDim(const DxbcImageInfo& imageType) const {
+ return getTexLayerDim(imageType) + imageType.array;
+ }
+
+
+ DxbcRegMask DxbcCompiler::getTexCoordMask(const DxbcImageInfo& imageType) const {
+ return DxbcRegMask::firstN(getTexCoordDim(imageType));
+ }
+
+
+ DxbcVectorType DxbcCompiler::getInputRegType(uint32_t regIdx) const {
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::VertexShader: {
+ const DxbcSgnEntry* entry = m_isgn->findByRegister(regIdx);
+
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+
+ if (entry != nullptr) {
+ result.ctype = entry->componentType;
+ result.ccount = entry->componentMask.popCount();
+ }
+
+ return result;
+ }
+
+ case DxbcProgramType::DomainShader: {
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+ return result;
+ }
+
+ default: {
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+
+ if (m_isgn->findByRegister(regIdx))
+ result.ccount = m_isgn->regMask(regIdx).minComponents();
+ return result;
+ }
+ }
+ }
+
+
+ DxbcVectorType DxbcCompiler::getOutputRegType(uint32_t regIdx) const {
+ switch (m_programInfo.type()) {
+ case DxbcProgramType::PixelShader: {
+ const DxbcSgnEntry* entry = m_osgn->findByRegister(regIdx);
+
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+
+ if (entry != nullptr) {
+ result.ctype = entry->componentType;
+ result.ccount = entry->componentMask.popCount();
+ }
+
+ return result;
+ }
+
+ case DxbcProgramType::HullShader: {
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+ return result;
+ }
+
+ default: {
+ DxbcVectorType result;
+ result.ctype = DxbcScalarType::Float32;
+ result.ccount = 4;
+
+ if (m_osgn->findByRegister(regIdx))
+ result.ccount = m_osgn->regMask(regIdx).minComponents();
+ return result;
+ }
+ }
+ }
+
+
+ DxbcImageInfo DxbcCompiler::getResourceType(
+ DxbcResourceDim resourceType,
+ bool isUav) const {
+ uint32_t ms = m_moduleInfo.options.disableMsaa ? 0 : 1;
+
+ DxbcImageInfo typeInfo = [resourceType, isUav, ms] () -> DxbcImageInfo {
+ switch (resourceType) {
+ case DxbcResourceDim::Buffer: return { spv::DimBuffer, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_MAX_ENUM };
+ case DxbcResourceDim::Texture1D: return { spv::Dim1D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_1D };
+ case DxbcResourceDim::Texture1DArr: return { spv::Dim1D, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_1D_ARRAY };
+ case DxbcResourceDim::Texture2D: return { spv::Dim2D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D };
+ case DxbcResourceDim::Texture2DArr: return { spv::Dim2D, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
+ case DxbcResourceDim::Texture2DMs: return { spv::Dim2D, 0, ms,isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D };
+ case DxbcResourceDim::Texture2DMsArr: return { spv::Dim2D, 1, ms,isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_2D_ARRAY };
+ case DxbcResourceDim::Texture3D: return { spv::Dim3D, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_3D };
+ case DxbcResourceDim::TextureCube: return { spv::DimCube, 0, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_CUBE };
+ case DxbcResourceDim::TextureCubeArr: return { spv::DimCube, 1, 0, isUav ? 2u : 1u, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY };
+ default: throw DxvkError(str::format("DxbcCompiler: Unsupported resource type: ", resourceType));
+ }
+ }();
+
+ return typeInfo;
+ }
+
+
+ spv::ImageFormat DxbcCompiler::getScalarImageFormat(DxbcScalarType type) const {
+ switch (type) {
+ case DxbcScalarType::Float32: return spv::ImageFormatR32f;
+ case DxbcScalarType::Sint32: return spv::ImageFormatR32i;
+ case DxbcScalarType::Uint32: return spv::ImageFormatR32ui;
+ default: throw DxvkError("DxbcCompiler: Unhandled scalar resource type");
+ }
+ }
+
+
+ bool DxbcCompiler::isDoubleType(DxbcScalarType type) const {
+ return type == DxbcScalarType::Sint64
+ || type == DxbcScalarType::Uint64
+ || type == DxbcScalarType::Float64;
+ }
+
+ DxbcRegisterPointer DxbcCompiler::getIndexableTempPtr(
+ const DxbcRegister& operand,
+ DxbcRegisterValue vectorId) {
+ // x# regs are indexed as follows:
+ // (0) register index (immediate)
+ // (1) element index (relative)
+ const uint32_t regId = operand.idx[0].offset;
+
+ DxbcRegisterInfo info;
+ info.type.ctype = DxbcScalarType::Float32;
+ info.type.ccount = m_xRegs[regId].ccount;
+ info.type.alength = 0;
+ info.sclass = spv::StorageClassPrivate;
+
+ DxbcRegisterPointer result;
+ result.type.ctype = info.type.ctype;
+ result.type.ccount = info.type.ccount;
+ result.id = m_module.opAccessChain(
+ getPointerTypeId(info),
+ m_xRegs.at(regId).varId,
+ 1, &vectorId.id);
+
+ return result;
+ }
+
+ uint32_t DxbcCompiler::getScalarTypeId(DxbcScalarType type) {
+ if (type == DxbcScalarType::Float64)
+ m_module.enableCapability(spv::CapabilityFloat64);
+
+ if (type == DxbcScalarType::Sint64 || type == DxbcScalarType::Uint64)
+ m_module.enableCapability(spv::CapabilityInt64);
+
+ switch (type) {
+ case DxbcScalarType::Uint32: return m_module.defIntType(32, 0);
+ case DxbcScalarType::Uint64: return m_module.defIntType(64, 0);
+ case DxbcScalarType::Sint32: return m_module.defIntType(32, 1);
+ case DxbcScalarType::Sint64: return m_module.defIntType(64, 1);
+ case DxbcScalarType::Float32: return m_module.defFloatType(32);
+ case DxbcScalarType::Float64: return m_module.defFloatType(64);
+ case DxbcScalarType::Bool: return m_module.defBoolType();
+ }
+
+ throw DxvkError("DxbcCompiler: Invalid scalar type");
+ }
+
+
+ uint32_t DxbcCompiler::getVectorTypeId(const DxbcVectorType& type) {
+ uint32_t typeId = this->getScalarTypeId(type.ctype);
+
+ if (type.ccount > 1)
+ typeId = m_module.defVectorType(typeId, type.ccount);
+
+ return typeId;
+ }
+
+
+ uint32_t DxbcCompiler::getArrayTypeId(const DxbcArrayType& type) {
+ DxbcVectorType vtype;
+ vtype.ctype = type.ctype;
+ vtype.ccount = type.ccount;
+
+ uint32_t typeId = this->getVectorTypeId(vtype);
+
+ if (type.alength != 0) {
+ typeId = m_module.defArrayType(typeId,
+ m_module.constu32(type.alength));
+ }
+
+ return typeId;
+ }
+
+
+ uint32_t DxbcCompiler::getPointerTypeId(const DxbcRegisterInfo& type) {
+ return m_module.defPointerType(
+ this->getArrayTypeId(type.type),
+ type.sclass);
+ }
+
+
+ uint32_t DxbcCompiler::getPerVertexBlockId() {
+ uint32_t t_f32 = m_module.defFloatType(32);
+ uint32_t t_f32_v4 = m_module.defVectorType(t_f32, 4);
+// uint32_t t_f32_a4 = m_module.defArrayType(t_f32, m_module.constu32(4));
+
+ std::array<uint32_t, 1> members;
+ members[PerVertex_Position] = t_f32_v4;
+// members[PerVertex_CullDist] = t_f32_a4;
+// members[PerVertex_ClipDist] = t_f32_a4;
+
+ uint32_t typeId = m_module.defStructTypeUnique(
+ members.size(), members.data());
+
+ m_module.memberDecorateBuiltIn(typeId, PerVertex_Position, spv::BuiltInPosition);
+// m_module.memberDecorateBuiltIn(typeId, PerVertex_CullDist, spv::BuiltInCullDistance);
+// m_module.memberDecorateBuiltIn(typeId, PerVertex_ClipDist, spv::BuiltInClipDistance);
+ m_module.decorateBlock(typeId);
+
+ m_module.setDebugName(typeId, "s_per_vertex");
+ m_module.setDebugMemberName(typeId, PerVertex_Position, "position");
+// m_module.setDebugMemberName(typeId, PerVertex_CullDist, "cull_dist");
+// m_module.setDebugMemberName(typeId, PerVertex_ClipDist, "clip_dist");
+ return typeId;
+ }
+
+
+ uint32_t DxbcCompiler::getFunctionId(
+ uint32_t functionNr) {
+ auto entry = m_subroutines.find(functionNr);
+ if (entry != m_subroutines.end())
+ return entry->second;
+
+ uint32_t functionId = m_module.allocateId();
+ m_subroutines.insert({ functionNr, functionId });
+ return functionId;
+ }
+
+
+ DxbcCompilerHsForkJoinPhase* DxbcCompiler::getCurrentHsForkJoinPhase() {
+ switch (m_hs.currPhaseType) {
+ case DxbcCompilerHsPhase::Fork: return &m_hs.forkPhases.at(m_hs.currPhaseId);
+ case DxbcCompilerHsPhase::Join: return &m_hs.joinPhases.at(m_hs.currPhaseId);
+ default: return nullptr;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.h
new file mode 100644
index 00000000..2404642e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_compiler.h
@@ -0,0 +1,1265 @@
+#pragma once
+
+#include <array>
+#include <vector>
+
+#include "../spirv/spirv_module.h"
+
+#include "dxbc_analysis.h"
+#include "dxbc_chunk_isgn.h"
+#include "dxbc_decoder.h"
+#include "dxbc_defs.h"
+#include "dxbc_modinfo.h"
+#include "dxbc_names.h"
+#include "dxbc_util.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Vector type
+ *
+ * Convenience struct that stores a scalar
+ * type and a component count. The compiler
+ * can use this to generate SPIR-V types.
+ */
+ struct DxbcVectorType {
+ DxbcScalarType ctype;
+ uint32_t ccount;
+ };
+
+
+ /**
+ * \brief Array type
+ *
+ * Convenience struct that stores a scalar type, a
+ * component count and an array size. An array of
+ * length 0 will be evaluated to a vector type. The
+ * compiler can use this to generate SPIR-V types.
+ */
+ struct DxbcArrayType {
+ DxbcScalarType ctype;
+ uint32_t ccount;
+ uint32_t alength;
+ };
+
+
+ /**
+ * \brief Register info
+ *
+ * Stores the array type of a register and
+ * its storage class. The compiler can use
+ * this to generate SPIR-V pointer types.
+ */
+ struct DxbcRegisterInfo {
+ DxbcArrayType type;
+ spv::StorageClass sclass;
+ };
+
+
+ /**
+ * \brief Register value
+ *
+ * Stores a vector type and a SPIR-V ID that
+ * represents an intermediate value. This is
+ * used to track the type of such values.
+ */
+ struct DxbcRegisterValue {
+ DxbcVectorType type;
+ uint32_t id;
+ };
+
+
+ /**
+ * \brief Register pointer
+ *
+ * Stores a vector type and a SPIR-V ID that
+ * represents a pointer to such a vector. This
+ * can be used to load registers conveniently.
+ */
+ struct DxbcRegisterPointer {
+ DxbcVectorType type;
+ uint32_t id;
+ };
+
+
+ struct DxbcXreg {
+ uint32_t ccount = 0;
+ uint32_t alength = 0;
+ uint32_t varId = 0;
+ };
+
+
+ struct DxbcGreg {
+ DxbcResourceType type = DxbcResourceType::Raw;
+ uint32_t elementStride = 0;
+ uint32_t elementCount = 0;
+ uint32_t varId = 0;
+ };
+
+
+ /**
+ * \brief Specialization constant properties
+ *
+ * Stores the name, data type and initial
+ * value of a specialization constant.
+ */
+ struct DxbcSpecConstant {
+ DxbcScalarType ctype;
+ uint32_t ccount;
+ uint32_t value;
+ const char* name;
+ };
+
+
+ /**
+ * \brief Helper struct for conditional execution
+ *
+ * Stores a set of labels required to implement either
+ * an if-then block or an if-then-else block. This is
+ * not used to implement control flow instructions.
+ */
+ struct DxbcConditional {
+ uint32_t labelIf = 0;
+ uint32_t labelElse = 0;
+ uint32_t labelEnd = 0;
+ };
+
+
+ struct DxbcXfbVar {
+ uint32_t varId = 0;
+ uint32_t streamId = 0;
+ uint32_t outputId = 0;
+ DxbcRegMask srcMask = 0;
+ DxbcRegMask dstMask = 0;
+ uint32_t location = 0;
+ uint32_t component = 0;
+ };
+
+
+ /**
+ * \brief Vertex shader-specific structure
+ */
+ struct DxbcCompilerVsPart {
+ uint32_t functionId = 0;
+
+ uint32_t builtinVertexId = 0;
+ uint32_t builtinInstanceId = 0;
+ uint32_t builtinBaseVertex = 0;
+ uint32_t builtinBaseInstance = 0;
+ };
+
+
+ /**
+ * \brief Geometry shader-specific structure
+ */
+ struct DxbcCompilerGsPart {
+ DxbcPrimitive inputPrimitive = DxbcPrimitive::Undefined;
+ DxbcPrimitiveTopology outputTopology = DxbcPrimitiveTopology::Undefined;
+ uint32_t outputVertexCount = 0;
+ uint32_t functionId = 0;
+
+ uint32_t builtinLayer = 0;
+ uint32_t builtinViewportId = 0;
+ uint32_t builtinInvocationId = 0;
+ uint32_t invocationCount = 0;
+ };
+
+
+ /**
+ * \brief Pixel shader-specific structure
+ */
+ struct DxbcCompilerPsPart {
+ uint32_t functionId = 0;
+
+ uint32_t builtinFragCoord = 0;
+ uint32_t builtinDepth = 0;
+ uint32_t builtinStencilRef = 0;
+ uint32_t builtinIsFrontFace = 0;
+ uint32_t builtinSampleId = 0;
+ uint32_t builtinSampleMaskIn = 0;
+ uint32_t builtinSampleMaskOut = 0;
+ uint32_t builtinLayer = 0;
+ uint32_t builtinViewportId = 0;
+
+ uint32_t builtinLaneId = 0;
+ uint32_t killState = 0;
+
+ uint32_t specRsSampleCount = 0;
+ };
+
+
+ /**
+ * \brief Compute shader-specific structure
+ */
+ struct DxbcCompilerCsPart {
+ uint32_t functionId = 0;
+
+ uint32_t workgroupSizeX = 0;
+ uint32_t workgroupSizeY = 0;
+ uint32_t workgroupSizeZ = 0;
+
+ uint32_t builtinGlobalInvocationId = 0;
+ uint32_t builtinLocalInvocationId = 0;
+ uint32_t builtinLocalInvocationIndex = 0;
+ uint32_t builtinWorkgroupId = 0;
+ };
+
+
+ /**
+ * \brief Hull shader fork/join phase
+ *
+ * Defines a function and built-in variables
+ * for a single fork or join phase sub-program.
+ */
+ struct DxbcCompilerHsForkJoinPhase {
+ uint32_t functionId = 0;
+ uint32_t instanceCount = 1;
+
+ uint32_t instanceId = 0;
+ uint32_t instanceIdPtr = 0;
+ };
+
+
+ /**
+ * \brief Hull shader control point phase
+ *
+ * Defines the function for the control
+ * point phase program of a hull shader.
+ */
+ struct DxbcCompilerHsControlPointPhase {
+ uint32_t functionId = 0;
+ };
+
+
+ /**
+ * \brief Hull shader phase
+ *
+ * Used to identify the current
+ * phase and function ID.
+ */
+ enum class DxbcCompilerHsPhase : uint32_t {
+ None, ///< No active phase
+ Decl, ///< \c hs_decls
+ ControlPoint, ///< \c hs_control_point_phase
+ Fork, ///< \c hs_fork_phase
+ Join, ///< \c hs_join_phase
+ };
+
+
+ /**
+ * \brief Hull shader-specific structure
+ */
+ struct DxbcCompilerHsPart {
+ DxbcCompilerHsPhase currPhaseType = DxbcCompilerHsPhase::None;
+ size_t currPhaseId = 0;
+
+ float maxTessFactor = 64.0f;
+
+ uint32_t vertexCountIn = 0;
+ uint32_t vertexCountOut = 0;
+
+ uint32_t builtinInvocationId = 0;
+ uint32_t builtinTessLevelOuter = 0;
+ uint32_t builtinTessLevelInner = 0;
+
+ uint32_t outputPerPatch = 0;
+ uint32_t outputPerVertex = 0;
+
+ uint32_t invocationBlockBegin = 0;
+ uint32_t invocationBlockEnd = 0;
+
+ uint32_t outputPerPatchMask = 0;
+
+ DxbcCompilerHsControlPointPhase cpPhase;
+ std::vector<DxbcCompilerHsForkJoinPhase> forkPhases;
+ std::vector<DxbcCompilerHsForkJoinPhase> joinPhases;
+ };
+
+
+ /**
+ * \brief Domain shader-specific structure
+ */
+ struct DxbcCompilerDsPart {
+ uint32_t functionId = 0;
+
+ uint32_t builtinTessCoord = 0;
+ uint32_t builtinTessLevelOuter = 0;
+ uint32_t builtinTessLevelInner = 0;
+
+ uint32_t vertexCountIn = 0;
+
+ uint32_t inputPerPatch = 0;
+ uint32_t inputPerVertex = 0;
+ };
+
+
+ enum class DxbcCfgBlockType : uint32_t {
+ If, Loop, Switch,
+ };
+
+
+ struct DxbcCfgBlockIf {
+ uint32_t ztestId;
+ uint32_t labelIf;
+ uint32_t labelElse;
+ uint32_t labelEnd;
+ size_t headerPtr;
+ };
+
+
+ struct DxbcCfgBlockLoop {
+ uint32_t labelHeader;
+ uint32_t labelBegin;
+ uint32_t labelContinue;
+ uint32_t labelBreak;
+ };
+
+
+ struct DxbcSwitchLabel {
+ SpirvSwitchCaseLabel desc;
+ DxbcSwitchLabel* next;
+ };
+
+
+ struct DxbcCfgBlockSwitch {
+ size_t insertPtr;
+ uint32_t selectorId;
+ uint32_t labelBreak;
+ uint32_t labelCase;
+ uint32_t labelDefault;
+ DxbcSwitchLabel* labelCases;
+ };
+
+
+ struct DxbcCfgBlock {
+ DxbcCfgBlockType type;
+
+ union {
+ DxbcCfgBlockIf b_if;
+ DxbcCfgBlockLoop b_loop;
+ DxbcCfgBlockSwitch b_switch;
+ };
+ };
+
+
+ struct DxbcBufferInfo {
+ DxbcImageInfo image;
+ DxbcScalarType stype;
+ DxbcResourceType type;
+ uint32_t typeId;
+ uint32_t varId;
+ uint32_t specId;
+ uint32_t stride;
+ uint32_t align;
+ };
+
+
+ /**
+ * \brief SPIR-V extension set
+ *
+ * Keeps track of which optional SPIR-V extensions
+ * are enabled so that any required setup code is
+ * only run once.
+ */
+ struct DxbcSpirvExtensions {
+ bool shaderViewportIndexLayer = false;
+ };
+
+
+ /**
+ * \brief DXBC to SPIR-V shader compiler
+ *
+ * Processes instructions from a DXBC shader and creates
+ * a DXVK shader object, which contains the SPIR-V module
+ * and information about the shader resource bindings.
+ */
+ class DxbcCompiler {
+
+ public:
+
+ DxbcCompiler(
+ const std::string& fileName,
+ const DxbcModuleInfo& moduleInfo,
+ const DxbcProgramInfo& programInfo,
+ const Rc<DxbcIsgn>& isgn,
+ const Rc<DxbcIsgn>& osgn,
+ const Rc<DxbcIsgn>& psgn,
+ const DxbcAnalysisInfo& analysis);
+ ~DxbcCompiler();
+
+ /**
+ * \brief Processes a single instruction
+ * \param [in] ins The instruction
+ */
+ void processInstruction(
+ const DxbcShaderInstruction& ins);
+
+ /**
+ * \brief Emits transform feedback passthrough
+ *
+ * Writes all captured input variables to the
+ * corresponding xfb outputs, and sets up the
+ * geometry shader for point-to-point mode.
+ */
+ void processXfbPassthrough();
+
+ /**
+ * \brief Finalizes the shader
+ * \returns The final shader object
+ */
+ Rc<DxvkShader> finalize();
+
+ private:
+
+ DxbcModuleInfo m_moduleInfo;
+ DxbcProgramInfo m_programInfo;
+ SpirvModule m_module;
+
+ Rc<DxbcIsgn> m_isgn;
+ Rc<DxbcIsgn> m_osgn;
+ Rc<DxbcIsgn> m_psgn;
+
+ const DxbcAnalysisInfo* m_analysis;
+
+ ///////////////////////////////////////////////////////
+ // Resource slot description for the shader. This will
+ // be used to map D3D11 bindings to DXVK bindings.
+ std::vector<DxvkResourceSlot> m_resourceSlots;
+
+ ////////////////////////////////////////////////
+ // Temporary r# vector registers with immediate
+ // indexing, and x# vector array registers.
+ std::vector<uint32_t> m_rRegs;
+ std::vector<DxbcXreg> m_xRegs;
+
+ /////////////////////////////////////////////
+ // Thread group shared memory (g#) registers
+ std::vector<DxbcGreg> m_gRegs;
+
+ ///////////////////////////////////////////////////////////
+ // v# registers as defined by the shader. The type of each
+ // of these inputs is either float4 or an array of float4.
+ std::array<
+ DxbcRegisterPointer,
+ DxbcMaxInterfaceRegs> m_vRegs;
+ std::vector<DxbcSvMapping> m_vMappings;
+
+ //////////////////////////////////////////////////////////
+ // o# registers as defined by the shader. In the fragment
+ // shader stage, these registers are typed by the signature,
+ // in all other stages, they are float4 registers or arrays.
+ std::array<
+ DxbcRegisterPointer,
+ DxbcMaxInterfaceRegs> m_oRegs;
+ std::vector<DxbcSvMapping> m_oMappings;
+
+ /////////////////////////////////////////////
+ // xfb output registers for geometry shaders
+ std::vector<DxbcXfbVar> m_xfbVars;
+
+ //////////////////////////////////////////////////////
+ // Shader resource variables. These provide access to
+ // constant buffers, samplers, textures, and UAVs.
+ std::array<DxbcConstantBuffer, 16> m_constantBuffers;
+ std::array<DxbcSampler, 16> m_samplers;
+ std::array<DxbcShaderResource, 128> m_textures;
+ std::array<DxbcUav, 64> m_uavs;
+
+ ///////////////////////////////////////////////
+ // Control flow information. Stores labels for
+ // currently active if-else blocks and loops.
+ std::vector<DxbcCfgBlock> m_controlFlowBlocks;
+
+ //////////////////////////////////////////////
+ // Function state tracking. Required in order
+ // to properly end functions in some cases.
+ bool m_insideFunction = false;
+
+ ///////////////////////////////////////////////////////////
+ // Array of input values. Since v# registers are indexable
+ // in DXBC, we need to copy them into an array first.
+ uint32_t m_vArrayLength = 0;
+ uint32_t m_vArrayLengthId = 0;
+
+ uint32_t m_vArray = 0;
+
+ ////////////////////////////////////////////////////
+ // Per-vertex input and output blocks. Depending on
+ // the shader stage, these may be declared as arrays.
+ uint32_t m_perVertexIn = 0;
+ uint32_t m_perVertexOut = 0;
+
+ uint32_t m_clipDistances = 0;
+ uint32_t m_cullDistances = 0;
+
+ uint32_t m_primitiveIdIn = 0;
+ uint32_t m_primitiveIdOut = 0;
+
+ //////////////////////////////////////////////////
+ // Immediate constant buffer. If defined, this is
+ // an array of four-component uint32 vectors.
+ uint32_t m_immConstBuf = 0;
+ DxvkShaderConstData m_immConstData;
+
+ ///////////////////////////////////////////////////
+ // Sample pos array. If defined, this iis an array
+ // of 32 four-component float vectors.
+ uint32_t m_samplePositions = 0;
+
+ ////////////////////////////////////////////
+ // Struct type used for UAV counter buffers
+ uint32_t m_uavCtrStructType = 0;
+ uint32_t m_uavCtrPointerType = 0;
+
+ ////////////////////////////////
+ // Function IDs for subroutines
+ std::unordered_map<uint32_t, uint32_t> m_subroutines;
+
+ ///////////////////////////////////////////////////
+ // Entry point description - we'll need to declare
+ // the function ID and all input/output variables.
+ std::vector<uint32_t> m_entryPointInterfaces;
+ uint32_t m_entryPointId = 0;
+
+ ////////////////////////////////////////////
+ // Inter-stage shader interface slots. Also
+ // covers vertex input and fragment output.
+ DxvkInterfaceSlots m_interfaceSlots;
+
+ ///////////////////////////////////
+ // Shader-specific data structures
+ DxbcCompilerVsPart m_vs;
+ DxbcCompilerHsPart m_hs;
+ DxbcCompilerDsPart m_ds;
+ DxbcCompilerGsPart m_gs;
+ DxbcCompilerPsPart m_ps;
+ DxbcCompilerCsPart m_cs;
+
+ /////////////////////////////
+ // Enabled SPIR-V extensions
+ DxbcSpirvExtensions m_extensions;
+
+ //////////////////////
+ // Global state stuff
+ bool m_precise = true;
+
+ /////////////////////////////////////////////////////
+ // Shader interface and metadata declaration methods
+ void emitDcl(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclGlobalFlags(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclTemps(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclIndexableTemp(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclInterfaceReg(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclInput(
+ uint32_t regIdx,
+ uint32_t regDim,
+ DxbcRegMask regMask,
+ DxbcSystemValue sv,
+ DxbcInterpolationMode im);
+
+ void emitDclOutput(
+ uint32_t regIdx,
+ uint32_t regDim,
+ DxbcRegMask regMask,
+ DxbcSystemValue sv,
+ DxbcInterpolationMode im);
+
+ void emitDclConstantBuffer(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclConstantBufferVar(
+ uint32_t regIdx,
+ uint32_t numConstants,
+ const char* name,
+ bool asSsbo);
+
+ void emitDclSampler(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclStream(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclResourceTyped(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclResourceRawStructured(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclThreadGroupSharedMemory(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclGsInputPrimitive(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclGsOutputTopology(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclMaxOutputVertexCount(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclInputControlPointCount(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclOutputControlPointCount(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclHsMaxTessFactor(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclTessDomain(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclTessPartitioning(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclTessOutputPrimitive(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclThreadGroup(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclGsInstanceCount(
+ const DxbcShaderInstruction& ins);
+
+ uint32_t emitDclUavCounter(
+ uint32_t regId);
+
+ ////////////////////////
+ // Custom data handlers
+ void emitDclImmediateConstantBuffer(
+ const DxbcShaderInstruction& ins);
+
+ void emitDclImmediateConstantBufferBaked(
+ uint32_t dwordCount,
+ const uint32_t* dwordArray);
+
+ void emitDclImmediateConstantBufferUbo(
+ uint32_t dwordCount,
+ const uint32_t* dwordArray);
+
+ void emitCustomData(
+ const DxbcShaderInstruction& ins);
+
+ //////////////////////////////
+ // Instruction class handlers
+ void emitVectorAlu(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorCmov(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorCmp(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorDeriv(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorDot(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorIdiv(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorImul(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorMsad(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorShift(
+ const DxbcShaderInstruction& ins);
+
+ void emitVectorSinCos(
+ const DxbcShaderInstruction& ins);
+
+ void emitGeometryEmit(
+ const DxbcShaderInstruction& ins);
+
+ void emitAtomic(
+ const DxbcShaderInstruction& ins);
+
+ void emitAtomicCounter(
+ const DxbcShaderInstruction& ins);
+
+ void emitBarrier(
+ const DxbcShaderInstruction& ins);
+
+ void emitBitExtract(
+ const DxbcShaderInstruction& ins);
+
+ void emitBitInsert(
+ const DxbcShaderInstruction& ins);
+
+ void emitBitScan(
+ const DxbcShaderInstruction& ins);
+
+ void emitBufferQuery(
+ const DxbcShaderInstruction& ins);
+
+ void emitBufferLoad(
+ const DxbcShaderInstruction& ins);
+
+ void emitBufferStore(
+ const DxbcShaderInstruction& ins);
+
+ void emitConvertFloat16(
+ const DxbcShaderInstruction& ins);
+
+ void emitConvertFloat64(
+ const DxbcShaderInstruction& ins);
+
+ void emitHullShaderPhase(
+ const DxbcShaderInstruction& ins);
+
+ void emitHullShaderInstCnt(
+ const DxbcShaderInstruction& ins);
+
+ void emitInterpolate(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureQuery(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureQueryLod(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureQueryMs(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureQueryMsPos(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureFetch(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureGather(
+ const DxbcShaderInstruction& ins);
+
+ void emitTextureSample(
+ const DxbcShaderInstruction& ins);
+
+ void emitTypedUavLoad(
+ const DxbcShaderInstruction& ins);
+
+ void emitTypedUavStore(
+ const DxbcShaderInstruction& ins);
+
+ /////////////////////////////////////
+ // Control flow instruction handlers
+ void emitControlFlowIf(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowElse(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowEndIf(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowSwitch(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowCase(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowDefault(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowEndSwitch(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowLoop(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowEndLoop(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowBreak(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowBreakc(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowRet(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowRetc(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowDiscard(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowLabel(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowCall(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlowCallc(
+ const DxbcShaderInstruction& ins);
+
+ void emitControlFlow(
+ const DxbcShaderInstruction& ins);
+
+ ////////////////////////////////////////////////
+ // Constant building methods. These are used to
+ // generate constant vectors that store the same
+ // value in each component.
+ DxbcRegisterValue emitBuildConstVecf32(
+ float x,
+ float y,
+ float z,
+ float w,
+ const DxbcRegMask& writeMask);
+
+ DxbcRegisterValue emitBuildConstVecu32(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z,
+ uint32_t w,
+ const DxbcRegMask& writeMask);
+
+ DxbcRegisterValue emitBuildConstVeci32(
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ int32_t w,
+ const DxbcRegMask& writeMask);
+
+ DxbcRegisterValue emitBuildConstVecf64(
+ double xy,
+ double zw,
+ const DxbcRegMask& writeMask);
+
+ DxbcRegisterValue emitBuildVector(
+ DxbcRegisterValue scalar,
+ uint32_t count);
+
+ DxbcRegisterValue emitBuildZeroVector(
+ DxbcVectorType type);
+
+ /////////////////////////////////////////
+ // Generic register manipulation methods
+ DxbcRegisterValue emitRegisterBitcast(
+ DxbcRegisterValue srcValue,
+ DxbcScalarType dstType);
+
+ DxbcRegisterValue emitRegisterSwizzle(
+ DxbcRegisterValue value,
+ DxbcRegSwizzle swizzle,
+ DxbcRegMask writeMask);
+
+ DxbcRegisterValue emitRegisterExtract(
+ DxbcRegisterValue value,
+ DxbcRegMask mask);
+
+ DxbcRegisterValue emitRegisterInsert(
+ DxbcRegisterValue dstValue,
+ DxbcRegisterValue srcValue,
+ DxbcRegMask srcMask);
+
+ DxbcRegisterValue emitRegisterConcat(
+ DxbcRegisterValue value1,
+ DxbcRegisterValue value2);
+
+ DxbcRegisterValue emitRegisterExtend(
+ DxbcRegisterValue value,
+ uint32_t size);
+
+ DxbcRegisterValue emitRegisterAbsolute(
+ DxbcRegisterValue value);
+
+ DxbcRegisterValue emitRegisterNegate(
+ DxbcRegisterValue value);
+
+ DxbcRegisterValue emitRegisterZeroTest(
+ DxbcRegisterValue value,
+ DxbcZeroTest test);
+
+ DxbcRegisterValue emitRegisterMaskBits(
+ DxbcRegisterValue value,
+ uint32_t mask);
+
+ DxbcRegisterValue emitSrcOperandModifiers(
+ DxbcRegisterValue value,
+ DxbcRegModifiers modifiers);
+
+ DxbcRegisterValue emitDstOperandModifiers(
+ DxbcRegisterValue value,
+ DxbcOpModifiers modifiers);
+
+ ////////////////////////////////
+ // Pointer manipulation methods
+ DxbcRegisterPointer emitArrayAccess(
+ DxbcRegisterPointer pointer,
+ spv::StorageClass sclass,
+ uint32_t index);
+
+ ///////////////////////////////////////
+ // Image register manipulation methods
+ uint32_t emitLoadSampledImage(
+ const DxbcShaderResource& textureResource,
+ const DxbcSampler& samplerResource,
+ bool isDepthCompare);
+
+ ////////////////////////
+ // Address load methods
+ DxbcRegisterPointer emitGetTempPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetIndexableTempPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetInputPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetOutputPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetConstBufPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetImmConstBufPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetOperandPtr(
+ const DxbcRegister& operand);
+
+ DxbcRegisterPointer emitGetAtomicPointer(
+ const DxbcRegister& operand,
+ const DxbcRegister& address);
+
+ ///////////////////////////////
+ // Resource load/store methods
+ DxbcRegisterValue emitRawBufferLoad(
+ const DxbcRegister& operand,
+ DxbcRegisterValue elementIndex,
+ DxbcRegMask writeMask);
+
+ void emitRawBufferStore(
+ const DxbcRegister& operand,
+ DxbcRegisterValue elementIndex,
+ DxbcRegisterValue value);
+
+ //////////////////////////
+ // Resource query methods
+ DxbcRegisterValue emitQueryBufferSize(
+ const DxbcRegister& resource);
+
+ DxbcRegisterValue emitQueryTexelBufferSize(
+ const DxbcRegister& resource);
+
+ DxbcRegisterValue emitQueryTextureLods(
+ const DxbcRegister& resource);
+
+ DxbcRegisterValue emitQueryTextureSamples(
+ const DxbcRegister& resource);
+
+ DxbcRegisterValue emitQueryTextureSize(
+ const DxbcRegister& resource,
+ DxbcRegisterValue lod);
+
+ ////////////////////////////////////
+ // Buffer index calculation methods
+ DxbcRegisterValue emitCalcBufferIndexStructured(
+ DxbcRegisterValue structId,
+ DxbcRegisterValue structOffset,
+ uint32_t structStride);
+
+ DxbcRegisterValue emitCalcBufferIndexRaw(
+ DxbcRegisterValue byteOffset);
+
+ DxbcRegisterValue emitCalcTexCoord(
+ DxbcRegisterValue coordVector,
+ const DxbcImageInfo& imageInfo);
+
+ DxbcRegisterValue emitLoadTexCoord(
+ const DxbcRegister& coordReg,
+ const DxbcImageInfo& imageInfo);
+
+ //////////////////////////////
+ // Operand load/store methods
+ DxbcRegisterValue emitIndexLoad(
+ DxbcRegIndex index);
+
+ DxbcRegisterValue emitValueLoad(
+ DxbcRegisterPointer ptr);
+
+ void emitValueStore(
+ DxbcRegisterPointer ptr,
+ DxbcRegisterValue value,
+ DxbcRegMask writeMask);
+
+ DxbcRegisterValue emitRegisterLoadRaw(
+ const DxbcRegister& reg);
+
+ DxbcRegisterValue emitConstantBufferLoad(
+ const DxbcRegister& reg,
+ DxbcRegMask writeMask);
+
+ DxbcRegisterValue emitRegisterLoad(
+ const DxbcRegister& reg,
+ DxbcRegMask writeMask);
+
+ void emitRegisterStore(
+ const DxbcRegister& reg,
+ DxbcRegisterValue value);
+
+ ////////////////////////////////////////
+ // Spec constant declaration and access
+ uint32_t emitNewSpecConstant(
+ DxvkSpecConstantId specId,
+ DxbcScalarType type,
+ uint32_t value,
+ const char* name);
+
+ ////////////////////////////
+ // Input/output preparation
+ void emitInputSetup();
+ void emitInputSetup(uint32_t vertexCount);
+
+ void emitOutputSetup();
+ void emitOutputMapping();
+ void emitOutputDepthClamp();
+
+ void emitInitWorkgroupMemory();
+
+ //////////////////////////////////////////
+ // System value load methods (per shader)
+ DxbcRegisterValue emitVsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask);
+
+ DxbcRegisterValue emitGsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ uint32_t vertexId);
+
+ DxbcRegisterValue emitPsSystemValueLoad(
+ DxbcSystemValue sv,
+ DxbcRegMask mask);
+
+ ///////////////////////////////////////////
+ // System value store methods (per shader)
+ void emitVsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value);
+
+ void emitHsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value);
+
+ void emitDsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value);
+
+ void emitGsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value);
+
+ void emitPsSystemValueStore(
+ DxbcSystemValue sv,
+ DxbcRegMask mask,
+ const DxbcRegisterValue& value);
+
+ ///////////////////////////////
+ // Special system value stores
+ void emitClipCullStore(
+ DxbcSystemValue sv,
+ uint32_t dstArray);
+
+ void emitClipCullLoad(
+ DxbcSystemValue sv,
+ uint32_t srcArray);
+
+ ///////////////////////////////
+ // Some state checking methods
+ uint32_t emitUavWriteTest(
+ const DxbcBufferInfo& uav);
+
+ //////////////////////////////////////
+ // Common function definition methods
+ void emitInit();
+
+ void emitFunctionBegin(
+ uint32_t entryPoint,
+ uint32_t returnType,
+ uint32_t funcType);
+
+ void emitFunctionEnd();
+
+ void emitFunctionLabel();
+
+ void emitMainFunctionBegin();
+
+ /////////////////////////////////
+ // Shader initialization methods
+ void emitVsInit();
+ void emitHsInit();
+ void emitDsInit();
+ void emitGsInit();
+ void emitPsInit();
+ void emitCsInit();
+
+ ///////////////////////////////
+ // Shader finalization methods
+ void emitVsFinalize();
+ void emitHsFinalize();
+ void emitDsFinalize();
+ void emitGsFinalize();
+ void emitPsFinalize();
+ void emitCsFinalize();
+
+ ///////////////////////
+ // Xfb related methods
+ void emitXfbOutputDeclarations();
+
+ void emitXfbOutputSetup(
+ uint32_t streamId,
+ bool passthrough);
+
+ ///////////////////////////////
+ // Hull shader phase methods
+ void emitHsControlPointPhase(
+ const DxbcCompilerHsControlPointPhase& phase);
+
+ void emitHsForkJoinPhase(
+ const DxbcCompilerHsForkJoinPhase& phase);
+
+ void emitHsPhaseBarrier();
+
+ void emitHsInvocationBlockBegin(
+ uint32_t count);
+
+ void emitHsInvocationBlockEnd();
+
+ void emitHsOutputSetup();
+
+ uint32_t emitTessInterfacePerPatch(
+ spv::StorageClass storageClass);
+
+ uint32_t emitTessInterfacePerVertex(
+ spv::StorageClass storageClass,
+ uint32_t vertexCount);
+
+ //////////////
+ // Misc stuff
+ void emitDclInputArray(
+ uint32_t vertexCount);
+
+ void emitDclInputPerVertex(
+ uint32_t vertexCount,
+ const char* varName);
+
+ uint32_t emitDclClipCullDistanceArray(
+ uint32_t length,
+ spv::BuiltIn builtIn,
+ spv::StorageClass storageClass);
+
+ DxbcCompilerHsControlPointPhase emitNewHullShaderControlPointPhase();
+
+ DxbcCompilerHsControlPointPhase emitNewHullShaderPassthroughPhase();
+
+ DxbcCompilerHsForkJoinPhase emitNewHullShaderForkJoinPhase();
+
+ uint32_t emitSamplePosArray();
+
+ void emitFloatControl();
+
+ ///////////////////////////////
+ // Variable definition methods
+ uint32_t emitNewVariable(
+ const DxbcRegisterInfo& info);
+
+ uint32_t emitNewBuiltinVariable(
+ const DxbcRegisterInfo& info,
+ spv::BuiltIn builtIn,
+ const char* name);
+
+ uint32_t emitBuiltinTessLevelOuter(
+ spv::StorageClass storageClass);
+
+ uint32_t emitBuiltinTessLevelInner(
+ spv::StorageClass storageClass);
+
+ ////////////////////////////////
+ // Extension enablement methods
+ void enableShaderViewportIndexLayer();
+
+ ////////////////
+ // Misc methods
+ DxbcCfgBlock* cfgFindBlock(
+ const std::initializer_list<DxbcCfgBlockType>& types);
+
+ DxbcBufferInfo getBufferInfo(
+ const DxbcRegister& reg);
+
+ uint32_t getTexSizeDim(
+ const DxbcImageInfo& imageType) const;
+
+ uint32_t getTexLayerDim(
+ const DxbcImageInfo& imageType) const;
+
+ uint32_t getTexCoordDim(
+ const DxbcImageInfo& imageType) const;
+
+ DxbcRegMask getTexCoordMask(
+ const DxbcImageInfo& imageType) const;
+
+ DxbcVectorType getInputRegType(
+ uint32_t regIdx) const;
+
+ DxbcVectorType getOutputRegType(
+ uint32_t regIdx) const;
+
+ DxbcImageInfo getResourceType(
+ DxbcResourceDim resourceType,
+ bool isUav) const;
+
+ spv::ImageFormat getScalarImageFormat(
+ DxbcScalarType type) const;
+
+ bool isDoubleType(
+ DxbcScalarType type) const;
+
+ DxbcRegisterPointer getIndexableTempPtr(
+ const DxbcRegister& operand,
+ DxbcRegisterValue vectorId);
+
+ ///////////////////////////
+ // Type definition methods
+ uint32_t getScalarTypeId(
+ DxbcScalarType type);
+
+ uint32_t getVectorTypeId(
+ const DxbcVectorType& type);
+
+ uint32_t getArrayTypeId(
+ const DxbcArrayType& type);
+
+ uint32_t getPointerTypeId(
+ const DxbcRegisterInfo& type);
+
+ uint32_t getPerVertexBlockId();
+
+ uint32_t getFunctionId(
+ uint32_t functionNr);
+
+ DxbcCompilerHsForkJoinPhase* getCurrentHsForkJoinPhase();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.cpp
new file mode 100644
index 00000000..0de7ddad
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.cpp
@@ -0,0 +1,360 @@
+#include "dxbc_decoder.h"
+
+namespace dxvk {
+
+ const uint32_t* DxbcCodeSlice::ptrAt(uint32_t id) const {
+ if (m_ptr + id >= m_end)
+ throw DxvkError("DxbcCodeSlice: End of stream");
+ return m_ptr + id;
+ }
+
+
+ uint32_t DxbcCodeSlice::at(uint32_t id) const {
+ if (m_ptr + id >= m_end)
+ throw DxvkError("DxbcCodeSlice: End of stream");
+ return m_ptr[id];
+ }
+
+
+ uint32_t DxbcCodeSlice::read() {
+ if (m_ptr >= m_end)
+ throw DxvkError("DxbcCodeSlice: End of stream");
+ return *(m_ptr++);
+ }
+
+
+ DxbcCodeSlice DxbcCodeSlice::take(uint32_t n) const {
+ if (m_ptr + n > m_end)
+ throw DxvkError("DxbcCodeSlice: End of stream");
+ return DxbcCodeSlice(m_ptr, m_ptr + n);
+ }
+
+
+ DxbcCodeSlice DxbcCodeSlice::skip(uint32_t n) const {
+ if (m_ptr + n > m_end)
+ throw DxvkError("DxbcCodeSlice: End of stream");
+ return DxbcCodeSlice(m_ptr + n, m_end);
+ }
+
+
+
+ void DxbcDecodeContext::decodeInstruction(DxbcCodeSlice& code) {
+ const uint32_t token0 = code.at(0);
+
+ // Initialize the instruction structure. Some of these values
+ // may not get written otherwise while decoding the instruction.
+ m_instruction.op = static_cast<DxbcOpcode>(bit::extract(token0, 0, 10));
+ m_instruction.opClass = DxbcInstClass::Undefined;
+ m_instruction.sampleControls = { 0, 0, 0 };
+ m_instruction.dstCount = 0;
+ m_instruction.srcCount = 0;
+ m_instruction.immCount = 0;
+ m_instruction.dst = m_dstOperands.data();
+ m_instruction.src = m_srcOperands.data();
+ m_instruction.imm = m_immOperands.data();
+ m_instruction.customDataType = DxbcCustomDataClass::Comment;
+ m_instruction.customDataSize = 0;
+ m_instruction.customData = nullptr;
+
+ // Reset the index pointer, which may still contain
+ // a non-zero value from the previous iteration
+ m_indexId = 0;
+
+ // Instruction length, in DWORDs. This includes the token
+ // itself and any other prefix that an instruction may have.
+ uint32_t length = 0;
+
+ if (m_instruction.op == DxbcOpcode::CustomData) {
+ length = code.at(1);
+ this->decodeCustomData(code.take(length));
+ } else {
+ length = bit::extract(token0, 24, 30);
+ this->decodeOperation(code.take(length));
+ }
+
+ // Advance the caller's slice to the next token so that
+ // they can make consecutive calls to decodeInstruction()
+ code = code.skip(length);
+ }
+
+
+ void DxbcDecodeContext::decodeCustomData(DxbcCodeSlice code) {
+ const uint32_t blockLength = code.at(1);
+
+ if (blockLength < 2) {
+ Logger::err("DxbcDecodeContext: Invalid custom data block");
+ return;
+ }
+
+ // Custom data blocks have their own instruction class
+ m_instruction.op = DxbcOpcode::CustomData;
+ m_instruction.opClass = DxbcInstClass::CustomData;
+
+ // We'll point into the code buffer rather than making a copy
+ m_instruction.customDataType = static_cast<DxbcCustomDataClass>(
+ bit::extract(code.at(0), 11, 31));
+ m_instruction.customDataSize = blockLength - 2;
+ m_instruction.customData = code.ptrAt(2);
+ }
+
+
+ void DxbcDecodeContext::decodeOperation(DxbcCodeSlice code) {
+ uint32_t token = code.read();
+
+ // Result modifiers, which are applied to common ALU ops
+ m_instruction.modifiers.saturate = !!bit::extract(token, 13, 13);
+ m_instruction.modifiers.precise = !!bit::extract(token, 19, 22);
+
+ // Opcode controls. It will depend on the
+ // opcode itself which ones are valid.
+ m_instruction.controls = DxbcShaderOpcodeControls(token);
+
+ // Process extended opcode tokens
+ while (bit::extract(token, 31, 31)) {
+ token = code.read();
+
+ const DxbcExtOpcode extOpcode
+ = static_cast<DxbcExtOpcode>(bit::extract(token, 0, 5));
+
+ switch (extOpcode) {
+ case DxbcExtOpcode::SampleControls: {
+ struct {
+ int u : 4;
+ int v : 4;
+ int w : 4;
+ } aoffimmi;
+
+ aoffimmi.u = bit::extract(token, 9, 12);
+ aoffimmi.v = bit::extract(token, 13, 16);
+ aoffimmi.w = bit::extract(token, 17, 20);
+
+ // Four-bit signed numbers, sign-extend them
+ m_instruction.sampleControls.u = aoffimmi.u;
+ m_instruction.sampleControls.v = aoffimmi.v;
+ m_instruction.sampleControls.w = aoffimmi.w;
+ } break;
+
+ case DxbcExtOpcode::ResourceDim:
+ case DxbcExtOpcode::ResourceReturnType:
+ break; // part of resource description
+
+ default:
+ Logger::warn(str::format(
+ "DxbcDecodeContext: Unhandled extended opcode: ",
+ extOpcode));
+ }
+ }
+
+ // Retrieve the instruction format in order to parse the
+ // operands. Doing this mostly automatically means that
+ // the compiler can rely on the operands being valid.
+ const DxbcInstFormat format = dxbcInstructionFormat(m_instruction.op);
+ m_instruction.opClass = format.instructionClass;
+
+ for (uint32_t i = 0; i < format.operandCount; i++)
+ this->decodeOperand(code, format.operands[i]);
+ }
+
+
+ void DxbcDecodeContext::decodeComponentSelection(DxbcRegister& reg, uint32_t token) {
+ // Pick the correct component selection mode based on the
+ // component count. We'll simplify this here so that the
+ // compiler can assume that everything is a 4D vector.
+ reg.componentCount = static_cast<DxbcComponentCount>(bit::extract(token, 0, 1));
+
+ switch (reg.componentCount) {
+ // No components - used for samplers etc.
+ case DxbcComponentCount::Component0:
+ reg.mask = DxbcRegMask(false, false, false, false);
+ reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
+ break;
+
+ // One component - used for immediates
+ // and a few built-in registers.
+ case DxbcComponentCount::Component1:
+ reg.mask = DxbcRegMask(true, false, false, false);
+ reg.swizzle = DxbcRegSwizzle(0, 0, 0, 0);
+ break;
+
+ // Four components - everything else. This requires us
+ // to actually parse the component selection mode.
+ case DxbcComponentCount::Component4: {
+ const DxbcRegMode componentMode =
+ static_cast<DxbcRegMode>(bit::extract(token, 2, 3));
+
+ switch (componentMode) {
+ // Write mask for destination operands
+ case DxbcRegMode::Mask:
+ reg.mask = bit::extract(token, 4, 7);
+ reg.swizzle = DxbcRegSwizzle(0, 1, 2, 3);
+ break;
+
+ // Swizzle for source operands (including resources)
+ case DxbcRegMode::Swizzle:
+ reg.mask = DxbcRegMask(true, true, true, true);
+ reg.swizzle = DxbcRegSwizzle(
+ bit::extract(token, 4, 5),
+ bit::extract(token, 6, 7),
+ bit::extract(token, 8, 9),
+ bit::extract(token, 10, 11));
+ break;
+
+ // Selection of one component. We can generate both a
+ // mask and a swizzle for this so that the compiler
+ // won't have to deal with this case specifically.
+ case DxbcRegMode::Select1: {
+ const uint32_t n = bit::extract(token, 4, 5);
+ reg.mask = DxbcRegMask(n == 0, n == 1, n == 2, n == 3);
+ reg.swizzle = DxbcRegSwizzle(n, n, n, n);
+ } break;
+
+ default:
+ Logger::warn("DxbcDecodeContext: Invalid component selection mode");
+ }
+ } break;
+
+ default:
+ Logger::warn("DxbcDecodeContext: Invalid component count");
+ }
+ }
+
+
+ void DxbcDecodeContext::decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
+ while (bit::extract(token, 31, 31)) {
+ token = code.read();
+
+ // Type of the extended operand token
+ const DxbcOperandExt extTokenType =
+ static_cast<DxbcOperandExt>(bit::extract(token, 0, 5));
+
+ switch (extTokenType) {
+ // Operand modifiers, which are used to manipulate the
+ // value of a source operand during the load operation
+ case DxbcOperandExt::OperandModifier:
+ reg.modifiers = bit::extract(token, 6, 13);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcDecodeContext: Unhandled extended operand token: ",
+ extTokenType));
+ }
+ }
+ }
+
+
+ void DxbcDecodeContext::decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg) {
+ if (reg.type == DxbcOperandType::Imm32
+ || reg.type == DxbcOperandType::Imm64) {
+ switch (reg.componentCount) {
+ // This is commonly used if only one vector
+ // component is involved in an operation
+ case DxbcComponentCount::Component1: {
+ reg.imm.u32_1 = code.read();
+ } break;
+
+ // Typical four-component vector
+ case DxbcComponentCount::Component4: {
+ reg.imm.u32_4[0] = code.read();
+ reg.imm.u32_4[1] = code.read();
+ reg.imm.u32_4[2] = code.read();
+ reg.imm.u32_4[3] = code.read();
+ } break;
+
+ default:
+ Logger::warn("DxbcDecodeContext: Invalid component count for immediate operand");
+ }
+ }
+ }
+
+
+ void DxbcDecodeContext::decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token) {
+ reg.idxDim = bit::extract(token, 20, 21);
+
+ for (uint32_t i = 0; i < reg.idxDim; i++) {
+ // An index can be encoded in various different ways
+ const DxbcOperandIndexRepresentation repr =
+ static_cast<DxbcOperandIndexRepresentation>(
+ bit::extract(token, 22 + 3 * i, 24 + 3 * i));
+
+ switch (repr) {
+ case DxbcOperandIndexRepresentation::Imm32:
+ reg.idx[i].offset = static_cast<int32_t>(code.read());
+ reg.idx[i].relReg = nullptr;
+ break;
+
+ case DxbcOperandIndexRepresentation::Relative:
+ reg.idx[i].offset = 0;
+ reg.idx[i].relReg = &m_indices.at(m_indexId);
+
+ this->decodeRegister(code,
+ m_indices.at(m_indexId++),
+ DxbcScalarType::Sint32);
+ break;
+
+ case DxbcOperandIndexRepresentation::Imm32Relative:
+ reg.idx[i].offset = static_cast<int32_t>(code.read());
+ reg.idx[i].relReg = &m_indices.at(m_indexId);
+
+ this->decodeRegister(code,
+ m_indices.at(m_indexId++),
+ DxbcScalarType::Sint32);
+ break;
+
+ default:
+ Logger::warn(str::format(
+ "DxbcDecodeContext: Unhandled index representation: ",
+ repr));
+ }
+ }
+ }
+
+
+ void DxbcDecodeContext::decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type) {
+ const uint32_t token = code.read();
+
+ reg.type = static_cast<DxbcOperandType>(bit::extract(token, 12, 19));
+ reg.dataType = type;
+ reg.modifiers = 0;
+ reg.idxDim = 0;
+
+ for (uint32_t i = 0; i < DxbcMaxRegIndexDim; i++) {
+ reg.idx[i].relReg = nullptr;
+ reg.idx[i].offset = 0;
+ }
+
+ this->decodeComponentSelection(reg, token);
+ this->decodeOperandExtensions(code, reg, token);
+ this->decodeOperandImmediates(code, reg);
+ this->decodeOperandIndex(code, reg, token);
+ }
+
+
+ void DxbcDecodeContext::decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type) {
+ imm.u32 = code.read();
+ }
+
+
+ void DxbcDecodeContext::decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format) {
+ switch (format.kind) {
+ case DxbcOperandKind::DstReg: {
+ const uint32_t operandId = m_instruction.dstCount++;
+ this->decodeRegister(code, m_dstOperands.at(operandId), format.type);
+ } break;
+
+ case DxbcOperandKind::SrcReg: {
+ const uint32_t operandId = m_instruction.srcCount++;
+ this->decodeRegister(code, m_srcOperands.at(operandId), format.type);
+ } break;
+
+ case DxbcOperandKind::Imm32: {
+ const uint32_t operandId = m_instruction.immCount++;
+ this->decodeImm32(code, m_immOperands.at(operandId), format.type);
+ } break;
+
+ default:
+ throw DxvkError("DxbcDecodeContext: Invalid operand format");
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.h
new file mode 100644
index 00000000..72b4e961
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_decoder.h
@@ -0,0 +1,504 @@
+#pragma once
+
+#include <array>
+
+#include "dxbc_common.h"
+#include "dxbc_decoder.h"
+#include "dxbc_defs.h"
+#include "dxbc_enums.h"
+#include "dxbc_names.h"
+
+namespace dxvk {
+
+ constexpr size_t DxbcMaxRegIndexDim = 3;
+
+ struct DxbcRegister;
+
+ /**
+ * \brief Source operand modifiers
+ *
+ * These are applied after loading
+ * an operand register.
+ */
+ enum class DxbcRegModifier : uint32_t {
+ Neg = 0,
+ Abs = 1,
+ };
+
+ using DxbcRegModifiers = Flags<DxbcRegModifier>;
+
+
+ /**
+ * \brief Constant buffer binding
+ *
+ * Stores information required to
+ * access a constant buffer.
+ */
+ struct DxbcConstantBuffer {
+ uint32_t varId = 0;
+ uint32_t size = 0;
+ };
+
+ /**
+ * \brief Sampler binding
+ *
+ * Stores a sampler variable that can be
+ * used together with a texture resource.
+ */
+ struct DxbcSampler {
+ uint32_t varId = 0;
+ uint32_t typeId = 0;
+ };
+
+
+ /**
+ * \brief Image type information
+ */
+ struct DxbcImageInfo {
+ spv::Dim dim = spv::Dim1D;
+ uint32_t array = 0;
+ uint32_t ms = 0;
+ uint32_t sampled = 0;
+ VkImageViewType vtype = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ };
+
+
+ /**
+ * \brief Shader resource binding
+ *
+ * Stores a resource variable
+ * and associated type IDs.
+ */
+ struct DxbcShaderResource {
+ DxbcResourceType type = DxbcResourceType::Typed;
+ DxbcImageInfo imageInfo;
+ uint32_t varId = 0;
+ uint32_t specId = 0;
+ DxbcScalarType sampledType = DxbcScalarType::Float32;
+ uint32_t sampledTypeId = 0;
+ uint32_t imageTypeId = 0;
+ uint32_t colorTypeId = 0;
+ uint32_t depthTypeId = 0;
+ uint32_t structStride = 0;
+ uint32_t structAlign = 0;
+ };
+
+
+ /**
+ * \brief Unordered access binding
+ *
+ * Stores a resource variable that is provided
+ * by a UAV, as well as associated type IDs.
+ */
+ struct DxbcUav {
+ DxbcResourceType type = DxbcResourceType::Typed;
+ DxbcImageInfo imageInfo;
+ uint32_t varId = 0;
+ uint32_t ctrId = 0;
+ uint32_t specId = 0;
+ DxbcScalarType sampledType = DxbcScalarType::Float32;
+ uint32_t sampledTypeId = 0;
+ uint32_t imageTypeId = 0;
+ uint32_t structStride = 0;
+ uint32_t structAlign = 0;
+ };
+
+
+ /**
+ * \brief Component swizzle
+ *
+ * Maps vector components to
+ * other vector components.
+ */
+ class DxbcRegSwizzle {
+
+ public:
+
+ DxbcRegSwizzle() { }
+ DxbcRegSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
+ : m_mask((x << 0) | (y << 2) | (z << 4) | (w << 6)) { }
+
+ uint32_t operator [] (uint32_t id) const {
+ return (m_mask >> (id + id)) & 0x3;
+ }
+
+ bool operator == (const DxbcRegSwizzle& other) const { return m_mask == other.m_mask; }
+ bool operator != (const DxbcRegSwizzle& other) const { return m_mask != other.m_mask; }
+
+ private:
+
+ uint8_t m_mask = 0;
+
+ };
+
+
+ /**
+ * \brief Component mask
+ *
+ * Enables access to certain
+ * subset of vector components.
+ */
+ class DxbcRegMask {
+
+ public:
+
+ DxbcRegMask() { }
+ DxbcRegMask(uint32_t mask) : m_mask(mask) { }
+ DxbcRegMask(bool x, bool y, bool z, bool w)
+ : m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
+ | (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
+
+ bool operator [] (uint32_t id) const {
+ return (m_mask >> id) & 1;
+ }
+
+ uint32_t popCount() const {
+ const uint8_t n[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ return n[m_mask & 0xF];
+ }
+
+ uint32_t firstSet() const {
+ const uint8_t n[16] = { 4, 0, 1, 0, 2, 0, 1, 0,
+ 3, 0, 1, 0, 2, 0, 1, 0 };
+ return n[m_mask & 0xF];
+ }
+
+ uint32_t minComponents() const {
+ const uint8_t n[16] = { 0, 1, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4 };
+ return n[m_mask & 0xF];
+ }
+
+ bool operator == (const DxbcRegMask& other) const { return m_mask == other.m_mask; }
+ bool operator != (const DxbcRegMask& other) const { return m_mask != other.m_mask; }
+
+ DxbcRegMask& operator |= (const DxbcRegMask& other) {
+ m_mask |= other.m_mask;
+ return *this;
+ }
+
+ static DxbcRegMask firstN(uint32_t n) {
+ return DxbcRegMask(n >= 1, n >= 2, n >= 3, n >= 4);
+ }
+
+ static DxbcRegMask select(uint32_t n) {
+ return DxbcRegMask(n == 0, n == 1, n == 2, n == 3);
+ }
+
+ std::string maskString() const {
+ std::string out = "";
+ out += (m_mask & 0x1) ? "x" : "";
+ out += (m_mask & 0x2) ? "y" : "";
+ out += (m_mask & 0x4) ? "z" : "";
+ out += (m_mask & 0x8) ? "w" : "";
+ return out;
+ }
+
+ operator bool () const {
+ return m_mask != 0;
+ }
+
+ private:
+
+ uint8_t m_mask = 0;
+
+ };
+
+
+ /**
+ * \brief System value mapping
+ *
+ * Maps a system value to a given set of
+ * components of an input or output register.
+ */
+ struct DxbcSvMapping {
+ uint32_t regId;
+ DxbcRegMask regMask;
+ DxbcSystemValue sv;
+ };
+
+
+ struct DxbcRegIndex {
+ DxbcRegister* relReg;
+ int32_t offset;
+ };
+
+
+ /**
+ * \brief Instruction operand
+ */
+ struct DxbcRegister {
+ DxbcOperandType type;
+ DxbcScalarType dataType;
+ DxbcComponentCount componentCount;
+
+ uint32_t idxDim;
+ DxbcRegIndex idx[DxbcMaxRegIndexDim];
+
+ DxbcRegMask mask;
+ DxbcRegSwizzle swizzle;
+ DxbcRegModifiers modifiers;
+
+ union {
+ uint32_t u32_4[4];
+ uint32_t u32_1;
+ } imm;
+ };
+
+
+ /**
+ * \brief Instruction result modifiers
+ *
+ * Modifiers that are applied
+ * to all destination operands.
+ */
+ struct DxbcOpModifiers {
+ bool saturate;
+ bool precise;
+ };
+
+
+ /**
+ * \brief Opcode controls
+ *
+ * Instruction-specific controls. Usually,
+ * only one of the members will be valid.
+ */
+ class DxbcShaderOpcodeControls {
+
+ public:
+
+ DxbcShaderOpcodeControls()
+ : m_bits(0) { }
+
+ DxbcShaderOpcodeControls(uint32_t bits)
+ : m_bits(bits) { }
+
+ DxbcInstructionReturnType returnType() const {
+ return DxbcInstructionReturnType(bit::extract(m_bits, 11, 11));
+ }
+
+ DxbcGlobalFlags globalFlags() const {
+ return DxbcGlobalFlags(bit::extract(m_bits, 11, 14));
+ }
+
+ DxbcZeroTest zeroTest() const {
+ return DxbcZeroTest(bit::extract(m_bits, 18, 18));
+ }
+
+ DxbcSyncFlags syncFlags() const {
+ return DxbcSyncFlags(bit::extract(m_bits, 11, 14));
+ }
+
+ DxbcResourceDim resourceDim() const {
+ return DxbcResourceDim(bit::extract(m_bits, 11, 15));
+ }
+
+ DxbcResinfoType resinfoType() const {
+ return DxbcResinfoType(bit::extract(m_bits, 11, 12));
+ }
+
+ DxbcInterpolationMode interpolation() const {
+ return DxbcInterpolationMode(bit::extract(m_bits, 11, 14));
+ }
+
+ DxbcSamplerMode samplerMode() const {
+ return DxbcSamplerMode(bit::extract(m_bits, 11, 14));
+ }
+
+ DxbcPrimitiveTopology primitiveTopology() const {
+ return DxbcPrimitiveTopology(bit::extract(m_bits, 11, 17));
+ }
+
+ DxbcPrimitive primitive() const {
+ return DxbcPrimitive(bit::extract(m_bits, 11, 16));
+ }
+
+ DxbcTessDomain tessDomain() const {
+ return DxbcTessDomain(bit::extract(m_bits, 11, 12));
+ }
+
+ DxbcTessOutputPrimitive tessOutputPrimitive() const {
+ return DxbcTessOutputPrimitive(bit::extract(m_bits, 11, 13));
+ }
+
+ DxbcTessPartitioning tessPartitioning() const {
+ return DxbcTessPartitioning(bit::extract(m_bits, 11, 13));
+ }
+
+ DxbcUavFlags uavFlags() const {
+ return DxbcUavFlags(bit::extract(m_bits, 16, 16));
+ }
+
+ DxbcConstantBufferAccessType accessType() const {
+ return DxbcConstantBufferAccessType(bit::extract(m_bits, 11, 11));
+ }
+
+ uint32_t controlPointCount() const {
+ return bit::extract(m_bits, 11, 16);
+ }
+
+ bool precise() const {
+ return bit::extract(m_bits, 19, 22) != 0;
+ }
+
+ private:
+
+ uint32_t m_bits;
+
+ };
+
+
+ /**
+ * \brief Sample controls
+ *
+ * Constant texel offset with
+ * values raning from -8 to 7.
+ */
+ struct DxbcShaderSampleControls {
+ int u, v, w;
+ };
+
+
+ /**
+ * \brief Immediate value
+ *
+ * Immediate argument represented either
+ * as a 32-bit or 64-bit unsigned integer,
+ * or a 32-bit or 32-bit floating point number.
+ */
+ union DxbcImmediate {
+ float f32;
+ double f64;
+ uint32_t u32;
+ uint64_t u64;
+ };
+
+
+ /**
+ * \brief Shader instruction
+ *
+ * Note that this structure may store pointer to
+ * external structures, such as the original code
+ * buffer. This is safe to use if and only if:
+ * - The \ref DxbcDecodeContext that created it
+ * still exists and was not moved
+ * - The code buffer that was being decoded
+ * still exists and was not moved.
+ */
+ struct DxbcShaderInstruction {
+ DxbcOpcode op;
+ DxbcInstClass opClass;
+ DxbcOpModifiers modifiers;
+ DxbcShaderOpcodeControls controls;
+ DxbcShaderSampleControls sampleControls;
+
+ uint32_t dstCount;
+ uint32_t srcCount;
+ uint32_t immCount;
+
+ const DxbcRegister* dst;
+ const DxbcRegister* src;
+ const DxbcImmediate* imm;
+
+ DxbcCustomDataClass customDataType;
+ uint32_t customDataSize;
+ const uint32_t* customData;
+ };
+
+
+ /**
+ * \brief DXBC code slice
+ *
+ * Convenient pointer pair that allows
+ * reading the code word stream safely.
+ */
+ class DxbcCodeSlice {
+
+ public:
+
+ DxbcCodeSlice(
+ const uint32_t* ptr,
+ const uint32_t* end)
+ : m_ptr(ptr), m_end(end) { }
+
+ const uint32_t* ptrAt(uint32_t id) const;
+
+ uint32_t at(uint32_t id) const;
+ uint32_t read();
+
+ DxbcCodeSlice take(uint32_t n) const;
+ DxbcCodeSlice skip(uint32_t n) const;
+
+ bool atEnd() const {
+ return m_ptr == m_end;
+ }
+
+ private:
+
+ const uint32_t* m_ptr = nullptr;
+ const uint32_t* m_end = nullptr;
+
+ };
+
+
+ /**
+ * \brief Decode context
+ *
+ * Stores data that is required to decode a single
+ * instruction. This data is not persistent, so it
+ * should be forwarded to the compiler right away.
+ */
+ class DxbcDecodeContext {
+
+ public:
+
+ /**
+ * \brief Retrieves current instruction
+ *
+ * This is only valid after a call to \ref decode.
+ * \returns Reference to last decoded instruction
+ */
+ const DxbcShaderInstruction& getInstruction() const {
+ return m_instruction;
+ }
+
+ /**
+ * \brief Decodes an instruction
+ *
+ * This also advances the given code slice by the
+ * number of dwords consumed by the instruction.
+ * \param [in] code Code slice
+ */
+ void decodeInstruction(DxbcCodeSlice& code);
+
+ private:
+
+ DxbcShaderInstruction m_instruction;
+
+ std::array<DxbcRegister, 8> m_dstOperands;
+ std::array<DxbcRegister, 8> m_srcOperands;
+ std::array<DxbcImmediate, 4> m_immOperands;
+ std::array<DxbcRegister, 12> m_indices;
+
+ // Index into the indices array. Used when decoding
+ // instruction operands with relative indexing.
+ uint32_t m_indexId = 0;
+
+ void decodeCustomData(DxbcCodeSlice code);
+ void decodeOperation(DxbcCodeSlice code);
+
+ void decodeComponentSelection(DxbcRegister& reg, uint32_t token);
+ void decodeOperandExtensions(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
+ void decodeOperandImmediates(DxbcCodeSlice& code, DxbcRegister& reg);
+ void decodeOperandIndex(DxbcCodeSlice& code, DxbcRegister& reg, uint32_t token);
+
+ void decodeRegister(DxbcCodeSlice& code, DxbcRegister& reg, DxbcScalarType type);
+ void decodeImm32(DxbcCodeSlice& code, DxbcImmediate& imm, DxbcScalarType type);
+
+ void decodeOperand(DxbcCodeSlice& code, const DxbcInstOperandFormat& format);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.cpp
new file mode 100644
index 00000000..4e383d8a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.cpp
@@ -0,0 +1,1117 @@
+#include "dxbc_defs.h"
+
+namespace dxvk {
+
+ const std::array<DxbcInstFormat, 218> g_instructionFormats = {{
+ /* Add */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* And */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Break */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Breakc */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Call */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Callc */
+ { 2, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Case */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Continue */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Continuec */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Cut */
+ { 0, DxbcInstClass::GeometryEmit },
+ /* Default */
+ { 0, DxbcInstClass::ControlFlow },
+ /* DerivRtx */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DerivRty */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Discard */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Div */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Dp2 */
+ { 3, DxbcInstClass::VectorDot, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Dp3 */
+ { 3, DxbcInstClass::VectorDot, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Dp4 */
+ { 3, DxbcInstClass::VectorDot, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Else */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Emit */
+ { 0, DxbcInstClass::GeometryEmit },
+ /* EmitThenCut */
+ { 0, DxbcInstClass::GeometryEmit },
+ /* EndIf */
+ { 0, DxbcInstClass::ControlFlow },
+ /* EndLoop */
+ { 0, DxbcInstClass::ControlFlow },
+ /* EndSwitch */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Eq */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Exp */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Frc */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* FtoI */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* FtoU */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Ge */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* IAdd */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* If */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* IEq */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IGe */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* ILt */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IMad */
+ { 4, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IMax */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IMin */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IMul */
+ { 4, DxbcInstClass::VectorImul, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* INe */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* INeg */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* IShl */
+ { 3, DxbcInstClass::VectorShift, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* IShr */
+ { 3, DxbcInstClass::VectorShift, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ItoF */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* Label */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* Ld */
+ { 3, DxbcInstClass::TextureFetch, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* LdMs */
+ { 4, DxbcInstClass::TextureFetch, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* Log */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Loop */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Lt */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Mad */
+ { 4, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Min */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Max */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* CustomData */
+ { 0, DxbcInstClass::CustomData },
+ /* Mov */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Movc */
+ { 4, DxbcInstClass::VectorCmov, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Mul */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Ne */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Nop */
+ { 0, DxbcInstClass::NoOperation },
+ /* Not */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Or */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ResInfo */
+ { 3, DxbcInstClass::TextureQuery, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Ret */
+ { 0, DxbcInstClass::ControlFlow },
+ /* Retc */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* RoundNe */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* RoundNi */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* RoundPi */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* RoundZ */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Rsq */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Sample */
+ { 4, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SampleC */
+ { 5, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SampleClz */
+ { 5, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SampleL */
+ { 5, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SampleD */
+ { 6, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SampleB */
+ { 5, DxbcInstClass::TextureSample, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Sqrt */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Switch */
+ { 1, DxbcInstClass::ControlFlow, {
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* SinCos */
+ { 3, DxbcInstClass::VectorSinCos, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* UDiv */
+ { 4, DxbcInstClass::VectorIdiv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ULt */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UGe */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UMul */
+ { 4, DxbcInstClass::VectorImul, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UMad */
+ { 4, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UMax */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UMin */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UShr */
+ { 3, DxbcInstClass::VectorShift, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UtoF */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Xor */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* DclResource */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclConstantBuffer */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclSampler */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclIndexRange */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclGsOutputPrimitiveTopology */
+ { 0, DxbcInstClass::Declaration },
+ /* DclGsInputPrimitive */
+ { 0, DxbcInstClass::Declaration },
+ /* DclMaxOutputVertexCount */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclInput */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclInputSgv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclInputSiv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclInputPs */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclInputPsSgv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclInputPsSiv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclOutput */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclOutputSgv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclOutputSiv */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclTemps */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclIndexableTemp */
+ { 3, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclGlobalFlags */
+ { 0, DxbcInstClass::Declaration },
+ /* Reserved0 */
+ { 0, DxbcInstClass::Undefined },
+ /* Lod */
+ { 4, DxbcInstClass::TextureQueryLod, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Gather4 */
+ { 4, DxbcInstClass::TextureGather, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* SamplePos */
+ { 3, DxbcInstClass::TextureQueryMsPos, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* SampleInfo */
+ { 2, DxbcInstClass::TextureQueryMs, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Reserved1 */
+ { },
+ /* HsDecls */
+ { 0, DxbcInstClass::HullShaderPhase },
+ /* HsControlPointPhase */
+ { 0, DxbcInstClass::HullShaderPhase },
+ /* HsForkPhase */
+ { 0, DxbcInstClass::HullShaderPhase },
+ /* HsJoinPhase */
+ { 0, DxbcInstClass::HullShaderPhase },
+ /* EmitStream */
+ { 1, DxbcInstClass::GeometryEmit, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* CutStream */
+ { 1, DxbcInstClass::GeometryEmit, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* EmitThenCutStream */
+ { 1, DxbcInstClass::GeometryEmit, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* InterfaceCall */
+ { },
+ /* BufInfo */
+ { 2, DxbcInstClass::BufferQuery, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* DerivRtxCoarse */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DerivRtxFine */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DerivRtyCoarse */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DerivRtyFine */
+ { 2, DxbcInstClass::VectorDeriv, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Gather4C */
+ { 5, DxbcInstClass::TextureGather, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Gather4Po */
+ { 5, DxbcInstClass::TextureGather, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Gather4PoC */
+ { 6, DxbcInstClass::TextureGather, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* Rcp */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* F32toF16 */
+ { 2, DxbcInstClass::ConvertFloat16, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* F16toF32 */
+ { 2, DxbcInstClass::ConvertFloat16, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UAddc */
+ { },
+ /* USubb */
+ { },
+ /* CountBits */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* FirstBitHi */
+ { 2, DxbcInstClass::BitScan, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* FirstBitLo */
+ { 2, DxbcInstClass::BitScan, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* FirstBitShi */
+ { 2, DxbcInstClass::BitScan, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* UBfe */
+ { 4, DxbcInstClass::BitExtract, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* IBfe */
+ { 4, DxbcInstClass::BitExtract, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* Bfi */
+ { 5, DxbcInstClass::BitInsert, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* BfRev */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Swapc */
+ { 5, DxbcInstClass::VectorCmov, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DclStream */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* DclFunctionBody */
+ { },
+ /* DclFunctionTable */
+ { },
+ /* DclInterface */
+ { },
+ /* DclInputControlPointCount */
+ { 0, DxbcInstClass::Declaration },
+ /* DclOutputControlPointCount */
+ { 0, DxbcInstClass::Declaration },
+ /* DclTessDomain */
+ { 0, DxbcInstClass::Declaration },
+ /* DclTessPartitioning */
+ { 0, DxbcInstClass::Declaration },
+ /* DclTessOutputPrimitive */
+ { 0, DxbcInstClass::Declaration },
+ /* DclHsMaxTessFactor */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Float32 },
+ } },
+ /* DclHsForkPhaseInstanceCount */
+ { 1, DxbcInstClass::HullShaderInstCnt, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclHsJoinPhaseInstanceCount */
+ { 1, DxbcInstClass::HullShaderInstCnt, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclThreadGroup */
+ { 3, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclUavTyped */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclUavRaw */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclUavStructured */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclThreadGroupSharedMemoryRaw */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclThreadGroupSharedMemoryStructured */
+ { 3, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* DclResourceRaw */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ } },
+ /* DclResourceStructured */
+ { 2, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* LdUavTyped */
+ { 3, DxbcInstClass::TypedUavLoad, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* StoreUavTyped */
+ { 3, DxbcInstClass::TypedUavStore, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* LdRaw */
+ { 3, DxbcInstClass::BufferLoad, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* StoreRaw */
+ { 3, DxbcInstClass::BufferStore, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* LdStructured */
+ { 4, DxbcInstClass::BufferLoad, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* StoreStructured */
+ { 4, DxbcInstClass::BufferStore, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicAnd */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicOr */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicXor */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicCmpStore */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicIAdd */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicIMax */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* AtomicIMin */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* AtomicUMax */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* AtomicUMin */
+ { 3, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicAlloc */
+ { 2, DxbcInstClass::AtomicCounter, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicConsume */
+ { 2, DxbcInstClass::AtomicCounter, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicIAdd */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicAnd */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicOr */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicXor */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicExch */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicCmpExch */
+ { 5, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicIMax */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* ImmAtomicIMin */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* ImmAtomicUMax */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* ImmAtomicUMin */
+ { 4, DxbcInstClass::Atomic, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* Sync */
+ { 0, DxbcInstClass::Barrier },
+ /* DAdd */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DMax */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DMin */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DMul */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DEq */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DGe */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DLt */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DNe */
+ { 3, DxbcInstClass::VectorCmp, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DMov */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DMovc */
+ { 4, DxbcInstClass::VectorCmov, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DtoF */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* FtoD */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* EvalSnapped */
+ { 3, DxbcInstClass::Interpolate, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* EvalSampleIndex */
+ { 3, DxbcInstClass::Interpolate, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* EvalCentroid */
+ { 2, DxbcInstClass::Interpolate, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
+ } },
+ /* DclGsInstanceCount */
+ { 1, DxbcInstClass::Declaration, {
+ { DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
+ } },
+ /* Abort */
+ { },
+ /* DebugBreak */
+ { },
+ /* ReservedBegin11_1 */
+ { },
+ /* DDiv */
+ { 3, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DFma */
+ { 4, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DRcp */
+ { 2, DxbcInstClass::VectorAlu, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* Msad */
+ { 4, DxbcInstClass::VectorMsad, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ /* DtoI */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Sint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* DtoU */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Float64 },
+ } },
+ /* ItoD */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
+ } },
+ /* UtoD */
+ { 2, DxbcInstClass::ConvertFloat64, {
+ { DxbcOperandKind::DstReg, DxbcScalarType::Float64 },
+ { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
+ } },
+ }};
+
+
+ DxbcInstFormat dxbcInstructionFormat(DxbcOpcode opcode) {
+ const uint32_t idx = static_cast<uint32_t>(opcode);
+
+ return (idx < g_instructionFormats.size())
+ ? g_instructionFormats.at(idx)
+ : DxbcInstFormat();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.h
new file mode 100644
index 00000000..decd7670
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_defs.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "dxbc_enums.h"
+
+namespace dxvk {
+
+ constexpr size_t DxbcMaxInterfaceRegs = 32;
+ constexpr size_t DxbcMaxOperandCount = 8;
+
+ /**
+ * \brief Operand kind
+ *
+ * In the instruction format definition, this specified
+ * whether an operand uses an actual operand token, or
+ * whether it is stored as an immediate value.
+ */
+ enum class DxbcOperandKind {
+ DstReg, ///< Destination register
+ SrcReg, ///< Source register
+ Imm32, ///< Constant number
+ };
+
+ /**
+ * \brief Instruction class
+ *
+ * Instructions with a similar format are grouped into
+ * instruction classes in order to make implementing
+ * new instructions easier.
+ */
+ enum class DxbcInstClass {
+ Declaration, ///< Interface or resource declaration
+ CustomData, ///< Immediate constant buffer
+ ControlFlow, ///< Control flow instructions
+ GeometryEmit, ///< Special geometry shader instructions
+ Atomic, ///< Atomic operations
+ AtomicCounter, ///< Atomic counter operations
+ Barrier, ///< Execution or memory barrier
+ BitExtract, ///< Bit field extract operations
+ BitInsert, ///< Bit field insert operations
+ BitScan, ///< Bit scan operations
+ BufferQuery, ///< Buffer query instruction
+ BufferLoad, ///< Structured or raw buffer load
+ BufferStore, ///< Structured or raw buffer store
+ ConvertFloat16, ///< 16-bit float packing/unpacking
+ ConvertFloat64, ///< 64-bit float conversion
+ HullShaderPhase, ///< Hull shader phase declaration
+ HullShaderInstCnt, ///< Hull shader phase instance count
+ Interpolate, ///< Input attribute interpolation
+ NoOperation, ///< The most useful instruction class
+ TextureQuery, ///< Texture query instruction
+ TextureQueryLod, ///< Texture LOD query instruction
+ TextureQueryMs, ///< Multisample texture query
+ TextureQueryMsPos, ///< Sample position query
+ TextureFetch, ///< Texture fetch instruction
+ TextureGather, ///< Texture gather instruction
+ TextureSample, ///< Texture sampling instruction
+ TypedUavLoad, ///< Typed UAV load
+ TypedUavStore, ///< Typed UAV store
+ VectorAlu, ///< Component-wise vector instructions
+ VectorCmov, ///< Component-wise conditional move
+ VectorCmp, ///< Component-wise vector comparison
+ VectorDeriv, ///< Vector derivatives
+ VectorDot, ///< Dot product instruction
+ VectorIdiv, ///< Component-wise integer division
+ VectorImul, ///< Component-wise integer multiplication
+ VectorMsad, ///< Component-wise sum of absolute difference
+ VectorShift, ///< Bit shift operations on vectors
+ VectorSinCos, ///< Sine and Cosine instruction
+ Undefined, ///< Instruction code not defined
+ };
+
+ /**
+ * \brief Instruction operand format
+ *
+ * Stores the kind and the expected data type
+ * of an operand. Used when parsing instructions.
+ */
+ struct DxbcInstOperandFormat {
+ DxbcOperandKind kind;
+ DxbcScalarType type;
+ };
+
+ /**
+ * \brief Instruction format
+ *
+ * Defines the instruction class as well as
+ * the format of the insttruction operands.
+ */
+ struct DxbcInstFormat {
+ uint32_t operandCount = 0;
+ DxbcInstClass instructionClass = DxbcInstClass::Undefined;
+ DxbcInstOperandFormat operands[DxbcMaxOperandCount];
+ };
+
+ /**
+ * \brief Retrieves instruction format info
+ *
+ * \param [in] opcode The opcode to retrieve
+ * \returns Instruction format info
+ */
+ DxbcInstFormat dxbcInstructionFormat(DxbcOpcode opcode);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_enums.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_enums.h
new file mode 100644
index 00000000..214780d0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_enums.h
@@ -0,0 +1,635 @@
+#pragma once
+
+#include "dxbc_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Instruction code listing
+ */
+ enum class DxbcOpcode : uint32_t {
+ Add = 0,
+ And = 1,
+ Break = 2,
+ Breakc = 3,
+ Call = 4,
+ Callc = 5,
+ Case = 6,
+ Continue = 7,
+ Continuec = 8,
+ Cut = 9,
+ Default = 10,
+ DerivRtx = 11,
+ DerivRty = 12,
+ Discard = 13,
+ Div = 14,
+ Dp2 = 15,
+ Dp3 = 16,
+ Dp4 = 17,
+ Else = 18,
+ Emit = 19,
+ EmitThenCut = 20,
+ EndIf = 21,
+ EndLoop = 22,
+ EndSwitch = 23,
+ Eq = 24,
+ Exp = 25,
+ Frc = 26,
+ FtoI = 27,
+ FtoU = 28,
+ Ge = 29,
+ IAdd = 30,
+ If = 31,
+ IEq = 32,
+ IGe = 33,
+ ILt = 34,
+ IMad = 35,
+ IMax = 36,
+ IMin = 37,
+ IMul = 38,
+ INe = 39,
+ INeg = 40,
+ IShl = 41,
+ IShr = 42,
+ ItoF = 43,
+ Label = 44,
+ Ld = 45,
+ LdMs = 46,
+ Log = 47,
+ Loop = 48,
+ Lt = 49,
+ Mad = 50,
+ Min = 51,
+ Max = 52,
+ CustomData = 53,
+ Mov = 54,
+ Movc = 55,
+ Mul = 56,
+ Ne = 57,
+ Nop = 58,
+ Not = 59,
+ Or = 60,
+ ResInfo = 61,
+ Ret = 62,
+ Retc = 63,
+ RoundNe = 64,
+ RoundNi = 65,
+ RoundPi = 66,
+ RoundZ = 67,
+ Rsq = 68,
+ Sample = 69,
+ SampleC = 70,
+ SampleClz = 71,
+ SampleL = 72,
+ SampleD = 73,
+ SampleB = 74,
+ Sqrt = 75,
+ Switch = 76,
+ SinCos = 77,
+ UDiv = 78,
+ ULt = 79,
+ UGe = 80,
+ UMul = 81,
+ UMad = 82,
+ UMax = 83,
+ UMin = 84,
+ UShr = 85,
+ UtoF = 86,
+ Xor = 87,
+ DclResource = 88,
+ DclConstantBuffer = 89,
+ DclSampler = 90,
+ DclIndexRange = 91,
+ DclGsOutputPrimitiveTopology = 92,
+ DclGsInputPrimitive = 93,
+ DclMaxOutputVertexCount = 94,
+ DclInput = 95,
+ DclInputSgv = 96,
+ DclInputSiv = 97,
+ DclInputPs = 98,
+ DclInputPsSgv = 99,
+ DclInputPsSiv = 100,
+ DclOutput = 101,
+ DclOutputSgv = 102,
+ DclOutputSiv = 103,
+ DclTemps = 104,
+ DclIndexableTemp = 105,
+ DclGlobalFlags = 106,
+ Reserved0 = 107,
+ Lod = 108,
+ Gather4 = 109,
+ SamplePos = 110,
+ SampleInfo = 111,
+ Reserved1 = 112,
+ HsDecls = 113,
+ HsControlPointPhase = 114,
+ HsForkPhase = 115,
+ HsJoinPhase = 116,
+ EmitStream = 117,
+ CutStream = 118,
+ EmitThenCutStream = 119,
+ InterfaceCall = 120,
+ BufInfo = 121,
+ DerivRtxCoarse = 122,
+ DerivRtxFine = 123,
+ DerivRtyCoarse = 124,
+ DerivRtyFine = 125,
+ Gather4C = 126,
+ Gather4Po = 127,
+ Gather4PoC = 128,
+ Rcp = 129,
+ F32toF16 = 130,
+ F16toF32 = 131,
+ UAddc = 132,
+ USubb = 133,
+ CountBits = 134,
+ FirstBitHi = 135,
+ FirstBitLo = 136,
+ FirstBitShi = 137,
+ UBfe = 138,
+ IBfe = 139,
+ Bfi = 140,
+ BfRev = 141,
+ Swapc = 142,
+ DclStream = 143,
+ DclFunctionBody = 144,
+ DclFunctionTable = 145,
+ DclInterface = 146,
+ DclInputControlPointCount = 147,
+ DclOutputControlPointCount = 148,
+ DclTessDomain = 149,
+ DclTessPartitioning = 150,
+ DclTessOutputPrimitive = 151,
+ DclHsMaxTessFactor = 152,
+ DclHsForkPhaseInstanceCount = 153,
+ DclHsJoinPhaseInstanceCount = 154,
+ DclThreadGroup = 155,
+ DclUavTyped = 156,
+ DclUavRaw = 157,
+ DclUavStructured = 158,
+ DclThreadGroupSharedMemoryRaw = 159,
+ DclThreadGroupSharedMemoryStructured = 160,
+ DclResourceRaw = 161,
+ DclResourceStructured = 162,
+ LdUavTyped = 163,
+ StoreUavTyped = 164,
+ LdRaw = 165,
+ StoreRaw = 166,
+ LdStructured = 167,
+ StoreStructured = 168,
+ AtomicAnd = 169,
+ AtomicOr = 170,
+ AtomicXor = 171,
+ AtomicCmpStore = 172,
+ AtomicIAdd = 173,
+ AtomicIMax = 174,
+ AtomicIMin = 175,
+ AtomicUMax = 176,
+ AtomicUMin = 177,
+ ImmAtomicAlloc = 178,
+ ImmAtomicConsume = 179,
+ ImmAtomicIAdd = 180,
+ ImmAtomicAnd = 181,
+ ImmAtomicOr = 182,
+ ImmAtomicXor = 183,
+ ImmAtomicExch = 184,
+ ImmAtomicCmpExch = 185,
+ ImmAtomicIMax = 186,
+ ImmAtomicIMin = 187,
+ ImmAtomicUMax = 188,
+ ImmAtomicUMin = 189,
+ Sync = 190,
+ DAdd = 191,
+ DMax = 192,
+ DMin = 193,
+ DMul = 194,
+ DEq = 195,
+ DGe = 196,
+ DLt = 197,
+ DNe = 198,
+ DMov = 199,
+ DMovc = 200,
+ DtoF = 201,
+ FtoD = 202,
+ EvalSnapped = 203,
+ EvalSampleIndex = 204,
+ EvalCentroid = 205,
+ DclGsInstanceCount = 206,
+ Abort = 207,
+ DebugBreak = 208,
+ ReservedBegin11_1 = 209,
+ DDiv = 210,
+ DFma = 211,
+ DRcp = 212,
+ Msad = 213,
+ DtoI = 214,
+ DtoU = 215,
+ ItoD = 216,
+ UtoD = 217,
+ };
+
+
+ /**
+ * \brief Extended opcode
+ */
+ enum class DxbcExtOpcode : uint32_t {
+ Empty = 0,
+ SampleControls = 1,
+ ResourceDim = 2,
+ ResourceReturnType = 3,
+ };
+
+
+ /**
+ * \brief Operand type
+ *
+ * Selects the 'register file' from which
+ * to retrieve an operand's value.
+ */
+ enum class DxbcOperandType : uint32_t {
+ Temp = 0,
+ Input = 1,
+ Output = 2,
+ IndexableTemp = 3,
+ Imm32 = 4,
+ Imm64 = 5,
+ Sampler = 6,
+ Resource = 7,
+ ConstantBuffer = 8,
+ ImmediateConstantBuffer = 9,
+ Label = 10,
+ InputPrimitiveId = 11,
+ OutputDepth = 12,
+ Null = 13,
+ Rasterizer = 14,
+ OutputCoverageMask = 15,
+ Stream = 16,
+ FunctionBody = 17,
+ FunctionTable = 18,
+ Interface = 19,
+ FunctionInput = 20,
+ FunctionOutput = 21,
+ OutputControlPointId = 22,
+ InputForkInstanceId = 23,
+ InputJoinInstanceId = 24,
+ InputControlPoint = 25,
+ OutputControlPoint = 26,
+ InputPatchConstant = 27,
+ InputDomainPoint = 28,
+ ThisPointer = 29,
+ UnorderedAccessView = 30,
+ ThreadGroupSharedMemory = 31,
+ InputThreadId = 32,
+ InputThreadGroupId = 33,
+ InputThreadIdInGroup = 34,
+ InputCoverageMask = 35,
+ InputThreadIndexInGroup = 36,
+ InputGsInstanceId = 37,
+ OutputDepthGe = 38,
+ OutputDepthLe = 39,
+ CycleCounter = 40,
+ OutputStencilRef = 41,
+ };
+
+
+ /**
+ * \brief Number of components
+ *
+ * Used by operands to determine whether the
+ * operand has one, four or zero components.
+ */
+ enum class DxbcComponentCount : uint32_t {
+ Component0 = 0,
+ Component1 = 1,
+ Component4 = 2,
+ };
+
+
+ /**
+ * \brief Component selection mode
+ *
+ * When an operand has four components, the
+ * component selection mode deterines which
+ * components are used for the operation.
+ */
+ enum class DxbcRegMode : uint32_t {
+ Mask = 0,
+ Swizzle = 1,
+ Select1 = 2,
+ };
+
+
+ /**
+ * \brief Index representation
+ *
+ * Determines how an operand
+ * register index is stored.
+ */
+ enum class DxbcOperandIndexRepresentation : uint32_t {
+ Imm32 = 0,
+ Imm64 = 1,
+ Relative = 2,
+ Imm32Relative = 3,
+ Imm64Relative = 4,
+ };
+
+
+ /**
+ * \brief Extended operand type
+ */
+ enum class DxbcOperandExt : uint32_t {
+ OperandModifier = 1,
+ };
+
+
+ /**
+ * \brief Resource dimension
+ * The type of a resource.
+ */
+ enum class DxbcResourceDim : uint32_t {
+ Unknown = 0,
+ Buffer = 1,
+ Texture1D = 2,
+ Texture2D = 3,
+ Texture2DMs = 4,
+ Texture3D = 5,
+ TextureCube = 6,
+ Texture1DArr = 7,
+ Texture2DArr = 8,
+ Texture2DMsArr = 9,
+ TextureCubeArr = 10,
+ RawBuffer = 11,
+ StructuredBuffer = 12,
+ };
+
+
+ /**
+ * \brief Resource return type
+ * Data type for resource read ops.
+ */
+ enum class DxbcResourceReturnType : uint32_t {
+ Unorm = 1,
+ Snorm = 2,
+ Sint = 3,
+ Uint = 4,
+ Float = 5,
+ Mixed = 6, /// ?
+ Double = 7,
+ Continued = 8, /// ?
+ Unused = 9, /// ?
+ };
+
+
+ /**
+ * \brief Register component type
+ * Data type of a register component.
+ */
+ enum class DxbcRegisterComponentType : uint32_t {
+ Unknown = 0,
+ Uint32 = 1,
+ Sint32 = 2,
+ Float32 = 3,
+ };
+
+
+ /**
+ * \brief Instruction return type
+ */
+ enum class DxbcInstructionReturnType : uint32_t {
+ Float = 0,
+ Uint = 1,
+ };
+
+
+ enum class DxbcSystemValue : uint32_t {
+ None = 0,
+ Position = 1,
+ ClipDistance = 2,
+ CullDistance = 3,
+ RenderTargetId = 4,
+ ViewportId = 5,
+ VertexId = 6,
+ PrimitiveId = 7,
+ InstanceId = 8,
+ IsFrontFace = 9,
+ SampleIndex = 10,
+ FinalQuadUeq0EdgeTessFactor = 11,
+ FinalQuadVeq0EdgeTessFactor = 12,
+ FinalQuadUeq1EdgeTessFactor = 13,
+ FinalQuadVeq1EdgeTessFactor = 14,
+ FinalQuadUInsideTessFactor = 15,
+ FinalQuadVInsideTessFactor = 16,
+ FinalTriUeq0EdgeTessFactor = 17,
+ FinalTriVeq0EdgeTessFactor = 18,
+ FinalTriWeq0EdgeTessFactor = 19,
+ FinalTriInsideTessFactor = 20,
+ FinalLineDetailTessFactor = 21,
+ FinalLineDensityTessFactor = 22,
+ Target = 64,
+ Depth = 65,
+ Coverage = 66,
+ DepthGe = 67,
+ DepthLe = 68
+ };
+
+
+ enum class DxbcInterpolationMode : uint32_t {
+ Undefined = 0,
+ Constant = 1,
+ Linear = 2,
+ LinearCentroid = 3,
+ LinearNoPerspective = 4,
+ LinearNoPerspectiveCentroid = 5,
+ LinearSample = 6,
+ LinearNoPerspectiveSample = 7,
+ };
+
+
+ enum class DxbcGlobalFlag : uint32_t {
+ RefactoringAllowed = 0,
+ DoublePrecision = 1,
+ EarlyFragmentTests = 2,
+ RawStructuredBuffers = 3,
+ };
+
+ using DxbcGlobalFlags = Flags<DxbcGlobalFlag>;
+
+ enum class DxbcZeroTest : uint32_t {
+ TestZ = 0,
+ TestNz = 1,
+ };
+
+ enum class DxbcResinfoType : uint32_t {
+ Float = 0,
+ RcpFloat = 1,
+ Uint = 2,
+ };
+
+ enum class DxbcSyncFlag : uint32_t {
+ ThreadsInGroup = 0,
+ ThreadGroupSharedMemory = 1,
+ UavMemoryGroup = 2,
+ UavMemoryGlobal = 3,
+ };
+
+ using DxbcSyncFlags = Flags<DxbcSyncFlag>;
+
+
+ /**
+ * \brief Geometry shader input primitive
+ */
+ enum class DxbcPrimitive : uint32_t {
+ Undefined = 0,
+ Point = 1,
+ Line = 2,
+ Triangle = 3,
+ LineAdj = 6,
+ TriangleAdj = 7,
+ Patch1 = 8,
+ Patch2 = 9,
+ Patch3 = 10,
+ Patch4 = 11,
+ Patch5 = 12,
+ Patch6 = 13,
+ Patch7 = 14,
+ Patch8 = 15,
+ Patch9 = 16,
+ Patch10 = 17,
+ Patch11 = 18,
+ Patch12 = 19,
+ Patch13 = 20,
+ Patch14 = 21,
+ Patch15 = 22,
+ Patch16 = 23,
+ Patch17 = 24,
+ Patch18 = 25,
+ Patch19 = 26,
+ Patch20 = 27,
+ Patch21 = 28,
+ Patch22 = 29,
+ Patch23 = 30,
+ Patch24 = 31,
+ Patch25 = 32,
+ Patch26 = 33,
+ Patch27 = 34,
+ Patch28 = 35,
+ Patch29 = 36,
+ Patch30 = 37,
+ Patch31 = 38,
+ Patch32 = 39,
+ };
+
+
+ /**
+ * \brief Geometry shader output topology
+ */
+ enum class DxbcPrimitiveTopology : uint32_t {
+ Undefined = 0,
+ PointList = 1,
+ LineList = 2,
+ LineStrip = 3,
+ TriangleList = 4,
+ TriangleStrip = 5,
+ LineListAdj = 10,
+ LineStripAdj = 11,
+ TriangleListAdj = 12,
+ TriangleStripAdj = 13,
+ };
+
+
+ /**
+ * \brief Sampler operation mode
+ */
+ enum class DxbcSamplerMode : uint32_t {
+ Default = 0,
+ Comparison = 1,
+ Mono = 2,
+ };
+
+
+ /**
+ * \brief Scalar value type
+ *
+ * Enumerates possible register component
+ * types. Scalar types are represented as
+ * a one-component vector type.
+ */
+ enum class DxbcScalarType : uint32_t {
+ Uint32 = 0,
+ Uint64 = 1,
+ Sint32 = 2,
+ Sint64 = 3,
+ Float32 = 4,
+ Float64 = 5,
+ Bool = 6,
+ };
+
+
+ /**
+ * \brief Tessellator domain
+ */
+ enum class DxbcTessDomain : uint32_t {
+ Undefined = 0,
+ Isolines = 1,
+ Triangles = 2,
+ Quads = 3,
+ };
+
+ /**
+ * \brief Tessellator partitioning
+ */
+ enum class DxbcTessPartitioning : uint32_t {
+ Undefined = 0,
+ Integer = 1,
+ Pow2 = 2,
+ FractOdd = 3,
+ FractEven = 4,
+ };
+
+ /**
+ * \brief UAV definition flags
+ */
+ enum class DxbcUavFlag : uint32_t {
+ GloballyCoherent = 0,
+ };
+
+ using DxbcUavFlags = Flags<DxbcUavFlag>;
+
+ /**
+ * \brief Tessellator output primitive
+ */
+ enum class DxbcTessOutputPrimitive : uint32_t {
+ Undefined = 0,
+ Point = 1,
+ Line = 2,
+ TriangleCw = 3,
+ TriangleCcw = 4,
+ };
+
+ /**
+ * \brief Custom data class
+ *
+ * Stores which type of custom data is
+ * referenced by the instruction.
+ */
+ enum class DxbcCustomDataClass : uint32_t {
+ Comment = 0,
+ DebugInfo = 1,
+ Opaque = 2,
+ ImmConstBuf = 3,
+ };
+
+
+ enum class DxbcResourceType : uint32_t {
+ Typed = 0,
+ Raw = 1,
+ Structured = 2,
+ };
+
+
+ enum class DxbcConstantBufferAccessType : uint32_t {
+ StaticallyIndexed = 0,
+ DynamicallyIndexed = 1,
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.cpp
new file mode 100644
index 00000000..9b5f6989
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.cpp
@@ -0,0 +1,30 @@
+#include "dxbc_header.h"
+
+namespace dxvk {
+
+ DxbcHeader::DxbcHeader(DxbcReader& reader) {
+ // FourCC at the start of the file, must be 'DXBC'
+ DxbcTag fourcc = reader.readTag();
+
+ if (fourcc != "DXBC")
+ throw DxvkError("DxbcHeader::DxbcHeader: Invalid fourcc, expected 'DXBC'");
+
+ // Stuff we don't actually need to store
+ reader.skip(4 * sizeof(uint32_t)); // Check sum
+ reader.skip(1 * sizeof(uint32_t)); // Constant 1
+ reader.skip(1 * sizeof(uint32_t)); // Bytecode length
+
+ // Number of chunks in the file
+ uint32_t chunkCount = reader.readu32();
+
+ // Chunk offsets are stored immediately after
+ for (uint32_t i = 0; i < chunkCount; i++)
+ m_chunkOffsets.push_back(reader.readu32());
+ }
+
+
+ DxbcHeader::~DxbcHeader() {
+
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.h
new file mode 100644
index 00000000..8eca0d49
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_header.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <vector>
+
+#include "dxbc_reader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXBC header
+ *
+ * Stores information about the shader file itself
+ * and the data chunks stored inside the file.
+ */
+ class DxbcHeader {
+
+ public:
+
+ DxbcHeader(DxbcReader& reader);
+ ~DxbcHeader();
+
+ /**
+ * \brief Number of chunks
+ * \returns Chunk count
+ */
+ uint32_t numChunks() const {
+ return m_chunkOffsets.size();
+ }
+
+ /**
+ * \brief Chunk offset
+ *
+ * Retrieves the offset of a chunk, in
+ * bytes, from the start of the file.
+ * \param [in] chunkId Chunk index
+ * \returns Byte offset of that chunk
+ */
+ uint32_t chunkOffset(uint32_t chunkId) const {
+ return m_chunkOffsets.at(chunkId);
+ }
+
+ private:
+
+ std::vector<uint32_t> m_chunkOffsets;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_include.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_include.h
new file mode 100644
index 00000000..9b86ade6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_include.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "../dxvk/dxvk_shader.h"
+
+#include "../util/com/com_guid.h"
+#include "../util/com/com_object.h"
+#include "../util/com/com_pointer.h"
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#include "../util/util_bit.h"
+#include "../util/util_enum.h"
+#include "../util/util_error.h"
+#include "../util/util_string.h"
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_modinfo.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_modinfo.h
new file mode 100644
index 00000000..13e733dd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_modinfo.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "dxbc_options.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Tessellation info
+ *
+ * Stores the maximum tessellation factor
+ * to export from tessellation shaders.
+ */
+ struct DxbcTessInfo {
+ float maxTessFactor;
+ };
+
+ /**
+ * \brief Xfb capture entry
+ *
+ * Stores an output variable to capture,
+ * as well as the buffer to write it to.
+ */
+ struct DxbcXfbEntry {
+ const char* semanticName;
+ uint32_t semanticIndex;
+ uint32_t componentIndex;
+ uint32_t componentCount;
+ uint32_t streamId;
+ uint32_t bufferId;
+ uint32_t offset;
+ };
+
+ /**
+ * \brief Xfb info
+ *
+ * Stores capture entries and output buffer
+ * strides. This structure must only be
+ * defined if \c entryCount is non-zero.
+ */
+ struct DxbcXfbInfo {
+ uint32_t entryCount;
+ DxbcXfbEntry entries[128];
+ uint32_t strides[4];
+ int32_t rasterizedStream;
+ };
+
+ /**
+ * \brief Shader module info
+ *
+ * Stores information which may affect shader compilation.
+ * This data can be supplied by the client API implementation.
+ */
+ struct DxbcModuleInfo {
+ DxbcOptions options;
+ DxbcTessInfo* tess;
+ DxbcXfbInfo* xfb;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.cpp
new file mode 100644
index 00000000..d406bf29
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.cpp
@@ -0,0 +1,116 @@
+#include "dxbc_analysis.h"
+#include "dxbc_compiler.h"
+#include "dxbc_module.h"
+
+namespace dxvk {
+
+ DxbcModule::DxbcModule(DxbcReader& reader)
+ : m_header(reader) {
+ for (uint32_t i = 0; i < m_header.numChunks(); i++) {
+
+ // The chunk tag is stored at the beginning of each chunk
+ auto chunkReader = reader.clone(m_header.chunkOffset(i));
+ auto tag = chunkReader.readTag();
+
+ // The chunk size follows right after the four-character
+ // code. This does not include the eight bytes that are
+ // consumed by the FourCC and chunk length entry.
+ auto chunkLength = chunkReader.readu32();
+
+ chunkReader = chunkReader.clone(8);
+ chunkReader = chunkReader.resize(chunkLength);
+
+ if ((tag == "SHDR") || (tag == "SHEX"))
+ m_shexChunk = new DxbcShex(chunkReader);
+
+ if ((tag == "ISGN") || (tag == "ISG1"))
+ m_isgnChunk = new DxbcIsgn(chunkReader, tag);
+
+ if ((tag == "OSGN") || (tag == "OSG5") || (tag == "OSG1"))
+ m_osgnChunk = new DxbcIsgn(chunkReader, tag);
+
+ if ((tag == "PCSG") || (tag == "PSG1"))
+ m_psgnChunk = new DxbcIsgn(chunkReader, tag);
+ }
+ }
+
+
+ DxbcModule::~DxbcModule() {
+
+ }
+
+
+ Rc<DxvkShader> DxbcModule::compile(
+ const DxbcModuleInfo& moduleInfo,
+ const std::string& fileName) const {
+ if (m_shexChunk == nullptr)
+ throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk");
+
+ DxbcAnalysisInfo analysisInfo;
+
+ DxbcAnalyzer analyzer(moduleInfo,
+ m_shexChunk->programInfo(),
+ m_isgnChunk, m_osgnChunk,
+ m_psgnChunk, analysisInfo);
+
+ this->runAnalyzer(analyzer, m_shexChunk->slice());
+
+ DxbcCompiler compiler(
+ fileName, moduleInfo,
+ m_shexChunk->programInfo(),
+ m_isgnChunk, m_osgnChunk,
+ m_psgnChunk, analysisInfo);
+
+ this->runCompiler(compiler, m_shexChunk->slice());
+
+ return compiler.finalize();
+ }
+
+
+ Rc<DxvkShader> DxbcModule::compilePassthroughShader(
+ const DxbcModuleInfo& moduleInfo,
+ const std::string& fileName) const {
+ if (m_shexChunk == nullptr)
+ throw DxvkError("DxbcModule::compile: No SHDR/SHEX chunk");
+
+ DxbcAnalysisInfo analysisInfo;
+
+ DxbcCompiler compiler(
+ fileName, moduleInfo,
+ DxbcProgramType::GeometryShader,
+ m_osgnChunk, m_osgnChunk,
+ m_psgnChunk, analysisInfo);
+
+ compiler.processXfbPassthrough();
+ return compiler.finalize();
+ }
+
+
+ void DxbcModule::runAnalyzer(
+ DxbcAnalyzer& analyzer,
+ DxbcCodeSlice slice) const {
+ DxbcDecodeContext decoder;
+
+ while (!slice.atEnd()) {
+ decoder.decodeInstruction(slice);
+
+ analyzer.processInstruction(
+ decoder.getInstruction());
+ }
+ }
+
+
+ void DxbcModule::runCompiler(
+ DxbcCompiler& compiler,
+ DxbcCodeSlice slice) const {
+ DxbcDecodeContext decoder;
+
+ while (!slice.atEnd()) {
+ decoder.decodeInstruction(slice);
+
+ compiler.processInstruction(
+ decoder.getInstruction());
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.h
new file mode 100644
index 00000000..d785d959
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_module.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "../dxvk/dxvk_shader.h"
+
+#include "dxbc_chunk_isgn.h"
+#include "dxbc_chunk_shex.h"
+#include "dxbc_header.h"
+#include "dxbc_modinfo.h"
+#include "dxbc_reader.h"
+
+// References used for figuring out DXBC:
+// - https://github.com/tgjones/slimshader-cpp
+// - Wine
+
+namespace dxvk {
+
+ class DxbcAnalyzer;
+ class DxbcCompiler;
+
+ /**
+ * \brief DXBC shader module
+ *
+ * Reads the DXBC byte code and extracts information
+ * about the resource bindings and the instruction
+ * stream. A module can then be compiled to SPIR-V.
+ */
+ class DxbcModule {
+
+ public:
+
+ DxbcModule(DxbcReader& reader);
+ ~DxbcModule();
+
+ /**
+ * \brief Shader type
+ * \returns Shader type
+ */
+ DxbcProgramInfo programInfo() const {
+ return m_shexChunk->programInfo();
+ }
+
+ /**
+ * \brief Input and output signature chunks
+ *
+ * Parts of the D3D11 API need access to the
+ * input or output signature of the shader.
+ */
+ Rc<DxbcIsgn> isgn() const { return m_isgnChunk; }
+ Rc<DxbcIsgn> osgn() const { return m_osgnChunk; }
+
+ /**
+ * \brief Compiles DXBC shader to SPIR-V module
+ *
+ * \param [in] moduleInfo DXBC module info
+ * \param [in] fileName File name, will be added to
+ * the compiled SPIR-V for debugging purposes.
+ * \returns The compiled shader object
+ */
+ Rc<DxvkShader> compile(
+ const DxbcModuleInfo& moduleInfo,
+ const std::string& fileName) const;
+
+ /**
+ * \brief Compiles a pass-through geometry shader
+ *
+ * Applications can pass a vertex shader to create
+ * a geometry shader with stream output. In this
+ * case, we have to create a passthrough geometry
+ * shader, which operates in point to point mode.
+ * \param [in] moduleInfo DXBC module info
+ * \param [in] fileName SPIR-V shader name
+ */
+ Rc<DxvkShader> compilePassthroughShader(
+ const DxbcModuleInfo& moduleInfo,
+ const std::string& fileName) const;
+
+ private:
+
+ DxbcHeader m_header;
+
+ Rc<DxbcIsgn> m_isgnChunk;
+ Rc<DxbcIsgn> m_osgnChunk;
+ Rc<DxbcIsgn> m_psgnChunk;
+ Rc<DxbcShex> m_shexChunk;
+
+ void runAnalyzer(
+ DxbcAnalyzer& analyzer,
+ DxbcCodeSlice slice) const;
+
+ void runCompiler(
+ DxbcCompiler& compiler,
+ DxbcCodeSlice slice) const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.cpp
new file mode 100644
index 00000000..c6a00ecc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.cpp
@@ -0,0 +1,445 @@
+#include "dxbc_names.h"
+
+namespace dxvk {
+
+ std::ostream& operator << (std::ostream& os, DxbcOpcode e) {
+ switch (e) {
+ ENUM_NAME(DxbcOpcode::Add);
+ ENUM_NAME(DxbcOpcode::And);
+ ENUM_NAME(DxbcOpcode::Break);
+ ENUM_NAME(DxbcOpcode::Breakc);
+ ENUM_NAME(DxbcOpcode::Call);
+ ENUM_NAME(DxbcOpcode::Callc);
+ ENUM_NAME(DxbcOpcode::Case);
+ ENUM_NAME(DxbcOpcode::Continue);
+ ENUM_NAME(DxbcOpcode::Continuec);
+ ENUM_NAME(DxbcOpcode::Cut);
+ ENUM_NAME(DxbcOpcode::Default);
+ ENUM_NAME(DxbcOpcode::DerivRtx);
+ ENUM_NAME(DxbcOpcode::DerivRty);
+ ENUM_NAME(DxbcOpcode::Discard);
+ ENUM_NAME(DxbcOpcode::Div);
+ ENUM_NAME(DxbcOpcode::Dp2);
+ ENUM_NAME(DxbcOpcode::Dp3);
+ ENUM_NAME(DxbcOpcode::Dp4);
+ ENUM_NAME(DxbcOpcode::Else);
+ ENUM_NAME(DxbcOpcode::Emit);
+ ENUM_NAME(DxbcOpcode::EmitThenCut);
+ ENUM_NAME(DxbcOpcode::EndIf);
+ ENUM_NAME(DxbcOpcode::EndLoop);
+ ENUM_NAME(DxbcOpcode::EndSwitch);
+ ENUM_NAME(DxbcOpcode::Eq);
+ ENUM_NAME(DxbcOpcode::Exp);
+ ENUM_NAME(DxbcOpcode::Frc);
+ ENUM_NAME(DxbcOpcode::FtoI);
+ ENUM_NAME(DxbcOpcode::FtoU);
+ ENUM_NAME(DxbcOpcode::Ge);
+ ENUM_NAME(DxbcOpcode::IAdd);
+ ENUM_NAME(DxbcOpcode::If);
+ ENUM_NAME(DxbcOpcode::IEq);
+ ENUM_NAME(DxbcOpcode::IGe);
+ ENUM_NAME(DxbcOpcode::ILt);
+ ENUM_NAME(DxbcOpcode::IMad);
+ ENUM_NAME(DxbcOpcode::IMax);
+ ENUM_NAME(DxbcOpcode::IMin);
+ ENUM_NAME(DxbcOpcode::IMul);
+ ENUM_NAME(DxbcOpcode::INe);
+ ENUM_NAME(DxbcOpcode::INeg);
+ ENUM_NAME(DxbcOpcode::IShl);
+ ENUM_NAME(DxbcOpcode::IShr);
+ ENUM_NAME(DxbcOpcode::ItoF);
+ ENUM_NAME(DxbcOpcode::Label);
+ ENUM_NAME(DxbcOpcode::Ld);
+ ENUM_NAME(DxbcOpcode::LdMs);
+ ENUM_NAME(DxbcOpcode::Log);
+ ENUM_NAME(DxbcOpcode::Loop);
+ ENUM_NAME(DxbcOpcode::Lt);
+ ENUM_NAME(DxbcOpcode::Mad);
+ ENUM_NAME(DxbcOpcode::Min);
+ ENUM_NAME(DxbcOpcode::Max);
+ ENUM_NAME(DxbcOpcode::CustomData);
+ ENUM_NAME(DxbcOpcode::Mov);
+ ENUM_NAME(DxbcOpcode::Movc);
+ ENUM_NAME(DxbcOpcode::Mul);
+ ENUM_NAME(DxbcOpcode::Ne);
+ ENUM_NAME(DxbcOpcode::Nop);
+ ENUM_NAME(DxbcOpcode::Not);
+ ENUM_NAME(DxbcOpcode::Or);
+ ENUM_NAME(DxbcOpcode::ResInfo);
+ ENUM_NAME(DxbcOpcode::Ret);
+ ENUM_NAME(DxbcOpcode::Retc);
+ ENUM_NAME(DxbcOpcode::RoundNe);
+ ENUM_NAME(DxbcOpcode::RoundNi);
+ ENUM_NAME(DxbcOpcode::RoundPi);
+ ENUM_NAME(DxbcOpcode::RoundZ);
+ ENUM_NAME(DxbcOpcode::Rsq);
+ ENUM_NAME(DxbcOpcode::Sample);
+ ENUM_NAME(DxbcOpcode::SampleC);
+ ENUM_NAME(DxbcOpcode::SampleClz);
+ ENUM_NAME(DxbcOpcode::SampleL);
+ ENUM_NAME(DxbcOpcode::SampleD);
+ ENUM_NAME(DxbcOpcode::SampleB);
+ ENUM_NAME(DxbcOpcode::Sqrt);
+ ENUM_NAME(DxbcOpcode::Switch);
+ ENUM_NAME(DxbcOpcode::SinCos);
+ ENUM_NAME(DxbcOpcode::UDiv);
+ ENUM_NAME(DxbcOpcode::ULt);
+ ENUM_NAME(DxbcOpcode::UGe);
+ ENUM_NAME(DxbcOpcode::UMul);
+ ENUM_NAME(DxbcOpcode::UMad);
+ ENUM_NAME(DxbcOpcode::UMax);
+ ENUM_NAME(DxbcOpcode::UMin);
+ ENUM_NAME(DxbcOpcode::UShr);
+ ENUM_NAME(DxbcOpcode::UtoF);
+ ENUM_NAME(DxbcOpcode::Xor);
+ ENUM_NAME(DxbcOpcode::DclResource);
+ ENUM_NAME(DxbcOpcode::DclConstantBuffer);
+ ENUM_NAME(DxbcOpcode::DclSampler);
+ ENUM_NAME(DxbcOpcode::DclIndexRange);
+ ENUM_NAME(DxbcOpcode::DclGsOutputPrimitiveTopology);
+ ENUM_NAME(DxbcOpcode::DclGsInputPrimitive);
+ ENUM_NAME(DxbcOpcode::DclMaxOutputVertexCount);
+ ENUM_NAME(DxbcOpcode::DclInput);
+ ENUM_NAME(DxbcOpcode::DclInputSgv);
+ ENUM_NAME(DxbcOpcode::DclInputSiv);
+ ENUM_NAME(DxbcOpcode::DclInputPs);
+ ENUM_NAME(DxbcOpcode::DclInputPsSgv);
+ ENUM_NAME(DxbcOpcode::DclInputPsSiv);
+ ENUM_NAME(DxbcOpcode::DclOutput);
+ ENUM_NAME(DxbcOpcode::DclOutputSgv);
+ ENUM_NAME(DxbcOpcode::DclOutputSiv);
+ ENUM_NAME(DxbcOpcode::DclTemps);
+ ENUM_NAME(DxbcOpcode::DclIndexableTemp);
+ ENUM_NAME(DxbcOpcode::DclGlobalFlags);
+ ENUM_NAME(DxbcOpcode::Reserved0);
+ ENUM_NAME(DxbcOpcode::Lod);
+ ENUM_NAME(DxbcOpcode::Gather4);
+ ENUM_NAME(DxbcOpcode::SamplePos);
+ ENUM_NAME(DxbcOpcode::SampleInfo);
+ ENUM_NAME(DxbcOpcode::Reserved1);
+ ENUM_NAME(DxbcOpcode::HsDecls);
+ ENUM_NAME(DxbcOpcode::HsControlPointPhase);
+ ENUM_NAME(DxbcOpcode::HsForkPhase);
+ ENUM_NAME(DxbcOpcode::HsJoinPhase);
+ ENUM_NAME(DxbcOpcode::EmitStream);
+ ENUM_NAME(DxbcOpcode::CutStream);
+ ENUM_NAME(DxbcOpcode::EmitThenCutStream);
+ ENUM_NAME(DxbcOpcode::InterfaceCall);
+ ENUM_NAME(DxbcOpcode::BufInfo);
+ ENUM_NAME(DxbcOpcode::DerivRtxCoarse);
+ ENUM_NAME(DxbcOpcode::DerivRtxFine);
+ ENUM_NAME(DxbcOpcode::DerivRtyCoarse);
+ ENUM_NAME(DxbcOpcode::DerivRtyFine);
+ ENUM_NAME(DxbcOpcode::Gather4C);
+ ENUM_NAME(DxbcOpcode::Gather4Po);
+ ENUM_NAME(DxbcOpcode::Gather4PoC);
+ ENUM_NAME(DxbcOpcode::Rcp);
+ ENUM_NAME(DxbcOpcode::F32toF16);
+ ENUM_NAME(DxbcOpcode::F16toF32);
+ ENUM_NAME(DxbcOpcode::UAddc);
+ ENUM_NAME(DxbcOpcode::USubb);
+ ENUM_NAME(DxbcOpcode::CountBits);
+ ENUM_NAME(DxbcOpcode::FirstBitHi);
+ ENUM_NAME(DxbcOpcode::FirstBitLo);
+ ENUM_NAME(DxbcOpcode::FirstBitShi);
+ ENUM_NAME(DxbcOpcode::UBfe);
+ ENUM_NAME(DxbcOpcode::IBfe);
+ ENUM_NAME(DxbcOpcode::Bfi);
+ ENUM_NAME(DxbcOpcode::BfRev);
+ ENUM_NAME(DxbcOpcode::Swapc);
+ ENUM_NAME(DxbcOpcode::DclStream);
+ ENUM_NAME(DxbcOpcode::DclFunctionBody);
+ ENUM_NAME(DxbcOpcode::DclFunctionTable);
+ ENUM_NAME(DxbcOpcode::DclInterface);
+ ENUM_NAME(DxbcOpcode::DclInputControlPointCount);
+ ENUM_NAME(DxbcOpcode::DclOutputControlPointCount);
+ ENUM_NAME(DxbcOpcode::DclTessDomain);
+ ENUM_NAME(DxbcOpcode::DclTessPartitioning);
+ ENUM_NAME(DxbcOpcode::DclTessOutputPrimitive);
+ ENUM_NAME(DxbcOpcode::DclHsMaxTessFactor);
+ ENUM_NAME(DxbcOpcode::DclHsForkPhaseInstanceCount);
+ ENUM_NAME(DxbcOpcode::DclHsJoinPhaseInstanceCount);
+ ENUM_NAME(DxbcOpcode::DclThreadGroup);
+ ENUM_NAME(DxbcOpcode::DclUavTyped);
+ ENUM_NAME(DxbcOpcode::DclUavRaw);
+ ENUM_NAME(DxbcOpcode::DclUavStructured);
+ ENUM_NAME(DxbcOpcode::DclThreadGroupSharedMemoryRaw);
+ ENUM_NAME(DxbcOpcode::DclThreadGroupSharedMemoryStructured);
+ ENUM_NAME(DxbcOpcode::DclResourceRaw);
+ ENUM_NAME(DxbcOpcode::DclResourceStructured);
+ ENUM_NAME(DxbcOpcode::LdUavTyped);
+ ENUM_NAME(DxbcOpcode::StoreUavTyped);
+ ENUM_NAME(DxbcOpcode::LdRaw);
+ ENUM_NAME(DxbcOpcode::StoreRaw);
+ ENUM_NAME(DxbcOpcode::LdStructured);
+ ENUM_NAME(DxbcOpcode::StoreStructured);
+ ENUM_NAME(DxbcOpcode::AtomicAnd);
+ ENUM_NAME(DxbcOpcode::AtomicOr);
+ ENUM_NAME(DxbcOpcode::AtomicXor);
+ ENUM_NAME(DxbcOpcode::AtomicCmpStore);
+ ENUM_NAME(DxbcOpcode::AtomicIAdd);
+ ENUM_NAME(DxbcOpcode::AtomicIMax);
+ ENUM_NAME(DxbcOpcode::AtomicIMin);
+ ENUM_NAME(DxbcOpcode::AtomicUMax);
+ ENUM_NAME(DxbcOpcode::AtomicUMin);
+ ENUM_NAME(DxbcOpcode::ImmAtomicAlloc);
+ ENUM_NAME(DxbcOpcode::ImmAtomicConsume);
+ ENUM_NAME(DxbcOpcode::ImmAtomicIAdd);
+ ENUM_NAME(DxbcOpcode::ImmAtomicAnd);
+ ENUM_NAME(DxbcOpcode::ImmAtomicOr);
+ ENUM_NAME(DxbcOpcode::ImmAtomicXor);
+ ENUM_NAME(DxbcOpcode::ImmAtomicExch);
+ ENUM_NAME(DxbcOpcode::ImmAtomicCmpExch);
+ ENUM_NAME(DxbcOpcode::ImmAtomicIMax);
+ ENUM_NAME(DxbcOpcode::ImmAtomicIMin);
+ ENUM_NAME(DxbcOpcode::ImmAtomicUMax);
+ ENUM_NAME(DxbcOpcode::ImmAtomicUMin);
+ ENUM_NAME(DxbcOpcode::Sync);
+ ENUM_NAME(DxbcOpcode::DAdd);
+ ENUM_NAME(DxbcOpcode::DMax);
+ ENUM_NAME(DxbcOpcode::DMin);
+ ENUM_NAME(DxbcOpcode::DMul);
+ ENUM_NAME(DxbcOpcode::DEq);
+ ENUM_NAME(DxbcOpcode::DGe);
+ ENUM_NAME(DxbcOpcode::DLt);
+ ENUM_NAME(DxbcOpcode::DNe);
+ ENUM_NAME(DxbcOpcode::DMov);
+ ENUM_NAME(DxbcOpcode::DMovc);
+ ENUM_NAME(DxbcOpcode::DtoF);
+ ENUM_NAME(DxbcOpcode::FtoD);
+ ENUM_NAME(DxbcOpcode::EvalSnapped);
+ ENUM_NAME(DxbcOpcode::EvalSampleIndex);
+ ENUM_NAME(DxbcOpcode::EvalCentroid);
+ ENUM_NAME(DxbcOpcode::DclGsInstanceCount);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcExtOpcode e) {
+ switch (e) {
+ ENUM_NAME(DxbcExtOpcode::Empty);
+ ENUM_NAME(DxbcExtOpcode::SampleControls);
+ ENUM_NAME(DxbcExtOpcode::ResourceDim);
+ ENUM_NAME(DxbcExtOpcode::ResourceReturnType);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcOperandType e) {
+ switch (e) {
+ ENUM_NAME(DxbcOperandType::Temp);
+ ENUM_NAME(DxbcOperandType::Input);
+ ENUM_NAME(DxbcOperandType::Output);
+ ENUM_NAME(DxbcOperandType::IndexableTemp);
+ ENUM_NAME(DxbcOperandType::Imm32);
+ ENUM_NAME(DxbcOperandType::Imm64);
+ ENUM_NAME(DxbcOperandType::Sampler);
+ ENUM_NAME(DxbcOperandType::Resource);
+ ENUM_NAME(DxbcOperandType::ConstantBuffer);
+ ENUM_NAME(DxbcOperandType::ImmediateConstantBuffer);
+ ENUM_NAME(DxbcOperandType::Label);
+ ENUM_NAME(DxbcOperandType::InputPrimitiveId);
+ ENUM_NAME(DxbcOperandType::OutputDepth);
+ ENUM_NAME(DxbcOperandType::Null);
+ ENUM_NAME(DxbcOperandType::Rasterizer);
+ ENUM_NAME(DxbcOperandType::OutputCoverageMask);
+ ENUM_NAME(DxbcOperandType::Stream);
+ ENUM_NAME(DxbcOperandType::FunctionBody);
+ ENUM_NAME(DxbcOperandType::FunctionTable);
+ ENUM_NAME(DxbcOperandType::Interface);
+ ENUM_NAME(DxbcOperandType::FunctionInput);
+ ENUM_NAME(DxbcOperandType::FunctionOutput);
+ ENUM_NAME(DxbcOperandType::OutputControlPointId);
+ ENUM_NAME(DxbcOperandType::InputForkInstanceId);
+ ENUM_NAME(DxbcOperandType::InputJoinInstanceId);
+ ENUM_NAME(DxbcOperandType::InputControlPoint);
+ ENUM_NAME(DxbcOperandType::OutputControlPoint);
+ ENUM_NAME(DxbcOperandType::InputPatchConstant);
+ ENUM_NAME(DxbcOperandType::InputDomainPoint);
+ ENUM_NAME(DxbcOperandType::ThisPointer);
+ ENUM_NAME(DxbcOperandType::UnorderedAccessView);
+ ENUM_NAME(DxbcOperandType::ThreadGroupSharedMemory);
+ ENUM_NAME(DxbcOperandType::InputThreadId);
+ ENUM_NAME(DxbcOperandType::InputThreadGroupId);
+ ENUM_NAME(DxbcOperandType::InputThreadIdInGroup);
+ ENUM_NAME(DxbcOperandType::InputCoverageMask);
+ ENUM_NAME(DxbcOperandType::InputThreadIndexInGroup);
+ ENUM_NAME(DxbcOperandType::InputGsInstanceId);
+ ENUM_NAME(DxbcOperandType::OutputDepthGe);
+ ENUM_NAME(DxbcOperandType::OutputDepthLe);
+ ENUM_NAME(DxbcOperandType::CycleCounter);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandExt e) {
+ switch (e) {
+ ENUM_NAME(DxbcOperandExt::OperandModifier);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcComponentCount e) {
+ switch (e) {
+ ENUM_NAME(DxbcComponentCount::Component0);
+ ENUM_NAME(DxbcComponentCount::Component1);
+ ENUM_NAME(DxbcComponentCount::Component4);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcRegMode e) {
+ switch (e) {
+ ENUM_NAME(DxbcRegMode::Mask);
+ ENUM_NAME(DxbcRegMode::Swizzle);
+ ENUM_NAME(DxbcRegMode::Select1);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcOperandIndexRepresentation e) {
+ switch (e) {
+ ENUM_NAME(DxbcOperandIndexRepresentation::Imm32);
+ ENUM_NAME(DxbcOperandIndexRepresentation::Imm64);
+ ENUM_NAME(DxbcOperandIndexRepresentation::Relative);
+ ENUM_NAME(DxbcOperandIndexRepresentation::Imm32Relative);
+ ENUM_NAME(DxbcOperandIndexRepresentation::Imm64Relative);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcResourceDim e) {
+ switch (e) {
+ ENUM_NAME(DxbcResourceDim::Unknown);
+ ENUM_NAME(DxbcResourceDim::Buffer);
+ ENUM_NAME(DxbcResourceDim::Texture1D);
+ ENUM_NAME(DxbcResourceDim::Texture2D);
+ ENUM_NAME(DxbcResourceDim::Texture2DMs);
+ ENUM_NAME(DxbcResourceDim::Texture3D);
+ ENUM_NAME(DxbcResourceDim::TextureCube);
+ ENUM_NAME(DxbcResourceDim::Texture1DArr);
+ ENUM_NAME(DxbcResourceDim::Texture2DArr);
+ ENUM_NAME(DxbcResourceDim::Texture2DMsArr);
+ ENUM_NAME(DxbcResourceDim::TextureCubeArr);
+ ENUM_NAME(DxbcResourceDim::RawBuffer);
+ ENUM_NAME(DxbcResourceDim::StructuredBuffer);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcResourceReturnType e) {
+ switch (e) {
+ ENUM_NAME(DxbcResourceReturnType::Unorm);
+ ENUM_NAME(DxbcResourceReturnType::Snorm);
+ ENUM_NAME(DxbcResourceReturnType::Sint);
+ ENUM_NAME(DxbcResourceReturnType::Uint);
+ ENUM_NAME(DxbcResourceReturnType::Float);
+ ENUM_NAME(DxbcResourceReturnType::Mixed);
+ ENUM_NAME(DxbcResourceReturnType::Double);
+ ENUM_NAME(DxbcResourceReturnType::Continued);
+ ENUM_NAME(DxbcResourceReturnType::Unused);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcRegisterComponentType e) {
+ switch (e) {
+ ENUM_NAME(DxbcRegisterComponentType::Unknown);
+ ENUM_NAME(DxbcRegisterComponentType::Uint32);
+ ENUM_NAME(DxbcRegisterComponentType::Sint32);
+ ENUM_NAME(DxbcRegisterComponentType::Float32);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcInstructionReturnType e) {
+ switch (e) {
+ ENUM_NAME(DxbcInstructionReturnType::Float);
+ ENUM_NAME(DxbcInstructionReturnType::Uint);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, DxbcSystemValue e) {
+ switch (e) {
+ ENUM_NAME(DxbcSystemValue::None);
+ ENUM_NAME(DxbcSystemValue::Position);
+ ENUM_NAME(DxbcSystemValue::ClipDistance);
+ ENUM_NAME(DxbcSystemValue::CullDistance);
+ ENUM_NAME(DxbcSystemValue::RenderTargetId);
+ ENUM_NAME(DxbcSystemValue::ViewportId);
+ ENUM_NAME(DxbcSystemValue::VertexId);
+ ENUM_NAME(DxbcSystemValue::PrimitiveId);
+ ENUM_NAME(DxbcSystemValue::InstanceId);
+ ENUM_NAME(DxbcSystemValue::IsFrontFace);
+ ENUM_NAME(DxbcSystemValue::SampleIndex);
+ ENUM_NAME(DxbcSystemValue::FinalQuadUeq0EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalQuadVeq0EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalQuadUeq1EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalQuadVeq1EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalQuadUInsideTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalQuadVInsideTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalTriUeq0EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalTriVeq0EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalTriWeq0EdgeTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalTriInsideTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalLineDetailTessFactor);
+ ENUM_NAME(DxbcSystemValue::FinalLineDensityTessFactor);
+ ENUM_NAME(DxbcSystemValue::Target);
+ ENUM_NAME(DxbcSystemValue::Depth);
+ ENUM_NAME(DxbcSystemValue::Coverage);
+ ENUM_NAME(DxbcSystemValue::DepthGe);
+ ENUM_NAME(DxbcSystemValue::DepthLe);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+ std::ostream& operator << (std::ostream& os, dxvk::DxbcProgramType e) {
+ switch (e) {
+ ENUM_NAME(DxbcProgramType::PixelShader);
+ ENUM_NAME(DxbcProgramType::VertexShader);
+ ENUM_NAME(DxbcProgramType::GeometryShader);
+ ENUM_NAME(DxbcProgramType::HullShader);
+ ENUM_NAME(DxbcProgramType::DomainShader);
+ ENUM_NAME(DxbcProgramType::ComputeShader);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+ std::ostream& operator << (std::ostream& os, dxvk::DxbcCustomDataClass e) {
+ switch (e) {
+ ENUM_NAME(DxbcCustomDataClass::Comment);
+ ENUM_NAME(DxbcCustomDataClass::DebugInfo);
+ ENUM_NAME(DxbcCustomDataClass::Opaque);
+ ENUM_NAME(DxbcCustomDataClass::ImmConstBuf);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+ std::ostream& operator << (std::ostream& os, dxvk::DxbcScalarType e) {
+ switch (e) {
+ ENUM_NAME(DxbcScalarType::Uint32);
+ ENUM_NAME(DxbcScalarType::Uint64);
+ ENUM_NAME(DxbcScalarType::Sint32);
+ ENUM_NAME(DxbcScalarType::Sint64);
+ ENUM_NAME(DxbcScalarType::Float32);
+ ENUM_NAME(DxbcScalarType::Float64);
+ ENUM_NAME(DxbcScalarType::Bool);
+ ENUM_DEFAULT(e);
+ }
+ }
+
+
+} //namespace dxvk
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.h
new file mode 100644
index 00000000..52235ae5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_names.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <ostream>
+
+#include "dxbc_common.h"
+#include "dxbc_enums.h"
+
+namespace dxvk {
+
+ std::ostream& operator << (std::ostream& os, DxbcOpcode e);
+ std::ostream& operator << (std::ostream& os, DxbcExtOpcode e);
+ std::ostream& operator << (std::ostream& os, DxbcOperandType e);
+ std::ostream& operator << (std::ostream& os, DxbcOperandExt e);
+ std::ostream& operator << (std::ostream& os, DxbcComponentCount e);
+ std::ostream& operator << (std::ostream& os, DxbcRegMode e);
+ std::ostream& operator << (std::ostream& os, DxbcOperandIndexRepresentation e);
+ std::ostream& operator << (std::ostream& os, DxbcResourceDim e);
+ std::ostream& operator << (std::ostream& os, DxbcResourceReturnType e);
+ std::ostream& operator << (std::ostream& os, DxbcRegisterComponentType e);
+ std::ostream& operator << (std::ostream& os, DxbcInstructionReturnType e);
+ std::ostream& operator << (std::ostream& os, DxbcSystemValue e);
+ std::ostream& operator << (std::ostream& os, DxbcProgramType e);
+ std::ostream& operator << (std::ostream& os, DxbcCustomDataClass e);
+ std::ostream& operator << (std::ostream& os, DxbcScalarType e);
+
+} // namespace dxvk
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.cpp
new file mode 100644
index 00000000..fc89f74b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.cpp
@@ -0,0 +1,71 @@
+#include "../d3d11/d3d11_options.h"
+
+#include "dxbc_options.h"
+
+namespace dxvk {
+
+ DxbcOptions::DxbcOptions() {
+
+ }
+
+
+ DxbcOptions::DxbcOptions(const Rc<DxvkDevice>& device, const D3D11Options& options) {
+ const Rc<DxvkAdapter> adapter = device->adapter();
+
+ const DxvkDeviceFeatures& devFeatures = device->features();
+ const DxvkDeviceInfo& devInfo = adapter->devicePropertiesExt();
+
+ useDepthClipWorkaround
+ = !devFeatures.extDepthClipEnable.depthClipEnable;
+ useStorageImageReadWithoutFormat
+ = devFeatures.core.features.shaderStorageImageReadWithoutFormat;
+ useSubgroupOpsForAtomicCounters
+ = (devInfo.coreSubgroup.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
+ && (devInfo.coreSubgroup.supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
+ useDemoteToHelperInvocation
+ = (devFeatures.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation);
+ useSubgroupOpsForEarlyDiscard
+ = (devInfo.coreSubgroup.subgroupSize >= 4)
+ && (devInfo.coreSubgroup.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT)
+ && (devInfo.coreSubgroup.supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
+ useSdivForBufferIndex
+ = adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0);
+
+ switch (device->config().useRawSsbo) {
+ case Tristate::Auto: minSsboAlignment = devInfo.core.properties.limits.minStorageBufferOffsetAlignment; break;
+ case Tristate::True: minSsboAlignment = 4u; break;
+ case Tristate::False: minSsboAlignment = ~0u; break;
+ }
+
+ invariantPosition = options.invariantPosition;
+ enableRtOutputNanFixup = options.enableRtOutputNanFixup;
+ zeroInitWorkgroupMemory = options.zeroInitWorkgroupMemory;
+ forceTgsmBarriers = options.forceTgsmBarriers;
+ disableMsaa = options.disableMsaa;
+ dynamicIndexedConstantBufferAsSsbo = options.constantBufferRangeCheck;
+
+ // Disable subgroup early discard on Nvidia because it may hurt performance
+ if (adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0))
+ useSubgroupOpsForEarlyDiscard = false;
+
+ // Figure out float control flags to match D3D11 rules
+ if (options.floatControls) {
+ if (devInfo.khrShaderFloatControls.shaderSignedZeroInfNanPreserveFloat32)
+ floatControl.set(DxbcFloatControlFlag::PreserveNan32);
+ if (devInfo.khrShaderFloatControls.shaderSignedZeroInfNanPreserveFloat64)
+ floatControl.set(DxbcFloatControlFlag::PreserveNan64);
+
+ if (devInfo.khrShaderFloatControls.denormBehaviorIndependence != VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE) {
+ if (devInfo.khrShaderFloatControls.shaderDenormFlushToZeroFloat32)
+ floatControl.set(DxbcFloatControlFlag::DenormFlushToZero32);
+ if (devInfo.khrShaderFloatControls.shaderDenormPreserveFloat64)
+ floatControl.set(DxbcFloatControlFlag::DenormPreserve64);
+ }
+ }
+
+ if (!devInfo.khrShaderFloatControls.shaderSignedZeroInfNanPreserveFloat32
+ || adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_MESA_RADV_KHR, 0, VK_MAKE_VERSION(20, 3, 0)))
+ enableRtOutputNanFixup = true;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.h
new file mode 100644
index 00000000..d21f3b1a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_options.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+
+namespace dxvk {
+
+ struct D3D11Options;
+
+ enum class DxbcFloatControlFlag : uint32_t {
+ DenormFlushToZero32,
+ DenormPreserve64,
+ PreserveNan32,
+ PreserveNan64,
+ };
+
+ using DxbcFloatControlFlags = Flags<DxbcFloatControlFlag>;
+
+ struct DxbcOptions {
+ DxbcOptions();
+ DxbcOptions(const Rc<DxvkDevice>& device, const D3D11Options& options);
+
+ // Clamp oDepth in fragment shaders if the depth
+ // clip device feature is not supported
+ bool useDepthClipWorkaround = false;
+
+ /// Use the ShaderImageReadWithoutFormat capability.
+ bool useStorageImageReadWithoutFormat = false;
+
+ /// Use subgroup operations to reduce the number of
+ /// atomic operations for append/consume buffers.
+ bool useSubgroupOpsForAtomicCounters = false;
+
+ /// Use a SPIR-V extension to implement D3D-style discards
+ bool useDemoteToHelperInvocation = false;
+
+ /// Use subgroup operations to discard fragment
+ /// shader invocations if derivatives remain valid.
+ bool useSubgroupOpsForEarlyDiscard = false;
+
+ /// Use SDiv instead of SHR to converte byte offsets to
+ /// dword offsets. Fixes RE2 and DMC5 on Nvidia drivers.
+ bool useSdivForBufferIndex = false;
+
+ /// Enables NaN fixup for render target outputs
+ bool enableRtOutputNanFixup = false;
+
+ /// Implement dynamically indexed uniform buffers
+ /// with storage buffers for tight bounds checking
+ bool dynamicIndexedConstantBufferAsSsbo = false;
+
+ /// Clear thread-group shared memory to zero
+ bool zeroInitWorkgroupMemory = false;
+
+ /// Declare vertex positions as invariant
+ bool invariantPosition = false;
+
+ /// Insert memory barriers after TGSM stoes
+ bool forceTgsmBarriers = false;
+
+ /// Replace ld_ms with ld
+ bool disableMsaa = false;
+
+ /// Float control flags
+ DxbcFloatControlFlags floatControl;
+
+ /// Minimum storage buffer alignment
+ VkDeviceSize minSsboAlignment = 0;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.cpp
new file mode 100644
index 00000000..9b9a340a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.cpp
@@ -0,0 +1,58 @@
+#include <cstring>
+
+#include "dxbc_reader.h"
+
+namespace dxvk {
+
+ DxbcTag DxbcReader::readTag() {
+ DxbcTag tag;
+ this->read(&tag, 4);
+ return tag;
+ }
+
+
+ std::string DxbcReader::readString() {
+ std::string result;
+
+ while (m_data[m_pos] != '\0')
+ result.push_back(m_data[m_pos++]);
+
+ m_pos++;
+ return result;
+ }
+
+
+ void DxbcReader::read(void* dst, size_t n) {
+ if (m_pos + n > m_size)
+ throw DxvkError("DxbcReader::read: Unexpected end of file");
+ std::memcpy(dst, m_data + m_pos, n);
+ m_pos += n;
+ }
+
+
+ void DxbcReader::skip(size_t n) {
+ if (m_pos + n > m_size)
+ throw DxvkError("DxbcReader::skip: Unexpected end of file");
+ m_pos += n;
+ }
+
+
+ DxbcReader DxbcReader::clone(size_t pos) const {
+ if (pos > m_size)
+ throw DxvkError("DxbcReader::clone: Invalid offset");
+ return DxbcReader(m_data + pos, m_size - pos);
+ }
+
+
+ DxbcReader DxbcReader::resize(size_t size) const {
+ if (size > m_size)
+ throw DxvkError("DxbcReader::resize: Invalid size");
+ return DxbcReader(m_data, size, m_pos);
+ }
+
+
+ void DxbcReader::store(std::ostream&& stream) const {
+ stream.write(m_data, m_size);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.h
new file mode 100644
index 00000000..a1600017
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_reader.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <cstddef>
+#include <string>
+
+#include "dxbc_tag.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXBC bytecode reader
+ *
+ * Holds references to the shader byte code and
+ * provides methods to read
+ */
+ class DxbcReader {
+
+ public:
+
+ DxbcReader(const char* data, size_t size)
+ : DxbcReader(data, size, 0) { }
+
+ auto readu8 () { return this->readNum<uint8_t> (); }
+ auto readu16() { return this->readNum<uint16_t>(); }
+ auto readu32() { return this->readNum<uint32_t>(); }
+ auto readu64() { return this->readNum<uint64_t>(); }
+
+ auto readi8 () { return this->readNum<int8_t> (); }
+ auto readi16() { return this->readNum<int16_t> (); }
+ auto readi32() { return this->readNum<int32_t> (); }
+ auto readi64() { return this->readNum<int64_t> (); }
+
+ auto readf32() { return this->readNum<float> (); }
+ auto readf64() { return this->readNum<double> (); }
+
+ template<typename T>
+ auto readEnum() {
+ using Tx = std::underlying_type_t<T>;
+ return static_cast<T>(this->readNum<Tx>());
+ }
+
+ DxbcTag readTag();
+
+ std::string readString();
+
+ void read(void* dst, size_t n);
+
+ void skip(size_t n);
+
+ DxbcReader clone(size_t pos) const;
+
+ DxbcReader resize(size_t size) const;
+
+ bool eof() const {
+ return m_pos >= m_size;
+ }
+
+ void store(std::ostream&& stream) const;
+
+ private:
+
+ DxbcReader(const char* data, size_t size, size_t pos)
+ : m_data(data), m_size(size), m_pos(pos) { }
+
+ const char* m_data = nullptr;
+ size_t m_size = 0;
+ size_t m_pos = 0;
+
+ template<typename T>
+ T readNum() {
+ T result;
+ this->read(&result, sizeof(result));
+ return result;
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_tag.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_tag.h
new file mode 100644
index 00000000..2ba17509
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_tag.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "dxbc_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Four-character tag
+ *
+ * Used to identify chunks in the
+ * compiled DXBC file by name.
+ */
+ class DxbcTag {
+
+ public:
+
+ DxbcTag() {
+ for (size_t i = 0; i < 4; i++)
+ m_chars[i] = '\0';
+ }
+
+ DxbcTag(const char* tag) {
+ for (size_t i = 0; i < 4; i++)
+ m_chars[i] = tag[i];
+ }
+
+ bool operator == (const DxbcTag& other) const {
+ bool result = true;
+ for (size_t i = 0; i < 4; i++)
+ result &= m_chars[i] == other.m_chars[i];
+ return result;
+ }
+
+ bool operator != (const DxbcTag& other) const {
+ return !this->operator == (other);
+ }
+
+ const char* operator & () const { return m_chars; }
+ char* operator & () { return m_chars; }
+
+ private:
+
+ char m_chars[4];
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.cpp b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.cpp
new file mode 100644
index 00000000..848f8ad7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.cpp
@@ -0,0 +1,26 @@
+#include "dxbc_util.h"
+
+namespace dxvk {
+
+ uint32_t primitiveVertexCount(DxbcPrimitive primitive) {
+ static const std::array<uint32_t, 8> s_vertexCounts = {
+ 0, // Undefined
+ 1, // Point
+ 2, // Line
+ 3, // Triangle
+ 0, // Undefined
+ 0, // Undefined
+ 4, // Line with adjacency
+ 6, // Triangle with adjacency
+ };
+
+ if (primitive >= DxbcPrimitive::Patch1) {
+ return static_cast<uint32_t>(primitive)
+ - static_cast<uint32_t>(DxbcPrimitive::Patch1);
+ } else {
+ return s_vertexCounts.at(
+ static_cast<uint32_t>(primitive));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.h b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.h
new file mode 100644
index 00000000..4bc49620
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/dxbc_util.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "dxbc_common.h"
+#include "dxbc_enums.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Binding numbers and properties
+ */
+ enum DxbcBindingProperties : uint32_t {
+ DxbcConstBufBindingIndex = 0,
+ DxbcConstBufBindingCount = 16,
+ DxbcSamplerBindingIndex = DxbcConstBufBindingIndex
+ + DxbcConstBufBindingCount,
+ DxbcSamplerBindingCount = 16,
+ DxbcResourceBindingIndex = DxbcSamplerBindingIndex
+ + DxbcSamplerBindingCount,
+ DxbcResourceBindingCount = 128,
+ DxbcStageBindingCount = DxbcConstBufBindingCount
+ + DxbcSamplerBindingCount
+ + DxbcResourceBindingCount,
+ DxbcUavBindingIndex = DxbcStageBindingCount * 6,
+ DxbcUavBindingCount = 64,
+ };
+
+
+ /**
+ * \brief Computes first binding index for a given stage
+ *
+ * \param [in] stage The shader stage
+ * \returns Index of first binding
+ */
+ inline uint32_t computeStageBindingOffset(DxbcProgramType stage) {
+ return DxbcStageBindingCount * uint32_t(stage);
+ }
+
+
+ /**
+ * \brief Computes first UAV binding index offset for a given stage
+ *
+ * \param [in] stage The shader stage
+ * \returns Index of first UAV binding
+ */
+ inline uint32_t computeStageUavBindingOffset(DxbcProgramType stage) {
+ return DxbcUavBindingIndex
+ + DxbcUavBindingCount * (stage == DxbcProgramType::ComputeShader ? 2 : 0);
+ }
+
+
+ /**
+ * \brief Computes constant buffer binding index
+ *
+ * \param [in] stage Shader stage
+ * \param [in] index Constant buffer index
+ * \returns Binding index
+ */
+ inline uint32_t computeConstantBufferBinding(DxbcProgramType stage, uint32_t index) {
+ return computeStageBindingOffset(stage) + DxbcConstBufBindingIndex + index;
+ }
+
+
+ /**
+ * \brief Computes sampler binding index
+ *
+ * \param [in] stage Shader stage
+ * \param [in] index Sampler index
+ * \returns Binding index
+ */
+ inline uint32_t computeSamplerBinding(DxbcProgramType stage, uint32_t index) {
+ return computeStageBindingOffset(stage) + DxbcSamplerBindingIndex + index;
+ }
+
+
+ /**
+ * \brief Computes resource binding index
+ *
+ * \param [in] stage Shader stage
+ * \param [in] index Resource index
+ * \returns Binding index
+ */
+ inline uint32_t computeSrvBinding(DxbcProgramType stage, uint32_t index) {
+ return computeStageBindingOffset(stage) + DxbcResourceBindingIndex + index;
+ }
+
+
+ /**
+ * \brief Computes UAV binding offset
+ *
+ * \param [in] stage Shader stage
+ * \param [in] index UAV index
+ * \returns Binding index
+ */
+ inline uint32_t computeUavBinding(DxbcProgramType stage, uint32_t index) {
+ return computeStageUavBindingOffset(stage) + index;
+ }
+
+
+ /**
+ * \brief Computes UAV counter binding offset
+ *
+ * \param [in] stage Shader stage
+ * \param [in] index UAV index
+ * \returns Binding index
+ */
+ inline uint32_t computeUavCounterBinding(DxbcProgramType stage, uint32_t index) {
+ return computeStageUavBindingOffset(stage) + DxbcUavBindingCount + index;
+ }
+
+ /**
+ * \brief Primitive vertex count
+ *
+ * Calculates the number of vertices
+ * for a given primitive type.
+ */
+ uint32_t primitiveVertexCount(
+ DxbcPrimitive primitive);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxbc/meson.build b/src/libs/dxvk-native-1.9.2a/src/dxbc/meson.build
new file mode 100644
index 00000000..3aa5c70b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxbc/meson.build
@@ -0,0 +1,23 @@
+dxbc_src = files([
+ 'dxbc_analysis.cpp',
+ 'dxbc_chunk_isgn.cpp',
+ 'dxbc_chunk_shex.cpp',
+ 'dxbc_common.cpp',
+ 'dxbc_compiler.cpp',
+ 'dxbc_defs.cpp',
+ 'dxbc_decoder.cpp',
+ 'dxbc_header.cpp',
+ 'dxbc_module.cpp',
+ 'dxbc_names.cpp',
+ 'dxbc_options.cpp',
+ 'dxbc_reader.cpp',
+ 'dxbc_util.cpp',
+])
+
+dxbc_lib = static_library('dxbc', dxbc_src,
+ include_directories : [ dxvk_include_path ],
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+dxbc_dep = declare_dependency(
+ link_with : [ dxbc_lib ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi.def b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi.def
new file mode 100644
index 00000000..c5509571
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi.def
@@ -0,0 +1,7 @@
+LIBRARY DXGI.DLL
+EXPORTS
+ CreateDXGIFactory @9
+ CreateDXGIFactory1 @10
+ CreateDXGIFactory2 @11
+ DXGIDeclareAdapterRemovalSupport @16
+ DXGIGetDebugInterface1 @17
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.cpp
new file mode 100644
index 00000000..2ae9c844
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.cpp
@@ -0,0 +1,482 @@
+#include <cstdlib>
+#include <cstring>
+
+#include <d3d10_1.h>
+
+#include "dxgi_adapter.h"
+#include "dxgi_enums.h"
+#include "dxgi_factory.h"
+#include "dxgi_format.h"
+#include "dxgi_options.h"
+#include "dxgi_output.h"
+
+#include "../wsi/wsi_monitor.h"
+#include "../util/util_luid.h"
+
+namespace dxvk {
+
+ DxgiVkAdapter::DxgiVkAdapter(DxgiAdapter* pAdapter)
+ : m_adapter(pAdapter) {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE DxgiVkAdapter::AddRef() {
+ return m_adapter->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE DxgiVkAdapter::Release() {
+ return m_adapter->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiVkAdapter::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_adapter->QueryInterface(riid, ppvObject);
+ }
+
+
+ void STDMETHODCALLTYPE DxgiVkAdapter::GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev) {
+ auto adapter = m_adapter->GetDXVKAdapter();
+ auto instance = m_adapter->GetDXVKInstance();
+
+ if (pInstance)
+ *pInstance = instance->handle();
+
+ if (pPhysDev)
+ *pPhysDev = adapter->handle();
+ }
+
+
+
+
+ DxgiAdapter::DxgiAdapter(
+ DxgiFactory* factory,
+ const Rc<DxvkAdapter>& adapter,
+ UINT index)
+ : m_factory (factory),
+ m_adapter (adapter),
+ m_interop (this),
+ m_index (index) {
+
+ }
+
+
+ DxgiAdapter::~DxgiAdapter() {
+ if (m_eventThread.joinable()) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_eventCookie = ~0u;
+ m_cond.notify_one();
+
+ lock.unlock();
+ m_eventThread.join();
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIAdapter)
+ || riid == __uuidof(IDXGIAdapter1)
+ || riid == __uuidof(IDXGIAdapter2)
+ || riid == __uuidof(IDXGIAdapter3)
+ || riid == __uuidof(IDXGIAdapter4)
+ || riid == __uuidof(IDXGIDXVKAdapter)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkInteropAdapter)) {
+ *ppvObject = ref(&m_interop);
+ return S_OK;
+ }
+
+ Logger::warn("DxgiAdapter::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::GetParent(REFIID riid, void** ppParent) {
+ return m_factory->QueryInterface(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::CheckInterfaceSupport(
+ REFGUID InterfaceName,
+ LARGE_INTEGER* pUMDVersion) {
+ HRESULT hr = DXGI_ERROR_UNSUPPORTED;
+
+ if (InterfaceName == __uuidof(IDXGIDevice)
+ || InterfaceName == __uuidof(ID3D10Device)
+ || InterfaceName == __uuidof(ID3D10Device1))
+ hr = S_OK;
+
+ // We can't really reconstruct the version numbers
+ // returned by Windows drivers from Vulkan data
+ if (SUCCEEDED(hr) && pUMDVersion)
+ pUMDVersion->QuadPart = ~0ull;
+
+ if (FAILED(hr)) {
+ Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
+ Logger::err(str::format(InterfaceName));
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::EnumOutputs(
+ UINT Output,
+ IDXGIOutput** ppOutput) {
+ InitReturnPtr(ppOutput);
+
+ if (ppOutput == nullptr)
+ return E_INVALIDARG;
+
+ HMONITOR monitor = wsi::enumMonitors(Output);
+
+ if (!monitor) {
+ *ppOutput = nullptr;
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+ *ppOutput = ref(new DxgiOutput(m_factory, this, monitor));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc(DXGI_ADAPTER_DESC* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ DXGI_ADAPTER_DESC3 desc;
+ HRESULT hr = GetDesc3(&desc);
+
+ if (SUCCEEDED(hr)) {
+ std::memcpy(pDesc->Description, desc.Description, sizeof(pDesc->Description));
+
+ pDesc->VendorId = desc.VendorId;
+ pDesc->DeviceId = desc.DeviceId;
+ pDesc->SubSysId = desc.SubSysId;
+ pDesc->Revision = desc.Revision;
+ pDesc->DedicatedVideoMemory = desc.DedicatedVideoMemory;
+ pDesc->DedicatedSystemMemory = desc.DedicatedSystemMemory;
+ pDesc->SharedSystemMemory = desc.SharedSystemMemory;
+ pDesc->AdapterLuid = desc.AdapterLuid;
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc1(DXGI_ADAPTER_DESC1* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ DXGI_ADAPTER_DESC3 desc;
+ HRESULT hr = GetDesc3(&desc);
+
+ if (SUCCEEDED(hr)) {
+ std::memcpy(pDesc->Description, desc.Description, sizeof(pDesc->Description));
+
+ pDesc->VendorId = desc.VendorId;
+ pDesc->DeviceId = desc.DeviceId;
+ pDesc->SubSysId = desc.SubSysId;
+ pDesc->Revision = desc.Revision;
+ pDesc->DedicatedVideoMemory = desc.DedicatedVideoMemory;
+ pDesc->DedicatedSystemMemory = desc.DedicatedSystemMemory;
+ pDesc->SharedSystemMemory = desc.SharedSystemMemory;
+ pDesc->AdapterLuid = desc.AdapterLuid;
+ pDesc->Flags = desc.Flags;
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc2(DXGI_ADAPTER_DESC2* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ DXGI_ADAPTER_DESC3 desc;
+ HRESULT hr = GetDesc3(&desc);
+
+ if (SUCCEEDED(hr)) {
+ std::memcpy(pDesc->Description, desc.Description, sizeof(pDesc->Description));
+
+ pDesc->VendorId = desc.VendorId;
+ pDesc->DeviceId = desc.DeviceId;
+ pDesc->SubSysId = desc.SubSysId;
+ pDesc->Revision = desc.Revision;
+ pDesc->DedicatedVideoMemory = desc.DedicatedVideoMemory;
+ pDesc->DedicatedSystemMemory = desc.DedicatedSystemMemory;
+ pDesc->SharedSystemMemory = desc.SharedSystemMemory;
+ pDesc->AdapterLuid = desc.AdapterLuid;
+ pDesc->Flags = desc.Flags;
+ pDesc->GraphicsPreemptionGranularity = desc.GraphicsPreemptionGranularity;
+ pDesc->ComputePreemptionGranularity = desc.ComputePreemptionGranularity;
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::GetDesc3(
+ DXGI_ADAPTER_DESC3* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ const DxgiOptions* options = m_factory->GetOptions();
+
+ auto deviceProp = m_adapter->deviceProperties();
+ auto memoryProp = m_adapter->memoryProperties();
+ auto deviceId = m_adapter->devicePropertiesExt().coreDeviceId;
+
+ // Custom Vendor / Device ID
+ if (options->customVendorId >= 0)
+ deviceProp.vendorID = options->customVendorId;
+
+ if (options->customDeviceId >= 0)
+ deviceProp.deviceID = options->customDeviceId;
+
+ const char* description = deviceProp.deviceName;
+ // Custom device description
+ if (!options->customDeviceDesc.empty())
+ description = options->customDeviceDesc.c_str();
+
+ // XXX nvapi workaround for a lot of Unreal Engine 4 games
+ if (options->customVendorId < 0 && options->customDeviceId < 0
+ && options->nvapiHack && deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia)) {
+ Logger::info("DXGI: NvAPI workaround enabled, reporting AMD GPU");
+ deviceProp.vendorID = uint16_t(DxvkGpuVendor::Amd);
+ deviceProp.deviceID = 0x67df; /* RX 480 */
+ }
+
+ // Convert device name
+ std::memset(pDesc->Description, 0, sizeof(pDesc->Description));
+ str::tows(description, pDesc->Description);
+
+ // Get amount of video memory
+ // based on the Vulkan heaps
+ VkDeviceSize deviceMemory = 0;
+ VkDeviceSize sharedMemory = 0;
+
+ for (uint32_t i = 0; i < memoryProp.memoryHeapCount; i++) {
+ VkMemoryHeap heap = memoryProp.memoryHeaps[i];
+
+ if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
+ deviceMemory += heap.size;
+ else
+ sharedMemory += heap.size;
+ }
+
+ // Some games think we are on Intel given a lack of
+ // NVAPI or AGS/atiadlxx support.
+ // Report our device memory as shared memory,
+ // and some small amount for the carveout.
+ if (options->emulateUMA && !m_adapter->isUnifiedMemoryArchitecture()) {
+ sharedMemory = deviceMemory;
+ deviceMemory = 128 * (1 << 20);
+ }
+
+ // Some games are silly and need their memory limited
+ if (options->maxDeviceMemory > 0
+ && options->maxDeviceMemory < deviceMemory)
+ deviceMemory = options->maxDeviceMemory;
+
+ if (options->maxSharedMemory > 0
+ && options->maxSharedMemory < sharedMemory)
+ sharedMemory = options->maxSharedMemory;
+
+ if (env::is32BitHostPlatform()) {
+ // The value returned by DXGI is a 32-bit value
+ // on 32-bit platforms, so we need to clamp it
+ VkDeviceSize maxMemory = 0xC0000000;
+ deviceMemory = std::min(deviceMemory, maxMemory);
+ sharedMemory = std::min(sharedMemory, maxMemory);
+ }
+
+ pDesc->VendorId = deviceProp.vendorID;
+ pDesc->DeviceId = deviceProp.deviceID;
+ pDesc->SubSysId = 0;
+ pDesc->Revision = 0;
+ pDesc->DedicatedVideoMemory = deviceMemory;
+ pDesc->DedicatedSystemMemory = 0;
+ pDesc->SharedSystemMemory = sharedMemory;
+ pDesc->AdapterLuid = LUID { 0, 0 };
+ pDesc->Flags = DXGI_ADAPTER_FLAG3_NONE;
+ pDesc->GraphicsPreemptionGranularity = DXGI_GRAPHICS_PREEMPTION_DMA_BUFFER_BOUNDARY;
+ pDesc->ComputePreemptionGranularity = DXGI_COMPUTE_PREEMPTION_DMA_BUFFER_BOUNDARY;
+
+ if (deviceId.deviceLUIDValid)
+ std::memcpy(&pDesc->AdapterLuid, deviceId.deviceLUID, VK_LUID_SIZE);
+ else
+ pDesc->AdapterLuid = GetAdapterLUID(m_index);
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::QueryVideoMemoryInfo(
+ UINT NodeIndex,
+ DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup,
+ DXGI_QUERY_VIDEO_MEMORY_INFO* pVideoMemoryInfo) {
+ if (NodeIndex > 0 || !pVideoMemoryInfo)
+ return E_INVALIDARG;
+
+ if (MemorySegmentGroup != DXGI_MEMORY_SEGMENT_GROUP_LOCAL
+ && MemorySegmentGroup != DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL)
+ return E_INVALIDARG;
+
+ DxvkAdapterMemoryInfo memInfo = m_adapter->getMemoryHeapInfo();
+
+ VkMemoryHeapFlags heapFlagMask = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+ VkMemoryHeapFlags heapFlags = 0;
+
+ if (MemorySegmentGroup == DXGI_MEMORY_SEGMENT_GROUP_LOCAL)
+ heapFlags |= VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+
+ pVideoMemoryInfo->Budget = 0;
+ pVideoMemoryInfo->CurrentUsage = 0;
+
+ for (uint32_t i = 0; i < memInfo.heapCount; i++) {
+ if ((memInfo.heaps[i].heapFlags & heapFlagMask) != heapFlags)
+ continue;
+
+ pVideoMemoryInfo->Budget += memInfo.heaps[i].memoryBudget;
+ pVideoMemoryInfo->CurrentUsage += memInfo.heaps[i].memoryAllocated;
+ }
+
+ // We don't implement reservation, but the observable
+ // behaviour should match that of Windows drivers
+ uint32_t segmentId = uint32_t(MemorySegmentGroup);
+
+ pVideoMemoryInfo->AvailableForReservation = pVideoMemoryInfo->Budget / 2;
+ pVideoMemoryInfo->CurrentReservation = m_memReservation[segmentId];
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::SetVideoMemoryReservation(
+ UINT NodeIndex,
+ DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup,
+ UINT64 Reservation) {
+ DXGI_QUERY_VIDEO_MEMORY_INFO info;
+
+ HRESULT hr = QueryVideoMemoryInfo(
+ NodeIndex, MemorySegmentGroup, &info);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (Reservation > info.AvailableForReservation)
+ return DXGI_ERROR_INVALID_CALL;
+
+ uint32_t segmentId = uint32_t(MemorySegmentGroup);
+ m_memReservation[segmentId] = Reservation;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::RegisterHardwareContentProtectionTeardownStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiAdapter::RegisterHardwareContentProtectionTeardownStatusEvent: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiAdapter::RegisterVideoMemoryBudgetChangeNotificationEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ #ifndef DXVK_NATIVE
+ if (!hEvent || !pdwCookie)
+ return E_INVALIDARG;
+
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ DWORD cookie = ++m_eventCookie;
+
+ m_eventMap.insert({ cookie, hEvent });
+
+ if (!m_eventThread.joinable())
+ m_eventThread = dxvk::thread([this] { runEventThread(); });
+
+ // This method seems to fire the
+ // event immediately on Windows
+ SetEvent(hEvent);
+
+ *pdwCookie = cookie;
+ return S_OK;
+ #else
+ return E_NOTIMPL;
+ #endif
+ }
+
+
+ void STDMETHODCALLTYPE DxgiAdapter::UnregisterHardwareContentProtectionTeardownStatus(
+ DWORD dwCookie) {
+ Logger::err("DxgiAdapter::UnregisterHardwareContentProtectionTeardownStatus: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE DxgiAdapter::UnregisterVideoMemoryBudgetChangeNotification(
+ DWORD dwCookie) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_eventMap.erase(dwCookie);
+ }
+
+
+ Rc<DxvkAdapter> STDMETHODCALLTYPE DxgiAdapter::GetDXVKAdapter() {
+ return m_adapter;
+ }
+
+
+ Rc<DxvkInstance> STDMETHODCALLTYPE DxgiAdapter::GetDXVKInstance() {
+ return m_factory->GetDXVKInstance();
+ }
+
+
+ void DxgiAdapter::runEventThread() {
+#ifndef DXVK_NATIVE
+ env::setThreadName(str::format("dxvk-adapter-", m_index));
+
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ DxvkAdapterMemoryInfo memoryInfoOld = m_adapter->getMemoryHeapInfo();
+
+ while (true) {
+ m_cond.wait_for(lock, std::chrono::milliseconds(1500),
+ [this] { return m_eventCookie == ~0u; });
+
+ if (m_eventCookie == ~0u)
+ return;
+
+ auto memoryInfoNew = m_adapter->getMemoryHeapInfo();
+ bool budgetChanged = false;
+
+ for (uint32_t i = 0; i < memoryInfoNew.heapCount; i++) {
+ budgetChanged |= memoryInfoNew.heaps[i].memoryBudget
+ != memoryInfoOld.heaps[i].memoryBudget;
+ }
+
+ if (budgetChanged) {
+ memoryInfoOld = memoryInfoNew;
+
+ for (const auto& pair : m_eventMap)
+ SetEvent(pair.second);
+ }
+ }
+#endif
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.h
new file mode 100644
index 00000000..ef17d7ff
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_adapter.h
@@ -0,0 +1,129 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "dxgi_format.h"
+#include "dxgi_interfaces.h"
+#include "dxgi_output.h"
+
+namespace dxvk {
+
+ class DxgiAdapter;
+ class DxgiFactory;
+ class DxgiOutput;
+
+
+ class DxgiVkAdapter : public IDXGIVkInteropAdapter {
+
+ public:
+
+ DxgiVkAdapter(DxgiAdapter* pAdapter);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ void STDMETHODCALLTYPE GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev);
+
+ private:
+
+ DxgiAdapter* m_adapter;
+
+ };
+
+
+ class DxgiAdapter : public DxgiObject<IDXGIDXVKAdapter> {
+
+ public:
+
+ DxgiAdapter(
+ DxgiFactory* factory,
+ const Rc<DxvkAdapter>& adapter,
+ UINT index);
+
+ ~DxgiAdapter();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent) final;
+
+ HRESULT STDMETHODCALLTYPE CheckInterfaceSupport(
+ REFGUID InterfaceName,
+ LARGE_INTEGER* pUMDVersion) final;
+
+ HRESULT STDMETHODCALLTYPE EnumOutputs(
+ UINT Output,
+ IDXGIOutput** ppOutput) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_ADAPTER_DESC* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc1(
+ DXGI_ADAPTER_DESC1* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc2(
+ DXGI_ADAPTER_DESC2* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc3(
+ DXGI_ADAPTER_DESC3* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE QueryVideoMemoryInfo(
+ UINT NodeIndex,
+ DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup,
+ DXGI_QUERY_VIDEO_MEMORY_INFO* pVideoMemoryInfo) final;
+
+ HRESULT STDMETHODCALLTYPE SetVideoMemoryReservation(
+ UINT NodeIndex,
+ DXGI_MEMORY_SEGMENT_GROUP MemorySegmentGroup,
+ UINT64 Reservation) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterHardwareContentProtectionTeardownStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterVideoMemoryBudgetChangeNotificationEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) final;
+
+ void STDMETHODCALLTYPE UnregisterHardwareContentProtectionTeardownStatus(
+ DWORD dwCookie) final;
+
+ void STDMETHODCALLTYPE UnregisterVideoMemoryBudgetChangeNotification(
+ DWORD dwCookie) final;
+
+ Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final;
+
+ Rc<DxvkInstance> STDMETHODCALLTYPE GetDXVKInstance() final;
+
+ private:
+
+ Com<DxgiFactory> m_factory;
+ Rc<DxvkAdapter> m_adapter;
+ DxgiVkAdapter m_interop;
+
+ UINT m_index;
+ UINT64 m_memReservation[2] = { 0, 0 };
+
+ dxvk::mutex m_mutex;
+ dxvk::condition_variable m_cond;
+
+ DWORD m_eventCookie = 0;
+ std::unordered_map<DWORD, HANDLE> m_eventMap;
+ dxvk::thread m_eventThread;
+
+ void runEventThread();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.cpp
new file mode 100644
index 00000000..5d9e75d1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.cpp
@@ -0,0 +1,123 @@
+#include "dxgi_enums.h"
+
+std::ostream& operator << (std::ostream& os, DXGI_FORMAT e) {
+ switch (e) {
+ ENUM_NAME(DXGI_FORMAT_UNKNOWN);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32A32_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32A32_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32A32_UINT);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32A32_SINT);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32_UINT);
+ ENUM_NAME(DXGI_FORMAT_R32G32B32_SINT);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_UINT);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R16G16B16A16_SINT);
+ ENUM_NAME(DXGI_FORMAT_R32G32_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R32G32_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R32G32_UINT);
+ ENUM_NAME(DXGI_FORMAT_R32G32_SINT);
+ ENUM_NAME(DXGI_FORMAT_R32G8X24_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
+ ENUM_NAME(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT);
+ ENUM_NAME(DXGI_FORMAT_R10G10B10A2_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R10G10B10A2_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R10G10B10A2_UINT);
+ ENUM_NAME(DXGI_FORMAT_R11G11B10_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_UINT);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R8G8B8A8_SINT);
+ ENUM_NAME(DXGI_FORMAT_R16G16_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R16G16_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R16G16_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R16G16_UINT);
+ ENUM_NAME(DXGI_FORMAT_R16G16_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R16G16_SINT);
+ ENUM_NAME(DXGI_FORMAT_R32_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_D32_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R32_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_R32_UINT);
+ ENUM_NAME(DXGI_FORMAT_R32_SINT);
+ ENUM_NAME(DXGI_FORMAT_R24G8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_D24_UNORM_S8_UINT);
+ ENUM_NAME(DXGI_FORMAT_R24_UNORM_X8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_X24_TYPELESS_G8_UINT);
+ ENUM_NAME(DXGI_FORMAT_R8G8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R8G8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R8G8_UINT);
+ ENUM_NAME(DXGI_FORMAT_R8G8_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R8G8_SINT);
+ ENUM_NAME(DXGI_FORMAT_R16_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R16_FLOAT);
+ ENUM_NAME(DXGI_FORMAT_D16_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R16_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R16_UINT);
+ ENUM_NAME(DXGI_FORMAT_R16_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R16_SINT);
+ ENUM_NAME(DXGI_FORMAT_R8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_R8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R8_UINT);
+ ENUM_NAME(DXGI_FORMAT_R8_SNORM);
+ ENUM_NAME(DXGI_FORMAT_R8_SINT);
+ ENUM_NAME(DXGI_FORMAT_A8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R1_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R9G9B9E5_SHAREDEXP);
+ ENUM_NAME(DXGI_FORMAT_R8G8_B8G8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_G8R8_G8B8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC1_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC1_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC1_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_BC2_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC2_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC2_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_BC3_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC3_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC3_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_BC4_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC4_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC4_SNORM);
+ ENUM_NAME(DXGI_FORMAT_BC5_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC5_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC5_SNORM);
+ ENUM_NAME(DXGI_FORMAT_B5G6R5_UNORM);
+ ENUM_NAME(DXGI_FORMAT_B5G5R5A1_UNORM);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8A8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8X8_UNORM);
+ ENUM_NAME(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8A8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8X8_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_BC6H_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC6H_UF16);
+ ENUM_NAME(DXGI_FORMAT_BC6H_SF16);
+ ENUM_NAME(DXGI_FORMAT_BC7_TYPELESS);
+ ENUM_NAME(DXGI_FORMAT_BC7_UNORM);
+ ENUM_NAME(DXGI_FORMAT_BC7_UNORM_SRGB);
+ ENUM_NAME(DXGI_FORMAT_AYUV);
+ ENUM_NAME(DXGI_FORMAT_Y410);
+ ENUM_NAME(DXGI_FORMAT_Y416);
+ ENUM_NAME(DXGI_FORMAT_NV12);
+ ENUM_NAME(DXGI_FORMAT_P010);
+ ENUM_NAME(DXGI_FORMAT_P016);
+ ENUM_NAME(DXGI_FORMAT_420_OPAQUE);
+ ENUM_NAME(DXGI_FORMAT_YUY2);
+ ENUM_NAME(DXGI_FORMAT_Y210);
+ ENUM_NAME(DXGI_FORMAT_Y216);
+ ENUM_NAME(DXGI_FORMAT_NV11);
+ ENUM_NAME(DXGI_FORMAT_AI44);
+ ENUM_NAME(DXGI_FORMAT_IA44);
+ ENUM_NAME(DXGI_FORMAT_P8);
+ ENUM_NAME(DXGI_FORMAT_A8P8);
+ ENUM_NAME(DXGI_FORMAT_B4G4R4A4_UNORM);
+ ENUM_DEFAULT(e);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.h
new file mode 100644
index 00000000..2a48427e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_enums.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "dxgi_include.h"
+
+std::ostream& operator << (std::ostream& os, DXGI_FORMAT e);
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.cpp
new file mode 100644
index 00000000..f159999d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.cpp
@@ -0,0 +1,401 @@
+#include "dxgi_factory.h"
+#include "dxgi_swapchain.h"
+#include "dxgi_swapchain_dispatcher.h"
+
+namespace dxvk {
+
+ DxgiFactory::DxgiFactory(UINT Flags)
+ : m_instance (new DxvkInstance()),
+ m_monitorInfo (this),
+ m_options (m_instance->config()),
+ m_flags (Flags) {
+ for (uint32_t i = 0; m_instance->enumAdapters(i) != nullptr; i++)
+ m_instance->enumAdapters(i)->logAdapterInfo();
+ }
+
+
+ DxgiFactory::~DxgiFactory() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIFactory)
+ || riid == __uuidof(IDXGIFactory1)
+ || riid == __uuidof(IDXGIFactory2)
+ || riid == __uuidof(IDXGIFactory3)
+ || riid == __uuidof(IDXGIFactory4)
+ || riid == __uuidof(IDXGIFactory5)
+ || riid == __uuidof(IDXGIFactory6)
+ || riid == __uuidof(IDXGIFactory7)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ if (riid == __uuidof(IDXGIVkMonitorInfo)) {
+ *ppvObject = ref(&m_monitorInfo);
+ return S_OK;
+ }
+
+ Logger::warn("DxgiFactory::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::GetParent(REFIID riid, void** ppParent) {
+ InitReturnPtr(ppParent);
+
+ Logger::warn("DxgiFactory::GetParent: Unknown interface query");
+ return E_NOINTERFACE;
+ }
+
+
+ BOOL STDMETHODCALLTYPE DxgiFactory::IsWindowedStereoEnabled() {
+ // We don't support Stereo 3D at the moment
+ return FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSoftwareAdapter(
+ HMODULE Module,
+ IDXGIAdapter** ppAdapter) {
+ InitReturnPtr(ppAdapter);
+
+ if (ppAdapter == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ Logger::err("DXGI: CreateSoftwareAdapter: Software adapters not supported");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChain(
+ IUnknown* pDevice,
+ DXGI_SWAP_CHAIN_DESC* pDesc,
+ IDXGISwapChain** ppSwapChain) {
+ if (ppSwapChain == nullptr || pDesc == nullptr || pDevice == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ DXGI_SWAP_CHAIN_DESC1 desc;
+ desc.Width = pDesc->BufferDesc.Width;
+ desc.Height = pDesc->BufferDesc.Height;
+ desc.Format = pDesc->BufferDesc.Format;
+ desc.Stereo = FALSE;
+ desc.SampleDesc = pDesc->SampleDesc;
+ desc.BufferUsage = pDesc->BufferUsage;
+ desc.BufferCount = pDesc->BufferCount;
+ desc.Scaling = DXGI_SCALING_STRETCH;
+ desc.SwapEffect = pDesc->SwapEffect;
+ desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
+ desc.Flags = pDesc->Flags;
+
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC descFs;
+ descFs.RefreshRate = pDesc->BufferDesc.RefreshRate;
+ descFs.ScanlineOrdering = pDesc->BufferDesc.ScanlineOrdering;
+ descFs.Scaling = pDesc->BufferDesc.Scaling;
+ descFs.Windowed = pDesc->Windowed;
+
+ IDXGISwapChain1* swapChain = nullptr;
+ HRESULT hr = CreateSwapChainForHwnd(
+ pDevice, pDesc->OutputWindow,
+ &desc, &descFs, nullptr,
+ &swapChain);
+
+ *ppSwapChain = swapChain;
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwnd(
+ IUnknown* pDevice,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) {
+ InitReturnPtr(ppSwapChain);
+
+ if (!ppSwapChain || !pDesc || !hWnd || !pDevice)
+ return DXGI_ERROR_INVALID_CALL;
+
+ Com<IWineDXGISwapChainFactory> wineDevice;
+
+ if (SUCCEEDED(pDevice->QueryInterface(
+ __uuidof(IWineDXGISwapChainFactory),
+ reinterpret_cast<void**>(&wineDevice)))) {
+ IDXGISwapChain4* frontendSwapChain;
+
+ HRESULT hr = wineDevice->CreateSwapChainForHwnd(
+ this, hWnd, pDesc, pFullscreenDesc,
+ pRestrictToOutput, reinterpret_cast<IDXGISwapChain1**>(&frontendSwapChain));
+
+ // No ref as that's handled by the object we're wrapping
+ // which was ref'ed on creation.
+ if (SUCCEEDED(hr))
+ *ppSwapChain = new DxgiSwapChainDispatcher(frontendSwapChain);
+
+ return hr;
+ }
+
+ Logger::err("DXGI: CreateSwapChainForHwnd: Unsupported device type");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForCoreWindow(
+ IUnknown* pDevice,
+ IUnknown* pWindow,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) {
+ InitReturnPtr(ppSwapChain);
+
+ Logger::err("DxgiFactory::CreateSwapChainForCoreWindow: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForComposition(
+ IUnknown* pDevice,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) {
+ InitReturnPtr(ppSwapChain);
+
+ Logger::err("DxgiFactory::CreateSwapChainForComposition: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapters(
+ UINT Adapter,
+ IDXGIAdapter** ppAdapter) {
+ InitReturnPtr(ppAdapter);
+
+ if (ppAdapter == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ IDXGIAdapter1* handle = nullptr;
+ HRESULT hr = this->EnumAdapters1(Adapter, &handle);
+ *ppAdapter = handle;
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapters1(
+ UINT Adapter,
+ IDXGIAdapter1** ppAdapter) {
+ InitReturnPtr(ppAdapter);
+
+ if (ppAdapter == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ Rc<DxvkAdapter> dxvkAdapter
+ = m_instance->enumAdapters(Adapter);
+
+ if (dxvkAdapter == nullptr)
+ return DXGI_ERROR_NOT_FOUND;
+
+ *ppAdapter = ref(new DxgiAdapter(this, dxvkAdapter, Adapter));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapterByLuid(
+ LUID AdapterLuid,
+ REFIID riid,
+ void** ppvAdapter) {
+ InitReturnPtr(ppvAdapter);
+ uint32_t adapterId = 0;
+
+ while (true) {
+ Com<IDXGIAdapter> adapter;
+ HRESULT hr = EnumAdapters(adapterId++, &adapter);
+
+ if (FAILED(hr))
+ return hr;
+
+ DXGI_ADAPTER_DESC desc;
+ adapter->GetDesc(&desc);
+
+ if (!std::memcmp(&AdapterLuid, &desc.AdapterLuid, sizeof(LUID)))
+ return adapter->QueryInterface(riid, ppvAdapter);
+ }
+
+ // This should be unreachable
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::EnumAdapterByGpuPreference(
+ UINT Adapter,
+ DXGI_GPU_PREFERENCE GpuPreference,
+ REFIID riid,
+ void** ppvAdapter) {
+ InitReturnPtr(ppvAdapter);
+ uint32_t adapterCount = m_instance->adapterCount();
+
+ if (Adapter >= adapterCount)
+ return DXGI_ERROR_NOT_FOUND;
+
+ // We know that the backend lists dedicated GPUs before
+ // any integrated ones, so just list adapters in reverse
+ // order. We have no other way to estimate performance.
+ if (GpuPreference == DXGI_GPU_PREFERENCE_MINIMUM_POWER)
+ Adapter = adapterCount - Adapter - 1;
+
+ Com<IDXGIAdapter> adapter;
+ HRESULT hr = this->EnumAdapters(Adapter, &adapter);
+
+ if (FAILED(hr))
+ return hr;
+
+ return adapter->QueryInterface(riid, ppvAdapter);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::EnumWarpAdapter(
+ REFIID riid,
+ void** ppvAdapter) {
+ InitReturnPtr(ppvAdapter);
+
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("DxgiFactory::EnumWarpAdapter: WARP not supported, returning first hardware adapter");
+
+ Com<IDXGIAdapter1> adapter;
+ HRESULT hr = EnumAdapters1(0, &adapter);
+
+ if (FAILED(hr))
+ return hr;
+
+ return adapter->QueryInterface(riid, ppvAdapter);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::GetWindowAssociation(HWND *pWindowHandle) {
+ if (pWindowHandle == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ *pWindowHandle = m_associatedWindow;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::GetSharedResourceAdapterLuid(
+ HANDLE hResource,
+ LUID* pLuid) {
+ Logger::err("DxgiFactory::GetSharedResourceAdapterLuid: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::MakeWindowAssociation(HWND WindowHandle, UINT Flags) {
+ Logger::warn("DXGI: MakeWindowAssociation: Ignoring flags");
+ m_associatedWindow = WindowHandle;
+ return S_OK;
+ }
+
+
+ BOOL STDMETHODCALLTYPE DxgiFactory::IsCurrent() {
+ return TRUE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterOcclusionStatusWindow(
+ HWND WindowHandle,
+ UINT wMsg,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiFactory::RegisterOcclusionStatusWindow: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterStereoStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiFactory::RegisterStereoStatusEvent: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterStereoStatusWindow(
+ HWND WindowHandle,
+ UINT wMsg,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiFactory::RegisterStereoStatusWindow: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterOcclusionStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiFactory::RegisterOcclusionStatusEvent: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ void STDMETHODCALLTYPE DxgiFactory::UnregisterStereoStatus(
+ DWORD dwCookie) {
+ Logger::err("DxgiFactory::UnregisterStereoStatus: Not implemented");
+ }
+
+
+ void STDMETHODCALLTYPE DxgiFactory::UnregisterOcclusionStatus(
+ DWORD dwCookie) {
+ Logger::err("DxgiFactory::UnregisterOcclusionStatus: Not implemented");
+ }
+
+
+ UINT STDMETHODCALLTYPE DxgiFactory::GetCreationFlags() {
+ return m_flags;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::CheckFeatureSupport(
+ DXGI_FEATURE Feature,
+ void* pFeatureSupportData,
+ UINT FeatureSupportDataSize) {
+ switch (Feature) {
+ case DXGI_FEATURE_PRESENT_ALLOW_TEARING: {
+ auto info = static_cast<BOOL*>(pFeatureSupportData);
+
+ if (FeatureSupportDataSize != sizeof(*info))
+ return E_INVALIDARG;
+
+ *info = TRUE;
+ } return S_OK;
+
+ default:
+ Logger::err(str::format("DxgiFactory: CheckFeatureSupport: Unknown feature: ", uint32_t(Feature)));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::RegisterAdaptersChangedEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) {
+ Logger::err("DxgiFactory: RegisterAdaptersChangedEvent: Stub");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiFactory::UnregisterAdaptersChangedEvent(
+ DWORD Cookie) {
+ Logger::err("DxgiFactory: UnregisterAdaptersChangedEvent: Stub");
+ return E_NOTIMPL;
+ }
+
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.h
new file mode 100644
index 00000000..f398c78d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_factory.h
@@ -0,0 +1,157 @@
+#pragma once
+
+#include <vector>
+
+#include "dxgi_adapter.h"
+#include "dxgi_monitor.h"
+#include "dxgi_options.h"
+
+#include "../dxvk/dxvk_instance.h"
+
+namespace dxvk {
+
+ class DxgiFactory : public DxgiObject<IDXGIFactory7> {
+
+ public:
+
+ DxgiFactory(UINT Flags);
+ ~DxgiFactory();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent) final;
+
+ BOOL STDMETHODCALLTYPE IsWindowedStereoEnabled() final;
+
+ HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
+ HMODULE Module,
+ IDXGIAdapter** ppAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE CreateSwapChain(
+ IUnknown* pDevice,
+ DXGI_SWAP_CHAIN_DESC* pDesc,
+ IDXGISwapChain** ppSwapChain) final;
+
+ HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd(
+ IUnknown* pDevice,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) final;
+
+ HRESULT STDMETHODCALLTYPE CreateSwapChainForCoreWindow(
+ IUnknown* pDevice,
+ IUnknown* pWindow,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) final;
+
+ HRESULT STDMETHODCALLTYPE CreateSwapChainForComposition(
+ IUnknown* pDevice,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) final;
+
+ HRESULT STDMETHODCALLTYPE EnumAdapters(
+ UINT Adapter,
+ IDXGIAdapter** ppAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE EnumAdapters1(
+ UINT Adapter,
+ IDXGIAdapter1** ppAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE EnumAdapterByLuid(
+ LUID AdapterLuid,
+ REFIID riid,
+ void** ppvAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE EnumAdapterByGpuPreference(
+ UINT Adapter,
+ DXGI_GPU_PREFERENCE GpuPreference,
+ REFIID riid,
+ void** ppvAdapter);
+
+ HRESULT STDMETHODCALLTYPE EnumWarpAdapter(
+ REFIID riid,
+ void** ppvAdapter) final;
+
+ HRESULT STDMETHODCALLTYPE GetWindowAssociation(
+ HWND* pWindowHandle) final;
+
+ HRESULT STDMETHODCALLTYPE GetSharedResourceAdapterLuid(
+ HANDLE hResource,
+ LUID* pLuid) final;
+
+ HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
+ HWND WindowHandle,
+ UINT Flags) final;
+
+ BOOL STDMETHODCALLTYPE IsCurrent() final;
+
+ HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusWindow(
+ HWND WindowHandle,
+ UINT wMsg,
+ DWORD* pdwCookie) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterStereoStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterStereoStatusWindow(
+ HWND WindowHandle,
+ UINT wMsg,
+ DWORD* pdwCookie) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterOcclusionStatusEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie) final;
+
+ void STDMETHODCALLTYPE UnregisterStereoStatus(
+ DWORD dwCookie) final;
+
+ void STDMETHODCALLTYPE UnregisterOcclusionStatus(
+ DWORD dwCookie) final;
+
+ UINT STDMETHODCALLTYPE GetCreationFlags() final;
+
+ HRESULT STDMETHODCALLTYPE CheckFeatureSupport(
+ DXGI_FEATURE Feature,
+ void* pFeatureSupportData,
+ UINT FeatureSupportDataSize) final;
+
+ HRESULT STDMETHODCALLTYPE RegisterAdaptersChangedEvent(
+ HANDLE hEvent,
+ DWORD* pdwCookie);
+
+ HRESULT STDMETHODCALLTYPE UnregisterAdaptersChangedEvent(
+ DWORD Cookie);
+
+ Rc<DxvkInstance> GetDXVKInstance() const {
+ return m_instance;
+ }
+
+ const DxgiOptions* GetOptions() const {
+ return &m_options;
+ }
+
+ DxgiMonitorInfo* GetMonitorInfo() {
+ return &m_monitorInfo;
+ }
+
+ private:
+
+ Rc<DxvkInstance> m_instance;
+ DxgiMonitorInfo m_monitorInfo;
+ DxgiOptions m_options;
+ UINT m_flags;
+
+ HWND m_associatedWindow = nullptr;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.cpp
new file mode 100644
index 00000000..f628e5d9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.cpp
@@ -0,0 +1,976 @@
+#include "dxgi_format.h"
+
+#include <array>
+
+namespace dxvk {
+
+ const std::array<DXGI_VK_FORMAT_MAPPING, 133> g_dxgiFormats = {{
+ // DXGI_FORMAT_UNKNOWN
+ { },
+ // DXGI_FORMAT_R32G32B32A32_TYPELESS
+ { VK_FORMAT_R32G32B32A32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32A32_UINT },
+ // DXGI_FORMAT_R32G32B32A32_FLOAT
+ { VK_FORMAT_R32G32B32A32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32A32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32B32A32_UINT
+ { VK_FORMAT_R32G32B32A32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32A32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32B32A32_SINT
+ { VK_FORMAT_R32G32B32A32_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32A32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32B32_TYPELESS
+ { VK_FORMAT_R32G32B32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32_UINT },
+ // DXGI_FORMAT_R32G32B32_FLOAT
+ { VK_FORMAT_R32G32B32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32B32_UINT
+ { VK_FORMAT_R32G32B32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32B32_SINT
+ { VK_FORMAT_R32G32B32_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32B32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16B16A16_TYPELESS
+ { VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT },
+ // DXGI_FORMAT_R16G16B16A16_FLOAT
+ { VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16B16A16_UNORM
+ { VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16B16A16_UINT
+ { VK_FORMAT_R16G16B16A16_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16B16A16_SNORM
+ { VK_FORMAT_R16G16B16A16_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16B16A16_SINT
+ { VK_FORMAT_R16G16B16A16_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32_TYPELESS
+ { VK_FORMAT_R32G32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32_UINT },
+ // DXGI_FORMAT_R32G32_FLOAT
+ { VK_FORMAT_R32G32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32_UINT
+ { VK_FORMAT_R32G32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G32_SINT
+ { VK_FORMAT_R32G32_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32G32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32G8X24_TYPELESS
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_D32_FLOAT_S8X24_UINT
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+ // DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D32_SFLOAT_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_STENCIL_BIT },
+ // DXGI_FORMAT_R10G10B10A2_TYPELESS
+ { VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_A2B10G10R10_UINT_PACK32 },
+ // DXGI_FORMAT_R10G10B10A2_UNORM
+ { VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_A2B10G10R10_UINT_PACK32,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R10G10B10A2_UINT
+ { VK_FORMAT_A2B10G10R10_UINT_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_A2B10G10R10_UINT_PACK32,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R11G11B10_FLOAT
+ { VK_FORMAT_B10G11R11_UFLOAT_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8B8A8_TYPELESS
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT },
+ // DXGI_FORMAT_R8G8B8A8_UNORM
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
+ { VK_FORMAT_R8G8B8A8_SRGB,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8B8A8_UINT
+ { VK_FORMAT_R8G8B8A8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8B8A8_SNORM
+ { VK_FORMAT_R8G8B8A8_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8B8A8_SINT
+ { VK_FORMAT_R8G8B8A8_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16_TYPELESS
+ { VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT },
+ // DXGI_FORMAT_R16G16_FLOAT
+ { VK_FORMAT_R16G16_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16_UNORM
+ { VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16_UINT
+ { VK_FORMAT_R16G16_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16_SNORM
+ { VK_FORMAT_R16G16_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16G16_SINT
+ { VK_FORMAT_R16G16_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16G16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32_TYPELESS
+ { VK_FORMAT_R32_UINT,
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_R32_UINT },
+ // DXGI_FORMAT_D32_FLOAT
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_R32_FLOAT
+ { VK_FORMAT_R32_SFLOAT,
+ VK_FORMAT_D32_SFLOAT,
+ VK_FORMAT_R32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_R32_UINT
+ { VK_FORMAT_R32_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R32_SINT
+ { VK_FORMAT_R32_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R32_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R24G8_TYPELESS
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_D24_UNORM_S8_UINT
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+ // DXGI_FORMAT_R24_UNORM_X8_TYPELESS
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_X24_TYPELESS_G8_UINT
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_STENCIL_BIT },
+ // DXGI_FORMAT_R8G8_TYPELESS
+ { VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8_UINT },
+ // DXGI_FORMAT_R8G8_UNORM
+ { VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8_UINT
+ { VK_FORMAT_R8G8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8_SNORM
+ { VK_FORMAT_R8G8_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8_SINT
+ { VK_FORMAT_R8G8_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16_TYPELESS
+ { VK_FORMAT_R16_UNORM,
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_R16_UINT },
+ // DXGI_FORMAT_R16_FLOAT
+ { VK_FORMAT_R16_SFLOAT,
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_R16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_D16_UNORM
+ { VK_FORMAT_UNDEFINED,
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_UNDEFINED,
+ 0, VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_R16_UNORM
+ { VK_FORMAT_R16_UNORM,
+ VK_FORMAT_D16_UNORM,
+ VK_FORMAT_R16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ VK_IMAGE_ASPECT_DEPTH_BIT },
+ // DXGI_FORMAT_R16_UINT
+ { VK_FORMAT_R16_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16_SNORM
+ { VK_FORMAT_R16_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R16_SINT
+ { VK_FORMAT_R16_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R16_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8_TYPELESS
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8_UINT },
+ // DXGI_FORMAT_R8_UNORM
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8_UINT
+ { VK_FORMAT_R8_UINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8_SNORM
+ { VK_FORMAT_R8_SNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8_SINT
+ { VK_FORMAT_R8_SINT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_A8_UNORM
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0,
+ { VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }},
+ // DXGI_FORMAT_R1_UNORM
+ { }, // Unsupported
+ // DXGI_FORMAT_R9G9B9E5_SHAREDEXP
+ { VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_R8G8_B8G8_UNORM
+ { VK_FORMAT_B8G8R8G8_422_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_G8R8_G8B8_UNORM
+ { VK_FORMAT_G8B8G8R8_422_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC1_TYPELESS
+ { VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC1_UNORM
+ { VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC1_UNORM_SRGB
+ { VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC2_TYPELESS
+ { VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC2_UNORM
+ { VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC2_UNORM_SRGB
+ { VK_FORMAT_BC2_SRGB_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC3_TYPELESS
+ { VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC3_UNORM
+ { VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC3_UNORM_SRGB
+ { VK_FORMAT_BC3_SRGB_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC4_TYPELESS
+ { VK_FORMAT_BC4_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC4_UNORM
+ { VK_FORMAT_BC4_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC4_SNORM
+ { VK_FORMAT_BC4_SNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC5_TYPELESS
+ { VK_FORMAT_BC5_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC5_UNORM
+ { VK_FORMAT_BC5_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC5_SNORM
+ { VK_FORMAT_BC5_SNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B5G6R5_UNORM
+ { VK_FORMAT_R5G6B5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B5G5R5A1_UNORM
+ { VK_FORMAT_A1R5G5B5_UNORM_PACK16,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B8G8R8A8_UNORM
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B8G8R8X8_UNORM
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }},
+ // DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
+ { }, // Unsupported
+ // DXGI_FORMAT_B8G8R8A8_TYPELESS
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
+ { VK_FORMAT_B8G8R8A8_SRGB,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B8G8R8X8_TYPELESS
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
+ { VK_FORMAT_B8G8R8A8_SRGB,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
+ VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }},
+ // DXGI_FORMAT_BC6H_TYPELESS
+ { VK_FORMAT_BC6H_UFLOAT_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC6H_UF16
+ { VK_FORMAT_BC6H_UFLOAT_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC6H_SF16
+ { VK_FORMAT_BC6H_SFLOAT_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC7_TYPELESS
+ { VK_FORMAT_BC7_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED },
+ // DXGI_FORMAT_BC7_UNORM
+ { VK_FORMAT_BC7_UNORM_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_BC7_UNORM_SRGB
+ { VK_FORMAT_BC7_SRGB_BLOCK,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_AYUV
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_IMAGE_ASPECT_COLOR_BIT, 0,
+ { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_B,
+ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_A } },
+ // DXGI_FORMAT_Y410
+ { }, // Unsupported
+ // DXGI_FORMAT_Y416
+ { }, // Unsupported
+ // DXGI_FORMAT_NV12
+ { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT },
+ // DXGI_FORMAT_P010
+ { }, // Unsupported
+ // DXGI_FORMAT_P016
+ { }, // Unsupported
+ // DXGI_FORMAT_420_OPAQUE
+ { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT },
+ // DXGI_FORMAT_YUY2
+ { VK_FORMAT_G8B8G8R8_422_UNORM,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_Y210
+ { }, // Unsupported
+ // DXGI_FORMAT_Y216
+ { }, // Unsupported
+ // DXGI_FORMAT_NV11
+ { }, // Unsupported
+ // DXGI_FORMAT_AI44
+ { }, // Unsupported
+ // DXGI_FORMAT_IA44
+ { }, // Unsupported
+ // DXGI_FORMAT_P8
+ { }, // Unsupported
+ // DXGI_FORMAT_A8P8
+ { }, // Unsupported
+ // DXGI_FORMAT_B4G4R4A4_UNORM
+ { VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT,
+ VK_FORMAT_UNDEFINED,
+ VK_FORMAT_UNDEFINED,
+ VK_IMAGE_ASPECT_COLOR_BIT },
+ // DXGI_FORMAT_P208
+ { }, // Unsupported
+ // DXGI_FORMAT_V208
+ { }, // Unsupported
+ // DXGI_FORMAT_V408
+ { }, // Unsupported
+ }};
+
+
+ const std::array<DXGI_VK_FORMAT_FAMILY, 133> g_dxgiFamilies = {{
+ // DXGI_FORMAT_UNKNOWN
+ { },
+ // DXGI_FORMAT_R32G32B32A32_TYPELESS
+ { VK_FORMAT_R32G32B32A32_UINT,
+ VK_FORMAT_R32G32B32A32_SINT,
+ VK_FORMAT_R32G32B32A32_SFLOAT },
+ // DXGI_FORMAT_R32G32B32A32_FLOAT
+ { },
+ // DXGI_FORMAT_R32G32B32A32_UINT
+ { },
+ // DXGI_FORMAT_R32G32B32A32_SINT
+ { },
+ // DXGI_FORMAT_R32G32B32_TYPELESS
+ { VK_FORMAT_R32G32B32_UINT,
+ VK_FORMAT_R32G32B32_SINT,
+ VK_FORMAT_R32G32B32_SFLOAT },
+ // DXGI_FORMAT_R32G32B32_FLOAT
+ { },
+ // DXGI_FORMAT_R32G32B32_UINT
+ { },
+ // DXGI_FORMAT_R32G32B32_SINT
+ { },
+ // DXGI_FORMAT_R16G16B16A16_TYPELESS
+ { VK_FORMAT_R16G16B16A16_UNORM,
+ VK_FORMAT_R16G16B16A16_SNORM,
+ VK_FORMAT_R16G16B16A16_UINT,
+ VK_FORMAT_R16G16B16A16_SINT,
+ VK_FORMAT_R16G16B16A16_SFLOAT },
+ // DXGI_FORMAT_R16G16B16A16_FLOAT
+ { },
+ // DXGI_FORMAT_R16G16B16A16_UNORM
+ { },
+ // DXGI_FORMAT_R16G16B16A16_UINT
+ { },
+ // DXGI_FORMAT_R16G16B16A16_SNORM
+ { },
+ // DXGI_FORMAT_R16G16B16A16_SINT
+ { },
+ // DXGI_FORMAT_R32G32_TYPELESS
+ { VK_FORMAT_R32G32_UINT,
+ VK_FORMAT_R32G32_SINT,
+ VK_FORMAT_R32G32_SFLOAT },
+ // DXGI_FORMAT_R32G32_FLOAT
+ { },
+ // DXGI_FORMAT_R32G32_UINT
+ { },
+ // DXGI_FORMAT_R32G32_SINT
+ { },
+ // DXGI_FORMAT_R32G8X24_TYPELESS
+ { },
+ // DXGI_FORMAT_D32_FLOAT_S8X24_UINT
+ { },
+ // DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS
+ { },
+ // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT
+ { },
+ // DXGI_FORMAT_R10G10B10A2_TYPELESS
+ { VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_FORMAT_A2B10G10R10_UINT_PACK32 },
+ // DXGI_FORMAT_R10G10B10A2_UNORM
+ { },
+ // DXGI_FORMAT_R10G10B10A2_UINT
+ { },
+ // DXGI_FORMAT_R11G11B10_FLOAT
+ { },
+ // DXGI_FORMAT_R8G8B8A8_TYPELESS
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SNORM,
+ VK_FORMAT_R8G8B8A8_SRGB,
+ VK_FORMAT_R8G8B8A8_UINT,
+ VK_FORMAT_R8G8B8A8_SINT },
+ // DXGI_FORMAT_R8G8B8A8_UNORM
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SRGB },
+ // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_SRGB },
+ // DXGI_FORMAT_R8G8B8A8_UINT
+ { },
+ // DXGI_FORMAT_R8G8B8A8_SNORM
+ { },
+ // DXGI_FORMAT_R8G8B8A8_SINT
+ { },
+ // DXGI_FORMAT_R16G16_TYPELESS
+ { VK_FORMAT_R16G16_UNORM,
+ VK_FORMAT_R16G16_SNORM,
+ VK_FORMAT_R16G16_UINT,
+ VK_FORMAT_R16G16_SINT,
+ VK_FORMAT_R16G16_SFLOAT },
+ // DXGI_FORMAT_R16G16_FLOAT
+ { },
+ // DXGI_FORMAT_R16G16_UNORM
+ { },
+ // DXGI_FORMAT_R16G16_UINT
+ { },
+ // DXGI_FORMAT_R16G16_SNORM
+ { },
+ // DXGI_FORMAT_R16G16_SINT
+ { },
+ // DXGI_FORMAT_R32_TYPELESS
+ { VK_FORMAT_R32_UINT,
+ VK_FORMAT_R32_SINT,
+ VK_FORMAT_R32_SFLOAT },
+ // DXGI_FORMAT_D32_FLOAT
+ { },
+ // DXGI_FORMAT_R32_FLOAT
+ { },
+ // DXGI_FORMAT_R32_UINT
+ { },
+ // DXGI_FORMAT_R32_SINT
+ { },
+ // DXGI_FORMAT_R24G8_TYPELESS
+ { },
+ // DXGI_FORMAT_D24_UNORM_S8_UINT
+ { },
+ // DXGI_FORMAT_R24_UNORM_X8_TYPELESS
+ { },
+ // DXGI_FORMAT_X24_TYPELESS_G8_UINT
+ { },
+ // DXGI_FORMAT_R8G8_TYPELESS
+ { VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_R8G8_SNORM,
+ VK_FORMAT_R8G8_UINT,
+ VK_FORMAT_R8G8_SINT },
+ // DXGI_FORMAT_R8G8_UNORM
+ { },
+ // DXGI_FORMAT_R8G8_UINT
+ { },
+ // DXGI_FORMAT_R8G8_SNORM
+ { },
+ // DXGI_FORMAT_R8G8_SINT
+ { },
+ // DXGI_FORMAT_R16_TYPELESS
+ { VK_FORMAT_R16_UNORM,
+ VK_FORMAT_R16_SNORM,
+ VK_FORMAT_R16_UINT,
+ VK_FORMAT_R16_SINT,
+ VK_FORMAT_R16_SFLOAT },
+ // DXGI_FORMAT_R16_FLOAT
+ { },
+ // DXGI_FORMAT_D16_UNORM
+ { },
+ // DXGI_FORMAT_R16_UNORM
+ { },
+ // DXGI_FORMAT_R16_UINT
+ { },
+ // DXGI_FORMAT_R16_SNORM
+ { },
+ // DXGI_FORMAT_R16_SINT
+ { },
+ // DXGI_FORMAT_R8_TYPELESS
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8_SNORM,
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_R8_SINT },
+ // DXGI_FORMAT_R8_UNORM
+ { },
+ // DXGI_FORMAT_R8_UINT
+ { },
+ // DXGI_FORMAT_R8_SNORM
+ { },
+ // DXGI_FORMAT_R8_SINT
+ { },
+ // DXGI_FORMAT_A8_UNORM
+ { },
+ // DXGI_FORMAT_R1_UNORM
+ { }, // Unsupported
+ // DXGI_FORMAT_R9G9B9E5_SHAREDEXP
+ { },
+ // DXGI_FORMAT_R8G8_B8G8_UNORM
+ { },
+ // DXGI_FORMAT_G8R8_G8B8_UNORM
+ { },
+ // DXGI_FORMAT_BC1_TYPELESS
+ { VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_BC1_RGBA_SRGB_BLOCK },
+ // DXGI_FORMAT_BC1_UNORM
+ { VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_BC1_RGBA_SRGB_BLOCK },
+ // DXGI_FORMAT_BC1_UNORM_SRGB
+ { VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
+ VK_FORMAT_BC1_RGBA_SRGB_BLOCK },
+ // DXGI_FORMAT_BC2_TYPELESS
+ { VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_BC2_SRGB_BLOCK },
+ // DXGI_FORMAT_BC2_UNORM
+ { VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_BC2_SRGB_BLOCK },
+ // DXGI_FORMAT_BC2_UNORM_SRGB
+ { VK_FORMAT_BC2_UNORM_BLOCK,
+ VK_FORMAT_BC2_SRGB_BLOCK },
+ // DXGI_FORMAT_BC3_TYPELESS
+ { VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_BC3_SRGB_BLOCK },
+ // DXGI_FORMAT_BC3_UNORM
+ { VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_BC3_SRGB_BLOCK },
+ // DXGI_FORMAT_BC3_UNORM_SRGB
+ { VK_FORMAT_BC3_UNORM_BLOCK,
+ VK_FORMAT_BC3_SRGB_BLOCK },
+ // DXGI_FORMAT_BC4_TYPELESS
+ { VK_FORMAT_BC4_UNORM_BLOCK,
+ VK_FORMAT_BC4_SNORM_BLOCK },
+ // DXGI_FORMAT_BC4_UNORM
+ { },
+ // DXGI_FORMAT_BC4_SNORM
+ { },
+ // DXGI_FORMAT_BC5_TYPELESS
+ { VK_FORMAT_BC5_UNORM_BLOCK,
+ VK_FORMAT_BC5_SNORM_BLOCK },
+ // DXGI_FORMAT_BC5_UNORM
+ { },
+ // DXGI_FORMAT_BC5_SNORM
+ { },
+ // DXGI_FORMAT_B5G6R5_UNORM
+ { },
+ // DXGI_FORMAT_B5G5R5A1_UNORM
+ { },
+ // DXGI_FORMAT_B8G8R8A8_UNORM
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_B8G8R8X8_UNORM
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
+ { }, // Unsupported
+ // DXGI_FORMAT_B8G8R8A8_TYPELESS
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_B8G8R8X8_TYPELESS
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_B8G8R8X8_UNORM_SRGB
+ { VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_B8G8R8A8_SRGB },
+ // DXGI_FORMAT_BC6H_TYPELESS
+ { VK_FORMAT_BC6H_UFLOAT_BLOCK,
+ VK_FORMAT_BC6H_SFLOAT_BLOCK },
+ // DXGI_FORMAT_BC6H_UF16
+ { },
+ // DXGI_FORMAT_BC6H_SF16
+ { },
+ // DXGI_FORMAT_BC7_TYPELESS
+ { VK_FORMAT_BC7_UNORM_BLOCK,
+ VK_FORMAT_BC7_SRGB_BLOCK },
+ // DXGI_FORMAT_BC7_UNORM
+ { VK_FORMAT_BC7_UNORM_BLOCK,
+ VK_FORMAT_BC7_SRGB_BLOCK },
+ // DXGI_FORMAT_BC7_UNORM_SRGB
+ { VK_FORMAT_BC7_UNORM_BLOCK,
+ VK_FORMAT_BC7_SRGB_BLOCK },
+ // DXGI_FORMAT_AYUV
+ { VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UINT },
+ // DXGI_FORMAT_Y410
+ { }, // Unsupported
+ // DXGI_FORMAT_Y416
+ { }, // Unsupported
+ // DXGI_FORMAT_NV12
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_R8G8_UINT },
+ // DXGI_FORMAT_P010
+ { }, // Unsupported
+ // DXGI_FORMAT_P016
+ { }, // Unsupported
+ // DXGI_FORMAT_420_OPAQUE
+ { VK_FORMAT_R8_UNORM,
+ VK_FORMAT_R8G8_UNORM,
+ VK_FORMAT_R8_UINT,
+ VK_FORMAT_R8G8_UINT },
+ // DXGI_FORMAT_YUY2
+ { VK_FORMAT_G8B8G8R8_422_UNORM,
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UINT },
+ // DXGI_FORMAT_Y210
+ { }, // Unsupported
+ // DXGI_FORMAT_Y216
+ { }, // Unsupported
+ // DXGI_FORMAT_NV11
+ { }, // Unsupported
+ // DXGI_FORMAT_AI44
+ { }, // Unsupported
+ // DXGI_FORMAT_IA44
+ { }, // Unsupported
+ // DXGI_FORMAT_P8
+ { }, // Unsupported
+ // DXGI_FORMAT_A8P8
+ { }, // Unsupported
+ // DXGI_FORMAT_B4G4R4A4_UNORM
+ { }, // Unsupported
+ // DXGI_FORMAT_P208
+ { }, // Unsupported
+ // DXGI_FORMAT_V208
+ { }, // Unsupported
+ // DXGI_FORMAT_V408
+ { }, // Unsupported
+ }};
+
+
+ DXGIVkFormatTable::DXGIVkFormatTable(const Rc<DxvkAdapter>& adapter)
+ : m_dxgiFormats (g_dxgiFormats), m_dxgiFamilies(g_dxgiFamilies) {
+ // AMD do not support 24-bit depth buffers on Vulkan,
+ // so we have to fall back to a 32-bit depth format.
+ if (!CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT,
+ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
+ Logger::info("DXGI: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
+ RemapDepthFormat(DXGI_FORMAT_R24G8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
+ RemapDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
+ RemapDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
+ RemapDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
+ }
+
+ if (!adapter->features().ext4444Formats.formatA4R4G4B4) {
+ RemapColorFormat(DXGI_FORMAT_B4G4R4A4_UNORM, VK_FORMAT_B4G4R4A4_UNORM_PACK16,
+ { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R,
+ VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_B });
+ }
+ }
+
+
+ DXGIVkFormatTable::~DXGIVkFormatTable() {
+
+ }
+
+
+ DXGI_VK_FORMAT_INFO DXGIVkFormatTable::GetFormatInfo(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ return GetFormatInfoFromMapping(
+ GetFormatMapping(Format), Mode);
+ }
+
+
+ DXGI_VK_FORMAT_INFO DXGIVkFormatTable::GetPackedFormatInfo(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ return GetFormatInfoFromMapping(
+ GetPackedFormatMapping(Format), Mode);
+ }
+
+
+ DXGI_VK_FORMAT_FAMILY DXGIVkFormatTable::GetFormatFamily(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ if (Mode == DXGI_VK_FORMAT_MODE_DEPTH)
+ return DXGI_VK_FORMAT_FAMILY();
+
+ const size_t formatId = size_t(Format);
+
+ return formatId < m_dxgiFamilies.size()
+ ? m_dxgiFamilies[formatId]
+ : m_dxgiFamilies[0];
+ }
+
+
+ DXGI_VK_FORMAT_INFO DXGIVkFormatTable::GetFormatInfoFromMapping(
+ const DXGI_VK_FORMAT_MAPPING* pMapping,
+ DXGI_VK_FORMAT_MODE Mode) const {
+ switch (Mode) {
+ case DXGI_VK_FORMAT_MODE_ANY:
+ return pMapping->FormatColor != VK_FORMAT_UNDEFINED
+ ? DXGI_VK_FORMAT_INFO { pMapping->FormatColor, pMapping->AspectColor, pMapping->Swizzle }
+ : DXGI_VK_FORMAT_INFO { pMapping->FormatDepth, pMapping->AspectDepth };
+
+ case DXGI_VK_FORMAT_MODE_COLOR:
+ return { pMapping->FormatColor, pMapping->AspectColor, pMapping->Swizzle };
+
+ case DXGI_VK_FORMAT_MODE_DEPTH:
+ return { pMapping->FormatDepth, pMapping->AspectDepth };
+
+ case DXGI_VK_FORMAT_MODE_RAW:
+ return { pMapping->FormatRaw, pMapping->AspectColor };
+ }
+
+ Logger::err("DXGI: GetFormatInfoFromMapping: Internal error");
+ return DXGI_VK_FORMAT_INFO();
+ }
+
+
+ const DXGI_VK_FORMAT_MAPPING* DXGIVkFormatTable::GetFormatMapping(
+ DXGI_FORMAT Format) const {
+ const size_t formatId = size_t(Format);
+
+ return formatId < m_dxgiFormats.size()
+ ? &m_dxgiFormats[formatId]
+ : &m_dxgiFormats[0];
+ }
+
+
+ const DXGI_VK_FORMAT_MAPPING* DXGIVkFormatTable::GetPackedFormatMapping(
+ DXGI_FORMAT Format) const {
+ const size_t formatId = size_t(Format);
+
+ return formatId < g_dxgiFormats.size()
+ ? &g_dxgiFormats[formatId]
+ : &g_dxgiFormats[0];
+ }
+
+
+ bool DXGIVkFormatTable::CheckImageFormatSupport(
+ const Rc<DxvkAdapter>& Adapter,
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const {
+ VkFormatProperties supported = Adapter->formatProperties(Format);
+
+ return (supported.linearTilingFeatures & Features) == Features
+ || (supported.optimalTilingFeatures & Features) == Features;
+ }
+
+
+ void DXGIVkFormatTable::RemapDepthFormat(
+ DXGI_FORMAT Format,
+ VkFormat Target) {
+ m_dxgiFormats[uint32_t(Format)].FormatDepth = Target;
+ }
+
+
+ void DXGIVkFormatTable::RemapColorFormat(
+ DXGI_FORMAT Format,
+ VkFormat Target,
+ VkComponentMapping Swizzle) {
+ m_dxgiFormats[uint32_t(Format)].FormatColor = Target;
+ m_dxgiFormats[uint32_t(Format)].Swizzle = Swizzle;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.h
new file mode 100644
index 00000000..59e64937
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_format.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#include "dxgi_include.h"
+
+#include "../dxvk/dxvk_adapter.h"
+#include "../dxvk/dxvk_format.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Format mapping
+ *
+ * Maps a DXGI format to a set of Vulkan formats.
+ */
+ struct DXGI_VK_FORMAT_MAPPING {
+ VkFormat FormatColor = VK_FORMAT_UNDEFINED; ///< Corresponding color format
+ VkFormat FormatDepth = VK_FORMAT_UNDEFINED; ///< Corresponding depth format
+ VkFormat FormatRaw = VK_FORMAT_UNDEFINED; ///< Bit-compatible integer format
+ VkImageAspectFlags AspectColor = 0; ///< Defined aspects for the color format
+ VkImageAspectFlags AspectDepth = 0; ///< Defined aspects for the depth format
+ VkComponentMapping Swizzle = { ///< Color component swizzle
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ };
+
+ /**
+ * \brief Format info
+ *
+ * Stores a Vulkan image format for a given
+ * DXGI format and some additional information
+ * on how resources with the particular format
+ * are supposed to be used.
+ */
+ struct DXGI_VK_FORMAT_INFO {
+ VkFormat Format = VK_FORMAT_UNDEFINED; ///< Corresponding color format
+ VkImageAspectFlags Aspect = 0; ///< Defined image aspect mask
+ VkComponentMapping Swizzle = { ///< Component swizzle
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ };
+
+ /**
+ * \brief Format lookup mode
+ *
+ * When looking up an image format, additional information
+ * might be needed on how the image is going to be used.
+ * This is used to properly map typeless formats and color
+ * formats to depth formats if they are used on depth images.
+ */
+ enum DXGI_VK_FORMAT_MODE {
+ DXGI_VK_FORMAT_MODE_ANY = 0, ///< Color first, then depth
+ DXGI_VK_FORMAT_MODE_COLOR = 1, ///< Color only
+ DXGI_VK_FORMAT_MODE_DEPTH = 2, ///< Depth only
+ DXGI_VK_FORMAT_MODE_RAW = 3, ///< Unsigned integer format
+ };
+
+
+ /**
+ * \brief Format family
+ *
+ * Stores a set of compatible formats. This can
+ * be used to aggregate formats for the image
+ * format list extension.
+ */
+ struct DXGI_VK_FORMAT_FAMILY {
+ constexpr static size_t MaxSize = 8;
+
+ DXGI_VK_FORMAT_FAMILY() { }
+ DXGI_VK_FORMAT_FAMILY(const std::initializer_list<VkFormat>& FormatList) {
+ for (VkFormat f : FormatList)
+ Add(f);
+ }
+
+ BOOL Add(VkFormat Format) {
+ for (UINT i = 0; i < FormatCount; i++) {
+ if (Formats[i] == Format)
+ return TRUE;
+ }
+
+ if (FormatCount < MaxSize) {
+ Formats[FormatCount++] = Format;
+ return TRUE;
+ } return FALSE;
+ }
+
+ UINT FormatCount = 0;
+ VkFormat Formats[MaxSize];
+ };
+
+
+ /**
+ * \brief Format table
+ *
+ * Initializes a format table for a specific
+ * device and provides methods to look up
+ * formats.
+ */
+ class DXGIVkFormatTable {
+
+ public:
+
+ DXGIVkFormatTable(
+ const Rc<DxvkAdapter>& adapter);
+ ~DXGIVkFormatTable();
+
+ /**
+ * \brief Retrieves info for a given DXGI format
+ *
+ * \param [in] Format The DXGI format to look up
+ * \param [in] Mode the format lookup mode
+ * \returns Format info
+ */
+ DXGI_VK_FORMAT_INFO GetFormatInfo(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ /**
+ * \brief Retrieves original info for a given DXGI format
+ *
+ * Doesn't perform any format adjustment, so this
+ * can be used to determine the packed data format
+ * of a DXGI format for things like data uploads.
+ * \param [in] Format The DXGI format to look up
+ * \param [in] Mode the format lookup mode
+ * \returns Format info
+ */
+ DXGI_VK_FORMAT_INFO GetPackedFormatInfo(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ /**
+ * \brief Retrieves a format family
+ *
+ * \param [in] Format The format to query
+ * \param [in] Mode Image format mode
+ * \returns Image format family
+ */
+ DXGI_VK_FORMAT_FAMILY GetFormatFamily(
+ DXGI_FORMAT Format,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ private:
+
+ std::array<DXGI_VK_FORMAT_MAPPING, 133> m_dxgiFormats;
+ std::array<DXGI_VK_FORMAT_FAMILY, 133> m_dxgiFamilies;
+
+ DXGI_VK_FORMAT_INFO GetFormatInfoFromMapping(
+ const DXGI_VK_FORMAT_MAPPING* pMapping,
+ DXGI_VK_FORMAT_MODE Mode) const;
+
+ const DXGI_VK_FORMAT_MAPPING* GetFormatMapping(
+ DXGI_FORMAT Format) const;
+
+ const DXGI_VK_FORMAT_MAPPING* GetPackedFormatMapping(
+ DXGI_FORMAT Format) const;
+
+ bool CheckImageFormatSupport(
+ const Rc<DxvkAdapter>& Adapter,
+ VkFormat Format,
+ VkFormatFeatureFlags Features) const;
+
+ void RemapDepthFormat(
+ DXGI_FORMAT Format,
+ VkFormat Target);
+
+ void RemapColorFormat(
+ DXGI_FORMAT Format,
+ VkFormat Target,
+ VkComponentMapping Swizzle);
+
+ };
+
+}; \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_include.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_include.h
new file mode 100644
index 00000000..c1a18e56
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_include.h
@@ -0,0 +1,48 @@
+#pragma once
+
+//for some reason we need to specify __declspec(dllexport) for MinGW
+#if defined(__WINE__) || (defined(DXVK_NATIVE) && !defined(_WIN32))
+ #define DLLEXPORT __attribute__((visibility("default")))
+#elif defined(_MSC_VER)
+ #define DLLEXPORT
+#else
+ #define DLLEXPORT __declspec(dllexport)
+#endif
+
+#include "../util/com/com_guid.h"
+#include "../util/com/com_object.h"
+#include "../util/com/com_pointer.h"
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#include "../util/util_env.h"
+#include "../util/util_enum.h"
+#include "../util/util_error.h"
+#include "../util/util_flags.h"
+#include "../util/util_likely.h"
+#include "../util/util_math.h"
+#include "../util/util_monitor.h"
+#include "../util/util_string.h"
+
+#include <dxgi1_6.h>
+
+// For some reason, these are not exposed
+#ifndef DXGI_RESOURCE_PRIORITY_NORMAL
+ #define DXGI_RESOURCE_PRIORITY_MINIMUM (0x28000000)
+ #define DXGI_RESOURCE_PRIORITY_LOW (0x50000000)
+ #define DXGI_RESOURCE_PRIORITY_NORMAL (0x78000000)
+ #define DXGI_RESOURCE_PRIORITY_HIGH (0xa0000000)
+ #define DXGI_RESOURCE_PRIORITY_MAXIMUM (0xc8000000)
+#endif
+
+#ifndef DXGI_CPU_ACCESS_NONE
+ #define DXGI_CPU_ACCESS_NONE (0)
+ #define DXGI_CPU_ACCESS_DYNAMIC (1)
+ #define DXGI_CPU_ACCESS_READ_WRITE (2)
+ #define DXGI_CPU_ACCESS_SCRATCH (3)
+ #define DXGI_CPU_ACCESS_FIELD (0xf)
+#endif \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_interfaces.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_interfaces.h
new file mode 100644
index 00000000..f7a93950
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_interfaces.h
@@ -0,0 +1,378 @@
+#pragma once
+
+#include "../dxvk/dxvk_include.h"
+
+#include "dxgi_format.h"
+#include "dxgi_include.h"
+
+namespace dxvk {
+ class DxgiAdapter;
+ class DxgiSwapChain;
+ class DxvkAdapter;
+ class DxvkBuffer;
+ class DxvkDevice;
+ class DxvkImage;
+}
+
+struct IDXGIVkInteropDevice;
+
+
+/**
+ * \brief Per-monitor data
+ */
+struct DXGI_VK_MONITOR_DATA {
+ dxvk::DxgiSwapChain* pSwapChain;
+ DXGI_FRAME_STATISTICS FrameStats;
+ DXGI_GAMMA_CONTROL GammaCurve;
+};
+
+
+/**
+ * \brief Private DXGI presenter
+ *
+ * Presenter interface that allows the DXGI swap
+ * chain implementation to remain API-agnostic,
+ * so that common code can stay in one class.
+ */
+MIDL_INTERFACE("104001a6-7f36-4957-b932-86ade9567d91")
+IDXGIVkSwapChain : public IUnknown {
+ virtual HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_SWAP_CHAIN_DESC1* pDesc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAdapter(
+ REFIID riid,
+ void** ppvObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetImage(
+ UINT BufferId,
+ REFIID riid,
+ void** ppBuffer) = 0;
+
+ virtual UINT STDMETHODCALLTYPE GetImageIndex() = 0;
+
+ virtual UINT STDMETHODCALLTYPE GetFrameLatency() = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE GetFrameLatencyEvent() = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ChangeProperties(
+ const DXGI_SWAP_CHAIN_DESC1* pDesc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPresentRegion(
+ const RECT* pRegion) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetGammaControl(
+ UINT NumControlPoints,
+ const DXGI_RGB* pControlPoints) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFrameLatency(
+ UINT MaxLatency) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Present(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters) = 0;
+
+ virtual void STDMETHODCALLTYPE NotifyModeChange(
+ BOOL Windowed,
+ const DXGI_MODE_DESC* pDisplayMode) = 0;
+};
+
+
+/**
+ * \brief Private DXGI adapter interface
+ *
+ * The implementation of \c IDXGIAdapter holds a
+ * \ref DxvkAdapter which can be retrieved using
+ * this interface.
+ */
+MIDL_INTERFACE("907bf281-ea3c-43b4-a8e4-9f231107b4ff")
+IDXGIDXVKAdapter : public IDXGIAdapter4 {
+ virtual dxvk::Rc<dxvk::DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() = 0;
+
+ virtual dxvk::Rc<dxvk::DxvkInstance> STDMETHODCALLTYPE GetDXVKInstance() = 0;
+
+};
+
+
+/**
+ * \brief Private DXGI device interface
+ */
+MIDL_INTERFACE("92a5d77b-b6e1-420a-b260-fdd701272827")
+IDXGIDXVKDevice : public IUnknown {
+ virtual void STDMETHODCALLTYPE SetAPIVersion(
+ UINT Version) = 0;
+
+ virtual UINT STDMETHODCALLTYPE GetAPIVersion() = 0;
+
+};
+
+
+/**
+ * \brief Private DXGI monitor info interface
+ *
+ * Can be queried from the DXGI factory to store monitor
+ * info globally, with a lifetime that exceeds that of
+ * the \c IDXGIOutput or \c IDXGIAdapter objects.
+ */
+MIDL_INTERFACE("c06a236f-5be3-448a-8943-89c611c0c2c1")
+IDXGIVkMonitorInfo : public IUnknown {
+ /**
+ * \brief Initializes monitor data
+ *
+ * Fails if data for the given monitor already exists.
+ * \param [in] hMonitor The monitor handle
+ * \param [in] pData Initial data
+ */
+ virtual HRESULT STDMETHODCALLTYPE InitMonitorData(
+ HMONITOR hMonitor,
+ const DXGI_VK_MONITOR_DATA* pData) = 0;
+
+ /**
+ * \brief Retrieves and locks monitor data
+ *
+ * Fails if no data for the given monitor exists.
+ * \param [in] hMonitor The monitor handle
+ * \param [out] Pointer to monitor data
+ * \returns S_OK on success
+ */
+ virtual HRESULT STDMETHODCALLTYPE AcquireMonitorData(
+ HMONITOR hMonitor,
+ DXGI_VK_MONITOR_DATA** ppData) = 0;
+
+ /**
+ * \brief Unlocks monitor data
+ *
+ * Must be called after each successful
+ * call to \ref AcquireMonitorData.
+ * \param [in] hMonitor The monitor handle
+ */
+ virtual void STDMETHODCALLTYPE ReleaseMonitorData() = 0;
+
+};
+
+
+/**
+ * \brief DXGI surface interface for Vulkan interop
+ *
+ * Provides access to the backing resource of a
+ * DXGI surface, which is typically a D3D texture.
+ */
+MIDL_INTERFACE("5546cf8c-77e7-4341-b05d-8d4d5000e77d")
+IDXGIVkInteropSurface : public IUnknown {
+ /**
+ * \brief Retrieves device interop interfaceSlots
+ *
+ * Queries the device that owns the surface for
+ * the \ref IDXGIVkInteropDevice interface.
+ * \param [out] ppDevice The device interface
+ * \returns \c S_OK on success
+ */
+ virtual HRESULT STDMETHODCALLTYPE GetDevice(
+ IDXGIVkInteropDevice** ppDevice) = 0;
+
+ /**
+ * \brief Retrieves Vulkan image info
+ *
+ * Retrieves both the image handle as well as the image's
+ * properties. Any of the given pointers may be \c nullptr.
+ *
+ * If \c pInfo is not \c nullptr, the following rules apply:
+ * - \c pInfo->sType \e must be \c VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
+ * - \c pInfo->pNext \e must be \c nullptr or point to a supported
+ * extension-specific structure (currently none)
+ * - \c pInfo->queueFamilyIndexCount must be the length of the
+ * \c pInfo->pQueueFamilyIndices array, in \c uint32_t units.
+ * - \c pInfo->pQueueFamilyIndices must point to a pre-allocated
+ * array of \c uint32_t of size \c pInfo->pQueueFamilyIndices.
+ *
+ * \note As of now, the sharing mode will always be
+ * \c VK_SHARING_MODE_EXCLUSIVE and no queue
+ * family indices will be written to the array.
+ *
+ * After the call, the structure pointed to by \c pInfo can
+ * be used to create an image with identical properties.
+ *
+ * If \c pLayout is not \c nullptr, it will receive the
+ * layout that the image will be in after flushing any
+ * outstanding commands on the device.
+ * \param [out] pHandle The image handle
+ * \param [out] pLayout Image layout
+ * \param [out] pInfo Image properties
+ * \returns \c S_OK on success, or \c E_INVALIDARG
+ */
+ virtual HRESULT STDMETHODCALLTYPE GetVulkanImageInfo(
+ VkImage* pHandle,
+ VkImageLayout* pLayout,
+ VkImageCreateInfo* pInfo) = 0;
+};
+
+
+/**
+ * \brief DXGI device interface for Vulkan interop
+ *
+ * Provides access to the device and instance handles
+ * as well as the queue that is used for rendering.
+ */
+MIDL_INTERFACE("e2ef5fa5-dc21-4af7-90c4-f67ef6a09323")
+IDXGIVkInteropDevice : public IUnknown {
+ /**
+ * \brief Queries Vulkan handles used by DXVK
+ *
+ * \param [out] pInstance The Vulkan instance
+ * \param [out] pPhysDev The physical device
+ * \param [out] pDevide The device handle
+ */
+ virtual void STDMETHODCALLTYPE GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev,
+ VkDevice* pDevice) = 0;
+
+ /**
+ * \brief Queries the rendering queue used by DXVK
+ *
+ * \param [out] pQueue The Vulkan queue handle
+ * \param [out] pQueueFamilyIndex Queue family index
+ */
+ virtual void STDMETHODCALLTYPE GetSubmissionQueue(
+ VkQueue* pQueue,
+ uint32_t* pQueueFamilyIndex) = 0;
+
+ /**
+ * \brief Transitions a surface to a given layout
+ *
+ * Executes an explicit image layout transition on the
+ * D3D device. Note that the image subresources \e must
+ * be transitioned back to its original layout before
+ * using it again from D3D11.
+ * \param [in] pSurface The image to transform
+ * \param [in] pSubresources Subresources to transform
+ * \param [in] OldLayout Current image layout
+ * \param [in] NewLayout Desired image layout
+ */
+ virtual void STDMETHODCALLTYPE TransitionSurfaceLayout(
+ IDXGIVkInteropSurface* pSurface,
+ const VkImageSubresourceRange* pSubresources,
+ VkImageLayout OldLayout,
+ VkImageLayout NewLayout) = 0;
+
+ /**
+ * \brief Flushes outstanding D3D rendering commands
+ *
+ * Must be called before submitting Vulkan commands
+ * to the rendering queue if those commands use the
+ * backing resource of a D3D11 object.
+ */
+ virtual void STDMETHODCALLTYPE FlushRenderingCommands() = 0;
+
+ /**
+ * \brief Locks submission queue
+ *
+ * Should be called immediately before submitting
+ * Vulkan commands to the rendering queue in order
+ * to prevent DXVK from using the queue.
+ *
+ * While the submission queue is locked, no D3D11
+ * methods must be called from the locking thread,
+ * or otherwise a deadlock might occur.
+ */
+ virtual void STDMETHODCALLTYPE LockSubmissionQueue() = 0;
+
+ /**
+ * \brief Releases submission queue
+ *
+ * Should be called immediately after submitting
+ * Vulkan commands to the rendering queue in order
+ * to allow DXVK to submit new commands.
+ */
+ virtual void STDMETHODCALLTYPE ReleaseSubmissionQueue() = 0;
+};
+
+struct D3D11_TEXTURE2D_DESC1;
+struct ID3D11Texture2D;
+
+/**
+ * \brief See IDXGIVkInteropDevice.
+ */
+MIDL_INTERFACE("e2ef5fa5-dc21-4af7-90c4-f67ef6a09324")
+IDXGIVkInteropDevice1 : public IDXGIVkInteropDevice {
+ /**
+ * \brief Queries the rendering queue used by DXVK
+ *
+ * \param [out] pQueue The Vulkan queue handle
+ * \param [out] pQueueIndex Queue index
+ * \param [out] pQueueFamilyIndex Queue family index
+ */
+ virtual void STDMETHODCALLTYPE GetSubmissionQueue1(
+ VkQueue* pQueue,
+ uint32_t* pQueueIndex,
+ uint32_t* pQueueFamilyIndex) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateTexture2DFromVkImage(
+ const D3D11_TEXTURE2D_DESC1 *pDesc,
+ VkImage vkImage,
+ ID3D11Texture2D **ppTexture2D) = 0;
+};
+
+/**
+ * \brief DXGI adapter interface for Vulkan interop
+ *
+ * Provides access to the physical device and
+ * instance handles for the given DXGI adapter.
+ */
+MIDL_INTERFACE("3a6d8f2c-b0e8-4ab4-b4dc-4fd24891bfa5")
+IDXGIVkInteropAdapter : public IUnknown {
+ /**
+ * \brief Queries Vulkan handles used by DXVK
+ *
+ * \param [out] pInstance The Vulkan instance
+ * \param [out] pPhysDev The physical device
+ */
+ virtual void STDMETHODCALLTYPE GetVulkanHandles(
+ VkInstance* pInstance,
+ VkPhysicalDevice* pPhysDev) = 0;
+};
+
+
+/**
+ * \brief IWineDXGISwapChainFactory device interface
+ *
+ * Allows a swap chain to be created from a device.
+ * See include/wine/winedxgi.idl for definition.
+ */
+MIDL_INTERFACE("53cb4ff0-c25a-4164-a891-0e83db0a7aac")
+IWineDXGISwapChainFactory : public IUnknown {
+ virtual HRESULT STDMETHODCALLTYPE CreateSwapChainForHwnd(
+ IDXGIFactory* pFactory,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
+ IDXGIOutput* pRestrictToOutput,
+ IDXGISwapChain1** ppSwapChain) = 0;
+};
+
+
+#ifdef _MSC_VER
+struct __declspec(uuid("907bf281-ea3c-43b4-a8e4-9f231107b4ff")) IDXGIDXVKAdapter;
+struct __declspec(uuid("92a5d77b-b6e1-420a-b260-fdd701272827")) IDXGIDXVKDevice;
+struct __declspec(uuid("c06a236f-5be3-448a-8943-89c611c0c2c1")) IDXGIVkMonitorInfo;
+struct __declspec(uuid("3a6d8f2c-b0e8-4ab4-b4dc-4fd24891bfa5")) IDXGIVkInteropAdapter;
+struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09323")) IDXGIVkInteropDevice;
+struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09324")) IDXGIVkInteropDevice1;
+struct __declspec(uuid("5546cf8c-77e7-4341-b05d-8d4d5000e77d")) IDXGIVkInteropSurface;
+struct __declspec(uuid("104001a6-7f36-4957-b932-86ade9567d91")) IDXGIVkSwapChain;
+struct __declspec(uuid("53cb4ff0-c25a-4164-a891-0e83db0a7aac")) IWineDXGISwapChainFactory;
+#else
+__CRT_UUID_DECL(IDXGIDXVKAdapter, 0x907bf281,0xea3c,0x43b4,0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff);
+__CRT_UUID_DECL(IDXGIDXVKDevice, 0x92a5d77b,0xb6e1,0x420a,0xb2,0x60,0xfd,0xf7,0x01,0x27,0x28,0x27);
+__CRT_UUID_DECL(IDXGIVkMonitorInfo, 0xc06a236f,0x5be3,0x448a,0x89,0x43,0x89,0xc6,0x11,0xc0,0xc2,0xc1);
+__CRT_UUID_DECL(IDXGIVkInteropAdapter, 0x3a6d8f2c,0xb0e8,0x4ab4,0xb4,0xdc,0x4f,0xd2,0x48,0x91,0xbf,0xa5);
+__CRT_UUID_DECL(IDXGIVkInteropDevice, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x23);
+__CRT_UUID_DECL(IDXGIVkInteropDevice1, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x24);
+__CRT_UUID_DECL(IDXGIVkInteropSurface, 0x5546cf8c,0x77e7,0x4341,0xb0,0x5d,0x8d,0x4d,0x50,0x00,0xe7,0x7d);
+__CRT_UUID_DECL(IDXGIVkSwapChain, 0x104001a6,0x7f36,0x4957,0xb9,0x32,0x86,0xad,0xe9,0x56,0x7d,0x91);
+__CRT_UUID_DECL(IWineDXGISwapChainFactory, 0x53cb4ff0,0xc25a,0x4164,0xa8,0x91,0x0e,0x83,0xdb,0x0a,0x7a,0xac);
+#endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_main.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_main.cpp
new file mode 100644
index 00000000..88208fd8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_main.cpp
@@ -0,0 +1,59 @@
+#include "dxgi_factory.h"
+#include "dxgi_include.h"
+
+namespace dxvk {
+
+#ifndef VBOX
+ Logger Logger::s_instance("dxgi.log");
+#endif
+
+ HRESULT createDxgiFactory(UINT Flags, REFIID riid, void **ppFactory) {
+ try {
+ Com<DxgiFactory> factory = new DxgiFactory(Flags);
+ HRESULT hr = factory->QueryInterface(riid, ppFactory);
+
+ if (FAILED(hr))
+ return hr;
+
+ return S_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return E_FAIL;
+ }
+ }
+}
+
+extern "C" {
+ DLLEXPORT HRESULT __stdcall CreateDXGIFactory2(UINT Flags, REFIID riid, void **ppFactory) {
+ dxvk::Logger::warn("CreateDXGIFactory2: Ignoring flags");
+ return dxvk::createDxgiFactory(Flags, riid, ppFactory);
+ }
+
+ DLLEXPORT HRESULT __stdcall CreateDXGIFactory1(REFIID riid, void **ppFactory) {
+ return dxvk::createDxgiFactory(0, riid, ppFactory);
+ }
+
+ DLLEXPORT HRESULT __stdcall CreateDXGIFactory(REFIID riid, void **ppFactory) {
+ return dxvk::createDxgiFactory(0, riid, ppFactory);
+ }
+
+ DLLEXPORT HRESULT __stdcall DXGIDeclareAdapterRemovalSupport() {
+ static bool enabled = false;
+
+ if (std::exchange(enabled, true))
+ return 0x887a0036; // DXGI_ERROR_ALREADY_EXISTS;
+
+ dxvk::Logger::warn("DXGIDeclareAdapterRemovalSupport: Stub");
+ return S_OK;
+ }
+
+ DLLEXPORT HRESULT __stdcall DXGIGetDebugInterface1(UINT Flags, REFIID riid, void **ppDebug) {
+ static bool errorShown = false;
+
+ if (!std::exchange(errorShown, true))
+ dxvk::Logger::warn("DXGIGetDebugInterface1: Stub");
+
+ return E_NOINTERFACE;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.cpp
new file mode 100644
index 00000000..16b376fa
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.cpp
@@ -0,0 +1,111 @@
+#include "dxgi_monitor.h"
+
+namespace dxvk {
+
+ DxgiMonitorInfo::DxgiMonitorInfo(IUnknown* pParent)
+ : m_parent(pParent) {
+
+ }
+
+
+ DxgiMonitorInfo::~DxgiMonitorInfo() {
+
+ }
+
+
+ ULONG STDMETHODCALLTYPE DxgiMonitorInfo::AddRef() {
+ return m_parent->AddRef();
+ }
+
+
+ ULONG STDMETHODCALLTYPE DxgiMonitorInfo::Release() {
+ return m_parent->Release();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiMonitorInfo::QueryInterface(
+ REFIID riid,
+ void** ppvObject) {
+ return m_parent->QueryInterface(riid, ppvObject);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiMonitorInfo::InitMonitorData(
+ HMONITOR hMonitor,
+ const DXGI_VK_MONITOR_DATA* pData) {
+ if (!hMonitor || !pData)
+ return E_INVALIDARG;
+
+ std::lock_guard<dxvk::mutex> lock(m_monitorMutex);
+ auto result = m_monitorData.insert({ hMonitor, *pData });
+
+ return result.second ? S_OK : E_INVALIDARG;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiMonitorInfo::AcquireMonitorData(
+ HMONITOR hMonitor,
+ DXGI_VK_MONITOR_DATA** ppData) {
+ InitReturnPtr(ppData);
+
+ if (!hMonitor || !ppData)
+ return E_INVALIDARG;
+
+ m_monitorMutex.lock();
+
+ auto entry = m_monitorData.find(hMonitor);
+ if (entry == m_monitorData.end()) {
+ m_monitorMutex.unlock();
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+ *ppData = &entry->second;
+ return S_OK;
+ }
+
+
+ void STDMETHODCALLTYPE DxgiMonitorInfo::ReleaseMonitorData() {
+ m_monitorMutex.unlock();
+ }
+
+
+ uint32_t GetMonitorFormatBpp(DXGI_FORMAT Format) {
+ switch (Format) {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ return 32;
+
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ return 64;
+
+ default:
+ Logger::warn(str::format(
+ "GetMonitorFormatBpp: Unknown format: ",
+ Format));
+ return 32;
+ }
+ }
+
+ DXGI_FORMAT GetBppMonitorFormat(uint32_t bpp) {
+ switch (bpp) {
+ case 32:
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+
+ case 64:
+ return DXGI_FORMAT_R16G16B16A16_FLOAT;
+
+ default:
+ Logger::warn(str::format(
+ "GetBppMonitorFormat: Unknown bpp: ",
+ bpp));
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.h
new file mode 100644
index 00000000..ebeabf9b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_monitor.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "dxgi_interfaces.h"
+
+#include "../wsi/wsi_mode.h"
+
+namespace dxvk {
+
+ class DxgiSwapChain;
+
+ class DxgiMonitorInfo : public IDXGIVkMonitorInfo {
+
+ public:
+
+ DxgiMonitorInfo(IUnknown* pParent);
+
+ ~DxgiMonitorInfo();
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE InitMonitorData(
+ HMONITOR hMonitor,
+ const DXGI_VK_MONITOR_DATA* pData);
+
+ HRESULT STDMETHODCALLTYPE AcquireMonitorData(
+ HMONITOR hMonitor,
+ DXGI_VK_MONITOR_DATA** ppData);
+
+ void STDMETHODCALLTYPE ReleaseMonitorData();
+
+ private:
+
+ IUnknown* m_parent;
+
+ dxvk::mutex m_monitorMutex;
+ std::unordered_map<HMONITOR, DXGI_VK_MONITOR_DATA> m_monitorData;
+
+ };
+
+
+ /**
+ * \brief Queries bits per pixel for a format
+ *
+ * The format must be a valid swap chain format.
+ * \param [in] Format The DXGI format to query
+ * \returns Bits per pixel for this format
+ */
+ uint32_t GetMonitorFormatBpp(
+ DXGI_FORMAT Format);
+
+ /**
+ * \brief Queries bits per pixel for a format
+ *
+ * \param [in] Bits per pixel to query
+ * \returns Format The DXGI format
+ */
+ DXGI_FORMAT GetBppMonitorFormat(
+ uint32_t bpp);
+
+ /**
+ * \brief Converts two display modes
+ */
+ inline void ConvertDisplayMode(
+ const wsi::WsiMode& WsiMode,
+ DXGI_MODE_DESC1* pDxgiMode) {
+ pDxgiMode->Width = WsiMode.width;
+ pDxgiMode->Height = WsiMode.height;
+ pDxgiMode->RefreshRate = DXGI_RATIONAL{ WsiMode.refreshRate.numerator, WsiMode.refreshRate.denominator };
+ pDxgiMode->Format = GetBppMonitorFormat(WsiMode.bitsPerPixel);
+ pDxgiMode->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
+ pDxgiMode->Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ pDxgiMode->Stereo = FALSE;
+ }
+
+ /**
+ * \brief Converts two display modes
+ */
+ inline void ConvertDisplayMode(
+ const DXGI_MODE_DESC1& DxgiMode,
+ wsi::WsiMode* pWsiMode) {
+ pWsiMode->width = DxgiMode.Width;
+ pWsiMode->height = DxgiMode.Height;
+ pWsiMode->refreshRate = wsi::WsiRational{ DxgiMode.RefreshRate.Numerator, DxgiMode.RefreshRate.Denominator };
+ pWsiMode->bitsPerPixel = GetMonitorFormatBpp(DxgiMode.Format);
+ pWsiMode->interlaced = false;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_object.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_object.h
new file mode 100644
index 00000000..aac2bb4c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_object.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "dxgi_include.h"
+
+#include "../util/com/com_private_data.h"
+
+namespace dxvk {
+
+ template<typename Base>
+ class DxgiObject : public ComObject<Base> {
+
+ public:
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData) final {
+ return m_privateData.getData(
+ Name, pDataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) final {
+ return m_privateData.setData(
+ Name, DataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown) final {
+ return m_privateData.setInterface(
+ Name, pUnknown);
+ }
+
+ private:
+
+ ComPrivateData m_privateData;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.cpp
new file mode 100644
index 00000000..19d4e7a5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.cpp
@@ -0,0 +1,46 @@
+#include "dxgi_options.h"
+
+#include <unordered_map>
+
+namespace dxvk {
+
+ static int32_t parsePciId(const std::string& str) {
+ if (str.size() != 4)
+ return -1;
+
+ int32_t id = 0;
+
+ for (size_t i = 0; i < str.size(); i++) {
+ id *= 16;
+
+ if (str[i] >= '0' && str[i] <= '9')
+ id += str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ id += str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ id += str[i] - 'a' + 10;
+ else
+ return -1;
+ }
+
+ return id;
+ }
+
+
+ DxgiOptions::DxgiOptions(const Config& config) {
+ // Fetch these as a string representing a hexadecimal number and parse it.
+ this->customVendorId = parsePciId(config.getOption<std::string>("dxgi.customVendorId"));
+ this->customDeviceId = parsePciId(config.getOption<std::string>("dxgi.customDeviceId"));
+ this->customDeviceDesc = config.getOption<std::string>("dxgi.customDeviceDesc", "");
+
+ // Emulate a UMA device
+ this->emulateUMA = config.getOption<bool>("dxgi.emulateUMA", false);
+
+ // Interpret the memory limits as Megabytes
+ this->maxDeviceMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxDeviceMemory", 0)) << 20;
+ this->maxSharedMemory = VkDeviceSize(config.getOption<int32_t>("dxgi.maxSharedMemory", 0)) << 20;
+
+ this->nvapiHack = config.getOption<bool>("dxgi.nvapiHack", true);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.h
new file mode 100644
index 00000000..8eb19d08
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_options.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "../util/config/config.h"
+
+#include "../dxvk/dxvk_include.h"
+
+#include "dxgi_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXGI options
+ *
+ * Per-app options that control the
+ * behaviour of some DXGI classes.
+ */
+ struct DxgiOptions {
+ DxgiOptions(const Config& config);
+
+ /// Override PCI vendor and device IDs reported to the
+ /// application. This may make apps think they are running
+ /// on a different GPU than they do and behave differently.
+ int32_t customVendorId;
+ int32_t customDeviceId;
+ std::string customDeviceDesc;
+
+ /// Override maximum reported VRAM size. This may be
+ /// useful for some 64-bit games which do not support
+ /// more than 4 GiB of VRAM.
+ VkDeviceSize maxDeviceMemory;
+ VkDeviceSize maxSharedMemory;
+
+ /// Emulate UMA
+ bool emulateUMA;
+
+ /// Enables nvapi workaround
+ bool nvapiHack;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.cpp
new file mode 100644
index 00000000..36978926
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.cpp
@@ -0,0 +1,589 @@
+#include <algorithm>
+#include <numeric>
+
+#include <cstdlib>
+#include <cstring>
+
+#include <sstream>
+#include <string>
+
+#include "dxgi_adapter.h"
+#include "dxgi_factory.h"
+#include "dxgi_output.h"
+#include "dxgi_swapchain.h"
+
+#include "../wsi/wsi_mode.h"
+#include "../dxvk/dxvk_format.h"
+
+namespace dxvk {
+
+ DxgiOutput::DxgiOutput(
+ const Com<DxgiFactory>& factory,
+ const Com<DxgiAdapter>& adapter,
+ HMONITOR monitor)
+ : m_monitorInfo(factory->GetMonitorInfo()),
+ m_adapter(adapter),
+ m_monitor(monitor) {
+ // Init monitor info if necessary
+ DXGI_VK_MONITOR_DATA monitorData;
+ monitorData.pSwapChain = nullptr;
+ monitorData.FrameStats = DXGI_FRAME_STATISTICS();
+ monitorData.GammaCurve.Scale = { 1.0f, 1.0f, 1.0f };
+ monitorData.GammaCurve.Offset = { 0.0f, 0.0f, 0.0f };
+
+ for (uint32_t i = 0; i < DXGI_VK_GAMMA_CP_COUNT; i++) {
+ const float value = GammaControlPointLocation(i);
+ monitorData.GammaCurve.GammaCurve[i] = { value, value, value };
+ }
+
+ m_monitorInfo->InitMonitorData(monitor, &monitorData);
+ }
+
+
+ DxgiOutput::~DxgiOutput() {
+
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIOutput)
+ || riid == __uuidof(IDXGIOutput1)
+ || riid == __uuidof(IDXGIOutput2)
+ || riid == __uuidof(IDXGIOutput3)
+ || riid == __uuidof(IDXGIOutput4)
+ || riid == __uuidof(IDXGIOutput5)
+ || riid == __uuidof(IDXGIOutput6)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("DxgiOutput::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetParent(REFIID riid, void **ppParent) {
+ return m_adapter->QueryInterface(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::FindClosestMatchingMode(
+ const DXGI_MODE_DESC *pModeToMatch,
+ DXGI_MODE_DESC *pClosestMatch,
+ IUnknown *pConcernedDevice) {
+ if (!pModeToMatch || !pClosestMatch)
+ return DXGI_ERROR_INVALID_CALL;
+
+ DXGI_MODE_DESC1 modeToMatch;
+ modeToMatch.Width = pModeToMatch->Width;
+ modeToMatch.Height = pModeToMatch->Height;
+ modeToMatch.RefreshRate = pModeToMatch->RefreshRate;
+ modeToMatch.Format = pModeToMatch->Format;
+ modeToMatch.ScanlineOrdering = pModeToMatch->ScanlineOrdering;
+ modeToMatch.Scaling = pModeToMatch->Scaling;
+ modeToMatch.Stereo = FALSE;
+
+ DXGI_MODE_DESC1 closestMatch = { };
+
+ HRESULT hr = FindClosestMatchingMode1(
+ &modeToMatch, &closestMatch, pConcernedDevice);
+
+ if (FAILED(hr))
+ return hr;
+
+ pClosestMatch->Width = closestMatch.Width;
+ pClosestMatch->Height = closestMatch.Height;
+ pClosestMatch->RefreshRate = closestMatch.RefreshRate;
+ pClosestMatch->Format = closestMatch.Format;
+ pClosestMatch->ScanlineOrdering = closestMatch.ScanlineOrdering;
+ pClosestMatch->Scaling = closestMatch.Scaling;
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::FindClosestMatchingMode1(
+ const DXGI_MODE_DESC1* pModeToMatch,
+ DXGI_MODE_DESC1* pClosestMatch,
+ IUnknown* pConcernedDevice) {
+ if (!pModeToMatch || !pClosestMatch)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (pModeToMatch->Format == DXGI_FORMAT_UNKNOWN && !pConcernedDevice)
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Both or neither must be zero
+ if ((pModeToMatch->Width == 0) ^ (pModeToMatch->Height == 0))
+ return DXGI_ERROR_INVALID_CALL;
+
+ wsi::WsiMode activeWsiMode = { };
+ wsi::getCurrentDisplayMode(m_monitor, &activeWsiMode);
+
+ DXGI_MODE_DESC1 activeMode = { };
+ ConvertDisplayMode(activeWsiMode, &activeMode);
+
+ DXGI_MODE_DESC1 defaultMode;
+ defaultMode.Width = 0;
+ defaultMode.Height = 0;
+ defaultMode.RefreshRate = { 0, 0 };
+ defaultMode.Format = DXGI_FORMAT_UNKNOWN;
+ defaultMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ defaultMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ defaultMode.Stereo = pModeToMatch->Stereo;
+
+ if (pModeToMatch->ScanlineOrdering == DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED)
+ defaultMode.ScanlineOrdering = activeMode.ScanlineOrdering;
+
+ if (pModeToMatch->Scaling == DXGI_MODE_SCALING_UNSPECIFIED)
+ defaultMode.Scaling = activeMode.Scaling;
+
+ DXGI_FORMAT targetFormat = pModeToMatch->Format;
+
+ if (pModeToMatch->Format == DXGI_FORMAT_UNKNOWN) {
+ defaultMode.Format = activeMode.Format;
+ targetFormat = activeMode.Format;
+ }
+
+ if (!pModeToMatch->Width) {
+ defaultMode.Width = activeMode.Width;
+ defaultMode.Height = activeMode.Height;
+ }
+
+ if (!pModeToMatch->RefreshRate.Numerator || !pModeToMatch->RefreshRate.Denominator) {
+ defaultMode.RefreshRate.Numerator = activeMode.RefreshRate.Numerator;
+ defaultMode.RefreshRate.Denominator = activeMode.RefreshRate.Denominator;
+ }
+
+ UINT modeCount = 0;
+ GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, nullptr);
+
+ if (modeCount == 0) {
+ Logger::err("DXGI: FindClosestMatchingMode: No modes found");
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+ std::vector<DXGI_MODE_DESC1> modes(modeCount);
+ GetDisplayModeList1(targetFormat, DXGI_ENUM_MODES_SCALING, &modeCount, modes.data());
+
+ FilterModesByDesc(modes, *pModeToMatch);
+ FilterModesByDesc(modes, defaultMode);
+
+ if (modes.empty())
+ return DXGI_ERROR_NOT_FOUND;
+
+ *pClosestMatch = modes[0];
+
+ Logger::debug(str::format(
+ "DXGI: For mode ",
+ pModeToMatch->Width, "x", pModeToMatch->Height, "@",
+ pModeToMatch->RefreshRate.Denominator ? (pModeToMatch->RefreshRate.Numerator / pModeToMatch->RefreshRate.Denominator) : 0,
+ " found closest mode ",
+ pClosestMatch->Width, "x", pClosestMatch->Height, "@",
+ pClosestMatch->RefreshRate.Denominator ? (pClosestMatch->RefreshRate.Numerator / pClosestMatch->RefreshRate.Denominator) : 0));
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDesc(DXGI_OUTPUT_DESC *pDesc) {
+ if (pDesc == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ DXGI_OUTPUT_DESC1 desc;
+ HRESULT hr = GetDesc1(&desc);
+
+ if (SUCCEEDED(hr)) {
+ std::memcpy(pDesc->DeviceName, desc.DeviceName, sizeof(pDesc->DeviceName));
+ pDesc->DesktopCoordinates = desc.DesktopCoordinates;
+ pDesc->AttachedToDesktop = desc.AttachedToDesktop;
+ pDesc->Rotation = desc.Rotation;
+ pDesc->Monitor = desc.Monitor;
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDesc1(
+ DXGI_OUTPUT_DESC1* pDesc) {
+ if (pDesc == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (!wsi::getDesktopCoordinates(m_monitor, &pDesc->DesktopCoordinates)) {
+ Logger::err("DXGI: Failed to query monitor coords");
+ return E_FAIL;
+ }
+
+ if (!wsi::getDisplayName(m_monitor, pDesc->DeviceName)) {
+ Logger::err("DXGI: Failed to query monitor name");
+ return E_FAIL;
+ }
+
+ pDesc->AttachedToDesktop = 1;
+ pDesc->Rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
+ pDesc->Monitor = m_monitor;
+ pDesc->BitsPerColor = 8;
+ pDesc->ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
+
+ // We don't really have a way to get these
+ for (uint32_t i = 0; i < 2; i++) {
+ pDesc->RedPrimary[i] = 0.0f;
+ pDesc->GreenPrimary[i] = 0.0f;
+ pDesc->BluePrimary[i] = 0.0f;
+ pDesc->WhitePoint[i] = 0.0f;
+ }
+
+ pDesc->MinLuminance = 0.0f;
+ pDesc->MaxLuminance = 0.0f;
+ pDesc->MaxFullFrameLuminance = 0.0f;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplayModeList(
+ DXGI_FORMAT EnumFormat,
+ UINT Flags,
+ UINT* pNumModes,
+ DXGI_MODE_DESC* pDesc) {
+ if (pNumModes == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ std::vector<DXGI_MODE_DESC1> modes;
+
+ if (pDesc)
+ modes.resize(std::max(1u, *pNumModes));
+
+ HRESULT hr = GetDisplayModeList1(
+ EnumFormat, Flags, pNumModes,
+ pDesc ? modes.data() : nullptr);
+
+ for (uint32_t i = 0; i < *pNumModes && i < modes.size(); i++) {
+ pDesc[i].Width = modes[i].Width;
+ pDesc[i].Height = modes[i].Height;
+ pDesc[i].RefreshRate = modes[i].RefreshRate;
+ pDesc[i].Format = modes[i].Format;
+ pDesc[i].ScanlineOrdering = modes[i].ScanlineOrdering;
+ pDesc[i].Scaling = modes[i].Scaling;
+ }
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplayModeList1(
+ DXGI_FORMAT EnumFormat,
+ UINT Flags,
+ UINT* pNumModes,
+ DXGI_MODE_DESC1* pDesc) {
+ if (pNumModes == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Special case, just return zero modes
+ if (EnumFormat == DXGI_FORMAT_UNKNOWN) {
+ *pNumModes = 0;
+ return S_OK;
+ }
+
+ // Walk over all modes that the display supports and
+ // return those that match the requested format etc.
+ wsi::WsiMode devMode = { };
+
+ uint32_t srcModeId = 0;
+ uint32_t dstModeId = 0;
+
+ std::vector<DXGI_MODE_DESC1> modeList;
+
+ while (wsi::getDisplayMode(m_monitor, srcModeId++, &devMode)) {
+ // Skip interlaced modes altogether
+ if (devMode.interlaced)
+ continue;
+
+ // Skip modes with incompatible formats
+ if (devMode.bitsPerPixel != GetMonitorFormatBpp(EnumFormat))
+ continue;
+
+ if (pDesc != nullptr) {
+ DXGI_MODE_DESC1 mode;
+ mode.Width = devMode.width;
+ mode.Height = devMode.height;
+ mode.RefreshRate = { devMode.refreshRate.numerator, devMode.refreshRate.denominator };
+ mode.Format = EnumFormat;
+ mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
+ mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+ mode.Stereo = FALSE;
+ modeList.push_back(mode);
+ }
+
+ dstModeId += 1;
+ }
+
+ // Sort display modes by width, height and refresh rate,
+ // in that order. Some games rely on correct ordering.
+ std::sort(modeList.begin(), modeList.end(),
+ [] (const DXGI_MODE_DESC1& a, const DXGI_MODE_DESC1& b) {
+ if (a.Width < b.Width) return true;
+ if (a.Width > b.Width) return false;
+
+ if (a.Height < b.Height) return true;
+ if (a.Height > b.Height) return false;
+
+ return (a.RefreshRate.Numerator / a.RefreshRate.Denominator)
+ < (b.RefreshRate.Numerator / b.RefreshRate.Denominator);
+ });
+
+ // If requested, write out the first set of display
+ // modes to the destination array.
+ if (pDesc != nullptr) {
+ for (uint32_t i = 0; i < *pNumModes && i < dstModeId; i++)
+ pDesc[i] = modeList[i];
+
+ if (dstModeId > *pNumModes)
+ return DXGI_ERROR_MORE_DATA;
+ }
+
+ *pNumModes = dstModeId;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplaySurfaceData(IDXGISurface* pDestination) {
+ Logger::err("DxgiOutput::GetDisplaySurfaceData: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+ HRESULT hr = m_monitorInfo->AcquireMonitorData(m_monitor, &monitorInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("DxgiOutput::GetFrameStatistics: Stub");
+
+ *pStats = monitorInfo->FrameStats;
+ m_monitorInfo->ReleaseMonitorData();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL* pArray) {
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+ HRESULT hr = m_monitorInfo->AcquireMonitorData(m_monitor, &monitorInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ *pArray = monitorInfo->GammaCurve;
+ m_monitorInfo->ReleaseMonitorData();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES* pGammaCaps) {
+ pGammaCaps->ScaleAndOffsetSupported = FALSE;
+ pGammaCaps->MaxConvertedValue = 1.0f;
+ pGammaCaps->MinConvertedValue = 0.0f;
+ pGammaCaps->NumGammaControlPoints = DXGI_VK_GAMMA_CP_COUNT;
+
+ for (uint32_t i = 0; i < pGammaCaps->NumGammaControlPoints; i++)
+ pGammaCaps->ControlPointPositions[i] = GammaControlPointLocation(i);
+ return S_OK;
+ }
+
+
+ void STDMETHODCALLTYPE DxgiOutput::ReleaseOwnership() {
+ Logger::warn("DxgiOutput::ReleaseOwnership: Stub");
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::SetDisplaySurface(IDXGISurface* pScanoutSurface) {
+ Logger::err("DxgiOutput::SetDisplaySurface: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplaySurfaceData1(IDXGIResource* pDestination) {
+ Logger::err("DxgiOutput::SetDisplaySurface1: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL* pArray) {
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+ HRESULT hr = m_monitorInfo->AcquireMonitorData(m_monitor, &monitorInfo);
+
+ if (FAILED(hr))
+ return hr;
+
+ monitorInfo->GammaCurve = *pArray;
+
+ if (monitorInfo->pSwapChain) {
+ hr = monitorInfo->pSwapChain->SetGammaControl(
+ DXGI_VK_GAMMA_CP_COUNT, pArray->GammaCurve);
+ }
+
+ m_monitorInfo->ReleaseMonitorData();
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::TakeOwnership(
+ IUnknown *pDevice,
+ BOOL Exclusive) {
+ Logger::warn("DxgiOutput::TakeOwnership: Stub");
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::WaitForVBlank() {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("DxgiOutput::WaitForVBlank: Stub");
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::DuplicateOutput(
+ IUnknown* pDevice,
+ IDXGIOutputDuplication** ppOutputDuplication) {
+ return DuplicateOutput1(pDevice, 0, 0, nullptr, ppOutputDuplication);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::DuplicateOutput1(
+ IUnknown* pDevice,
+ UINT Flags,
+ UINT SupportedFormatsCount,
+ const DXGI_FORMAT* pSupportedFormats,
+ IDXGIOutputDuplication** ppOutputDuplication) {
+ InitReturnPtr(ppOutputDuplication);
+
+ if (!pDevice)
+ return E_INVALIDARG;
+
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::err("DxgiOutput::DuplicateOutput1: Not implemented");
+
+ // At least return a valid error code
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ BOOL DxgiOutput::SupportsOverlays() {
+ return FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::CheckOverlaySupport(
+ DXGI_FORMAT EnumFormat,
+ IUnknown* pConcernedDevice,
+ UINT* pFlags) {
+ Logger::warn("DxgiOutput: CheckOverlaySupport: Stub");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::CheckOverlayColorSpaceSupport(
+ DXGI_FORMAT Format,
+ DXGI_COLOR_SPACE_TYPE ColorSpace,
+ IUnknown* pConcernedDevice,
+ UINT* pFlags) {
+ Logger::warn("DxgiOutput: CheckOverlayColorSpaceSupport: Stub");
+ return DXGI_ERROR_UNSUPPORTED;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiOutput::CheckHardwareCompositionSupport(
+ UINT* pFlags) {
+ Logger::warn("DxgiOutput: CheckHardwareCompositionSupport: Stub");
+
+ *pFlags = 0;
+ return S_OK;
+ }
+
+
+ void DxgiOutput::FilterModesByDesc(
+ std::vector<DXGI_MODE_DESC1>& Modes,
+ const DXGI_MODE_DESC1& TargetMode) {
+ uint32_t minDiffResolution = 0;
+ uint32_t minDiffRefreshRate = 0;
+
+ if (TargetMode.Width) {
+ minDiffResolution = std::accumulate(
+ Modes.begin(), Modes.end(), std::numeric_limits<uint32_t>::max(),
+ [&TargetMode] (uint32_t current, const DXGI_MODE_DESC1& mode) {
+ uint32_t diff = std::abs(int32_t(TargetMode.Width - mode.Width))
+ + std::abs(int32_t(TargetMode.Height - mode.Height));
+ return std::min(current, diff);
+ });
+ }
+
+ if (TargetMode.RefreshRate.Numerator && TargetMode.RefreshRate.Denominator) {
+ minDiffRefreshRate = std::accumulate(
+ Modes.begin(), Modes.end(), std::numeric_limits<uint64_t>::max(),
+ [&TargetMode] (uint64_t current, const DXGI_MODE_DESC1& mode) {
+ uint64_t rate = uint64_t(mode.RefreshRate.Numerator)
+ * uint64_t(TargetMode.RefreshRate.Denominator)
+ / uint64_t(mode.RefreshRate.Denominator);
+ uint64_t diff = std::abs(int64_t(rate - uint64_t(TargetMode.RefreshRate.Numerator)));
+ return std::min(current, diff);
+ });
+ }
+
+ bool testScanlineOrder = false;
+ bool testScaling = false;
+ bool testFormat = false;
+
+ for (const auto& mode : Modes) {
+ testScanlineOrder |= TargetMode.ScanlineOrdering != DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED
+ && TargetMode.ScanlineOrdering == mode.ScanlineOrdering;
+ testScaling |= TargetMode.Scaling != DXGI_MODE_SCALING_UNSPECIFIED
+ && TargetMode.Scaling == mode.Scaling;
+ testFormat |= TargetMode.Format != DXGI_FORMAT_UNKNOWN
+ && TargetMode.Format == mode.Format;
+ }
+
+ for (auto it = Modes.begin(); it != Modes.end(); ) {
+ bool skipMode = it->Stereo != TargetMode.Stereo;
+
+ if (testScanlineOrder)
+ skipMode |= it->ScanlineOrdering != TargetMode.ScanlineOrdering;
+
+ if (testScaling)
+ skipMode |= it->Scaling != TargetMode.Scaling;
+
+ if (testFormat)
+ skipMode |= it->Format != TargetMode.Format;
+
+ if (TargetMode.Width) {
+ uint32_t diff = std::abs(int32_t(TargetMode.Width - it->Width))
+ + std::abs(int32_t(TargetMode.Height - it->Height));
+ skipMode |= diff != minDiffResolution;
+ }
+
+ if (TargetMode.RefreshRate.Numerator && TargetMode.RefreshRate.Denominator) {
+ uint64_t rate = uint64_t(it->RefreshRate.Numerator)
+ * uint64_t(TargetMode.RefreshRate.Denominator)
+ / uint64_t(it->RefreshRate.Denominator);
+ uint64_t diff = std::abs(int64_t(rate - uint64_t(TargetMode.RefreshRate.Numerator)));
+ skipMode |= diff != minDiffRefreshRate;
+ }
+
+ it = skipMode ? Modes.erase(it) : ++it;
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.h
new file mode 100644
index 00000000..0dc30868
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_output.h
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "dxgi_monitor.h"
+#include "dxgi_object.h"
+
+namespace dxvk {
+
+ class DxgiAdapter;
+ class DxgiFactory;
+
+ /**
+ * \brief Number of gamma control points
+ */
+ constexpr uint32_t DXGI_VK_GAMMA_CP_COUNT = 1024;
+
+ /**
+ * \brief Computes gamma control point location
+ *
+ * \param [in] CpIndex Control point ID
+ * \returns Location of the control point
+ */
+ inline float GammaControlPointLocation(uint32_t CpIndex) {
+ return float(CpIndex) / float(DXGI_VK_GAMMA_CP_COUNT - 1);
+ }
+
+
+ class DxgiOutput : public DxgiObject<IDXGIOutput6> {
+
+ public:
+
+ DxgiOutput(
+ const Com<DxgiFactory>& factory,
+ const Com<DxgiAdapter>& adapter,
+ HMONITOR monitor);
+
+ ~DxgiOutput();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent) final;
+
+ HRESULT STDMETHODCALLTYPE FindClosestMatchingMode(
+ const DXGI_MODE_DESC* pModeToMatch,
+ DXGI_MODE_DESC* pClosestMatch,
+ IUnknown* pConcernedDevice) final;
+
+ HRESULT STDMETHODCALLTYPE FindClosestMatchingMode1(
+ const DXGI_MODE_DESC1* pModeToMatch,
+ DXGI_MODE_DESC1* pClosestMatch,
+ IUnknown* pConcernedDevice) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_OUTPUT_DESC* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc1(
+ DXGI_OUTPUT_DESC1* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDisplayModeList(
+ DXGI_FORMAT EnumFormat,
+ UINT Flags,
+ UINT* pNumModes,
+ DXGI_MODE_DESC* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDisplayModeList1(
+ DXGI_FORMAT EnumFormat,
+ UINT Flags,
+ UINT* pNumModes,
+ DXGI_MODE_DESC1* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData(
+ IDXGISurface* pDestination) final;
+
+ HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData1(
+ IDXGIResource* pDestination) final;
+
+ HRESULT STDMETHODCALLTYPE GetFrameStatistics(
+ DXGI_FRAME_STATISTICS* pStats) final;
+
+ HRESULT STDMETHODCALLTYPE GetGammaControl(
+ DXGI_GAMMA_CONTROL* pArray) final;
+
+ HRESULT STDMETHODCALLTYPE GetGammaControlCapabilities(
+ DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) final;
+
+ void STDMETHODCALLTYPE ReleaseOwnership() final;
+
+ HRESULT STDMETHODCALLTYPE SetDisplaySurface(
+ IDXGISurface* pScanoutSurface) final;
+
+ HRESULT STDMETHODCALLTYPE SetGammaControl(
+ const DXGI_GAMMA_CONTROL* pArray) final;
+
+ HRESULT STDMETHODCALLTYPE TakeOwnership(
+ IUnknown* pDevice,
+ BOOL Exclusive) final;
+
+ HRESULT STDMETHODCALLTYPE WaitForVBlank() final;
+
+ HRESULT STDMETHODCALLTYPE DuplicateOutput(
+ IUnknown* pDevice,
+ IDXGIOutputDuplication** ppOutputDuplication) final;
+
+ HRESULT STDMETHODCALLTYPE DuplicateOutput1(
+ IUnknown* pDevice,
+ UINT Flags,
+ UINT SupportedFormatsCount,
+ const DXGI_FORMAT* pSupportedFormats,
+ IDXGIOutputDuplication** ppOutputDuplication) final;
+
+ BOOL STDMETHODCALLTYPE SupportsOverlays() final;
+
+ HRESULT STDMETHODCALLTYPE CheckOverlaySupport(
+ DXGI_FORMAT EnumFormat,
+ IUnknown* pConcernedDevice,
+ UINT* pFlags) final;
+
+ HRESULT STDMETHODCALLTYPE CheckOverlayColorSpaceSupport(
+ DXGI_FORMAT Format,
+ DXGI_COLOR_SPACE_TYPE ColorSpace,
+ IUnknown* pConcernedDevice,
+ UINT* pFlags) final;
+
+ HRESULT STDMETHODCALLTYPE CheckHardwareCompositionSupport(
+ UINT* pFlags) final;
+
+ private:
+
+ DxgiMonitorInfo* m_monitorInfo = nullptr;
+ Com<DxgiAdapter> m_adapter = nullptr;
+ HMONITOR m_monitor = nullptr;
+
+ static void FilterModesByDesc(
+ std::vector<DXGI_MODE_DESC1>& Modes,
+ const DXGI_MODE_DESC1& TargetMode);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp
new file mode 100644
index 00000000..c49b9355
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp
@@ -0,0 +1,747 @@
+#include "dxgi_factory.h"
+#include "dxgi_output.h"
+#include "dxgi_swapchain.h"
+
+namespace dxvk {
+
+ DxgiSwapChain::DxgiSwapChain(
+ IDXGIFactory* pFactory,
+ IDXGIVkSwapChain* pPresenter,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc)
+ : m_factory (pFactory),
+ m_window (hWnd),
+ m_desc (*pDesc),
+ m_descFs (*pFullscreenDesc),
+ m_presentCount(0u),
+ m_presenter (pPresenter),
+ m_monitor (nullptr) {
+ if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&m_adapter))))
+ throw DxvkError("DXGI: Failed to get adapter for present device");
+
+ // Query monitor info form DXVK's DXGI factory, if available
+ m_factory->QueryInterface(__uuidof(IDXGIVkMonitorInfo), reinterpret_cast<void**>(&m_monitorInfo));
+
+ // Apply initial window mode and fullscreen state
+ if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
+ throw DxvkError("DXGI: Failed to set initial fullscreen state");
+ }
+
+
+ DxgiSwapChain::~DxgiSwapChain() {
+ wsi::restoreDisplayMode(m_monitor);
+
+ // Decouple swap chain from monitor if necessary
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+
+ if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) {
+ if (monitorInfo->pSwapChain == this)
+ monitorInfo->pSwapChain = nullptr;
+
+ ReleaseMonitorData();
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::QueryInterface(REFIID riid, void** ppvObject) {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGISwapChain)
+ || riid == __uuidof(IDXGISwapChain1)
+ || riid == __uuidof(IDXGISwapChain2)
+ || riid == __uuidof(IDXGISwapChain3)
+ || riid == __uuidof(IDXGISwapChain4)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("DxgiSwapChain::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return E_NOINTERFACE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetParent(REFIID riid, void** ppParent) {
+ return m_factory->QueryInterface(riid, ppParent);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDevice(REFIID riid, void** ppDevice) {
+ return m_presenter->GetDevice(riid, ppDevice);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) {
+ return m_presenter->GetImage(Buffer, riid, ppSurface);
+ }
+
+
+ UINT STDMETHODCALLTYPE DxgiSwapChain::GetCurrentBackBufferIndex() {
+ return m_presenter->GetImageIndex();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) {
+ InitReturnPtr(ppOutput);
+
+ if (!wsi::isWindow(m_window))
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (m_target != nullptr) {
+ *ppOutput = m_target.ref();
+ return S_OK;
+ }
+
+ return GetOutputFromMonitor(wsi::getWindowMonitor(m_window), ppOutput);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) {
+ if (!pDesc)
+ return E_INVALIDARG;
+
+ pDesc->BufferDesc.Width = m_desc.Width;
+ pDesc->BufferDesc.Height = m_desc.Height;
+ pDesc->BufferDesc.RefreshRate = m_descFs.RefreshRate;
+ pDesc->BufferDesc.Format = m_desc.Format;
+ pDesc->BufferDesc.ScanlineOrdering = m_descFs.ScanlineOrdering;
+ pDesc->BufferDesc.Scaling = m_descFs.Scaling;
+ pDesc->SampleDesc = m_desc.SampleDesc;
+ pDesc->BufferUsage = m_desc.BufferUsage;
+ pDesc->BufferCount = m_desc.BufferCount;
+ pDesc->OutputWindow = m_window;
+ pDesc->Windowed = m_descFs.Windowed;
+ pDesc->SwapEffect = m_desc.SwapEffect;
+ pDesc->Flags = m_desc.Flags;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc1(DXGI_SWAP_CHAIN_DESC1* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ *pDesc = m_desc;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetBackgroundColor(
+ DXGI_RGBA* pColor) {
+ Logger::err("DxgiSwapChain::GetBackgroundColor: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRotation(
+ DXGI_MODE_ROTATION* pRotation) {
+ Logger::err("DxgiSwapChain::GetRotation: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRestrictToOutput(
+ IDXGIOutput** ppRestrictToOutput) {
+ InitReturnPtr(ppRestrictToOutput);
+
+ Logger::err("DxgiSwapChain::GetRestrictToOutput: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
+ std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow);
+
+ if (!pStats)
+ return E_INVALIDARG;
+
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("DxgiSwapChain::GetFrameStatistics: Semi-stub");
+
+ // TODO deal with the refresh counts at some point
+ pStats->PresentCount = m_presentCount;
+ pStats->PresentRefreshCount = 0;
+ pStats->SyncRefreshCount = 0;
+#ifdef _WIN32
+ QueryPerformanceCounter(&pStats->SyncQPCTime);
+#endif
+ pStats->SyncGPUTime.QuadPart = 0;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenState(
+ BOOL* pFullscreen,
+ IDXGIOutput** ppTarget) {
+ if (!wsi::isWindow(m_window))
+ return DXGI_ERROR_INVALID_CALL;
+
+ HRESULT hr = S_OK;
+
+ if (pFullscreen != nullptr)
+ *pFullscreen = !m_descFs.Windowed;
+
+ if (ppTarget != nullptr)
+ *ppTarget = m_target.ref();
+
+ return hr;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenDesc(
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) {
+ if (pDesc == nullptr)
+ return E_INVALIDARG;
+
+ *pDesc = m_descFs;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetHwnd(
+ HWND* pHwnd) {
+ if (pHwnd == nullptr)
+ return E_INVALIDARG;
+
+ *pHwnd = m_window;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetCoreWindow(
+ REFIID refiid,
+ void** ppUnk) {
+ InitReturnPtr(ppUnk);
+
+ Logger::err("DxgiSwapChain::GetCoreWindow: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) {
+ if (pLastPresentCount == nullptr)
+ return E_INVALIDARG;
+
+ *pLastPresentCount = m_presentCount;
+ return S_OK;
+ }
+
+
+ BOOL STDMETHODCALLTYPE DxgiSwapChain::IsTemporaryMonoSupported() {
+ // This seems to be related to stereo 3D display
+ // modes, which we don't support at the moment
+ return FALSE;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
+ return Present1(SyncInterval, Flags, nullptr);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
+ if (!wsi::isWindow(m_window))
+ return S_OK;
+
+ if (SyncInterval > 4)
+ return DXGI_ERROR_INVALID_CALL;
+
+ std::lock_guard<dxvk::recursive_mutex> lockWin(m_lockWindow);
+ std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer);
+
+ try {
+ HRESULT hr = m_presenter->Present(SyncInterval, PresentFlags, nullptr);
+ if (hr == S_OK && !(PresentFlags & DXGI_PRESENT_TEST))
+ m_presentCount++;
+ return hr;
+ } catch (const DxvkError& err) {
+ Logger::err(err.message());
+ return DXGI_ERROR_DRIVER_INTERNAL_ERROR;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT NewFormat,
+ UINT SwapChainFlags) {
+ if (!wsi::isWindow(m_window))
+ return DXGI_ERROR_INVALID_CALL;
+
+ constexpr UINT PreserveFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+
+ if ((m_desc.Flags & PreserveFlags) != (SwapChainFlags & PreserveFlags))
+ return DXGI_ERROR_INVALID_CALL;
+
+ std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
+ m_desc.Width = Width;
+ m_desc.Height = Height;
+
+ wsi::getWindowSize(m_window,
+ m_desc.Width ? nullptr : &m_desc.Width,
+ m_desc.Height ? nullptr : &m_desc.Height);
+
+ if (BufferCount != 0)
+ m_desc.BufferCount = BufferCount;
+
+ if (NewFormat != DXGI_FORMAT_UNKNOWN)
+ m_desc.Format = NewFormat;
+
+ return m_presenter->ChangeProperties(&m_desc);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers1(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT Format,
+ UINT SwapChainFlags,
+ const UINT* pCreationNodeMask,
+ IUnknown* const* ppPresentQueue) {
+ static bool s_errorShown = false;
+
+ if (!std::exchange(s_errorShown, true))
+ Logger::warn("DxgiSwapChain::ResizeBuffers1: Stub");
+
+ return ResizeBuffers(BufferCount,
+ Width, Height, Format, SwapChainFlags);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) {
+ std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow);
+
+ if (pNewTargetParameters == nullptr)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (!wsi::isWindow(m_window))
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Update the swap chain description
+ if (pNewTargetParameters->RefreshRate.Numerator != 0)
+ m_descFs.RefreshRate = pNewTargetParameters->RefreshRate;
+
+ m_descFs.ScanlineOrdering = pNewTargetParameters->ScanlineOrdering;
+ m_descFs.Scaling = pNewTargetParameters->Scaling;
+
+ if (m_descFs.Windowed) {
+ wsi::resizeWindow(
+ m_window, &m_windowState,
+ pNewTargetParameters->Width,
+ pNewTargetParameters->Height);
+ } else {
+ Com<IDXGIOutput> output;
+
+ if (FAILED(GetOutputFromMonitor(m_monitor, &output))) {
+ Logger::err("DXGI: ResizeTarget: Failed to query containing output");
+ return E_FAIL;
+ }
+
+ // If the swap chain allows it, change the display mode
+ if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) {
+ ChangeDisplayMode(output.ptr(), pNewTargetParameters, false);
+ NotifyModeChange(m_monitor, FALSE);
+ }
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetFullscreenState(
+ BOOL Fullscreen,
+ IDXGIOutput* pTarget) {
+ std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow);
+
+ if (!Fullscreen && pTarget)
+ return DXGI_ERROR_INVALID_CALL;
+
+ if (m_descFs.Windowed && Fullscreen)
+ return this->EnterFullscreenMode(pTarget);
+ else if (!m_descFs.Windowed && !Fullscreen)
+ return this->LeaveFullscreenMode();
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetBackgroundColor(
+ const DXGI_RGBA* pColor) {
+ Logger::err("DxgiSwapChain::SetBackgroundColor: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetRotation(
+ DXGI_MODE_ROTATION Rotation) {
+ Logger::err("DxgiSwapChain::SetRotation: Not implemented");
+ return E_NOTIMPL;
+ }
+
+
+ HANDLE STDMETHODCALLTYPE DxgiSwapChain::GetFrameLatencyWaitableObject() {
+ if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+ return nullptr;
+
+ return m_presenter->GetFrameLatencyEvent();
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetMatrixTransform(
+ DXGI_MATRIX_3X2_F* pMatrix) {
+ // We don't support composition swap chains
+ Logger::err("DxgiSwapChain::GetMatrixTransform: Not supported");
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetMaximumFrameLatency(
+ UINT* pMaxLatency) {
+ if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+ return DXGI_ERROR_INVALID_CALL;
+
+ std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow);
+ *pMaxLatency = m_presenter->GetFrameLatency();
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetSourceSize(
+ UINT* pWidth,
+ UINT* pHeight) {
+ // TODO implement properly once supported
+ if (pWidth) *pWidth = m_desc.Width;
+ if (pHeight) *pHeight = m_desc.Height;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetMatrixTransform(
+ const DXGI_MATRIX_3X2_F* pMatrix) {
+ // We don't support composition swap chains
+ Logger::err("DxgiSwapChain::SetMatrixTransform: Not supported");
+ return DXGI_ERROR_INVALID_CALL;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetMaximumFrameLatency(
+ UINT MaxLatency) {
+ if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+ return DXGI_ERROR_INVALID_CALL;
+
+ std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow);
+ return m_presenter->SetFrameLatency(MaxLatency);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetSourceSize(
+ UINT Width,
+ UINT Height) {
+ if (Width == 0 || Width > m_desc.Width
+ || Height == 0 || Height > m_desc.Height)
+ return E_INVALIDARG;
+
+ RECT region;
+ region.left = 0;
+ region.top = 0;
+ region.right = Width;
+ region.bottom = Height;
+ return m_presenter->SetPresentRegion(&region);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::CheckColorSpaceSupport(
+ DXGI_COLOR_SPACE_TYPE ColorSpace,
+ UINT* pColorSpaceSupport) {
+ if (!pColorSpaceSupport)
+ return E_INVALIDARG;
+
+ UINT supportFlags = 0;
+
+ if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
+ supportFlags |= DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
+
+ *pColorSpaceSupport = supportFlags;
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) {
+ UINT support = 0;
+
+ HRESULT hr = CheckColorSpaceSupport(ColorSpace, &support);
+
+ if (FAILED(hr))
+ return hr;
+
+ if (!support)
+ return E_INVALIDARG;
+
+ return S_OK;
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetHDRMetaData(
+ DXGI_HDR_METADATA_TYPE Type,
+ UINT Size,
+ void* pMetaData) {
+ if (Size && !pMetaData)
+ return E_INVALIDARG;
+
+ switch (Type) {
+ case DXGI_HDR_METADATA_TYPE_NONE:
+ return S_OK;
+
+ case DXGI_HDR_METADATA_TYPE_HDR10:
+ if (Size != sizeof(DXGI_HDR_METADATA_HDR10))
+ return E_INVALIDARG;
+
+ // For some reason this always seems to succeed on Windows
+ Logger::warn("DXGI: HDR not supported");
+ return S_OK;
+
+ default:
+ Logger::err(str::format("DXGI: Invalid HDR metadata type: ", Type));
+ return E_INVALIDARG;
+ }
+ }
+
+
+ HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetGammaControl(
+ UINT NumPoints,
+ const DXGI_RGB* pGammaCurve) {
+ std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer);
+ return m_presenter->SetGammaControl(NumPoints, pGammaCurve);
+ }
+
+
+ HRESULT DxgiSwapChain::EnterFullscreenMode(IDXGIOutput* pTarget) {
+ Com<IDXGIOutput> output = pTarget;
+
+ if (!wsi::isWindow(m_window))
+ return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
+
+ if (output == nullptr) {
+ if (FAILED(GetContainingOutput(&output))) {
+ Logger::err("DXGI: EnterFullscreenMode: Cannot query containing output");
+ return E_FAIL;
+ }
+ }
+
+ const bool modeSwitch = m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+
+ if (modeSwitch) {
+ DXGI_MODE_DESC displayMode;
+ displayMode.Width = m_desc.Width;
+ displayMode.Height = m_desc.Height;
+ displayMode.RefreshRate = m_descFs.RefreshRate;
+ displayMode.Format = m_desc.Format;
+ // Ignore these two, games usually use them wrong and we don't
+ // support any scaling modes except UNSPECIFIED anyway.
+ displayMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
+ displayMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
+
+ if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode, true))) {
+ Logger::err("DXGI: EnterFullscreenMode: Failed to change display mode");
+ return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
+ }
+ }
+
+ // Update swap chain description
+ m_descFs.Windowed = FALSE;
+
+ // Move the window so that it covers the entire output
+ DXGI_OUTPUT_DESC desc;
+ output->GetDesc(&desc);
+
+ if (!wsi::enterFullscreenMode(desc.Monitor, m_window, &m_windowState, modeSwitch)) {
+ Logger::err("DXGI: EnterFullscreenMode: Failed to enter fullscreen mode");
+ return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
+ }
+
+ m_monitor = desc.Monitor;
+ m_target = std::move(output);
+
+ // Apply current gamma curve of the output
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+
+ if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) {
+ if (!monitorInfo->pSwapChain)
+ monitorInfo->pSwapChain = this;
+
+ SetGammaControl(DXGI_VK_GAMMA_CP_COUNT, monitorInfo->GammaCurve.GammaCurve);
+ ReleaseMonitorData();
+ }
+
+ NotifyModeChange(m_monitor, FALSE);
+ return S_OK;
+ }
+
+
+ HRESULT DxgiSwapChain::LeaveFullscreenMode() {
+ if (!wsi::restoreDisplayMode(m_monitor))
+ Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode");
+
+ // Reset gamma control and decouple swap chain from monitor
+ DXGI_VK_MONITOR_DATA* monitorInfo = nullptr;
+
+ if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) {
+ if (monitorInfo->pSwapChain == this)
+ monitorInfo->pSwapChain = nullptr;
+
+ SetGammaControl(0, nullptr);
+ ReleaseMonitorData();
+ }
+
+ // Restore internal state
+ HMONITOR monitor = m_monitor;
+
+ m_descFs.Windowed = TRUE;
+ m_monitor = nullptr;
+ m_target = nullptr;
+
+ if (!wsi::isWindow(m_window))
+ return S_OK;
+
+ if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) {
+ Logger::err("DXGI: LeaveFullscreenMode: Failed to exit fullscreen mode");
+ return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
+ }
+
+ NotifyModeChange(monitor, TRUE);
+ return S_OK;
+ }
+
+
+ HRESULT DxgiSwapChain::ChangeDisplayMode(
+ IDXGIOutput* pOutput,
+ const DXGI_MODE_DESC* pDisplayMode,
+ BOOL EnteringFullscreen) {
+ if (!pOutput)
+ return DXGI_ERROR_INVALID_CALL;
+
+ // Find a mode that the output supports
+ DXGI_OUTPUT_DESC outputDesc;
+ pOutput->GetDesc(&outputDesc);
+
+ DXGI_MODE_DESC preferredMode = *pDisplayMode;
+ DXGI_MODE_DESC selectedMode;
+
+ if (preferredMode.Format == DXGI_FORMAT_UNKNOWN)
+ preferredMode.Format = m_desc.Format;
+
+ HRESULT hr = pOutput->FindClosestMatchingMode(
+ &preferredMode, &selectedMode, nullptr);
+
+ if (FAILED(hr)) {
+ Logger::err(str::format(
+ "DXGI: Failed to query closest mode:",
+ "\n Format: ", preferredMode.Format,
+ "\n Mode: ", preferredMode.Width, "x", preferredMode.Height,
+ "@", preferredMode.RefreshRate.Numerator / preferredMode.RefreshRate.Denominator));
+ return hr;
+ }
+
+ DXGI_MODE_DESC1 selectedMode1;
+ selectedMode1.Width = selectedMode.Width;
+ selectedMode1.Height = selectedMode.Height;
+ selectedMode1.RefreshRate = selectedMode.RefreshRate;
+ selectedMode1.Format = selectedMode.Format;
+ selectedMode1.ScanlineOrdering = selectedMode.ScanlineOrdering;
+ selectedMode1.Scaling = selectedMode.Scaling;
+ selectedMode1.Stereo = false;
+
+ wsi::WsiMode wsiMode = { };
+ ConvertDisplayMode(selectedMode1, &wsiMode);
+
+ return wsi::setWindowMode(outputDesc.Monitor, m_window, &wsiMode, EnteringFullscreen)
+ ? S_OK
+ : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
+ }
+
+
+ HRESULT DxgiSwapChain::GetSampleCount(UINT Count, VkSampleCountFlagBits* pCount) const {
+ switch (Count) {
+ case 1: *pCount = VK_SAMPLE_COUNT_1_BIT; return S_OK;
+ case 2: *pCount = VK_SAMPLE_COUNT_2_BIT; return S_OK;
+ case 4: *pCount = VK_SAMPLE_COUNT_4_BIT; return S_OK;
+ case 8: *pCount = VK_SAMPLE_COUNT_8_BIT; return S_OK;
+ case 16: *pCount = VK_SAMPLE_COUNT_16_BIT; return S_OK;
+ }
+
+ return E_INVALIDARG;
+ }
+
+
+ HRESULT DxgiSwapChain::GetOutputFromMonitor(
+ HMONITOR Monitor,
+ IDXGIOutput** ppOutput) {
+ if (!ppOutput)
+ return DXGI_ERROR_INVALID_CALL;
+
+ for (uint32_t i = 0; SUCCEEDED(m_adapter->EnumOutputs(i, ppOutput)); i++) {
+ DXGI_OUTPUT_DESC outputDesc;
+ (*ppOutput)->GetDesc(&outputDesc);
+
+ if (outputDesc.Monitor == Monitor)
+ return S_OK;
+
+ (*ppOutput)->Release();
+ (*ppOutput) = nullptr;
+ }
+
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+
+ HRESULT DxgiSwapChain::AcquireMonitorData(
+ HMONITOR hMonitor,
+ DXGI_VK_MONITOR_DATA** ppData) {
+ return m_monitorInfo != nullptr
+ ? m_monitorInfo->AcquireMonitorData(hMonitor, ppData)
+ : E_NOINTERFACE;
+ }
+
+
+ void DxgiSwapChain::ReleaseMonitorData() {
+ if (m_monitorInfo != nullptr)
+ m_monitorInfo->ReleaseMonitorData();
+ }
+
+
+ void DxgiSwapChain::NotifyModeChange(
+ HMONITOR hMonitor,
+ BOOL Windowed) {
+ wsi::WsiMode mode;
+
+ if (wsi::getCurrentDisplayMode(hMonitor, &mode)) {
+ DXGI_MODE_DESC displayMode = { };
+ displayMode.Width = mode.width;
+ displayMode.Height = mode.height;
+ displayMode.RefreshRate = { mode.refreshRate.numerator, mode.refreshRate.denominator };
+ displayMode.Format = m_desc.Format;
+ displayMode.ScanlineOrdering = m_descFs.ScanlineOrdering;
+ displayMode.Scaling = m_descFs.Scaling;
+ m_presenter->NotifyModeChange(Windowed, &displayMode);
+ } else {
+ Logger::warn("Failed to query current display mode");
+ m_presenter->NotifyModeChange(Windowed, nullptr);
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.h
new file mode 100644
index 00000000..84953b2b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.h
@@ -0,0 +1,224 @@
+#pragma once
+
+#include <memory>
+#include <mutex>
+
+#include "dxgi_interfaces.h"
+#include "dxgi_monitor.h"
+#include "dxgi_object.h"
+
+#include "../d3d11/d3d11_interfaces.h"
+
+#include "../spirv/spirv_module.h"
+
+#include "../util/util_time.h"
+
+#include "../wsi/wsi_window.h"
+#include "../wsi/wsi_monitor.h"
+#include "../wsi/wsi_mode.h"
+
+namespace dxvk {
+
+ class DxgiDevice;
+ class DxgiFactory;
+ class DxgiOutput;
+
+ class DxgiSwapChain : public DxgiObject<IDXGISwapChain4> {
+
+ public:
+
+ DxgiSwapChain(
+ IDXGIFactory* pFactory,
+ IDXGIVkSwapChain* pPresenter,
+ HWND hWnd,
+ const DXGI_SWAP_CHAIN_DESC1* pDesc,
+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc);
+
+ ~DxgiSwapChain();
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final;
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent) final;
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice) final;
+
+ HRESULT STDMETHODCALLTYPE GetBuffer(
+ UINT Buffer,
+ REFIID riid,
+ void** ppSurface) final;
+
+ UINT STDMETHODCALLTYPE GetCurrentBackBufferIndex() final;
+
+ HRESULT STDMETHODCALLTYPE GetContainingOutput(
+ IDXGIOutput** ppOutput) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_SWAP_CHAIN_DESC* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetDesc1(
+ DXGI_SWAP_CHAIN_DESC1* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetFullscreenState(
+ BOOL* pFullscreen,
+ IDXGIOutput** ppTarget) final;
+
+ HRESULT STDMETHODCALLTYPE GetFullscreenDesc(
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) final;
+
+ HRESULT STDMETHODCALLTYPE GetHwnd(
+ HWND* pHwnd) final;
+
+ HRESULT STDMETHODCALLTYPE GetCoreWindow(
+ REFIID refiid,
+ void** ppUnk) final;
+
+ HRESULT STDMETHODCALLTYPE GetBackgroundColor(
+ DXGI_RGBA* pColor) final;
+
+ HRESULT STDMETHODCALLTYPE GetRotation(
+ DXGI_MODE_ROTATION* pRotation) final;
+
+ HRESULT STDMETHODCALLTYPE GetRestrictToOutput(
+ IDXGIOutput** ppRestrictToOutput) final;
+
+ HRESULT STDMETHODCALLTYPE GetFrameStatistics(
+ DXGI_FRAME_STATISTICS* pStats) final;
+
+ HRESULT STDMETHODCALLTYPE GetLastPresentCount(
+ UINT* pLastPresentCount) final;
+
+ BOOL STDMETHODCALLTYPE IsTemporaryMonoSupported() final;
+
+ HRESULT STDMETHODCALLTYPE Present(
+ UINT SyncInterval,
+ UINT Flags) final;
+
+ HRESULT STDMETHODCALLTYPE Present1(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters) final;
+
+ HRESULT STDMETHODCALLTYPE ResizeBuffers(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT NewFormat,
+ UINT SwapChainFlags) final;
+
+ HRESULT STDMETHODCALLTYPE ResizeBuffers1(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT Format,
+ UINT SwapChainFlags,
+ const UINT* pCreationNodeMask,
+ IUnknown* const* ppPresentQueue) final;
+
+ HRESULT STDMETHODCALLTYPE ResizeTarget(
+ const DXGI_MODE_DESC* pNewTargetParameters) final;
+
+ HRESULT STDMETHODCALLTYPE SetFullscreenState(
+ BOOL Fullscreen,
+ IDXGIOutput* pTarget) final;
+
+ HRESULT STDMETHODCALLTYPE SetBackgroundColor(
+ const DXGI_RGBA* pColor) final;
+
+ HRESULT STDMETHODCALLTYPE SetRotation(
+ DXGI_MODE_ROTATION Rotation) final;
+
+ HANDLE STDMETHODCALLTYPE GetFrameLatencyWaitableObject() final;
+
+ HRESULT STDMETHODCALLTYPE GetMatrixTransform(
+ DXGI_MATRIX_3X2_F* pMatrix) final;
+
+ HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(
+ UINT* pMaxLatency) final;
+
+ HRESULT STDMETHODCALLTYPE GetSourceSize(
+ UINT* pWidth,
+ UINT* pHeight) final;
+
+ HRESULT STDMETHODCALLTYPE SetMatrixTransform(
+ const DXGI_MATRIX_3X2_F* pMatrix) final;
+
+ HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(
+ UINT MaxLatency) final;
+
+ HRESULT STDMETHODCALLTYPE SetSourceSize(
+ UINT Width,
+ UINT Height) final;
+
+ HRESULT STDMETHODCALLTYPE CheckColorSpaceSupport(
+ DXGI_COLOR_SPACE_TYPE ColorSpace,
+ UINT* pColorSpaceSupport) final;
+
+ HRESULT STDMETHODCALLTYPE SetColorSpace1(
+ DXGI_COLOR_SPACE_TYPE ColorSpace) final;
+
+ HRESULT STDMETHODCALLTYPE SetHDRMetaData(
+ DXGI_HDR_METADATA_TYPE Type,
+ UINT Size,
+ void* pMetaData) final;
+
+ HRESULT STDMETHODCALLTYPE SetGammaControl(
+ UINT NumPoints,
+ const DXGI_RGB* pGammaCurve);
+
+ private:
+
+ dxvk::recursive_mutex m_lockWindow;
+ dxvk::mutex m_lockBuffer;
+
+ Com<IDXGIFactory> m_factory;
+ Com<IDXGIAdapter> m_adapter;
+ Com<IDXGIOutput> m_target;
+ Com<IDXGIVkMonitorInfo> m_monitorInfo;
+
+ HWND m_window;
+ DXGI_SWAP_CHAIN_DESC1 m_desc;
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_descFs;
+ UINT m_presentCount;
+
+ Com<IDXGIVkSwapChain> m_presenter;
+
+ HMONITOR m_monitor;
+ wsi::DxvkWindowState m_windowState;
+
+ HRESULT EnterFullscreenMode(
+ IDXGIOutput *pTarget);
+
+ HRESULT LeaveFullscreenMode();
+
+ HRESULT ChangeDisplayMode(
+ IDXGIOutput* pOutput,
+ const DXGI_MODE_DESC* pDisplayMode,
+ BOOL EnteringFullscreen);
+
+ HRESULT GetSampleCount(
+ UINT Count,
+ VkSampleCountFlagBits* pCount) const;
+
+ HRESULT GetOutputFromMonitor(
+ HMONITOR Monitor,
+ IDXGIOutput** ppOutput);
+
+ HRESULT AcquireMonitorData(
+ HMONITOR hMonitor,
+ DXGI_VK_MONITOR_DATA** ppData);
+
+ void ReleaseMonitorData();
+
+ void NotifyModeChange(
+ HMONITOR hMonitor,
+ BOOL Windowed);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain_dispatcher.h b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain_dispatcher.h
new file mode 100644
index 00000000..fd48d837
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain_dispatcher.h
@@ -0,0 +1,280 @@
+#pragma once
+
+#include "dxgi_swapchain.h"
+
+namespace dxvk {
+
+ class DxgiSwapChainDispatcher : public IDXGISwapChain4 {
+
+ public:
+
+ DxgiSwapChainDispatcher(IDXGISwapChain4* dispatch)
+ : m_dispatch(dispatch) {
+ }
+
+ virtual ~DxgiSwapChainDispatcher() {
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ return m_dispatch->AddRef();
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ ULONG refCount = m_dispatch->Release();
+
+ if (unlikely(!refCount))
+ delete this;
+
+ return refCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void** ppvObject) final {
+ if (ppvObject == nullptr)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (riid == __uuidof(IUnknown)
+ || riid == __uuidof(IDXGIObject)
+ || riid == __uuidof(IDXGIDeviceSubObject)
+ || riid == __uuidof(IDXGISwapChain)
+ || riid == __uuidof(IDXGISwapChain1)
+ || riid == __uuidof(IDXGISwapChain2)
+ || riid == __uuidof(IDXGISwapChain3)
+ || riid == __uuidof(IDXGISwapChain4)) {
+ *ppvObject = ref(this);
+ return S_OK;
+ }
+
+ Logger::warn("DxgiSwapChainDispatcher::QueryInterface: Unknown interface query");
+ Logger::warn(str::format(riid));
+ return m_dispatch->QueryInterface(riid, ppvObject);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID Name,
+ UINT* pDataSize,
+ void* pData) final {
+ return m_dispatch->GetPrivateData(Name, pDataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID Name,
+ UINT DataSize,
+ const void* pData) final {
+ return m_dispatch->SetPrivateData(Name, DataSize, pData);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID Name,
+ const IUnknown* pUnknown) final {
+ return m_dispatch->SetPrivateDataInterface(Name, pUnknown);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void** ppParent) final {
+ return m_dispatch->GetParent(riid, ppParent);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetDevice(
+ REFIID riid,
+ void** ppDevice) final {
+ return m_dispatch->GetDevice(riid, ppDevice);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetBuffer(
+ UINT Buffer,
+ REFIID riid,
+ void** ppSurface) final {
+ return m_dispatch->GetBuffer(Buffer, riid, ppSurface);
+ }
+
+ UINT STDMETHODCALLTYPE GetCurrentBackBufferIndex() final {
+ return m_dispatch->GetCurrentBackBufferIndex();
+ }
+
+ HRESULT STDMETHODCALLTYPE GetContainingOutput(
+ IDXGIOutput** ppOutput) final {
+ return m_dispatch->GetContainingOutput(ppOutput);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetDesc(
+ DXGI_SWAP_CHAIN_DESC* pDesc) final {
+ return m_dispatch->GetDesc(pDesc);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetDesc1(
+ DXGI_SWAP_CHAIN_DESC1* pDesc) final {
+ return m_dispatch->GetDesc1(pDesc);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetFullscreenState(
+ BOOL* pFullscreen,
+ IDXGIOutput** ppTarget) final {
+ return m_dispatch->GetFullscreenState(pFullscreen, ppTarget);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetFullscreenDesc(
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) final {
+ return m_dispatch->GetFullscreenDesc(pDesc);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetHwnd(
+ HWND* pHwnd) final {
+ return m_dispatch->GetHwnd(pHwnd);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetCoreWindow(
+ REFIID refiid,
+ void** ppUnk) final {
+ return m_dispatch->GetCoreWindow(refiid, ppUnk);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetBackgroundColor(
+ DXGI_RGBA* pColor) final {
+ return m_dispatch->GetBackgroundColor(pColor);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetRotation(
+ DXGI_MODE_ROTATION* pRotation) final {
+ return m_dispatch->GetRotation(pRotation);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetRestrictToOutput(
+ IDXGIOutput** ppRestrictToOutput) final {
+ return m_dispatch->GetRestrictToOutput(ppRestrictToOutput);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetFrameStatistics(
+ DXGI_FRAME_STATISTICS* pStats) final {
+ return m_dispatch->GetFrameStatistics(pStats);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetLastPresentCount(
+ UINT* pLastPresentCount) final {
+ return m_dispatch->GetLastPresentCount(pLastPresentCount);
+ }
+
+ BOOL STDMETHODCALLTYPE IsTemporaryMonoSupported() final {
+ return m_dispatch->IsTemporaryMonoSupported();
+ }
+
+ HRESULT STDMETHODCALLTYPE Present(
+ UINT SyncInterval,
+ UINT Flags) final {
+ return m_dispatch->Present(SyncInterval, Flags);
+ }
+
+ HRESULT STDMETHODCALLTYPE Present1(
+ UINT SyncInterval,
+ UINT PresentFlags,
+ const DXGI_PRESENT_PARAMETERS* pPresentParameters) final {
+ return m_dispatch->Present1(SyncInterval, PresentFlags, pPresentParameters);
+ }
+
+ HRESULT STDMETHODCALLTYPE ResizeBuffers(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT NewFormat,
+ UINT SwapChainFlags) final {
+ return m_dispatch->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags);
+ }
+
+ HRESULT STDMETHODCALLTYPE ResizeBuffers1(
+ UINT BufferCount,
+ UINT Width,
+ UINT Height,
+ DXGI_FORMAT Format,
+ UINT SwapChainFlags,
+ const UINT* pCreationNodeMask,
+ IUnknown* const* ppPresentQueue) final {
+ return m_dispatch->ResizeBuffers1(BufferCount, Width, Height, Format, SwapChainFlags, pCreationNodeMask, ppPresentQueue);
+ }
+
+ HRESULT STDMETHODCALLTYPE ResizeTarget(
+ const DXGI_MODE_DESC* pNewTargetParameters) final {
+ return m_dispatch->ResizeTarget(pNewTargetParameters);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetFullscreenState(
+ BOOL Fullscreen,
+ IDXGIOutput* pTarget) final {
+ return m_dispatch->SetFullscreenState(Fullscreen, pTarget);
+ }
+
+
+ HRESULT STDMETHODCALLTYPE SetBackgroundColor(
+ const DXGI_RGBA* pColor) final {
+ return m_dispatch->SetBackgroundColor(pColor);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetRotation(
+ DXGI_MODE_ROTATION Rotation) final {
+ return m_dispatch->SetRotation(Rotation);
+ }
+
+ HANDLE STDMETHODCALLTYPE GetFrameLatencyWaitableObject() final {
+ return m_dispatch->GetFrameLatencyWaitableObject();
+ }
+
+ HRESULT STDMETHODCALLTYPE GetMatrixTransform(
+ DXGI_MATRIX_3X2_F* pMatrix) final {
+ return m_dispatch->GetMatrixTransform(pMatrix);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(
+ UINT* pMaxLatency) final {
+ return m_dispatch->GetMaximumFrameLatency(pMaxLatency);
+ }
+
+ HRESULT STDMETHODCALLTYPE GetSourceSize(
+ UINT* pWidth,
+ UINT* pHeight) final {
+ return m_dispatch->GetSourceSize(pWidth, pHeight);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetMatrixTransform(
+ const DXGI_MATRIX_3X2_F* pMatrix) final {
+ return m_dispatch->SetMatrixTransform(pMatrix);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(
+ UINT MaxLatency) final {
+ return m_dispatch->SetMaximumFrameLatency(MaxLatency);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetSourceSize(
+ UINT Width,
+ UINT Height) final {
+ return m_dispatch->SetSourceSize(Width, Height);
+ }
+
+ HRESULT STDMETHODCALLTYPE CheckColorSpaceSupport(
+ DXGI_COLOR_SPACE_TYPE ColorSpace,
+ UINT* pColorSpaceSupport) final {
+ return m_dispatch->CheckColorSpaceSupport(ColorSpace, pColorSpaceSupport);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetColorSpace1(
+ DXGI_COLOR_SPACE_TYPE ColorSpace) final {
+ return m_dispatch->SetColorSpace1(ColorSpace);
+ }
+
+ HRESULT STDMETHODCALLTYPE SetHDRMetaData(
+ DXGI_HDR_METADATA_TYPE Type,
+ UINT Size,
+ void* pMetaData) final {
+ return m_dispatch->SetHDRMetaData(Type, Size, pMetaData);
+ }
+
+ private:
+
+ IDXGISwapChain4* m_dispatch;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/meson.build b/src/libs/dxvk-native-1.9.2a/src/dxgi/meson.build
new file mode 100644
index 00000000..f5e72054
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/meson.build
@@ -0,0 +1,25 @@
+dxgi_res = wrc_generator.process('version.rc')
+
+dxgi_src = [
+ 'dxgi_adapter.cpp',
+ 'dxgi_enums.cpp',
+ 'dxgi_factory.cpp',
+ 'dxgi_format.cpp',
+ 'dxgi_main.cpp',
+ 'dxgi_monitor.cpp',
+ 'dxgi_options.cpp',
+ 'dxgi_output.cpp',
+ 'dxgi_swapchain.cpp',
+]
+
+dxgi_dll = shared_library(so_prefix+'dxgi'+dll_ext, dxgi_src, dxgi_res,
+ name_prefix : '',
+ dependencies : [ dxvk_dep, wsi_dep ],
+ include_directories : dxvk_include_path,
+ install : true,
+ vs_module_defs : 'dxgi'+def_spec_ext,
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+dxgi_dep = declare_dependency(
+ link_with : [ dxgi_dll ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/version.rc b/src/libs/dxvk-native-1.9.2a/src/dxgi/version.rc
new file mode 100644
index 00000000..9461d718
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/version.rc
@@ -0,0 +1,32 @@
+#include <windows.h>
+
+// DLL version information.
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 10,0,17763,1
+PRODUCTVERSION 10,0,17763,1
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "CompanyName", "DXVK"
+ VALUE "FileDescription", "DirectX Graphics Infrastructure"
+ VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
+ VALUE "InternalName", "dxgi.dll"
+ VALUE "LegalCopyright", "zlib/libpng license"
+ VALUE "OriginalFilename", "dxgi.dll"
+ VALUE "ProductName", "DXVK"
+ VALUE "ProductVersion", "10.0.17763.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0809, 1200
+ END
+END
+
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.cpp
new file mode 100644
index 00000000..553f84c4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.cpp
@@ -0,0 +1,57 @@
+#include "dxso_analysis.h"
+
+namespace dxvk {
+
+ DxsoAnalyzer::DxsoAnalyzer(
+ DxsoAnalysisInfo& analysis)
+ : m_analysis(&analysis) { }
+
+ void DxsoAnalyzer::processInstruction(
+ const DxsoInstructionContext& ctx) {
+ DxsoOpcode opcode = ctx.instruction.opcode;
+
+ // Co-issued CNDs are issued before their parents,
+ // except when the parent is a CND.
+ if (opcode == DxsoOpcode::Cnd &&
+ m_parentOpcode != DxsoOpcode::Cnd &&
+ ctx.instruction.coissue) {
+ m_analysis->coissues.push_back(ctx);
+ }
+
+ if (opcode == DxsoOpcode::TexKill)
+ m_analysis->usesKill = true;
+
+ if (opcode == DxsoOpcode::DsX
+ || opcode == DxsoOpcode::DsY
+
+ || opcode == DxsoOpcode::Tex
+ || opcode == DxsoOpcode::TexCoord
+ || opcode == DxsoOpcode::TexBem
+ || opcode == DxsoOpcode::TexBemL
+ || opcode == DxsoOpcode::TexReg2Ar
+ || opcode == DxsoOpcode::TexReg2Gb
+ || opcode == DxsoOpcode::TexM3x2Pad
+ || opcode == DxsoOpcode::TexM3x2Tex
+ || opcode == DxsoOpcode::TexM3x3Pad
+ || opcode == DxsoOpcode::TexM3x3Tex
+ || opcode == DxsoOpcode::TexM3x3Spec
+ || opcode == DxsoOpcode::TexM3x3VSpec
+ || opcode == DxsoOpcode::TexReg2Rgb
+ || opcode == DxsoOpcode::TexDp3Tex
+ || opcode == DxsoOpcode::TexM3x2Depth
+ || opcode == DxsoOpcode::TexDp3
+ || opcode == DxsoOpcode::TexM3x3
+ // Explicit LOD.
+ //|| opcode == DxsoOpcode::TexLdd
+ //|| opcode == DxsoOpcode::TexLdl
+ || opcode == DxsoOpcode::TexDepth)
+ m_analysis->usesDerivatives = true;
+
+ m_parentOpcode = ctx.instruction.opcode;
+ }
+
+ void DxsoAnalyzer::finalize(size_t tokenCount) {
+ m_analysis->bytecodeByteLength = tokenCount * sizeof(uint32_t);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.h
new file mode 100644
index 00000000..c1321e09
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_analysis.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "dxso_modinfo.h"
+#include "dxso_decoder.h"
+
+namespace dxvk {
+
+ struct DxsoAnalysisInfo {
+ uint32_t bytecodeByteLength;
+
+ bool usesDerivatives = false;
+ bool usesKill = false;
+
+ std::vector<DxsoInstructionContext> coissues;
+ };
+
+ class DxsoAnalyzer {
+
+ public:
+
+ DxsoAnalyzer(
+ DxsoAnalysisInfo& analysis);
+
+ /**
+ * \brief Processes a single instruction
+ * \param [in] ins The instruction
+ */
+ void processInstruction(
+ const DxsoInstructionContext& ctx);
+
+ void finalize(size_t tokenCount);
+
+ private:
+
+ DxsoAnalysisInfo* m_analysis = nullptr;
+
+ DxsoOpcode m_parentOpcode;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.cpp
new file mode 100644
index 00000000..9fd73d93
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.cpp
@@ -0,0 +1,28 @@
+#include "dxso_code.h"
+
+namespace dxvk {
+
+ DxsoCode::DxsoCode(DxsoReader& reader) {
+ m_code =
+ reinterpret_cast<const uint32_t*>(reader.currentPtr());
+ }
+
+ const uint32_t* DxsoCodeIter::ptrAt(uint32_t id) const {
+ return m_ptr + id;
+ }
+
+
+ uint32_t DxsoCodeIter::at(uint32_t id) const {
+ return m_ptr[id];
+ }
+
+
+ uint32_t DxsoCodeIter::read() {
+ return *(m_ptr++);
+ }
+
+ DxsoCodeIter DxsoCodeIter::skip(uint32_t n) const {
+ return DxsoCodeIter(m_ptr + n);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.h
new file mode 100644
index 00000000..51fdab78
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_code.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "dxso_include.h"
+#include "dxso_reader.h"
+
+#include <vector>
+#include <cstdint>
+
+namespace dxvk {
+
+ /**
+ * \brief DXBC code iterator
+ *
+ * Convenient pointer wrapper that allows
+ * reading the code token stream.
+ */
+ class DxsoCodeIter {
+
+ public:
+
+ DxsoCodeIter(
+ const uint32_t* ptr)
+ : m_ptr(ptr) { }
+
+ const uint32_t* ptrAt(uint32_t id) const;
+
+ uint32_t at(uint32_t id) const;
+ uint32_t read();
+
+ DxsoCodeIter skip(uint32_t n) const;
+
+ private:
+
+ const uint32_t* m_ptr = nullptr;
+
+ };
+
+ class DxsoCode {
+
+ public:
+
+ DxsoCode(DxsoReader& reader);
+
+ DxsoCodeIter iter() const {
+ return DxsoCodeIter(m_code);
+ }
+
+ private:
+
+ const uint32_t* m_code;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.cpp
new file mode 100644
index 00000000..0709fa22
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.cpp
@@ -0,0 +1,26 @@
+#include "dxso_common.h"
+
+namespace dxvk {
+
+ VkShaderStageFlagBits DxsoProgramInfo::shaderStage() const {
+ switch (m_type) {
+ case DxsoProgramTypes::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
+ case DxsoProgramTypes::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
+ default: break;
+ }
+
+ throw DxvkError("DxsoProgramInfo::shaderStage: Unsupported program type");
+ }
+
+
+ spv::ExecutionModel DxsoProgramInfo::executionModel() const {
+ switch (m_type) {
+ case DxsoProgramTypes::PixelShader: return spv::ExecutionModelFragment;
+ case DxsoProgramTypes::VertexShader: return spv::ExecutionModelVertex;
+ default: break;
+ }
+
+ throw DxvkError("DxsoProgramInfo::executionModel: Unsupported program type");
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.h
new file mode 100644
index 00000000..fcc57cd8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_common.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "dxso_include.h"
+
+#include <cstdint>
+
+namespace dxvk {
+
+ /**
+ * \brief DXSO Program type
+ *
+ * Defines the shader stage that a DXSO
+ * module has been compiled for.
+ */
+ namespace DxsoProgramTypes {
+ enum DxsoProgramType : uint16_t {
+ VertexShader = 0,
+ PixelShader = 1,
+ Count = 2,
+ };
+ }
+ using DxsoProgramType = DxsoProgramTypes::DxsoProgramType;
+
+ class DxsoProgramInfo {
+
+ public:
+
+ DxsoProgramInfo() { }
+ DxsoProgramInfo(
+ DxsoProgramType type,
+ uint32_t minorVersion,
+ uint32_t majorVersion)
+ : m_type{ type }
+ , m_minorVersion{ minorVersion }
+ , m_majorVersion{ majorVersion } {}
+
+ /**
+ * \brief Program type
+ * \returns Program type
+ */
+ DxsoProgramType type() const {
+ return m_type;
+ }
+
+ /**
+ * \brief Vulkan shader stage
+ *
+ * The \c VkShaderStageFlagBits constant
+ * that corresponds to the program type.
+ * \returns Vulkan shader stage
+ */
+ VkShaderStageFlagBits shaderStage() const;
+
+ /**
+ * \brief SPIR-V execution model
+ *
+ * The execution model that corresponds
+ * to the Vulkan shader stage.
+ * \returns SPIR-V execution model
+ */
+ spv::ExecutionModel executionModel() const;
+
+ /**
+ * \brief Minor version
+ * \returns The minor version of the shader model.
+ */
+ uint32_t minorVersion() const {
+ return m_minorVersion;
+ }
+
+ /**
+ * \brief Major version
+ * \returns The major version of the shader model.
+ */
+ uint32_t majorVersion() const {
+ return m_majorVersion;
+ }
+
+ private:
+
+ DxsoProgramType m_type;
+
+ uint32_t m_minorVersion;
+ uint32_t m_majorVersion;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.cpp
new file mode 100644
index 00000000..f7bd312b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.cpp
@@ -0,0 +1,3862 @@
+#include "dxso_compiler.h"
+
+#include "dxso_analysis.h"
+
+#include "../d3d9/d3d9_caps.h"
+#include "../d3d9/d3d9_constant_set.h"
+#include "../d3d9/d3d9_state.h"
+#include "../d3d9/d3d9_spec_constants.h"
+#include "../d3d9/d3d9_fixed_function.h"
+#include "dxso_util.h"
+
+#include "../dxvk/dxvk_spec_const.h"
+
+#include <cfloat>
+
+namespace dxvk {
+
+ DxsoCompiler::DxsoCompiler(
+ const std::string& fileName,
+ const DxsoModuleInfo& moduleInfo,
+ const DxsoProgramInfo& programInfo,
+ const DxsoAnalysisInfo& analysis,
+ const D3D9ConstantLayout& layout)
+ : m_moduleInfo ( moduleInfo )
+ , m_programInfo( programInfo )
+ , m_analysis ( &analysis )
+ , m_layout ( &layout )
+ , m_module ( spvVersion(1, 3) ) {
+ // Declare an entry point ID. We'll need it during the
+ // initialization phase where the execution mode is set.
+ m_entryPointId = m_module.allocateId();
+
+ // Set the shader name so that we recognize it in renderdoc
+ m_module.setDebugSource(
+ spv::SourceLanguageUnknown, 0,
+ m_module.addDebugString(fileName.c_str()),
+ nullptr);
+
+ // Set the memory model. This is the same for all shaders.
+ m_module.setMemoryModel(
+ spv::AddressingModelLogical,
+ spv::MemoryModelGLSL450);
+
+ m_usedSamplers = 0;
+ m_usedRTs = 0;
+
+ for (uint32_t i = 0; i < m_rRegs.size(); i++)
+ m_rRegs.at(i) = DxsoRegisterPointer{ };
+
+ for (uint32_t i = 0; i < m_cFloat.size(); i++)
+ m_cFloat.at(i) = 0;
+
+ for (uint32_t i = 0; i < m_cInt.size(); i++)
+ m_cInt.at(i) = 0;
+
+ for (uint32_t i = 0; i < m_cBool.size(); i++)
+ m_cBool.at(i) = 0;
+
+ m_vs.addr = DxsoRegisterPointer{ };
+ m_vs.oPos = DxsoRegisterPointer{ };
+ m_fog = DxsoRegisterPointer{ };
+ m_vs.oPSize = DxsoRegisterPointer{ };
+
+ for (uint32_t i = 0; i < m_ps.oColor.size(); i++)
+ m_ps.oColor.at(i) = DxsoRegisterPointer{ };
+ m_ps.oDepth = DxsoRegisterPointer{ };
+ m_ps.vFace = DxsoRegisterPointer{ };
+ m_ps.vPos = DxsoRegisterPointer{ };
+
+ m_loopCounter = DxsoRegisterPointer{ };
+
+ this->emitInit();
+ }
+
+
+ void DxsoCompiler::processInstruction(
+ const DxsoInstructionContext& ctx,
+ uint32_t currentCoissueIdx) {
+ const DxsoOpcode opcode = ctx.instruction.opcode;
+
+ for (const auto& coissue : m_analysis->coissues) {
+ if (coissue.instructionIdx == ctx.instructionIdx &&
+ coissue.instructionIdx != currentCoissueIdx)
+ return;
+
+ if (coissue.instructionIdx == ctx.instructionIdx + 1)
+ processInstruction(coissue, coissue.instructionIdx);
+ }
+
+ switch (opcode) {
+ case DxsoOpcode::Nop:
+ return;
+
+ case DxsoOpcode::Dcl:
+ return this->emitDcl(ctx);
+
+ case DxsoOpcode::Def:
+ case DxsoOpcode::DefI:
+ case DxsoOpcode::DefB:
+ return this->emitDef(ctx);
+
+ case DxsoOpcode::Mov:
+ case DxsoOpcode::Mova:
+ return this->emitMov(ctx);
+
+ case DxsoOpcode::Add:
+ case DxsoOpcode::Sub:
+ case DxsoOpcode::Mad:
+ case DxsoOpcode::Mul:
+ case DxsoOpcode::Rcp:
+ case DxsoOpcode::Rsq:
+ case DxsoOpcode::Dp3:
+ case DxsoOpcode::Dp4:
+ case DxsoOpcode::Slt:
+ case DxsoOpcode::Sge:
+ case DxsoOpcode::Min:
+ case DxsoOpcode::ExpP:
+ case DxsoOpcode::Exp:
+ case DxsoOpcode::Max:
+ case DxsoOpcode::Pow:
+ case DxsoOpcode::Crs:
+ case DxsoOpcode::Abs:
+ case DxsoOpcode::Sgn:
+ case DxsoOpcode::Nrm:
+ case DxsoOpcode::SinCos:
+ case DxsoOpcode::Lit:
+ case DxsoOpcode::Dst:
+ case DxsoOpcode::LogP:
+ case DxsoOpcode::Log:
+ case DxsoOpcode::Lrp:
+ case DxsoOpcode::Frc:
+ case DxsoOpcode::Cmp:
+ case DxsoOpcode::Cnd:
+ case DxsoOpcode::Dp2Add:
+ case DxsoOpcode::DsX:
+ case DxsoOpcode::DsY:
+ return this->emitVectorAlu(ctx);
+
+ case DxsoOpcode::SetP:
+ return this->emitPredicateOp(ctx);
+
+ case DxsoOpcode::M3x2:
+ case DxsoOpcode::M3x3:
+ case DxsoOpcode::M3x4:
+ case DxsoOpcode::M4x3:
+ case DxsoOpcode::M4x4:
+ return this->emitMatrixAlu(ctx);
+
+ case DxsoOpcode::Loop:
+ return this->emitControlFlowLoop(ctx);
+ case DxsoOpcode::EndLoop:
+ return this->emitControlFlowEndLoop(ctx);
+
+ case DxsoOpcode::Rep:
+ return this->emitControlFlowRep(ctx);
+ case DxsoOpcode::EndRep:
+ return this->emitControlFlowEndRep(ctx);
+
+ case DxsoOpcode::Break:
+ return this->emitControlFlowBreak(ctx);
+ case DxsoOpcode::BreakC:
+ return this->emitControlFlowBreakC(ctx);
+
+ case DxsoOpcode::If:
+ case DxsoOpcode::Ifc:
+ return this->emitControlFlowIf(ctx);
+ case DxsoOpcode::Else:
+ return this->emitControlFlowElse(ctx);
+ case DxsoOpcode::EndIf:
+ return this->emitControlFlowEndIf(ctx);
+
+ case DxsoOpcode::TexCoord:
+ return this->emitTexCoord(ctx);
+
+ case DxsoOpcode::Tex:
+ case DxsoOpcode::TexLdl:
+ case DxsoOpcode::TexLdd:
+ case DxsoOpcode::TexDp3Tex:
+ case DxsoOpcode::TexReg2Ar:
+ case DxsoOpcode::TexReg2Gb:
+ case DxsoOpcode::TexReg2Rgb:
+ case DxsoOpcode::TexBem:
+ case DxsoOpcode::TexBemL:
+ case DxsoOpcode::TexM3x2Tex:
+ case DxsoOpcode::TexM3x3Tex:
+ case DxsoOpcode::TexM3x3Spec:
+ case DxsoOpcode::TexM3x3VSpec:
+ return this->emitTextureSample(ctx);
+ case DxsoOpcode::TexKill:
+ return this->emitTextureKill(ctx);
+ case DxsoOpcode::TexDepth:
+ return this->emitTextureDepth(ctx);
+
+ case DxsoOpcode::TexM3x3Pad:
+ case DxsoOpcode::TexM3x2Pad:
+ // We don't need to do anything here, these are just padding instructions
+ break;
+
+ case DxsoOpcode::End:
+ case DxsoOpcode::Comment:
+ case DxsoOpcode::Phase:
+ break;
+
+ default:
+ Logger::warn(str::format("DxsoCompiler::processInstruction: unhandled opcode: ", opcode));
+ break;
+ }
+ }
+
+ void DxsoCompiler::finalize() {
+ if (m_programInfo.type() == DxsoProgramTypes::VertexShader)
+ this->emitVsFinalize();
+ else
+ this->emitPsFinalize();
+
+ // Declare the entry point, we now have all the
+ // information we need, including the interfaces
+ m_module.addEntryPoint(m_entryPointId,
+ m_programInfo.executionModel(), "main",
+ m_entryPointInterfaces.size(),
+ m_entryPointInterfaces.data());
+ m_module.setDebugName(m_entryPointId, "main");
+ }
+
+
+ DxsoPermutations DxsoCompiler::compile() {
+ DxsoPermutations permutations = { };
+
+ // Create the shader module object
+ permutations[D3D9ShaderPermutations::None] = compileShader();
+
+ // If we need to add more permuations, might be worth making a copy of module
+ // before we do anything more. :-)
+ if (m_programInfo.type() == DxsoProgramType::PixelShader) {
+ if (m_ps.diffuseColorIn)
+ m_module.decorate(m_ps.diffuseColorIn, spv::DecorationFlat);
+
+ if (m_ps.specularColorIn)
+ m_module.decorate(m_ps.specularColorIn, spv::DecorationFlat);
+
+ permutations[D3D9ShaderPermutations::FlatShade] = compileShader();
+ }
+
+ return permutations;
+ }
+
+
+ Rc<DxvkShader> DxsoCompiler::compileShader() {
+ DxvkShaderOptions shaderOptions = { };
+ DxvkShaderConstData constData = { };
+
+ return new DxvkShader(
+ m_programInfo.shaderStage(),
+ m_resourceSlots.size(),
+ m_resourceSlots.data(),
+ m_interfaceSlots,
+ m_module.compile(),
+ shaderOptions,
+ std::move(constData));
+ }
+
+ void DxsoCompiler::emitInit() {
+ // Set up common capabilities for all shaders
+ m_module.enableCapability(spv::CapabilityShader);
+ m_module.enableCapability(spv::CapabilityImageQuery);
+
+ this->emitDclConstantBuffer();
+ this->emitDclInputArray();
+
+ // Initialize the shader module with capabilities
+ // etc. Each shader type has its own peculiarities.
+ switch (m_programInfo.type()) {
+ case DxsoProgramTypes::VertexShader: return this->emitVsInit();
+ case DxsoProgramTypes::PixelShader: return this->emitPsInit();
+ default: break;
+ }
+ }
+
+
+ void DxsoCompiler::emitDclConstantBuffer() {
+ const bool asSsbo = m_moduleInfo.options.vertexConstantBufferAsSSBO &&
+ m_programInfo.type() == DxsoProgramType::VertexShader;
+
+ std::array<uint32_t, 3> members = {
+ // float f[256 or 224 or 8192]
+ m_module.defArrayTypeUnique(
+ getVectorTypeId({ DxsoScalarType::Float32, 4 }),
+ m_module.constu32(m_layout->floatCount)),
+
+ // int i[16 or 2048]
+ m_module.defArrayTypeUnique(
+ getVectorTypeId({ DxsoScalarType::Sint32, 4 }),
+ m_module.constu32(m_layout->intCount)),
+
+ // uint32_t boolBitmask
+ // or uvec4 boolBitmask[512]
+ // Defined later...
+ 0
+ };
+
+ // Decorate array strides, this is required.
+ m_module.decorateArrayStride(members[0], 16);
+ m_module.decorateArrayStride(members[1], 16);
+
+ const bool swvp = m_layout->bitmaskCount != 1;
+
+ if (swvp) {
+ // Must be a multiple of 4 otherwise.
+ members[2] = m_module.defArrayTypeUnique(
+ getVectorTypeId({ DxsoScalarType::Uint32, 4 }),
+ m_module.constu32(m_layout->bitmaskCount / 4));
+
+ m_module.decorateArrayStride(members[2], 16);
+ }
+
+ const uint32_t structType =
+ m_module.defStructType(swvp ? 3 : 2, members.data());
+
+ m_module.decorate(structType, asSsbo
+ ? spv::DecorationBufferBlock
+ : spv::DecorationBlock);
+
+ m_module.memberDecorateOffset(structType, 0, m_layout->floatOffset());
+ m_module.memberDecorateOffset(structType, 1, m_layout->intOffset());
+
+ if (swvp)
+ m_module.memberDecorateOffset(structType, 2, m_layout->bitmaskOffset());
+
+ m_module.setDebugName(structType, "cbuffer_t");
+ m_module.setDebugMemberName(structType, 0, "f");
+ m_module.setDebugMemberName(structType, 1, "i");
+
+ if (swvp)
+ m_module.setDebugMemberName(structType, 2, "b");
+
+ m_cBuffer = m_module.newVar(
+ m_module.defPointerType(structType, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.setDebugName(m_cBuffer, "c");
+
+ const uint32_t bindingId = computeResourceSlotId(
+ m_programInfo.type(), DxsoBindingType::ConstantBuffer,
+ 0);
+
+ m_module.decorateDescriptorSet(m_cBuffer, 0);
+ m_module.decorateBinding(m_cBuffer, bindingId);
+
+ if (asSsbo)
+ m_module.decorate(m_cBuffer, spv::DecorationNonWritable);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = asSsbo
+ ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+ : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+
+ m_boolSpecConstant = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.decorateSpecId(m_boolSpecConstant, getSpecId(
+ m_programInfo.type() == DxsoProgramType::VertexShader
+ ? D3D9SpecConstantId::VertexShaderBools
+ : D3D9SpecConstantId::PixelShaderBools));
+ m_module.setDebugName(m_boolSpecConstant, "boolConstants");
+
+ m_depthSpecConstant = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.decorateSpecId(m_depthSpecConstant, getSpecId(D3D9SpecConstantId::SamplerDepthMode));
+ m_module.setDebugName(m_depthSpecConstant, "depthSamplers");
+ }
+
+
+ void DxsoCompiler::emitDclInputArray() {
+ DxsoArrayType info;
+ info.ctype = DxsoScalarType::Float32;
+ info.ccount = 4;
+ info.alength = DxsoMaxInterfaceRegs;
+
+ uint32_t arrayTypeId = getArrayTypeId(info);
+
+ // Define the actual variable. Note that this is private
+ // because we will copy input registers
+ // to the array during the setup phase.
+ const uint32_t ptrTypeId = m_module.defPointerType(
+ arrayTypeId, spv::StorageClassPrivate);
+
+ m_vArray = m_module.newVar(
+ ptrTypeId, spv::StorageClassPrivate);
+ m_module.setDebugName(m_vArray, "v");
+ }
+
+ void DxsoCompiler::emitDclOutputArray() {
+ DxsoArrayType info;
+ info.ctype = DxsoScalarType::Float32;
+ info.ccount = 4;
+ info.alength = m_programInfo.type() == DxsoProgramTypes::VertexShader
+ ? DxsoMaxInterfaceRegs
+ : caps::MaxSimultaneousRenderTargets;
+
+ uint32_t arrayTypeId = getArrayTypeId(info);
+
+ // Define the actual variable. Note that this is private
+ // because we will copy input registers
+ // to the array during the setup phase.
+ const uint32_t ptrTypeId = m_module.defPointerType(
+ arrayTypeId, spv::StorageClassPrivate);
+
+ m_oArray = m_module.newVar(
+ ptrTypeId, spv::StorageClassPrivate);
+ m_module.setDebugName(m_oArray, "o");
+ }
+
+
+ void DxsoCompiler::emitVsInit() {
+ m_module.enableCapability(spv::CapabilityClipDistance);
+
+ // Only VS needs this, because PS has
+ // non-indexable specialized output regs
+ this->emitDclOutputArray();
+
+ // Main function of the vertex shader
+ m_vs.functionId = m_module.allocateId();
+ m_module.setDebugName(m_vs.functionId, "vs_main");
+
+ this->setupRenderStateInfo();
+
+ this->emitFunctionBegin(
+ m_vs.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+ }
+
+
+ void DxsoCompiler::emitPsSharedConstants() {
+ m_ps.sharedState = GetSharedConstants(m_module);
+
+ const uint32_t bindingId = computeResourceSlotId(
+ m_programInfo.type(), DxsoBindingType::ConstantBuffer,
+ PSShared);
+
+ m_module.decorateDescriptorSet(m_ps.sharedState, 0);
+ m_module.decorateBinding(m_ps.sharedState, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ void DxsoCompiler::emitPsInit() {
+ m_module.enableCapability(spv::CapabilityDerivativeControl);
+
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeOriginUpperLeft);
+
+
+ // Main function of the pixel shader
+ m_ps.functionId = m_module.allocateId();
+ m_module.setDebugName(m_ps.functionId, "ps_main");
+
+ if (m_programInfo.majorVersion() < 2 || m_moduleInfo.options.forceSamplerTypeSpecConstants) {
+ m_ps.samplerTypeSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.decorateSpecId(m_ps.samplerTypeSpec, getSpecId(D3D9SpecConstantId::SamplerType));
+ m_module.setDebugName(m_ps.samplerTypeSpec, "s_sampler_types");
+
+ if (m_programInfo.majorVersion() < 2) {
+ m_ps.projectionSpec = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.decorateSpecId(m_ps.projectionSpec, getSpecId(D3D9SpecConstantId::ProjectionType));
+ m_module.setDebugName(m_ps.projectionSpec, "s_projections");
+ }
+ }
+
+ m_ps.fetch4Spec = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.decorateSpecId(m_ps.fetch4Spec, getSpecId(D3D9SpecConstantId::Fetch4));
+ m_module.setDebugName(m_ps.fetch4Spec, "s_fetch4");
+
+ this->setupRenderStateInfo();
+ this->emitPsSharedConstants();
+
+ this->emitFunctionBegin(
+ m_ps.functionId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ this->emitFunctionLabel();
+
+ // We may have to defer kill operations to the end of
+ // the shader in order to keep derivatives correct.
+ if (m_analysis->usesKill && m_moduleInfo.options.useDemoteToHelperInvocation) {
+ // This extension basically implements D3D-style discard
+ m_module.enableExtension("SPV_EXT_demote_to_helper_invocation");
+ m_module.enableCapability(spv::CapabilityDemoteToHelperInvocationEXT);
+ }
+ else if (m_analysis->usesKill && m_analysis->usesDerivatives) {
+ m_ps.killState = m_module.newVarInit(
+ m_module.defPointerType(m_module.defBoolType(), spv::StorageClassPrivate),
+ spv::StorageClassPrivate, m_module.constBool(false));
+
+ m_module.setDebugName(m_ps.killState, "ps_kill");
+
+ if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) {
+ m_module.enableCapability(spv::CapabilityGroupNonUniform);
+ m_module.enableCapability(spv::CapabilityGroupNonUniformBallot);
+
+ DxsoRegisterInfo laneId;
+ laneId.type = { DxsoScalarType::Uint32, 1, 0 };
+ laneId.sclass = spv::StorageClassInput;
+
+ m_ps.builtinLaneId = emitNewBuiltinVariable(
+ laneId, spv::BuiltInSubgroupLocalInvocationId,
+ "fLaneId", 0);
+ }
+ }
+ }
+
+
+ void DxsoCompiler::emitFunctionBegin(
+ uint32_t entryPoint,
+ uint32_t returnType,
+ uint32_t funcType) {
+ this->emitFunctionEnd();
+
+ m_module.functionBegin(
+ returnType, entryPoint, funcType,
+ spv::FunctionControlMaskNone);
+
+ m_insideFunction = true;
+ }
+
+
+ void DxsoCompiler::emitFunctionEnd() {
+ if (m_insideFunction) {
+ m_module.opReturn();
+ m_module.functionEnd();
+ }
+
+ m_insideFunction = false;
+ }
+
+
+ uint32_t DxsoCompiler::emitFunctionLabel() {
+ uint32_t labelId = m_module.allocateId();
+ m_module.opLabel(labelId);
+ return labelId;
+ }
+
+
+ void DxsoCompiler::emitMainFunctionBegin() {
+ this->emitFunctionBegin(
+ m_entryPointId,
+ m_module.defVoidType(),
+ m_module.defFunctionType(
+ m_module.defVoidType(), 0, nullptr));
+ m_mainFuncLabel = this->emitFunctionLabel();
+ }
+
+
+ uint32_t DxsoCompiler::emitNewVariable(const DxsoRegisterInfo& info) {
+ const uint32_t ptrTypeId = this->getPointerTypeId(info);
+ return m_module.newVar(ptrTypeId, info.sclass);
+ }
+
+
+ uint32_t DxsoCompiler::emitNewVariableDefault(
+ const DxsoRegisterInfo& info,
+ uint32_t value) {
+ const uint32_t ptrTypeId = this->getPointerTypeId(info);
+ if (value == 0)
+ return m_module.newVar(ptrTypeId, info.sclass);
+ else
+ return m_module.newVarInit(ptrTypeId, info.sclass, value);
+ }
+
+
+ uint32_t DxsoCompiler::emitNewBuiltinVariable(
+ const DxsoRegisterInfo& info,
+ spv::BuiltIn builtIn,
+ const char* name,
+ uint32_t value) {
+ const uint32_t varId = emitNewVariableDefault(info, value);
+
+ m_module.setDebugName(varId, name);
+ m_module.decorateBuiltIn(varId, builtIn);
+
+ if (m_programInfo.type() == DxsoProgramTypes::PixelShader
+ && info.type.ctype != DxsoScalarType::Float32
+ && info.type.ctype != DxsoScalarType::Bool
+ && info.sclass == spv::StorageClassInput)
+ m_module.decorate(varId, spv::DecorationFlat);
+
+ m_entryPointInterfaces.push_back(varId);
+ return varId;
+ }
+
+ DxsoCfgBlock* DxsoCompiler::cfgFindBlock(
+ const std::initializer_list<DxsoCfgBlockType>& types) {
+ for (auto cur = m_controlFlowBlocks.rbegin();
+ cur != m_controlFlowBlocks.rend(); cur++) {
+ for (auto type : types) {
+ if (cur->type == type)
+ return &(*cur);
+ }
+ }
+
+ return nullptr;
+ }
+
+ spv::BuiltIn semanticToBuiltIn(bool input, DxsoSemantic semantic) {
+ if (input)
+ return spv::BuiltInMax;
+
+ if (semantic == DxsoSemantic{ DxsoUsage::Position, 0 })
+ return spv::BuiltInPosition;
+
+ if (semantic == DxsoSemantic{ DxsoUsage::PointSize, 0 })
+ return spv::BuiltInPointSize;
+
+ return spv::BuiltInMax;
+ }
+
+ void DxsoCompiler::emitDclInterface(
+ bool input,
+ uint32_t regNumber,
+ DxsoSemantic semantic,
+ DxsoRegMask mask,
+ bool centroid) {
+ auto& sgn = input
+ ? m_isgn : m_osgn;
+
+ const bool pixel = m_programInfo.type() == DxsoProgramTypes::PixelShader;
+ const bool vertex = !pixel;
+
+ if (pixel && input && semantic.usage == DxsoUsage::Color && m_programInfo.majorVersion() < 3)
+ centroid = true;
+
+ uint32_t slot = 0;
+
+ uint32_t& slots = input
+ ? m_interfaceSlots.inputSlots
+ : m_interfaceSlots.outputSlots;
+
+ uint16_t& explicits = input
+ ? m_explicitInputs
+ : m_explicitOutputs;
+
+ // Some things we consider builtins could be packed in an output reg.
+ bool builtin = semanticToBuiltIn(input, semantic) != spv::BuiltInMax;
+
+ uint32_t i = sgn.elemCount++;
+
+ if (input && vertex) {
+ // Any slot will do! Let's chose the next one
+ slot = i;
+ }
+ else if ( (!input && vertex)
+ || (input && pixel ) ) {
+ // Don't register the slot if it belongs to a builtin
+ if (!builtin)
+ slot = RegisterLinkerSlot(semantic);
+ }
+ else { //if (!input && pixel)
+ // We want to make the output slot the same as the
+ // output register for pixel shaders so they go to
+ // the right render target.
+ slot = regNumber;
+ }
+
+ // Don't want to mark down any of these builtins.
+ if (!builtin)
+ slots |= 1u << slot;
+ explicits |= 1u << regNumber;
+
+ auto& elem = sgn.elems[i];
+ elem.slot = slot;
+ elem.regNumber = regNumber;
+ elem.semantic = semantic;
+ elem.mask = mask;
+ elem.centroid = centroid;
+ }
+
+ void DxsoCompiler::emitDclSampler(
+ uint32_t idx,
+ DxsoTextureType type) {
+ m_usedSamplers |= (1u << idx);
+
+ VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+
+ auto DclSampler = [this, &viewType](
+ uint32_t idx,
+ uint32_t bindingId,
+ DxsoSamplerType type,
+ bool depth,
+ bool implicit) {
+ // Setup our combines sampler.
+ DxsoSamplerInfo& sampler = !depth
+ ? m_samplers[idx].color[type]
+ : m_samplers[idx].depth[type];
+
+ spv::Dim dimensionality;
+
+ const char* suffix = "_2d";
+
+ switch (type) {
+ default:
+ case SamplerTypeTexture2D:
+ sampler.dimensions = 2;
+ dimensionality = spv::Dim2D;
+ viewType = VK_IMAGE_VIEW_TYPE_2D;
+ break;
+
+ case SamplerTypeTextureCube:
+ suffix = "_cube";
+ sampler.dimensions = 3;
+ dimensionality = spv::DimCube;
+ viewType = VK_IMAGE_VIEW_TYPE_CUBE;
+ break;
+
+ case SamplerTypeTexture3D:
+ suffix = "_3d";
+ sampler.dimensions = 3;
+ dimensionality = spv::Dim3D;
+ viewType = VK_IMAGE_VIEW_TYPE_3D;
+ break;
+ }
+
+ sampler.imageTypeId = m_module.defImageType(
+ m_module.defFloatType(32),
+ dimensionality, depth ? 1 : 0, 0, 0, 1,
+ spv::ImageFormatUnknown);
+
+ sampler.typeId = m_module.defSampledImageType(sampler.imageTypeId);
+
+ sampler.varId = m_module.newVar(
+ m_module.defPointerType(
+ sampler.typeId, spv::StorageClassUniformConstant),
+ spv::StorageClassUniformConstant);
+
+ std::string name = str::format("s", idx, suffix, depth ? "_shadow" : "");
+ m_module.setDebugName(sampler.varId, name.c_str());
+
+ m_module.decorateDescriptorSet(sampler.varId, 0);
+ m_module.decorateBinding (sampler.varId, bindingId);
+ };
+
+ const uint32_t binding = computeResourceSlotId(m_programInfo.type(),
+ DxsoBindingType::Image,
+ idx);
+
+ const bool implicit = m_programInfo.majorVersion() < 2 || m_moduleInfo.options.forceSamplerTypeSpecConstants;
+
+ if (!implicit) {
+ DxsoSamplerType samplerType =
+ SamplerTypeFromTextureType(type);
+
+ DclSampler(idx, binding, samplerType, false, implicit);
+
+ if (samplerType != SamplerTypeTexture3D) {
+ // We could also be depth compared!
+ DclSampler(idx, binding, samplerType, true, implicit);
+ }
+ }
+ else {
+ // Could be any of these!
+ // We will check with the spec constant at sample time.
+ for (uint32_t i = 0; i < SamplerTypeCount; i++) {
+ auto samplerType = static_cast<DxsoSamplerType>(i);
+
+ DclSampler(idx, binding, samplerType, false, implicit);
+
+ if (samplerType != SamplerTypeTexture3D)
+ DclSampler(idx, binding, samplerType, true, implicit);
+ }
+ }
+
+ DxsoSampler& sampler = m_samplers[idx];
+ sampler.boundConst = m_module.specConstBool(true);
+ sampler.type = type;
+ m_module.decorateSpecId(sampler.boundConst, binding);
+ m_module.setDebugName(sampler.boundConst,
+ str::format("s", idx, "_bound").c_str());
+
+ // Store descriptor info for the shader interface
+ DxvkResourceSlot resource;
+ resource.slot = binding;
+ resource.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ resource.view = implicit ? VK_IMAGE_VIEW_TYPE_MAX_ENUM : viewType;
+ resource.access = VK_ACCESS_SHADER_READ_BIT;
+ m_resourceSlots.push_back(resource);
+ }
+
+
+ uint32_t DxsoCompiler::emitArrayIndex(
+ uint32_t idx,
+ const DxsoBaseRegister* relative) {
+ uint32_t result = m_module.consti32(idx);
+
+ if (relative != nullptr) {
+ DxsoRegisterValue offset = emitRegisterLoad(*relative, DxsoRegMask(true, false, false, false), nullptr);
+
+ result = m_module.opIAdd(
+ getVectorTypeId(offset.type),
+ result, offset.id);
+ }
+
+ return result;
+ }
+
+
+ DxsoRegisterPointer DxsoCompiler::emitInputPtr(
+ bool texture,
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative) {
+ uint32_t idx = reg.id.num;
+
+ // Account for the two color regs.
+ if (texture)
+ idx += 2;
+
+ DxsoRegisterPointer input;
+
+ input.type = DxsoVectorType{ DxsoScalarType::Float32, 4 };
+
+ uint32_t index = this->emitArrayIndex(idx, relative);
+
+ const uint32_t typeId = getVectorTypeId(input.type);
+ input.id = m_module.opAccessChain(
+ m_module.defPointerType(typeId, spv::StorageClassPrivate),
+ m_vArray,
+ 1, &index);
+
+ return input;
+ }
+
+ DxsoRegisterPointer DxsoCompiler::emitRegisterPtr(
+ const char* name,
+ DxsoScalarType ctype,
+ uint32_t ccount,
+ uint32_t defaultVal,
+ spv::StorageClass storageClass,
+ spv::BuiltIn builtIn) {
+ DxsoRegisterPointer result;
+
+ DxsoRegisterInfo info;
+ info.type.ctype = ctype;
+ info.type.ccount = ccount;
+ info.type.alength = 1;
+ info.sclass = storageClass;
+
+ result.type = DxsoVectorType{ ctype, ccount };
+ if (builtIn == spv::BuiltInMax) {
+ result.id = this->emitNewVariableDefault(info, defaultVal);
+ m_module.setDebugName(result.id, name);
+ }
+ else {
+ result.id = this->emitNewBuiltinVariable(
+ info, builtIn, name, defaultVal);
+ }
+
+ return result;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitLoadConstant(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative) {
+ // struct cBuffer_t {
+ //
+ // Type Member Index
+ //
+ // float f[256 or 224]; 0
+ // int32_t i[16]; 1
+ // uint32_t boolBitmask; 2
+ // }
+ DxsoRegisterValue result = { };
+
+ switch (reg.id.type) {
+ case DxsoRegisterType::Const:
+ result.type = { DxsoScalarType::Float32, 4 };
+
+ if (!relative)
+ result.id = m_cFloat.at(reg.id.num);
+ break;
+
+ case DxsoRegisterType::ConstInt:
+ result.type = { DxsoScalarType::Sint32, 4 };
+ result.id = m_cInt.at(reg.id.num);
+ break;
+
+ case DxsoRegisterType::ConstBool:
+ result.type = { DxsoScalarType::Bool, 1 };
+ result.id = m_cBool.at(reg.id.num);
+ break;
+
+ default: break;
+ }
+
+ if (result.id)
+ return result;
+
+ switch (reg.id.type) {
+ case DxsoRegisterType::Const:
+ if (!relative) {
+ m_meta.maxConstIndexF = std::max(m_meta.maxConstIndexF, reg.id.num + 1);
+ m_meta.maxConstIndexF = std::min(m_meta.maxConstIndexF, m_layout->floatCount);
+ } else {
+ m_meta.maxConstIndexF = m_layout->floatCount;
+ m_meta.needsConstantCopies |= m_moduleInfo.options.strictConstantCopies
+ || m_cFloat.at(reg.id.num) != 0;
+ }
+ break;
+
+ case DxsoRegisterType::ConstInt:
+ m_meta.maxConstIndexI = std::max(m_meta.maxConstIndexI, reg.id.num + 1);
+ m_meta.maxConstIndexI = std::min(m_meta.maxConstIndexI, m_layout->intCount);
+ break;
+
+ case DxsoRegisterType::ConstBool:
+ m_meta.maxConstIndexB = std::max(m_meta.maxConstIndexB, reg.id.num + 1);
+ m_meta.maxConstIndexB = std::min(m_meta.maxConstIndexB, m_layout->boolCount);
+ m_meta.boolConstantMask |= 1 << reg.id.num;
+ break;
+
+ default: break;
+ }
+
+ uint32_t relativeIdx = this->emitArrayIndex(reg.id.num, relative);
+
+ if (reg.id.type != DxsoRegisterType::ConstBool) {
+ uint32_t structIdx = reg.id.type == DxsoRegisterType::Const
+ ? m_module.constu32(0)
+ : m_module.constu32(1);
+
+ std::array<uint32_t, 2> indices = { structIdx, relativeIdx };
+
+ uint32_t typeId = getVectorTypeId(result.type);
+ uint32_t ptrId = m_module.opAccessChain(
+ m_module.defPointerType(typeId, spv::StorageClassUniform),
+ m_cBuffer, indices.size(), indices.data());
+
+ result.id = m_module.opLoad(typeId, ptrId);
+
+ if (relative) {
+ uint32_t constCount = m_module.constu32(m_layout->floatCount);
+
+ // Expand condition to bvec4 since the result has four components
+ uint32_t cond = m_module.opULessThan(m_module.defBoolType(), relativeIdx, constCount);
+ std::array<uint32_t, 4> condIds = { cond, cond, cond, cond };
+
+ cond = m_module.opCompositeConstruct(
+ m_module.defVectorType(m_module.defBoolType(), 4),
+ condIds.size(), condIds.data());
+
+ result.id = m_module.opSelect(typeId, cond, result.id,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f));
+ }
+ } else {
+ // Bool constants have no relative indexing, so we can do the bitfield
+ // magic for SWVP at compile time.
+
+ uint32_t uintType = getScalarTypeId(DxsoScalarType::Uint32);
+ uint32_t uvec4Type = getVectorTypeId({ DxsoScalarType::Uint32, 4 });
+
+ // If not SWVP, spec const this
+ uint32_t bitfield;
+ if (m_layout->bitmaskCount != 1) {
+ std::array<uint32_t, 2> indices = { m_module.constu32(2), m_module.constu32(reg.id.num / 128) };
+
+ uint32_t indexCount = m_layout->bitmaskCount == 1 ? 1 : 2;
+ uint32_t accessType = m_layout->bitmaskCount == 1 ? uintType : uvec4Type;
+
+ uint32_t ptrId = m_module.opAccessChain(
+ m_module.defPointerType(accessType, spv::StorageClassUniform),
+ m_cBuffer, indexCount, indices.data());
+
+ bitfield = m_module.opLoad(accessType, ptrId);
+ }
+ else
+ bitfield = m_boolSpecConstant;
+
+ uint32_t bitIdx = m_module.consti32(reg.id.num % 32);
+
+ if (m_layout->bitmaskCount != 1) {
+ uint32_t index = (reg.id.num % 128) / 32;
+ bitfield = m_module.opCompositeExtract(uintType, bitfield, 1, &index);
+ }
+ uint32_t bit = m_module.opBitFieldUExtract(
+ uintType, bitfield, bitIdx, m_module.consti32(1));
+
+ result.id = m_module.opINotEqual(
+ getVectorTypeId(result.type),
+ bit, m_module.constu32(0));
+ }
+
+ return result;
+ }
+
+
+ DxsoRegisterPointer DxsoCompiler::emitOutputPtr(
+ bool texcrdOut,
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative) {
+ uint32_t idx = reg.id.num;
+
+ // Account for the two color regs.
+ if (texcrdOut)
+ idx += 2;
+
+ DxsoRegisterPointer input;
+
+ input.type = DxsoVectorType{ DxsoScalarType::Float32, 4 };
+
+ uint32_t index = this->emitArrayIndex(idx, relative);
+
+ const uint32_t typeId = getVectorTypeId(input.type);
+ input.id = m_module.opAccessChain(
+ m_module.defPointerType(typeId, spv::StorageClassPrivate),
+ m_oArray,
+ 1, &index);
+
+ return input;
+ }
+
+
+ DxsoRegisterPointer DxsoCompiler::emitGetOperandPtr(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative) {
+ switch (reg.id.type) {
+ case DxsoRegisterType::Temp: {
+ DxsoRegisterPointer& ptr = m_rRegs.at(reg.id.num);
+ if (ptr.id == 0) {
+ std::string name = str::format("r", reg.id.num);
+ ptr = this->emitRegisterPtr(
+ name.c_str(), DxsoScalarType::Float32, 4,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f));
+ }
+ return ptr;
+ }
+
+ case DxsoRegisterType::Input: {
+ if (!(m_explicitInputs & 1u << reg.id.num)) {
+ this->emitDclInterface(
+ true, reg.id.num,
+ DxsoSemantic{ DxsoUsage::Color, reg.id.num },
+ IdentityWriteMask, false);
+ }
+
+ return this->emitInputPtr(false, reg, relative);
+ }
+
+ case DxsoRegisterType::PixelTexcoord:
+ case DxsoRegisterType::Texture: {
+ if (m_programInfo.type() == DxsoProgramTypes::PixelShader) {
+ // Texture register
+
+ // SM2, or SM 1.4
+ if (reg.id.type == DxsoRegisterType::PixelTexcoord
+ || m_programInfo.majorVersion() >= 2
+ || (m_programInfo.majorVersion() == 1
+ && m_programInfo.minorVersion() == 4)) {
+ uint32_t adjustedNumber = reg.id.num + 2;
+ if (!(m_explicitInputs & 1u << adjustedNumber)) {
+ this->emitDclInterface(
+ true, adjustedNumber,
+ DxsoSemantic{ DxsoUsage::Texcoord, reg.id.num },
+ IdentityWriteMask, false);
+ }
+
+ return this->emitInputPtr(true, reg, relative);
+ }
+ else {
+ // User must use tex/texcoord to put data in this private register.
+ // We use the an oob id which fxc never generates for the texcoord data.
+ DxsoRegisterPointer& ptr = m_tRegs.at(reg.id.num);
+ if (ptr.id == 0) {
+ std::string name = str::format("t", reg.id.num);
+ ptr = this->emitRegisterPtr(
+ name.c_str(), DxsoScalarType::Float32, 4,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f));
+ }
+ return ptr;
+ }
+ }
+ else {
+ // Address register
+ if (m_vs.addr.id == 0) {
+ m_vs.addr = this->emitRegisterPtr(
+ "a0", DxsoScalarType::Sint32, 4,
+ m_module.constvec4i32(0, 0, 0, 0));
+ }
+ return m_vs.addr;
+ }
+ }
+
+ case DxsoRegisterType::RasterizerOut:
+ switch (reg.id.num) {
+ case RasterOutPosition:
+ if (m_vs.oPos.id == 0) {
+ m_vs.oPos = this->emitRegisterPtr(
+ "oPos", DxsoScalarType::Float32, 4,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f),
+ spv::StorageClassOutput, spv::BuiltInPosition);
+ }
+ return m_vs.oPos;
+
+ case RasterOutFog:
+ if (m_fog.id == 0) {
+ bool input = m_programInfo.type() == DxsoProgramType::PixelShader;
+ DxsoSemantic semantic = DxsoSemantic{ DxsoUsage::Fog, 0 };
+
+ uint32_t slot = RegisterLinkerSlot(semantic);
+
+ uint32_t& slots = input
+ ? m_interfaceSlots.inputSlots
+ : m_interfaceSlots.outputSlots;
+
+ slots |= 1u << slot;
+
+ m_fog = this->emitRegisterPtr(
+ input ? "vFog" : "oFog",
+ DxsoScalarType::Float32, 1,
+ input ? 0 : m_module.constf32(1.0f),
+ input ? spv::StorageClassInput : spv::StorageClassOutput);
+
+ m_entryPointInterfaces.push_back(m_fog.id);
+
+ m_module.decorateLocation(m_fog.id, slot);
+ }
+ return m_fog;
+
+ case RasterOutPointSize:
+ if (m_vs.oPSize.id == 0) {
+ m_vs.oPSize = this->emitRegisterPtr(
+ "oPSize", DxsoScalarType::Float32, 1,
+ m_module.constf32(0.0f),
+ spv::StorageClassOutput, spv::BuiltInPointSize);
+ }
+ return m_vs.oPSize;
+ }
+
+ case DxsoRegisterType::ColorOut: {
+ uint32_t idx = std::min(reg.id.num, 4u);
+
+ if (m_ps.oColor[idx].id == 0) {
+ std::string name = str::format("oC", idx);
+ m_ps.oColor[idx] = this->emitRegisterPtr(
+ name.c_str(), DxsoScalarType::Float32, 4,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f),
+ spv::StorageClassOutput);
+
+ m_interfaceSlots.outputSlots |= 1u << idx;
+ m_module.decorateLocation(m_ps.oColor[idx].id, idx);
+ m_module.decorateIndex(m_ps.oColor[idx].id, 0);
+
+ m_entryPointInterfaces.push_back(m_ps.oColor[idx].id);
+ m_usedRTs |= (1u << idx);
+ }
+ return m_ps.oColor[idx];
+ }
+
+ case DxsoRegisterType::AttributeOut: {
+ auto ptr = this->emitOutputPtr(false, reg, nullptr);
+
+ if (!(m_explicitOutputs & 1u << reg.id.num)) {
+ this->emitDclInterface(
+ false, reg.id.num,
+ DxsoSemantic{ DxsoUsage::Color, reg.id.num },
+ IdentityWriteMask, false);
+
+ m_module.opStore(ptr.id, m_module.constfReplicant(0, ptr.type.ccount));
+ }
+
+ return ptr;
+ }
+
+ case DxsoRegisterType::Output: {
+ bool texcrdOut = m_programInfo.type() == DxsoProgramTypes::VertexShader
+ && m_programInfo.majorVersion() != 3;
+
+ auto ptr = this->emitOutputPtr(texcrdOut, reg, !texcrdOut ? relative : nullptr);
+
+ if (texcrdOut) {
+ uint32_t adjustedNumber = reg.id.num + 2;
+ if (!(m_explicitOutputs & 1u << adjustedNumber)) {
+ this->emitDclInterface(
+ false, adjustedNumber,
+ DxsoSemantic{ DxsoUsage::Texcoord, reg.id.num },
+ IdentityWriteMask, false);
+
+ m_module.opStore(ptr.id, m_module.constfReplicant(0, ptr.type.ccount));
+ }
+ }
+
+ return ptr;
+ }
+
+ case DxsoRegisterType::DepthOut:
+ if (m_ps.oDepth.id == 0) {
+ m_module.setExecutionMode(m_entryPointId,
+ spv::ExecutionModeDepthReplacing);
+
+ m_ps.oDepth = this->emitRegisterPtr(
+ "oDepth", DxsoScalarType::Float32, 1,
+ m_module.constf32(0.0f),
+ spv::StorageClassOutput, spv::BuiltInFragDepth);
+ }
+ return m_ps.oDepth;
+
+ case DxsoRegisterType::Loop:
+ if (m_loopCounter.id == 0) {
+ m_loopCounter = this->emitRegisterPtr(
+ "aL", DxsoScalarType::Sint32, 1,
+ m_module.consti32(0));
+ }
+ return m_loopCounter;
+
+ case DxsoRegisterType::MiscType:
+ if (reg.id.num == MiscTypePosition) {
+ if (m_ps.vPos.id == 0) {
+ m_ps.vPos = this->emitRegisterPtr(
+ "vPos", DxsoScalarType::Float32, 4, 0);
+ }
+ return m_ps.vPos;
+ }
+ else { // MiscTypeFace
+ if (m_ps.vFace.id == 0) {
+ m_ps.vFace = this->emitRegisterPtr(
+ "vFace", DxsoScalarType::Float32, 4, 0);
+ }
+ return m_ps.vFace;
+ }
+
+ case DxsoRegisterType::Predicate: {
+ DxsoRegisterPointer& ptr = m_pRegs.at(reg.id.num);
+ if (ptr.id == 0) {
+ std::string name = str::format("p", reg.id.num);
+ ptr = this->emitRegisterPtr(
+ name.c_str(), DxsoScalarType::Bool, 4,
+ m_module.constvec4b32(false, false, false, false));
+ }
+ return ptr;
+ }
+
+ default: {
+ //Logger::warn(str::format("emitGetOperandPtr: unhandled reg type: ", reg.id.type));
+
+ DxsoRegisterPointer nullPointer;
+ nullPointer.id = 0;
+ return nullPointer;
+ }
+ }
+ }
+
+
+ uint32_t DxsoCompiler::emitBoolComparison(DxsoVectorType type, DxsoComparison cmp, uint32_t a, uint32_t b) {
+ const uint32_t typeId = getVectorTypeId(type);
+ switch (cmp) {
+ default:
+ case DxsoComparison::Never: return m_module.constbReplicant(false, type.ccount); break;
+ case DxsoComparison::GreaterThan: return m_module.opFOrdGreaterThan (typeId, a, b); break;
+ case DxsoComparison::Equal: return m_module.opFOrdEqual (typeId, a, b); break;
+ case DxsoComparison::GreaterEqual: return m_module.opFOrdGreaterThanEqual(typeId, a, b); break;
+ case DxsoComparison::LessThan: return m_module.opFOrdLessThan (typeId, a, b); break;
+ case DxsoComparison::NotEqual: return m_module.opFOrdNotEqual (typeId, a, b); break;
+ case DxsoComparison::LessEqual: return m_module.opFOrdLessThanEqual (typeId, a, b); break;
+ case DxsoComparison::Always: return m_module.constbReplicant(true, type.ccount); break;
+ }
+}
+
+
+ DxsoRegisterValue DxsoCompiler::emitValueLoad(
+ DxsoRegisterPointer ptr) {
+ DxsoRegisterValue result;
+ result.type = ptr.type;
+ result.id = m_module.opLoad(
+ getVectorTypeId(result.type),
+ ptr.id);
+ return result;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::applyPredicate(DxsoRegisterValue pred, DxsoRegisterValue dst, DxsoRegisterValue src) {
+ if (dst.type.ccount != pred.type.ccount) {
+ DxsoRegMask mask = DxsoRegMask(
+ pred.type.ccount > 0,
+ pred.type.ccount > 1,
+ pred.type.ccount > 2,
+ pred.type.ccount > 3);
+
+ pred = emitRegisterSwizzle(pred, IdentitySwizzle, mask);
+ }
+
+ dst.id = m_module.opSelect(
+ getVectorTypeId(dst.type),
+ pred.id,
+ src.id, dst.id);
+
+ return dst;
+ }
+
+
+ void DxsoCompiler::emitValueStore(
+ DxsoRegisterPointer ptr,
+ DxsoRegisterValue value,
+ DxsoRegMask writeMask,
+ DxsoRegisterValue predicate) {
+ // If the source value consists of only one component,
+ // it is stored in all components of the destination.
+ if (value.type.ccount == 1)
+ value = emitRegisterExtend(value, writeMask.popCount());
+
+ if (ptr.type.ccount == writeMask.popCount()) {
+ if (predicate.id)
+ value = applyPredicate(predicate, emitValueLoad(ptr), value);
+
+ // Simple case: We write to the entire register
+ m_module.opStore(ptr.id, value.id);
+ } else {
+ // We only write to part of the destination
+ // register, so we need to load and modify it
+ DxsoRegisterValue tmp = emitValueLoad(ptr);
+ tmp = emitRegisterInsert(tmp, value, writeMask);
+
+ if (predicate.id)
+ value = applyPredicate(predicate, emitValueLoad(ptr), tmp);
+
+ m_module.opStore(ptr.id, tmp.id);
+ }
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitClampBoundReplicant(
+ DxsoRegisterValue srcValue,
+ float lb,
+ float ub) {
+ srcValue.id = m_module.opFClamp(getVectorTypeId(srcValue.type), srcValue.id,
+ m_module.constfReplicant(lb, srcValue.type.ccount),
+ m_module.constfReplicant(ub, srcValue.type.ccount));
+
+ return srcValue;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitSaturate(
+ DxsoRegisterValue srcValue) {
+ return emitClampBoundReplicant(srcValue, 0.0f, 1.0f);
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitDot(
+ DxsoRegisterValue a,
+ DxsoRegisterValue b) {
+ DxsoRegisterValue dot;
+ dot.type = a.type;
+ dot.type.ccount = 1;
+
+ dot.id = m_module.opDot(getVectorTypeId(dot.type), a.id, b.id);
+
+ return dot;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitRegisterInsert(
+ DxsoRegisterValue dstValue,
+ DxsoRegisterValue srcValue,
+ DxsoRegMask srcMask) {
+ DxsoRegisterValue result;
+ result.type = dstValue.type;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (srcMask.popCount() == 0) {
+ // Nothing to do if the insertion mask is empty
+ result.id = dstValue.id;
+ } else if (dstValue.type.ccount == 1) {
+ // Both values are scalar, so the first component
+ // of the write mask decides which one to take.
+ result.id = srcMask[0] ? srcValue.id : dstValue.id;
+ } else if (srcValue.type.ccount == 1) {
+ // The source value is scalar. Since OpVectorShuffle
+ // requires both arguments to be vectors, we have to
+ // use OpCompositeInsert to modify the vector instead.
+ const uint32_t componentId = srcMask.firstSet();
+
+ result.id = m_module.opCompositeInsert(typeId,
+ srcValue.id, dstValue.id, 1, &componentId);
+ } else {
+ // Both arguments are vectors. We can determine which
+ // components to take from which vector and use the
+ // OpVectorShuffle instruction.
+ std::array<uint32_t, 4> components;
+ uint32_t srcComponentId = dstValue.type.ccount;
+
+ for (uint32_t i = 0; i < dstValue.type.ccount; i++)
+ components.at(i) = srcMask[i] ? srcComponentId++ : i;
+
+ result.id = m_module.opVectorShuffle(
+ typeId, dstValue.id, srcValue.id,
+ dstValue.type.ccount, components.data());
+ }
+
+ return result;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitRegisterLoadRaw(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative) {
+ switch (reg.id.type) {
+ case DxsoRegisterType::Const:
+ case DxsoRegisterType::ConstInt:
+ case DxsoRegisterType::ConstBool:
+ return emitLoadConstant(reg, relative);
+
+ default:
+ return emitValueLoad(emitGetOperandPtr(reg, relative));
+ }
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitRegisterExtend(
+ DxsoRegisterValue value,
+ uint32_t size) {
+ if (size == 1)
+ return value;
+
+ std::array<uint32_t, 4> ids = {{
+ value.id, value.id,
+ value.id, value.id,
+ }};
+
+ DxsoRegisterValue result;
+ result.type.ctype = value.type.ctype;
+ result.type.ccount = size;
+ result.id = m_module.opCompositeConstruct(
+ getVectorTypeId(result.type),
+ size, ids.data());
+ return result;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitRegisterSwizzle(
+ DxsoRegisterValue value,
+ DxsoRegSwizzle swizzle,
+ DxsoRegMask writeMask) {
+ if (value.type.ccount == 1)
+ return emitRegisterExtend(value, writeMask.popCount());
+
+ std::array<uint32_t, 4> indices;
+
+ uint32_t dstIndex = 0;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (writeMask[i])
+ indices[dstIndex++] = swizzle[i];
+ }
+
+ // If the swizzle combined with the mask can be reduced
+ // to a no-op, we don't need to insert any instructions.
+ bool isIdentitySwizzle = dstIndex == value.type.ccount;
+
+ for (uint32_t i = 0; i < dstIndex && isIdentitySwizzle; i++)
+ isIdentitySwizzle &= indices[i] == i;
+
+ if (isIdentitySwizzle)
+ return value;
+
+ // Use OpCompositeExtract if the resulting vector contains
+ // only one component, and OpVectorShuffle if it is a vector.
+ DxsoRegisterValue result;
+ result.type.ctype = value.type.ctype;
+ result.type.ccount = dstIndex;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (dstIndex == 1) {
+ result.id = m_module.opCompositeExtract(
+ typeId, value.id, 1, indices.data());
+ } else {
+ result.id = m_module.opVectorShuffle(
+ typeId, value.id, value.id,
+ dstIndex, indices.data());
+ }
+
+ return result;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitSrcOperandPreSwizzleModifiers(
+ DxsoRegisterValue value,
+ DxsoRegModifier modifier) {
+ // r / r.z
+ // r / r.w
+ if (modifier == DxsoRegModifier::Dz
+ || modifier == DxsoRegModifier::Dw) {
+ const uint32_t index = modifier == DxsoRegModifier::Dz ? 2 : 3;
+
+ std::array<uint32_t, 4> indices = { index, index, index, index };
+
+ uint32_t component = m_module.opVectorShuffle(
+ getVectorTypeId(value.type), value.id, value.id, value.type.ccount, indices.data());
+
+ value.id = m_module.opFDiv(
+ getVectorTypeId(value.type), value.id, component);
+ }
+
+ return value;
+ }
+
+
+ DxsoRegisterValue DxsoCompiler::emitSrcOperandPostSwizzleModifiers(
+ DxsoRegisterValue value,
+ DxsoRegModifier modifier) {
+ // r - 0.5
+ if (modifier == DxsoRegModifier::Bias
+ || modifier == DxsoRegModifier::BiasNeg) {
+ uint32_t halfVec = m_module.constfReplicant(
+ 0.5f, value.type.ccount);
+
+ value.id = m_module.opFSub(
+ getVectorTypeId(value.type), value.id, halfVec);
+ }
+
+ // fma(r, 2.0f, -1.0f)
+ if (modifier == DxsoRegModifier::Sign
+ || modifier == DxsoRegModifier::SignNeg) {
+ uint32_t twoVec = m_module.constfReplicant(
+ 2.0f, value.type.ccount);
+
+ uint32_t minusOneVec = m_module.constfReplicant(
+ -1.0f, value.type.ccount);
+
+ value.id = m_module.opFFma(
+ getVectorTypeId(value.type), value.id, twoVec, minusOneVec);
+ }
+
+ // 1 - r
+ if (modifier == DxsoRegModifier::Comp) {
+ uint32_t oneVec = m_module.constfReplicant(
+ 1.0f, value.type.ccount);
+
+ value.id = m_module.opFSub(
+ getVectorTypeId(value.type), oneVec, value.id);
+ }
+
+ // r * 2
+ if (modifier == DxsoRegModifier::X2
+ || modifier == DxsoRegModifier::X2Neg) {
+ uint32_t twoVec = m_module.constfReplicant(
+ 2.0f, value.type.ccount);
+
+ value.id = m_module.opFMul(
+ getVectorTypeId(value.type), value.id, twoVec);
+ }
+
+ // abs( r )
+ if (modifier == DxsoRegModifier::Abs
+ || modifier == DxsoRegModifier::AbsNeg) {
+ value.id = m_module.opFAbs(
+ getVectorTypeId(value.type), value.id);
+ }
+
+ // !r
+ if (modifier == DxsoRegModifier::Not) {
+ value.id =
+ m_module.opLogicalNot(getVectorTypeId(value.type), value.id);
+ }
+
+ // -r
+ // Treating as -r
+ // Treating as -r
+ // -r * 2
+ // -abs(r)
+ if (modifier == DxsoRegModifier::Neg
+ || modifier == DxsoRegModifier::BiasNeg
+ || modifier == DxsoRegModifier::SignNeg
+ || modifier == DxsoRegModifier::X2Neg
+ || modifier == DxsoRegModifier::AbsNeg) {
+ value.id = m_module.opFNegate(
+ getVectorTypeId(value.type), value.id);
+ }
+
+ return value;
+ }
+
+ DxsoRegisterValue DxsoCompiler::emitRegisterLoad(
+ const DxsoBaseRegister& reg,
+ DxsoRegMask writeMask,
+ const DxsoBaseRegister* relative) {
+ // Load operand from the operand pointer
+ DxsoRegisterValue result = emitRegisterLoadRaw(reg, relative);
+
+ // PS 1.x clamps float constants
+ if (m_programInfo.type() == DxsoProgramType::PixelShader && m_programInfo.majorVersion() == 1
+ && reg.id.type == DxsoRegisterType::Const)
+ result = emitClampBoundReplicant(result, -1.0f, 1.0f);
+
+ // Apply operand modifiers
+ result = emitSrcOperandPreSwizzleModifiers(result, reg.modifier);
+
+ // Apply operand swizzle to the operand value
+ result = emitRegisterSwizzle(result, reg.swizzle, writeMask);
+
+ // Apply operand modifiers
+ result = emitSrcOperandPostSwizzleModifiers(result, reg.modifier);
+ return result;
+ }
+
+ void DxsoCompiler::emitDcl(const DxsoInstructionContext& ctx) {
+ auto id = ctx.dst.id;
+
+ if (id.type == DxsoRegisterType::Sampler) {
+ this->emitDclSampler(
+ ctx.dst.id.num,
+ ctx.dcl.textureType);
+ }
+ else if (id.type == DxsoRegisterType::Input
+ || id.type == DxsoRegisterType::Texture
+ || id.type == DxsoRegisterType::Output) {
+ DxsoSemantic semantic = ctx.dcl.semantic;
+
+ uint32_t vIndex = id.num;
+
+ if (m_programInfo.type() == DxsoProgramTypes::PixelShader) {
+ // Semantic in PS < 3 is based upon id.
+ if (m_programInfo.majorVersion() < 3) {
+ // Account for the two color registers.
+ if (id.type == DxsoRegisterType::Texture)
+ vIndex += 2;
+
+ semantic = DxsoSemantic{
+ id.type == DxsoRegisterType::Texture ? DxsoUsage::Texcoord : DxsoUsage::Color,
+ id.num };
+ }
+ }
+
+ this->emitDclInterface(
+ id.type != DxsoRegisterType::Output,
+ vIndex,
+ semantic,
+ ctx.dst.mask,
+ ctx.dst.centroid);
+ }
+ else {
+ //Logger::warn(str::format("DxsoCompiler::emitDcl: unhandled register type ", id.type));
+ }
+ }
+
+ void DxsoCompiler::emitDef(const DxsoInstructionContext& ctx) {
+ switch (ctx.instruction.opcode) {
+ case DxsoOpcode::Def: emitDefF(ctx); break;
+ case DxsoOpcode::DefI: emitDefI(ctx); break;
+ case DxsoOpcode::DefB: emitDefB(ctx); break;
+ default:
+ throw DxvkError("DxsoCompiler::emitDef: Invalid definition opcode");
+ break;
+ }
+ }
+
+ void DxsoCompiler::emitDefF(const DxsoInstructionContext& ctx) {
+ const float* data = ctx.def.float32;
+
+ uint32_t constId = m_module.constvec4f32(data[0], data[1], data[2], data[3]);
+ m_cFloat.at(ctx.dst.id.num) = constId;
+
+ std::string name = str::format("cF", ctx.dst.id.num, "_def");
+ m_module.setDebugName(constId, name.c_str());
+
+ DxsoDefinedConstant constant;
+ constant.uboIdx = ctx.dst.id.num;
+ for (uint32_t i = 0; i < 4; i++)
+ constant.float32[i] = data[i];
+ m_constants.push_back(constant);
+ }
+
+ void DxsoCompiler::emitDefI(const DxsoInstructionContext& ctx) {
+ const int32_t* data = ctx.def.int32;
+
+ uint32_t constId = m_module.constvec4i32(data[0], data[1], data[2], data[3]);
+ m_cInt.at(ctx.dst.id.num) = constId;
+
+ std::string name = str::format("cI", ctx.dst.id.num, "_def");
+ m_module.setDebugName(constId, name.c_str());
+ }
+
+ void DxsoCompiler::emitDefB(const DxsoInstructionContext& ctx) {
+ const int32_t* data = ctx.def.int32;
+
+ uint32_t constId = m_module.constBool(data[0] != 0);
+ m_cBool.at(ctx.dst.id.num) = constId;
+
+ std::string name = str::format("cB", ctx.dst.id.num, "_def");
+ m_module.setDebugName(constId, name.c_str());
+ }
+
+
+ bool DxsoCompiler::isScalarRegister(DxsoRegisterId id) {
+ return id == DxsoRegisterId{DxsoRegisterType::DepthOut, 0}
+ || id == DxsoRegisterId{DxsoRegisterType::RasterizerOut, RasterOutPointSize}
+ || id == DxsoRegisterId{DxsoRegisterType::RasterizerOut, RasterOutFog};
+ }
+
+
+ void DxsoCompiler::emitMov(const DxsoInstructionContext& ctx) {
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ DxsoRegMask mask = ctx.dst.mask;
+
+ if (isScalarRegister(ctx.dst.id))
+ mask = DxsoRegMask(true, false, false, false);
+
+ DxsoRegisterValue src0 = emitRegisterLoad(ctx.src[0], mask);
+
+ DxsoRegisterValue result;
+ result.type.ctype = dst.type.ctype;
+ result.type.ccount = mask.popCount();
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ if (dst.type.ctype != src0.type.ctype) {
+ // We have Mova for this... but it turns out Mov has the same behaviour in d3d9!
+
+ // Convert float -> int32_t
+ // and vice versa
+ if (dst.type.ctype == DxsoScalarType::Sint32) {
+ // We need to floor for VS 1.1 and below, the documentation is a dirty stinking liar.
+ if (m_programInfo.majorVersion() < 2 && m_programInfo.minorVersion() < 2)
+ result.id = m_module.opFloor(getVectorTypeId(src0.type), src0.id);
+ else
+ result.id = m_module.opRound(getVectorTypeId(src0.type), src0.id);
+
+ result.id = m_module.opConvertFtoS(typeId, result.id);
+ }
+ else // Float32
+ result.id = m_module.opConvertStoF(typeId, src0.id);
+ }
+ else // No special stuff needed!
+ result.id = src0.id;
+
+ this->emitDstStore(dst, result, mask, ctx.dst.saturate, emitPredicateLoad(ctx), ctx.dst.shift, ctx.dst.id);
+ }
+
+
+ void DxsoCompiler::emitVectorAlu(const DxsoInstructionContext& ctx) {
+ const auto& src = ctx.src;
+
+ DxsoRegMask mask = ctx.dst.mask;
+
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ if (isScalarRegister(ctx.dst.id))
+ mask = DxsoRegMask(true, false, false, false);
+
+ DxsoRegisterValue result;
+ result.type.ctype = dst.type.ctype;
+ result.type.ccount = mask.popCount();
+
+ DxsoVectorType scalarType = result.type;
+ scalarType.ccount = 1;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+ const uint32_t scalarTypeId = getVectorTypeId(scalarType);
+
+ const DxsoOpcode opcode = ctx.instruction.opcode;
+ switch (opcode) {
+ case DxsoOpcode::Add:
+ result.id = m_module.opFAdd(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+ break;
+ case DxsoOpcode::Sub:
+ result.id = m_module.opFSub(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+ break;
+ case DxsoOpcode::Mad:
+ if (!m_moduleInfo.options.longMad) {
+ result.id = m_module.opFFma(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id,
+ emitRegisterLoad(src[2], mask).id);
+ }
+ else {
+ result.id = m_module.opFMul(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+
+ result.id = m_module.opFAdd(typeId,
+ result.id,
+ emitRegisterLoad(src[2], mask).id);
+ }
+ break;
+ case DxsoOpcode::Mul:
+ result.id = m_module.opFMul(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+ break;
+ case DxsoOpcode::Rcp:
+ result.id = m_module.opFDiv(typeId,
+ m_module.constfReplicant(1.0f, result.type.ccount),
+ emitRegisterLoad(src[0], mask).id);
+
+ if (m_moduleInfo.options.d3d9FloatEmulation) {
+ result.id = m_module.opNMin(typeId, result.id,
+ m_module.constfReplicant(FLT_MAX, result.type.ccount));
+ }
+ break;
+ case DxsoOpcode::Rsq:
+ result.id = m_module.opFAbs(typeId,
+ emitRegisterLoad(src[0], mask).id);
+
+ result.id = m_module.opInverseSqrt(typeId,
+ result.id);
+
+ if (m_moduleInfo.options.d3d9FloatEmulation) {
+ result.id = m_module.opNMin(typeId, result.id,
+ m_module.constfReplicant(FLT_MAX, result.type.ccount));
+ }
+ break;
+ case DxsoOpcode::Dp3: {
+ DxsoRegMask srcMask(true, true, true, false);
+ result = emitDot(
+ emitRegisterLoad(src[0], srcMask),
+ emitRegisterLoad(src[1], srcMask));
+ break;
+ }
+ case DxsoOpcode::Dp4:
+ result = emitDot(
+ emitRegisterLoad(src[0], IdentityWriteMask),
+ emitRegisterLoad(src[1], IdentityWriteMask));
+ break;
+ case DxsoOpcode::Slt:
+ case DxsoOpcode::Sge: {
+ const uint32_t boolTypeId =
+ getVectorTypeId({ DxsoScalarType::Bool, result.type.ccount });
+
+ uint32_t cmpResult = opcode == DxsoOpcode::Slt
+ ? m_module.opFOrdLessThan (boolTypeId, emitRegisterLoad(src[0], mask).id, emitRegisterLoad(src[1], mask).id)
+ : m_module.opFOrdGreaterThanEqual(boolTypeId, emitRegisterLoad(src[0], mask).id, emitRegisterLoad(src[1], mask).id);
+
+ result.id = m_module.opSelect(typeId, cmpResult,
+ m_module.constfReplicant(1.0f, result.type.ccount),
+ m_module.constfReplicant(0.0f, result.type.ccount));
+ break;
+ }
+ case DxsoOpcode::Min:
+ result.id = m_module.opFMin(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+ break;
+ case DxsoOpcode::Max:
+ result.id = m_module.opFMax(typeId,
+ emitRegisterLoad(src[0], mask).id,
+ emitRegisterLoad(src[1], mask).id);
+ break;
+ case DxsoOpcode::ExpP:
+ if (m_programInfo.majorVersion() < 2) {
+ DxsoRegMask srcMask(true, false, false, false);
+ uint32_t src0 = emitRegisterLoad(src[0], srcMask).id;
+
+ uint32_t index = 0;
+
+ std::array<uint32_t, 4> resultIndices;
+
+ if (mask[0]) resultIndices[index++] = m_module.opExp2(scalarTypeId, m_module.opFloor(scalarTypeId, src0));
+ if (mask[1]) resultIndices[index++] = m_module.opFSub(scalarTypeId, src0, m_module.opFloor(scalarTypeId, src0));
+ if (mask[2]) resultIndices[index++] = m_module.opExp2(scalarTypeId, src0);
+ if (mask[3]) resultIndices[index++] = m_module.constf32(1.0f);
+
+ if (result.type.ccount == 1)
+ result.id = resultIndices[0];
+ else
+ result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, resultIndices.data());
+
+ break;
+ }
+ case DxsoOpcode::Exp:
+ result.id = m_module.opExp2(typeId,
+ emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::Pow: {
+ uint32_t base = emitRegisterLoad(src[0], mask).id;
+ base = m_module.opFAbs(typeId, base);
+
+ uint32_t exponent = emitRegisterLoad(src[1], mask).id;
+
+ result.id = m_module.opPow(typeId, base, exponent);
+
+ if (m_moduleInfo.options.strictPow && m_moduleInfo.options.d3d9FloatEmulation) {
+ DxsoRegisterValue cmp;
+ cmp.type = { DxsoScalarType::Bool, result.type.ccount };
+ cmp.id = m_module.opFOrdEqual(getVectorTypeId(cmp.type),
+ exponent, m_module.constfReplicant(0.0f, cmp.type.ccount));
+
+ result.id = m_module.opSelect(typeId, cmp.id,
+ m_module.constfReplicant(1.0f, cmp.type.ccount), result.id);
+ }
+ break;
+ }
+ case DxsoOpcode::Crs: {
+ DxsoRegMask vec3Mask(true, true, true, false);
+
+ DxsoRegisterValue crossValue;
+ crossValue.type = { DxsoScalarType::Float32, 3 };
+ crossValue.id = m_module.opCross(getVectorTypeId(crossValue.type),
+ emitRegisterLoad(src[0], vec3Mask).id,
+ emitRegisterLoad(src[1], vec3Mask).id);
+
+ std::array<uint32_t, 3> indices = { 0, 0, 0 };
+
+ uint32_t index = 0;
+ for (uint32_t i = 0; i < indices.size(); i++) {
+ if (mask[i])
+ indices[index++] = m_module.opCompositeExtract(m_module.defFloatType(32), crossValue.id, 1, &i);
+ }
+
+ result.id = m_module.opCompositeConstruct(getVectorTypeId(result.type), result.type.ccount, indices.data());
+
+ break;
+ }
+ case DxsoOpcode::Abs:
+ result.id = m_module.opFAbs(typeId,
+ emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::Sgn:
+ result.id = m_module.opFSign(typeId,
+ emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::Nrm: {
+ // Nrm is 3D...
+ DxsoRegMask srcMask(true, true, true, false);
+ auto vec3 = emitRegisterLoad(src[0], srcMask);
+
+ DxsoRegisterValue dot = emitDot(vec3, vec3);
+ dot.id = m_module.opInverseSqrt (scalarTypeId, dot.id);
+ if (m_moduleInfo.options.d3d9FloatEmulation) {
+ dot.id = m_module.opNMin (scalarTypeId, dot.id,
+ m_module.constf32(FLT_MAX));
+ }
+
+ // r * rsq(r . r);
+ result.id = m_module.opVectorTimesScalar(
+ typeId,
+ emitRegisterLoad(src[0], mask).id,
+ dot.id);
+ break;
+ }
+ case DxsoOpcode::SinCos: {
+ DxsoRegMask srcMask(true, false, false, false);
+ uint32_t src0 = emitRegisterLoad(src[0], srcMask).id;
+
+ std::array<uint32_t, 4> sincosVectorIndices = { 0, 0, 0, 0 };
+
+ uint32_t index = 0;
+ if (mask[0])
+ sincosVectorIndices[index++] = m_module.opCos(scalarTypeId, src0);
+
+ if (mask[1])
+ sincosVectorIndices[index++] = m_module.opSin(scalarTypeId, src0);
+
+ for (; index < result.type.ccount; index++) {
+ if (sincosVectorIndices[index] == 0)
+ sincosVectorIndices[index] = m_module.constf32(0.0f);
+ }
+
+ if (result.type.ccount == 1)
+ result.id = sincosVectorIndices[0];
+ else
+ result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, sincosVectorIndices.data());
+
+ break;
+ }
+ case DxsoOpcode::Lit: {
+ DxsoRegMask srcMask(true, true, true, true);
+ uint32_t srcOp = emitRegisterLoad(src[0], srcMask).id;
+
+ const uint32_t x = 0;
+ const uint32_t y = 1;
+ const uint32_t w = 3;
+
+ uint32_t srcX = m_module.opCompositeExtract(scalarTypeId, srcOp, 1, &x);
+ uint32_t srcY = m_module.opCompositeExtract(scalarTypeId, srcOp, 1, &y);
+ uint32_t srcW = m_module.opCompositeExtract(scalarTypeId, srcOp, 1, &w);
+
+ uint32_t power = m_module.opFClamp(
+ scalarTypeId, srcW,
+ m_module.constf32(-127.9961f), m_module.constf32(127.9961f));
+
+ std::array<uint32_t, 4> resultIndices;
+
+ uint32_t index = 0;
+
+ if (mask[0]) resultIndices[index++] = m_module.constf32(1.0f);
+ if (mask[1]) resultIndices[index++] = m_module.opFMax(scalarTypeId, srcX, m_module.constf32(0));
+ if (mask[2]) resultIndices[index++] = m_module.opPow (scalarTypeId, m_module.opFMax(scalarTypeId, srcY, m_module.constf32(0)), power);
+ if (mask[3]) resultIndices[index++] = m_module.constf32(1.0f);
+
+ const uint32_t boolType = m_module.defBoolType();
+ uint32_t zTestX = m_module.opFOrdGreaterThanEqual(boolType, srcX, m_module.constf32(0));
+ uint32_t zTestY = m_module.opFOrdGreaterThanEqual(boolType, srcY, m_module.constf32(0));
+ uint32_t zTest = m_module.opLogicalAnd(boolType, zTestX, zTestY);
+
+ if (result.type.ccount > 2)
+ resultIndices[2] = m_module.opSelect(
+ scalarTypeId,
+ zTest,
+ resultIndices[2],
+ m_module.constf32(0.0f));
+
+ if (result.type.ccount == 1)
+ result.id = resultIndices[0];
+ else
+ result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, resultIndices.data());
+ break;
+ }
+ case DxsoOpcode::Dst: {
+ //dest.x = 1;
+ //dest.y = src0.y * src1.y;
+ //dest.z = src0.z;
+ //dest.w = src1.w;
+
+ DxsoRegMask srcMask(true, true, true, true);
+
+ uint32_t src0 = emitRegisterLoad(src[0], srcMask).id;
+ uint32_t src1 = emitRegisterLoad(src[1], srcMask).id;
+
+ const uint32_t y = 1;
+ const uint32_t z = 2;
+ const uint32_t w = 3;
+
+ uint32_t src0Y = m_module.opCompositeExtract(scalarTypeId, src0, 1, &y);
+ uint32_t src1Y = m_module.opCompositeExtract(scalarTypeId, src1, 1, &y);
+
+ uint32_t src0Z = m_module.opCompositeExtract(scalarTypeId, src0, 1, &z);
+ uint32_t src1W = m_module.opCompositeExtract(scalarTypeId, src1, 1, &w);
+
+ std::array<uint32_t, 4> resultIndices;
+ resultIndices[0] = m_module.constf32(1.0f);
+ resultIndices[1] = m_module.opFMul(scalarTypeId, src0Y, src1Y);
+ resultIndices[2] = src0Z;
+ resultIndices[3] = src1W;
+
+ if (result.type.ccount == 1)
+ result.id = resultIndices[0];
+ else
+ result.id = m_module.opCompositeConstruct(typeId, result.type.ccount, resultIndices.data());
+ break;
+ }
+ case DxsoOpcode::LogP:
+ case DxsoOpcode::Log:
+ result.id = m_module.opFAbs(typeId, emitRegisterLoad(src[0], mask).id);
+ result.id = m_module.opLog2(typeId, result.id);
+ if (m_moduleInfo.options.d3d9FloatEmulation) {
+ result.id = m_module.opNMax(typeId, result.id,
+ m_module.constfReplicant(-FLT_MAX, result.type.ccount));
+ }
+ break;
+ case DxsoOpcode::Lrp:
+ result.id = m_module.opFMix(typeId,
+ emitRegisterLoad(src[2], mask).id,
+ emitRegisterLoad(src[1], mask).id,
+ emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::Frc:
+ result.id = m_module.opFract(typeId,
+ emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::Cmp: {
+ const uint32_t boolTypeId =
+ getVectorTypeId({ DxsoScalarType::Bool, result.type.ccount });
+
+ uint32_t cmp = m_module.opFOrdGreaterThanEqual(
+ boolTypeId,
+ emitRegisterLoad(src[0], mask).id,
+ m_module.constfReplicant(0.0f, result.type.ccount));
+
+ result.id = m_module.opSelect(
+ typeId, cmp,
+ emitRegisterLoad(src[1], mask).id,
+ emitRegisterLoad(src[2], mask).id);
+ break;
+ }
+ case DxsoOpcode::Cnd: {
+ const uint32_t boolTypeId =
+ getVectorTypeId({ DxsoScalarType::Bool, result.type.ccount });
+
+ uint32_t cmp = m_module.opFOrdGreaterThan(
+ boolTypeId,
+ emitRegisterLoad(src[0], mask).id,
+ m_module.constfReplicant(0.5f, result.type.ccount));
+
+ result.id = m_module.opSelect(
+ typeId, cmp,
+ emitRegisterLoad(src[1], mask).id,
+ emitRegisterLoad(src[2], mask).id);
+ break;
+ }
+ case DxsoOpcode::Dp2Add: {
+ DxsoRegMask dotSrcMask(true, true, false, false);
+ DxsoRegMask addSrcMask(true, false, false, false);
+
+ DxsoRegisterValue dot = emitDot(
+ emitRegisterLoad(src[0], dotSrcMask),
+ emitRegisterLoad(src[1], dotSrcMask));
+
+ dot.id = m_module.opFAdd(scalarTypeId,
+ dot.id, emitRegisterLoad(src[2], addSrcMask).id);
+
+ result.id = dot.id;
+ result.type = scalarType;
+ break;
+ }
+ case DxsoOpcode::DsX:
+ result.id = m_module.opDpdx(
+ typeId, emitRegisterLoad(src[0], mask).id);
+ break;
+ case DxsoOpcode::DsY:
+ result.id = m_module.opDpdy(
+ typeId, emitRegisterLoad(src[0], mask).id);
+ break;
+ default:
+ Logger::warn(str::format("DxsoCompiler::emitVectorAlu: unimplemented op ", opcode));
+ return;
+ }
+
+ this->emitDstStore(dst, result, mask, ctx.dst.saturate, emitPredicateLoad(ctx), ctx.dst.shift, ctx.dst.id);
+ }
+
+
+ void DxsoCompiler::emitPredicateOp(const DxsoInstructionContext& ctx) {
+ const auto& src = ctx.src;
+
+ DxsoRegMask mask = ctx.dst.mask;
+
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ DxsoRegisterValue result;
+ result.type.ctype = dst.type.ctype;
+ result.type.ccount = mask.popCount();
+
+ result.id = emitBoolComparison(
+ result.type, ctx.instruction.specificData.comparison,
+ emitRegisterLoad(src[0], mask).id, emitRegisterLoad(src[1], mask).id);
+
+ this->emitValueStore(dst, result, mask, emitPredicateLoad(ctx));
+ }
+
+
+ void DxsoCompiler::emitMatrixAlu(const DxsoInstructionContext& ctx) {
+ const DxsoOpcode opcode = ctx.instruction.opcode;
+
+ uint32_t dotCount;
+ uint32_t componentCount;
+
+ switch (opcode) {
+ case DxsoOpcode::M3x2:
+ dotCount = 3;
+ componentCount = 2;
+ break;
+ case DxsoOpcode::M3x3:
+ dotCount = 3;
+ componentCount = 3;
+ break;
+ case DxsoOpcode::M3x4:
+ dotCount = 3;
+ componentCount = 4;
+ break;
+ case DxsoOpcode::M4x3:
+ dotCount = 4;
+ componentCount = 3;
+ break;
+ case DxsoOpcode::M4x4:
+ dotCount = 4;
+ componentCount = 4;
+ break;
+ default:
+ Logger::warn(str::format("DxsoCompiler::emitMatrixAlu: unimplemented op ", opcode));
+ return;
+ }
+
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ // Fix the dst mask if componentCount != maskCount
+ // ie. M4x3 on .xyzw.
+ uint32_t maskCnt = 0;
+ uint8_t mask = 0;
+ for (uint32_t i = 0; i < 4 && maskCnt < componentCount; i++) {
+ if (ctx.dst.mask[i]) {
+ mask |= 1 << i;
+ maskCnt++;
+ }
+ }
+ DxsoRegMask dstMask = DxsoRegMask(mask);
+
+ DxsoRegisterValue result;
+ result.type.ctype = dst.type.ctype;
+ result.type.ccount = componentCount;
+
+ DxsoVectorType scalarType;
+ scalarType.ctype = result.type.ctype;
+ scalarType.ccount = 1;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+ const uint32_t scalarTypeId = getVectorTypeId(scalarType);
+
+ DxsoRegMask srcMask(true, true, true, dotCount == 4);
+ std::array<uint32_t, 4> indices;
+
+ DxsoRegister src0 = ctx.src[0];
+ DxsoRegister src1 = ctx.src[1];
+
+ for (uint32_t i = 0; i < componentCount; i++) {
+ indices[i] = m_module.opDot(scalarTypeId,
+ emitRegisterLoad(src0, srcMask).id,
+ emitRegisterLoad(src1, srcMask).id);
+
+ src1.id.num++;
+ }
+
+ result.id = m_module.opCompositeConstruct(
+ typeId, componentCount, indices.data());
+
+ this->emitDstStore(dst, result, dstMask, ctx.dst.saturate, emitPredicateLoad(ctx), ctx.dst.shift, ctx.dst.id);
+ }
+
+
+void DxsoCompiler::emitControlFlowGenericLoop(
+ bool count,
+ uint32_t initialVar,
+ uint32_t strideVar,
+ uint32_t iterationCountVar) {
+ const uint32_t itType = m_module.defIntType(32, 1);
+
+ DxsoCfgBlock block;
+ block.type = DxsoCfgBlockType::Loop;
+ block.b_loop.labelHeader = m_module.allocateId();
+ block.b_loop.labelBegin = m_module.allocateId();
+ block.b_loop.labelContinue = m_module.allocateId();
+ block.b_loop.labelBreak = m_module.allocateId();
+ block.b_loop.iteratorPtr = m_module.newVar(
+ m_module.defPointerType(itType, spv::StorageClassPrivate), spv::StorageClassPrivate);
+ block.b_loop.strideVar = strideVar;
+ block.b_loop.countBackup = 0;
+
+ if (count) {
+ DxsoBaseRegister loop;
+ loop.id = { DxsoRegisterType::Loop, 0 };
+
+ DxsoRegisterPointer loopPtr = emitGetOperandPtr(loop, nullptr);
+ uint32_t loopVal = m_module.opLoad(
+ getVectorTypeId(loopPtr.type), loopPtr.id);
+
+ block.b_loop.countBackup = loopVal;
+
+ m_module.opStore(loopPtr.id, initialVar);
+ }
+
+ m_module.setDebugName(block.b_loop.iteratorPtr, "iter");
+
+ m_module.opStore(block.b_loop.iteratorPtr, iterationCountVar);
+
+ m_module.opBranch(block.b_loop.labelHeader);
+ m_module.opLabel (block.b_loop.labelHeader);
+
+ m_module.opLoopMerge(
+ block.b_loop.labelBreak,
+ block.b_loop.labelContinue,
+ spv::LoopControlMaskNone);
+
+ m_module.opBranch(block.b_loop.labelBegin);
+ m_module.opLabel (block.b_loop.labelBegin);
+
+ uint32_t iterator = m_module.opLoad(itType, block.b_loop.iteratorPtr);
+ uint32_t complete = m_module.opIEqual(m_module.defBoolType(), iterator, m_module.consti32(0));
+
+ const uint32_t breakBlock = m_module.allocateId();
+ const uint32_t mergeBlock = m_module.allocateId();
+
+ m_module.opSelectionMerge(mergeBlock,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ complete, breakBlock, mergeBlock);
+
+ m_module.opLabel(breakBlock);
+
+ m_module.opBranch(block.b_loop.labelBreak);
+
+ m_module.opLabel(mergeBlock);
+
+ iterator = m_module.opISub(itType, iterator, m_module.consti32(1));
+ m_module.opStore(block.b_loop.iteratorPtr, iterator);
+
+ m_controlFlowBlocks.push_back(block);
+ }
+
+ void DxsoCompiler::emitControlFlowGenericLoopEnd() {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxsoCfgBlockType::Loop)
+ throw DxvkError("DxsoCompiler: 'EndRep' without 'Rep' or 'Loop' found");
+
+ // Remove the block from the stack, it's closed
+ const DxsoCfgBlock block = m_controlFlowBlocks.back();
+ m_controlFlowBlocks.pop_back();
+
+ if (block.b_loop.strideVar) {
+ DxsoBaseRegister loop;
+ loop.id = { DxsoRegisterType::Loop, 0 };
+
+ DxsoRegisterPointer loopPtr = emitGetOperandPtr(loop, nullptr);
+ uint32_t val = m_module.opLoad(
+ getVectorTypeId(loopPtr.type), loopPtr.id);
+
+ val = m_module.opIAdd(
+ getVectorTypeId(loopPtr.type),
+ val, block.b_loop.strideVar);
+
+ m_module.opStore(loopPtr.id, val);
+ }
+
+ // Declare the continue block
+ m_module.opBranch(block.b_loop.labelContinue);
+ m_module.opLabel(block.b_loop.labelContinue);
+
+ // Declare the merge block
+ m_module.opBranch(block.b_loop.labelHeader);
+ m_module.opLabel(block.b_loop.labelBreak);
+
+ if (block.b_loop.countBackup) {
+ DxsoBaseRegister loop;
+ loop.id = { DxsoRegisterType::Loop, 0 };
+
+ DxsoRegisterPointer loopPtr = emitGetOperandPtr(loop, nullptr);
+
+ m_module.opStore(loopPtr.id, block.b_loop.countBackup);
+ }
+ }
+
+ void DxsoCompiler::emitControlFlowRep(const DxsoInstructionContext& ctx) {
+ DxsoRegMask srcMask(true, false, false, false);
+ this->emitControlFlowGenericLoop(
+ false, 0, 0,
+ emitRegisterLoad(ctx.src[0], srcMask).id);
+ }
+
+ void DxsoCompiler::emitControlFlowEndRep(const DxsoInstructionContext& ctx) {
+ emitControlFlowGenericLoopEnd();
+ }
+
+ void DxsoCompiler::emitControlFlowLoop(const DxsoInstructionContext& ctx) {
+ const uint32_t itType = m_module.defIntType(32, 1);
+
+ DxsoRegMask srcMask(true, true, true, false);
+ uint32_t integerRegister = emitRegisterLoad(ctx.src[1], srcMask).id;
+ uint32_t x = 0;
+ uint32_t y = 1;
+ uint32_t z = 2;
+
+ uint32_t iterCount = m_module.opCompositeExtract(itType, integerRegister, 1, &x);
+ uint32_t initialValue = m_module.opCompositeExtract(itType, integerRegister, 1, &y);
+ uint32_t strideSize = m_module.opCompositeExtract(itType, integerRegister, 1, &z);
+
+ this->emitControlFlowGenericLoop(
+ true,
+ initialValue,
+ strideSize,
+ iterCount);
+ }
+
+ void DxsoCompiler::emitControlFlowEndLoop(const DxsoInstructionContext& ctx) {
+ this->emitControlFlowGenericLoopEnd();
+ }
+
+ void DxsoCompiler::emitControlFlowBreak(const DxsoInstructionContext& ctx) {
+ DxsoCfgBlock* cfgBlock =
+ cfgFindBlock({ DxsoCfgBlockType::Loop });
+
+ if (cfgBlock == nullptr)
+ throw DxvkError("DxbcCompiler: 'Break' outside 'Rep' or 'Loop' found");
+
+ m_module.opBranch(cfgBlock->b_loop.labelBreak);
+
+ // Subsequent instructions assume that there is an open block
+ const uint32_t labelId = m_module.allocateId();
+ m_module.opLabel(labelId);
+ }
+
+ void DxsoCompiler::emitControlFlowBreakC(const DxsoInstructionContext& ctx) {
+ DxsoCfgBlock* cfgBlock =
+ cfgFindBlock({ DxsoCfgBlockType::Loop });
+
+ if (cfgBlock == nullptr)
+ throw DxvkError("DxbcCompiler: 'BreakC' outside 'Rep' or 'Loop' found");
+
+ DxsoRegMask srcMask(true, false, false, false);
+ auto a = emitRegisterLoad(ctx.src[0], srcMask);
+ auto b = emitRegisterLoad(ctx.src[1], srcMask);
+
+ uint32_t result = this->emitBoolComparison(
+ { DxsoScalarType::Bool, a.type.ccount },
+ ctx.instruction.specificData.comparison,
+ a.id, b.id);
+
+ // We basically have to wrap this into an 'if' block
+ const uint32_t breakBlock = m_module.allocateId();
+ const uint32_t mergeBlock = m_module.allocateId();
+
+ m_module.opSelectionMerge(mergeBlock,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ result, breakBlock, mergeBlock);
+
+ m_module.opLabel(breakBlock);
+
+ m_module.opBranch(cfgBlock->b_loop.labelBreak);
+
+ m_module.opLabel(mergeBlock);
+ }
+
+ void DxsoCompiler::emitControlFlowIf(const DxsoInstructionContext& ctx) {
+ const auto opcode = ctx.instruction.opcode;
+
+ uint32_t result;
+
+ DxsoRegMask srcMask(true, false, false, false);
+ if (opcode == DxsoOpcode::Ifc) {
+ auto a = emitRegisterLoad(ctx.src[0], srcMask);
+ auto b = emitRegisterLoad(ctx.src[1], srcMask);
+
+ result = this->emitBoolComparison(
+ { DxsoScalarType::Bool, a.type.ccount },
+ ctx.instruction.specificData.comparison,
+ a.id, b.id);
+ } else
+ result = emitRegisterLoad(ctx.src[0], srcMask).id;
+
+ // Declare the 'if' block. We do not know if there
+ // will be an 'else' block or not, so we'll assume
+ // that there is one and leave it empty otherwise.
+ DxsoCfgBlock block;
+ block.type = DxsoCfgBlockType::If;
+ block.b_if.ztestId = result;
+ block.b_if.labelIf = m_module.allocateId();
+ block.b_if.labelElse = 0;
+ block.b_if.labelEnd = m_module.allocateId();
+ block.b_if.headerPtr = m_module.getInsertionPtr();
+ m_controlFlowBlocks.push_back(block);
+
+ // We'll insert the branch instruction when closing
+ // the block, since we don't know whether or not an
+ // else block is needed right now.
+ m_module.opLabel(block.b_if.labelIf);
+ }
+
+ void DxsoCompiler::emitControlFlowElse(const DxsoInstructionContext& ctx) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxsoCfgBlockType::If
+ || m_controlFlowBlocks.back().b_if.labelElse != 0)
+ throw DxvkError("DxsoCompiler: 'Else' without 'If' found");
+
+ // Set the 'Else' flag so that we do
+ // not insert a dummy block on 'EndIf'
+ DxsoCfgBlock& block = m_controlFlowBlocks.back();
+ block.b_if.labelElse = m_module.allocateId();
+
+ // Close the 'If' block by branching to
+ // the merge block we declared earlier
+ m_module.opBranch(block.b_if.labelEnd);
+ m_module.opLabel (block.b_if.labelElse);
+ }
+
+ void DxsoCompiler::emitControlFlowEndIf(const DxsoInstructionContext& ctx) {
+ if (m_controlFlowBlocks.size() == 0
+ || m_controlFlowBlocks.back().type != DxsoCfgBlockType::If)
+ throw DxvkError("DxsoCompiler: 'EndIf' without 'If' found");
+
+ // Remove the block from the stack, it's closed
+ DxsoCfgBlock block = m_controlFlowBlocks.back();
+ m_controlFlowBlocks.pop_back();
+
+ // Write out the 'if' header
+ m_module.beginInsertion(block.b_if.headerPtr);
+
+ m_module.opSelectionMerge(
+ block.b_if.labelEnd,
+ spv::SelectionControlMaskNone);
+
+ m_module.opBranchConditional(
+ block.b_if.ztestId,
+ block.b_if.labelIf,
+ block.b_if.labelElse != 0
+ ? block.b_if.labelElse
+ : block.b_if.labelEnd);
+
+ m_module.endInsertion();
+
+ // End the active 'if' or 'else' block
+ m_module.opBranch(block.b_if.labelEnd);
+ m_module.opLabel (block.b_if.labelEnd);
+ }
+
+
+ void DxsoCompiler::emitTexCoord(const DxsoInstructionContext& ctx) {
+ DxsoRegisterValue result;
+
+ if (m_programInfo.majorVersion() == 1 && m_programInfo.minorVersion() == 4) {
+ // TexCrd Op (PS 1.4)
+ result = emitRegisterLoad(ctx.src[0], ctx.dst.mask);
+ } else {
+ // TexCoord Op (PS 1.0 - PS 1.3)
+ DxsoRegister texcoord;
+ texcoord.id.type = DxsoRegisterType::PixelTexcoord;
+ texcoord.id.num = ctx.dst.id.num;
+
+ result = emitRegisterLoadRaw(texcoord, nullptr);
+ // Saturate
+ result = emitSaturate(result);
+ // w = 1.0f
+ uint32_t wIndex = 3;
+ result.id = m_module.opCompositeInsert(getVectorTypeId(result.type),
+ m_module.constf32(1.0f),
+ result.id,
+ 1, &wIndex);
+ }
+
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ this->emitDstStore(dst, result, ctx.dst.mask, ctx.dst.saturate, emitPredicateLoad(ctx), ctx.dst.shift, ctx.dst.id);
+ }
+
+ void DxsoCompiler::emitTextureSample(const DxsoInstructionContext& ctx) {
+ DxsoRegisterPointer dst = emitGetOperandPtr(ctx.dst);
+
+ const DxsoOpcode opcode = ctx.instruction.opcode;
+
+ DxsoRegisterValue texcoordVar;
+ uint32_t samplerIdx;
+
+ DxsoRegMask vec3Mask(true, true, true, false);
+ DxsoRegMask srcMask (true, true, true, true);
+
+ auto GetProjectionValue = [&]() {
+ uint32_t w = 3;
+ return m_module.opCompositeExtract(
+ m_module.defFloatType(32), texcoordVar.id, 1, &w);
+ };
+
+ if (opcode == DxsoOpcode::TexM3x2Tex || opcode == DxsoOpcode::TexM3x3Tex || opcode == DxsoOpcode::TexM3x3Spec || opcode == DxsoOpcode::TexM3x3VSpec) {
+ const uint32_t count = opcode == DxsoOpcode::TexM3x2Tex ? 2 : 3;
+
+ auto n = emitRegisterLoad(ctx.src[0], vec3Mask);
+
+ std::array<uint32_t, 4> indices = { 0, 0, m_module.constf32(0.0f), m_module.constf32(0.0f) };
+ for (uint32_t i = 0; i < count; i++) {
+ auto reg = ctx.dst;
+ reg.id.num -= (count - 1) - i;
+ auto m = emitRegisterLoadTexcoord(reg, vec3Mask);
+
+ indices[i] = m_module.opDot(getScalarTypeId(DxsoScalarType::Float32), m.id, n.id);
+ }
+
+ if (opcode == DxsoOpcode::TexM3x3Spec || opcode == DxsoOpcode::TexM3x3VSpec) {
+ uint32_t vec3Type = getVectorTypeId({ DxsoScalarType::Float32, 3 });
+ uint32_t normal = m_module.opCompositeConstruct(vec3Type, 3, indices.data());
+
+ uint32_t eyeRay;
+ // VSpec -> Create eye ray from .w of last 3 tex coords (m, m-1, m-2)
+ // Spec -> Get eye ray from src[1]
+ if (opcode == DxsoOpcode::TexM3x3VSpec) {
+ DxsoRegMask wMask(false, false, false, true);
+
+ std::array<uint32_t, 3> eyeRayIndices;
+ for (uint32_t i = 0; i < 3; i++) {
+ auto reg = ctx.dst;
+ reg.id.num -= (count - 1) - i;
+ eyeRayIndices[i] = emitRegisterLoadTexcoord(reg, wMask).id;
+ }
+
+ eyeRay = m_module.opCompositeConstruct(vec3Type, eyeRayIndices.size(), eyeRayIndices.data());
+ }
+ else
+ eyeRay = emitRegisterLoad(ctx.src[1], vec3Mask).id;
+
+ eyeRay = m_module.opNormalize(vec3Type, eyeRay);
+ normal = m_module.opNormalize(vec3Type, normal);
+ uint32_t reflection = m_module.opReflect(vec3Type, eyeRay, normal);
+ reflection = m_module.opFNegate(vec3Type, reflection);
+
+ for (uint32_t i = 0; i < 3; i++)
+ indices[i] = m_module.opCompositeExtract(m_module.defFloatType(32), reflection, 1, &i);
+ }
+
+ texcoordVar.type = { DxsoScalarType::Float32, 4 };
+ texcoordVar.id = m_module.opCompositeConstruct(getVectorTypeId(texcoordVar.type), indices.size(), indices.data());
+
+ samplerIdx = ctx.dst.id.num;
+ }
+ else if (opcode == DxsoOpcode::TexBem || opcode == DxsoOpcode::TexBemL) {
+ auto m = emitRegisterLoadTexcoord(ctx.dst, srcMask);
+ auto n = emitRegisterLoad(ctx.src[0], srcMask);
+
+ texcoordVar = m;
+ samplerIdx = ctx.dst.id.num;
+
+ uint32_t texcoord_t = getVectorTypeId(texcoordVar.type);
+
+ // The projection (/.w) happens before this...
+ // Of course it does...
+ uint32_t bool_t = m_module.defBoolType();
+
+ uint32_t shouldProj = m_module.opBitFieldUExtract(
+ m_module.defIntType(32, 0), m_ps.projectionSpec,
+ m_module.consti32(samplerIdx), m_module.consti32(1));
+
+ shouldProj = m_module.opIEqual(bool_t, shouldProj, m_module.constu32(1));
+
+ uint32_t bvec4_t = m_module.defVectorType(bool_t, 4);
+ std::array<uint32_t, 4> indices = { shouldProj, shouldProj, shouldProj, shouldProj };
+ shouldProj = m_module.opCompositeConstruct(bvec4_t, indices.size(), indices.data());
+
+ uint32_t projScalar = m_module.opFDiv(m_module.defFloatType(32), m_module.constf32(1.0), GetProjectionValue());
+ uint32_t projResult = m_module.opVectorTimesScalar(texcoord_t, texcoordVar.id, projScalar);
+
+ texcoordVar.id = m_module.opSelect(texcoord_t, shouldProj, projResult, texcoordVar.id);
+
+ // u' = tc(m).x + [bm00(m) * t(n).x + bm10(m) * t(n).y]
+ // v' = tc(m).y + [bm01(m) * t(n).x + bm11(m) * t(n).y]
+
+ // But we flipped the bm indices so we can use dot here...
+
+ // u' = tc(m).x + dot(bm0, tn)
+ // v' = tc(m).y + dot(bm1, tn)
+
+ for (uint32_t i = 0; i < 2; i++) {
+ uint32_t fl_t = getScalarTypeId(DxsoScalarType::Float32);
+ uint32_t vec2_t = getVectorTypeId({ DxsoScalarType::Float32, 2 });
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ uint32_t tc_m_n = m_module.opCompositeExtract(fl_t, texcoordVar.id, 1, &i);
+
+ uint32_t offset = m_module.constu32(D3D9SharedPSStages_Count * ctx.dst.id.num + D3D9SharedPSStages_BumpEnvMat0 + i);
+ uint32_t bm = m_module.opAccessChain(m_module.defPointerType(vec2_t, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &offset);
+ bm = m_module.opLoad(vec2_t, bm);
+
+ uint32_t t = m_module.opVectorShuffle(vec2_t, n.id, n.id, 2, indices.data());
+
+ uint32_t dot = m_module.opDot(fl_t, bm, t);
+
+ uint32_t result = m_module.opFAdd(fl_t, tc_m_n, dot);
+ texcoordVar.id = m_module.opCompositeInsert(getVectorTypeId(texcoordVar.type), result, texcoordVar.id, 1, &i);
+ }
+ }
+ else if (opcode == DxsoOpcode::TexReg2Ar) {
+ texcoordVar = emitRegisterLoad(ctx.src[0], srcMask);
+ texcoordVar = emitRegisterSwizzle(texcoordVar, DxsoRegSwizzle(3, 0, 0, 0), srcMask);
+
+ samplerIdx = ctx.dst.id.num;
+ }
+ else if (opcode == DxsoOpcode::TexReg2Gb) {
+ texcoordVar = emitRegisterLoad(ctx.src[0], srcMask);
+ texcoordVar = emitRegisterSwizzle(texcoordVar, DxsoRegSwizzle(1, 2, 2, 2), srcMask);
+
+ samplerIdx = ctx.dst.id.num;
+ }
+ else if (opcode == DxsoOpcode::TexReg2Rgb) {
+ texcoordVar = emitRegisterLoad(ctx.src[0], srcMask);
+ texcoordVar = emitRegisterSwizzle(texcoordVar, DxsoRegSwizzle(0, 1, 2, 2), srcMask);
+
+ samplerIdx = ctx.dst.id.num;
+ }
+ else if (opcode == DxsoOpcode::TexDp3Tex) {
+ auto m = emitRegisterLoadTexcoord(ctx.dst, vec3Mask);
+ auto n = emitRegisterLoad(ctx.src[0], vec3Mask);
+
+ auto dot = emitDot(m, n);
+
+ std::array<uint32_t, 4> indices = { dot.id, m_module.constf32(0.0f), m_module.constf32(0.0f), m_module.constf32(0.0f) };
+
+ texcoordVar.type = { DxsoScalarType::Float32, 4 };
+ texcoordVar.id = m_module.opCompositeConstruct(getVectorTypeId(texcoordVar.type),
+ indices.size(), indices.data());
+
+ samplerIdx = ctx.dst.id.num;
+ }
+ else {
+ if (m_programInfo.majorVersion() >= 2) { // SM 2.0+
+ texcoordVar = emitRegisterLoad(ctx.src[0], srcMask);
+ samplerIdx = ctx.src[1].id.num;
+ } else if (
+ m_programInfo.majorVersion() == 1
+ && m_programInfo.minorVersion() == 4) { // SM 1.4
+ texcoordVar = emitRegisterLoad(ctx.src[0], srcMask);
+ samplerIdx = ctx.dst.id.num;
+ }
+ else { // SM 1.0-1.3
+ texcoordVar = emitRegisterLoadTexcoord(ctx.dst, srcMask);
+ samplerIdx = ctx.dst.id.num;
+ }
+ }
+
+ // SM < 1.x does not have dcl sampler type.
+ if (m_programInfo.majorVersion() < 2 && m_samplers[samplerIdx].color[SamplerTypeTexture2D].varId == 0)
+ emitDclSampler(samplerIdx, DxsoTextureType::Texture2D);
+
+ DxsoSampler sampler = m_samplers.at(samplerIdx);
+
+ auto SampleImage = [this, opcode, dst, ctx, samplerIdx, GetProjectionValue](DxsoRegisterValue texcoordVar, DxsoSamplerInfo& sampler, bool depth, DxsoSamplerType samplerType, uint32_t specConst) {
+ DxsoRegisterValue result;
+ result.type.ctype = dst.type.ctype;
+ result.type.ccount = depth ? 1 : 4;
+
+ const uint32_t typeId = getVectorTypeId(result.type);
+
+ SpirvImageOperands imageOperands;
+ if (m_programInfo.type() == DxsoProgramTypes::VertexShader) {
+ imageOperands.sLod = m_module.constf32(0.0f);
+ imageOperands.flags |= spv::ImageOperandsLodMask;
+ }
+
+ if (opcode == DxsoOpcode::TexLdl) {
+ uint32_t w = 3;
+ imageOperands.sLod = m_module.opCompositeExtract(
+ m_module.defFloatType(32), texcoordVar.id, 1, &w);
+ imageOperands.flags |= spv::ImageOperandsLodMask;
+ }
+
+ if (opcode == DxsoOpcode::TexLdd) {
+ DxsoRegMask gradMask(true, true, sampler.dimensions == 3, false);
+ imageOperands.flags |= spv::ImageOperandsGradMask;
+ imageOperands.sGradX = emitRegisterLoad(ctx.src[2], gradMask).id;
+ imageOperands.sGradY = emitRegisterLoad(ctx.src[3], gradMask).id;
+ }
+
+ uint32_t projDivider = 0;
+
+ if (opcode == DxsoOpcode::Tex
+ && m_programInfo.majorVersion() >= 2) {
+ if (ctx.instruction.specificData.texld == DxsoTexLdMode::Project) {
+ projDivider = GetProjectionValue();
+ }
+ else if (ctx.instruction.specificData.texld == DxsoTexLdMode::Bias) {
+ uint32_t w = 3;
+ imageOperands.sLodBias = m_module.opCompositeExtract(
+ m_module.defFloatType(32), texcoordVar.id, 1, &w);
+ imageOperands.flags |= spv::ImageOperandsBiasMask;
+ }
+ }
+
+ bool switchProjResult = m_programInfo.majorVersion() < 2 && samplerType != SamplerTypeTextureCube;
+
+ if (switchProjResult)
+ projDivider = GetProjectionValue();
+
+ // We already handled this...
+ if (opcode == DxsoOpcode::TexBem) {
+ switchProjResult = false;
+ projDivider = 0;
+ }
+
+ uint32_t reference = 0;
+
+ if (depth) {
+ uint32_t component = sampler.dimensions;
+ reference = m_module.opCompositeExtract(
+ m_module.defFloatType(32), texcoordVar.id, 1, &component);
+ }
+
+ if (projDivider != 0) {
+ for (uint32_t i = sampler.dimensions; i < 4; i++) {
+ texcoordVar.id = m_module.opCompositeInsert(getVectorTypeId(texcoordVar.type),
+ projDivider, texcoordVar.id, 1, &i);
+ }
+ }
+
+ uint32_t fetch4 = 0;
+ if (m_programInfo.type() == DxsoProgramType::PixelShader && samplerType != SamplerTypeTexture3D) {
+ fetch4 = m_module.opBitFieldUExtract(
+ m_module.defIntType(32, 0), m_ps.fetch4Spec,
+ m_module.consti32(samplerIdx), m_module.consti32(1));
+
+ uint32_t bool_t = m_module.defBoolType();
+ fetch4 = m_module.opIEqual(bool_t, fetch4, m_module.constu32(1));
+
+ uint32_t bvec4_t = m_module.defVectorType(bool_t, 4);
+ std::array<uint32_t, 4> indices = { fetch4, fetch4, fetch4, fetch4 };
+ fetch4 = m_module.opCompositeConstruct(bvec4_t, indices.size(), indices.data());
+ }
+
+ result.id = this->emitSample(
+ projDivider != 0,
+ typeId,
+ sampler,
+ texcoordVar,
+ reference,
+ fetch4,
+ imageOperands);
+
+ if (switchProjResult) {
+ uint32_t bool_t = m_module.defBoolType();
+
+ uint32_t nonProjResult = this->emitSample(
+ 0,
+ typeId,
+ sampler,
+ texcoordVar,
+ reference,
+ fetch4,
+ imageOperands);
+
+ uint32_t shouldProj = m_module.opBitFieldUExtract(
+ m_module.defIntType(32, 0), m_ps.projectionSpec,
+ m_module.consti32(samplerIdx), m_module.consti32(1));
+
+ shouldProj = m_module.opIEqual(m_module.defBoolType(), shouldProj, m_module.constu32(1));
+
+ // Depth -> .x
+ // Colour -> .xyzw
+ // Need to replicate the bool for the opSelect.
+ if (!depth) {
+ uint32_t bvec4_t = m_module.defVectorType(bool_t, 4);
+ std::array<uint32_t, 4> indices = { shouldProj, shouldProj, shouldProj, shouldProj };
+ shouldProj = m_module.opCompositeConstruct(bvec4_t, indices.size(), indices.data());
+ }
+
+ result.id = m_module.opSelect(typeId, shouldProj, result.id, nonProjResult);
+ }
+
+ // If we are sampling depth we've already specc'ed this!
+ // This path is always size 4 because it only hits on color.
+ if (specConst != 0) {
+ uint32_t bool_t = m_module.defBoolType();
+ uint32_t bvec4_t = m_module.defVectorType(bool_t, 4);
+ std::array<uint32_t, 4> indices = { specConst, specConst, specConst, specConst };
+ specConst = m_module.opCompositeConstruct(bvec4_t, indices.size(), indices.data());
+ result.id = m_module.opSelect(typeId, specConst, result.id, m_module.constvec4f32(0.0f, 0.0f, 0.0f, 1.0f));
+ }
+
+ // Apply operand swizzle to the operand value
+ result = emitRegisterSwizzle(result, IdentitySwizzle, ctx.dst.mask);
+
+ if (opcode == DxsoOpcode::TexBemL) {
+ uint32_t float_t = m_module.defFloatType(32);
+
+ uint32_t index = m_module.constu32(D3D9SharedPSStages_Count * ctx.dst.id.num + D3D9SharedPSStages_BumpEnvLScale);
+ uint32_t lScale = m_module.opAccessChain(m_module.defPointerType(float_t, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &index);
+ lScale = m_module.opLoad(float_t, lScale);
+
+ index = m_module.constu32(D3D9SharedPSStages_Count * ctx.dst.id.num + D3D9SharedPSStages_BumpEnvLOffset);
+ uint32_t lOffset = m_module.opAccessChain(m_module.defPointerType(float_t, spv::StorageClassUniform),
+ m_ps.sharedState, 1, &index);
+ lOffset = m_module.opLoad(float_t, lOffset);
+
+ uint32_t zIndex = 2;
+ uint32_t scale = m_module.opCompositeExtract(float_t, result.id, 1, &zIndex);
+ scale = m_module.opFMul(float_t, scale, lScale);
+ scale = m_module.opFAdd(float_t, scale, lOffset);
+ scale = m_module.opFClamp(float_t, scale, m_module.constf32(0.0f), m_module.constf32(1.0));
+
+ result.id = m_module.opVectorTimesScalar(getVectorTypeId(result.type), result.id, scale);
+ }
+
+ this->emitDstStore(dst, result, ctx.dst.mask, ctx.dst.saturate, emitPredicateLoad(ctx), ctx.dst.shift, ctx.dst.id);
+ };
+
+ auto SampleType = [&](DxsoSamplerType samplerType) {
+ // Only do the check for depth comp. samplers
+ // if we aren't a 3D texture
+ if (samplerType != SamplerTypeTexture3D) {
+ uint32_t colorLabel = m_module.allocateId();
+ uint32_t depthLabel = m_module.allocateId();
+ uint32_t endLabel = m_module.allocateId();
+
+ uint32_t typeId = m_module.defIntType(32, 0);
+ uint32_t offset = m_module.consti32(m_programInfo.type() == DxsoProgramTypes::VertexShader ? samplerIdx + 17 : samplerIdx);
+ uint32_t bitCnt = m_module.consti32(1);
+ uint32_t isDepth = m_module.opBitFieldUExtract(typeId, m_depthSpecConstant, offset, bitCnt);
+ isDepth = m_module.opIEqual(m_module.defBoolType(), isDepth, m_module.constu32(1));
+
+ m_module.opSelectionMerge(endLabel, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(isDepth, depthLabel, colorLabel);
+
+ m_module.opLabel(colorLabel);
+ SampleImage(texcoordVar, sampler.color[samplerType], false, samplerType, sampler.boundConst);
+ m_module.opBranch(endLabel);
+
+ m_module.opLabel(depthLabel);
+ // No spec constant as if we are unbound we always fall down the color path.
+ SampleImage(texcoordVar, sampler.depth[samplerType], true, samplerType, 0);
+ m_module.opBranch(endLabel);
+
+ m_module.opLabel(endLabel);
+ }
+ else
+ SampleImage(texcoordVar, sampler.color[samplerType], false, samplerType, sampler.boundConst);
+ };
+
+ if (m_programInfo.majorVersion() >= 2 && !m_moduleInfo.options.forceSamplerTypeSpecConstants) {
+ DxsoSamplerType samplerType =
+ SamplerTypeFromTextureType(sampler.type);
+
+ SampleType(samplerType);
+ }
+ else {
+ std::array<SpirvSwitchCaseLabel, 3> typeCaseLabels = {{
+ { uint32_t(SamplerTypeTexture2D), m_module.allocateId() },
+ { uint32_t(SamplerTypeTexture3D), m_module.allocateId() },
+ { uint32_t(SamplerTypeTextureCube), m_module.allocateId() },
+ }};
+
+ uint32_t switchEndLabel = m_module.allocateId();
+
+ uint32_t typeId = m_module.defIntType(32, 0);
+
+ uint32_t offset = m_module.consti32(samplerIdx * 2);
+ uint32_t bitCnt = m_module.consti32(2);
+ uint32_t type = m_module.opBitFieldUExtract(typeId, m_ps.samplerTypeSpec, offset, bitCnt);
+
+ m_module.opSelectionMerge(switchEndLabel, spv::SelectionControlMaskNone);
+ m_module.opSwitch(type,
+ typeCaseLabels[uint32_t(SamplerTypeTexture2D)].labelId,
+ typeCaseLabels.size(),
+ typeCaseLabels.data());
+
+ for (const auto& label : typeCaseLabels) {
+ m_module.opLabel(label.labelId);
+
+ SampleType(DxsoSamplerType(label.literal));
+
+ m_module.opBranch(switchEndLabel);
+ }
+
+ m_module.opLabel(switchEndLabel);
+ }
+ }
+
+ void DxsoCompiler::emitTextureKill(const DxsoInstructionContext& ctx) {
+ DxsoRegisterValue texReg;
+
+ if (m_programInfo.majorVersion() >= 2 ||
+ (m_programInfo.majorVersion() == 1
+ && m_programInfo.minorVersion() == 4)) // SM 2.0+ or 1.4
+ texReg = emitRegisterLoadRaw(ctx.dst, ctx.dst.hasRelative ? &ctx.dst.relative : nullptr);
+ else { // SM 1.0-1.3
+ DxsoRegister texcoord;
+ texcoord.id = { DxsoRegisterType::PixelTexcoord, ctx.dst.id.num };
+
+ texReg = emitRegisterLoadRaw(texcoord, nullptr);
+ }
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ // On SM1 it only works on the first
+ if (m_programInfo.majorVersion() < 2) {
+ texReg.type.ccount = 3;
+
+ texReg.id = m_module.opVectorShuffle(
+ getVectorTypeId(texReg.type),
+ texReg.id, texReg.id,
+ texReg.type.ccount, indices.data());
+ }
+ else {
+ // The writemask actually applies and works here...
+ // (FXC doesn't generate this but it fixes broken ENB shaders)
+ texReg = emitRegisterSwizzle(texReg, IdentitySwizzle, ctx.dst.mask);
+ }
+
+ const uint32_t boolVecTypeId =
+ getVectorTypeId({ DxsoScalarType::Bool, texReg.type.ccount });
+
+ uint32_t result = m_module.opFOrdLessThan(
+ boolVecTypeId, texReg.id,
+ m_module.constfReplicant(0.0f, texReg.type.ccount));
+
+ if (texReg.type.ccount != 1)
+ result = m_module.opAny(m_module.defBoolType(), result);
+
+ if (m_ps.killState == 0) {
+ uint32_t labelIf = m_module.allocateId();
+ uint32_t labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(result, labelIf, labelEnd);
+
+ m_module.opLabel(labelIf);
+
+ if (m_moduleInfo.options.useDemoteToHelperInvocation) {
+ m_module.opDemoteToHelperInvocation();
+ m_module.opBranch(labelEnd);
+ } else {
+ // OpKill terminates the block
+ m_module.opKill();
+ }
+
+ m_module.opLabel(labelEnd);
+ }
+ else {
+ uint32_t typeId = m_module.defBoolType();
+
+ uint32_t killState = m_module.opLoad (typeId, m_ps.killState);
+ killState = m_module.opLogicalOr(typeId, killState, result);
+ m_module.opStore(m_ps.killState, killState);
+
+ if (m_moduleInfo.options.useSubgroupOpsForEarlyDiscard) {
+ uint32_t ballot = m_module.opGroupNonUniformBallot(
+ getVectorTypeId({ DxsoScalarType::Uint32, 4 }),
+ m_module.constu32(spv::ScopeSubgroup),
+ killState);
+
+ uint32_t laneId = m_module.opLoad(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ m_ps.builtinLaneId);
+
+ uint32_t laneIdPart = m_module.opShiftRightLogical(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ laneId, m_module.constu32(5));
+
+ uint32_t laneMask = m_module.opVectorExtractDynamic(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ ballot, laneIdPart);
+
+ uint32_t laneIdQuad = m_module.opBitwiseAnd(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ laneId, m_module.constu32(0x1c));
+
+ laneMask = m_module.opShiftRightLogical(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ laneMask, laneIdQuad);
+
+ laneMask = m_module.opBitwiseAnd(
+ getScalarTypeId(DxsoScalarType::Uint32),
+ laneMask, m_module.constu32(0xf));
+
+ uint32_t killSubgroup = m_module.opIEqual(
+ m_module.defBoolType(),
+ laneMask, m_module.constu32(0xf));
+
+ uint32_t labelIf = m_module.allocateId();
+ uint32_t labelEnd = m_module.allocateId();
+
+ m_module.opSelectionMerge(labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(killSubgroup, labelIf, labelEnd);
+
+ // OpKill terminates the block
+ m_module.opLabel(labelIf);
+ m_module.opKill();
+
+ m_module.opLabel(labelEnd);
+ }
+ }
+ }
+
+ void DxsoCompiler::emitTextureDepth(const DxsoInstructionContext& ctx) {
+ const uint32_t fType = m_module.defFloatType(32);
+
+ DxsoRegMask srcMask(true, true, false, false);
+ uint32_t r5 = emitRegisterLoad(ctx.src[0], srcMask).id;
+ uint32_t x = 0;
+ uint32_t y = 1;
+
+ uint32_t xValue = m_module.opCompositeExtract(fType, r5, 1, &x);
+ uint32_t yValue = m_module.opCompositeExtract(fType, r5, 1, &y);
+
+ // The docs say if yValue is 0 the result is 1.0 but native drivers return
+ // 0 for xValue <= 0. So we don't have to do anything special since -INF and
+ // NAN get clamped to 0 at the end of the shader.
+ uint32_t result = m_module.opFDiv(fType, xValue, yValue);
+
+ DxsoBaseRegister depth;
+ depth.id = { DxsoRegisterType::DepthOut, 0 };
+
+ DxsoRegisterPointer depthPtr = emitGetOperandPtr(depth, nullptr);
+
+ m_module.opStore(depthPtr.id, result);
+ }
+
+
+ uint32_t DxsoCompiler::emitSample(
+ bool projected,
+ uint32_t resultType,
+ DxsoSamplerInfo& samplerInfo,
+ DxsoRegisterValue coordinates,
+ uint32_t reference,
+ uint32_t fetch4,
+ const SpirvImageOperands& operands) {
+ const bool depthCompare = reference != 0;
+ const bool explicitLod =
+ (operands.flags & spv::ImageOperandsLodMask)
+ || (operands.flags & spv::ImageOperandsGradMask);
+
+ const uint32_t sampledImage = m_module.opLoad(samplerInfo.typeId, samplerInfo.varId);
+
+ uint32_t val;
+
+ // No Fetch 4
+ if (projected) {
+ if (depthCompare) {
+ if (explicitLod)
+ val = m_module.opImageSampleProjDrefExplicitLod(resultType, sampledImage, coordinates.id, reference, operands);
+ else
+ val = m_module.opImageSampleProjDrefImplicitLod(resultType, sampledImage, coordinates.id, reference, operands);
+ }
+ else {
+ if (explicitLod)
+ val = m_module.opImageSampleProjExplicitLod(resultType, sampledImage, coordinates.id, operands);
+ else
+ val = m_module.opImageSampleProjImplicitLod(resultType, sampledImage, coordinates.id, operands);
+ }
+ }
+ else {
+ if (depthCompare) {
+ if (explicitLod)
+ val = m_module.opImageSampleDrefExplicitLod(resultType, sampledImage, coordinates.id, reference, operands);
+ else
+ val = m_module.opImageSampleDrefImplicitLod(resultType, sampledImage, coordinates.id, reference, operands);
+ }
+ else {
+ if (explicitLod)
+ val = m_module.opImageSampleExplicitLod(resultType, sampledImage, coordinates.id, operands);
+ else
+ val = m_module.opImageSampleImplicitLod(resultType, sampledImage, coordinates.id, operands);
+ }
+ }
+
+
+ if (fetch4 && !depthCompare) {
+ SpirvImageOperands fetch4Operands = operands;
+ fetch4Operands.flags &= ~spv::ImageOperandsLodMask;
+ fetch4Operands.flags &= ~spv::ImageOperandsGradMask;
+ fetch4Operands.flags &= ~spv::ImageOperandsBiasMask;
+
+ // Doesn't really work for cubes...
+ // D3D9 does support gather on 3D but we cannot :<
+ // Nothing probably relies on that though.
+ // If we come back to this ever, make sure to handle cube/3d differences.
+ if (samplerInfo.dimensions == 2) {
+ uint32_t image = m_module.opImage(samplerInfo.imageTypeId, sampledImage);
+
+ // Account for half texel offset...
+ // textureSize = 1.0f / float(2 * textureSize(sampler, 0))
+ DxsoRegisterValue textureSize;
+ textureSize.type = { DxsoScalarType::Sint32, samplerInfo.dimensions };
+ textureSize.id = m_module.opImageQuerySizeLod(getVectorTypeId(textureSize.type), image, m_module.consti32(0));
+ textureSize.id = m_module.opIMul(getVectorTypeId(textureSize.type), textureSize.id, m_module.constiReplicant(2, samplerInfo.dimensions));
+
+ textureSize.type = { DxsoScalarType::Float32, samplerInfo.dimensions };
+ textureSize.id = m_module.opConvertStoF(getVectorTypeId(textureSize.type), textureSize.id);
+ // HACK: Bias fetch4 half-texel offset to avoid a "grid" effect.
+ // Technically we should only do that for non-powers of two
+ // as only then does the imprecision need to be biased
+ // towards infinity -- but that's not really worth doing...
+ float numerator = 1.0f - 1.0f / 256.0f;
+ textureSize.id = m_module.opFDiv(getVectorTypeId(textureSize.type), m_module.constfReplicant(numerator, samplerInfo.dimensions), textureSize.id);
+
+ // coord => same dimensions as texture size (no cube here !)
+ const std::array<uint32_t, 4> naturalIndices = { 0, 1, 2, 3 };
+ coordinates.type.ccount = samplerInfo.dimensions;
+ coordinates.id = m_module.opVectorShuffle(getVectorTypeId(coordinates.type), coordinates.id, coordinates.id, coordinates.type.ccount, naturalIndices.data());
+ // coord += textureSize;
+ coordinates.id = m_module.opFAdd(getVectorTypeId(coordinates.type), coordinates.id, textureSize.id);
+ }
+
+ uint32_t fetch4Val = m_module.opImageGather(resultType, sampledImage, coordinates.id, m_module.consti32(0), fetch4Operands);
+ // B R G A swizzle... Funny D3D9 order.
+ const std::array<uint32_t, 4> indices = { 2, 0, 1, 3 };
+ fetch4Val = m_module.opVectorShuffle(resultType, fetch4Val, fetch4Val, indices.size(), indices.data());
+
+ val = m_module.opSelect(resultType, fetch4, fetch4Val, val);
+ }
+
+ return val;
+ }
+
+
+ void DxsoCompiler::emitInputSetup() {
+ uint32_t pointCoord = 0;
+ D3D9PointSizeInfoPS pointInfo;
+
+ if (m_programInfo.type() == DxsoProgramType::PixelShader) {
+ pointCoord = GetPointCoord(m_module, m_entryPointInterfaces);
+ pointInfo = GetPointSizeInfoPS(m_module, m_rsBlock);
+ }
+
+ for (uint32_t i = 0; i < m_isgn.elemCount; i++) {
+ const auto& elem = m_isgn.elems[i];
+ const uint32_t slot = elem.slot;
+
+ DxsoRegisterInfo info;
+ info.type.ctype = DxsoScalarType::Float32;
+ info.type.ccount = 4;
+ info.type.alength = 1;
+ info.sclass = spv::StorageClassInput;
+
+ DxsoRegisterPointer inputPtr;
+ inputPtr.id = emitNewVariable(info);
+ inputPtr.type.ctype = DxsoScalarType::Float32;
+ inputPtr.type.ccount = info.type.ccount;
+
+ m_module.decorateLocation(inputPtr.id, slot);
+
+ std::string name =
+ str::format("in_", elem.semantic.usage, elem.semantic.usageIndex);
+ m_module.setDebugName(inputPtr.id, name.c_str());
+
+ if (elem.centroid)
+ m_module.decorate(inputPtr.id, spv::DecorationCentroid);
+
+ m_entryPointInterfaces.push_back(inputPtr.id);
+
+ uint32_t typeId = this->getVectorTypeId({ DxsoScalarType::Float32, 4 });
+ uint32_t ptrTypeId = m_module.defPointerType(typeId, spv::StorageClassPrivate);
+
+ uint32_t regNumVar = m_module.constu32(elem.regNumber);
+
+ DxsoRegisterPointer indexPtr;
+ indexPtr.id = m_module.opAccessChain(ptrTypeId, m_vArray, 1, &regNumVar);
+ indexPtr.type = inputPtr.type;
+ indexPtr.type.ccount = 4;
+
+ DxsoRegisterValue indexVal = this->emitValueLoad(inputPtr);
+
+ DxsoRegisterValue workingReg;
+ workingReg.type = indexVal.type;
+
+ workingReg.id = m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+
+ DxsoRegMask mask = elem.mask;
+ if (mask.popCount() == 0)
+ mask = DxsoRegMask(true, true, true, true);
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < 4; i++) {
+ if (mask[i]) {
+ indices[i] = i + 4;
+ count++;
+ }
+ }
+
+ workingReg.id = m_module.opVectorShuffle(getVectorTypeId(workingReg.type),
+ workingReg.id, indexVal.id, 4, indices.data());
+
+ // We need to replace TEXCOORD inputs with gl_PointCoord
+ // if D3DRS_POINTSPRITEENABLE is set.
+ if (m_programInfo.type() == DxsoProgramType::PixelShader && elem.semantic.usage == DxsoUsage::Texcoord)
+ workingReg.id = m_module.opSelect(getVectorTypeId(workingReg.type), pointInfo.isSprite, pointCoord, workingReg.id);
+
+ if (m_programInfo.type() == DxsoProgramType::PixelShader && elem.semantic.usage == DxsoUsage::Color) {
+ if (elem.semantic.usageIndex == 0)
+ m_ps.diffuseColorIn = inputPtr.id;
+ else if (elem.semantic.usageIndex == 1)
+ m_ps.specularColorIn = inputPtr.id;
+ }
+
+ m_module.opStore(indexPtr.id, workingReg.id);
+ }
+ }
+
+
+ void DxsoCompiler::emitLinkerOutputSetup() {
+ bool outputtedColor0 = false;
+ bool outputtedColor1 = false;
+
+ for (uint32_t i = 0; i < m_osgn.elemCount; i++) {
+ const auto& elem = m_osgn.elems[i];
+ const uint32_t slot = elem.slot;
+
+ if (elem.semantic.usage == DxsoUsage::Color) {
+ if (elem.semantic.usageIndex == 0)
+ outputtedColor0 = true;
+ else
+ outputtedColor1 = true;
+ }
+
+ DxsoRegisterInfo info;
+ info.type.ctype = DxsoScalarType::Float32;
+ info.type.ccount = 4;
+ info.type.alength = 1;
+ info.sclass = spv::StorageClassOutput;
+
+ spv::BuiltIn builtIn =
+ semanticToBuiltIn(false, elem.semantic);
+
+ DxsoRegisterPointer outputPtr;
+ outputPtr.type.ctype = DxsoScalarType::Float32;
+ outputPtr.type.ccount = 4;
+
+ DxsoRegMask mask = elem.mask;
+
+ bool scalar = false;
+
+ if (builtIn == spv::BuiltInMax) {
+ outputPtr.id = emitNewVariableDefault(info,
+ m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f));
+ m_module.decorateLocation(outputPtr.id, slot);
+
+ std::string name =
+ str::format("out_", elem.semantic.usage, elem.semantic.usageIndex);
+ m_module.setDebugName(outputPtr.id, name.c_str());
+ }
+ else {
+ const char* name = "unknown_builtin";
+ if (builtIn == spv::BuiltInPosition)
+ name = "oPos";
+ else if (builtIn == spv::BuiltInPointSize) {
+ outputPtr.type.ccount = 1;
+ info.type.ccount = 1;
+ name = "oPSize";
+ bool maskValues[4];
+ for (uint32_t i = 0; i < 4; i++)
+ maskValues[i] = i == elem.mask.firstSet();
+ mask = DxsoRegMask(maskValues[0], maskValues[1], maskValues[2], maskValues[3]);
+ }
+
+ outputPtr.id = emitNewVariableDefault(info,
+ m_module.constfReplicant(0.0f, info.type.ccount));
+
+ m_module.setDebugName(outputPtr.id, name);
+ m_module.decorateBuiltIn(outputPtr.id, builtIn);
+
+ if (builtIn == spv::BuiltInPosition)
+ m_vs.oPos = outputPtr;
+ else if (builtIn == spv::BuiltInPointSize) {
+ scalar = true;
+ m_vs.oPSize = outputPtr;
+ }
+ }
+
+ m_entryPointInterfaces.push_back(outputPtr.id);
+
+ uint32_t typeId = this->getVectorTypeId({ DxsoScalarType::Float32, 4 });
+ uint32_t ptrTypeId = m_module.defPointerType(typeId, spv::StorageClassPrivate);
+
+ uint32_t regNumVar = m_module.constu32(elem.regNumber);
+
+ DxsoRegisterPointer indexPtr;
+ indexPtr.id = m_module.opAccessChain(ptrTypeId, m_oArray, 1, &regNumVar);
+ indexPtr.type = outputPtr.type;
+ indexPtr.type.ccount = 4;
+
+ DxsoRegisterValue indexVal = this->emitValueLoad(indexPtr);
+
+ DxsoRegisterValue workingReg;
+ workingReg.type.ctype = indexVal.type.ctype;
+ workingReg.type.ccount = scalar ? 1 : 4;
+
+ workingReg.id = scalar
+ ? m_module.constf32(0.0f)
+ : m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+
+ std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
+
+ if (scalar) {
+ workingReg.id = m_module.opCompositeExtract(getVectorTypeId(workingReg.type),
+ indexVal.id, 1, indices.data());
+ } else {
+ if (mask.popCount() == 0)
+ mask = DxsoRegMask(true, true, true, true);
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < 4; i++) {
+ if (mask[i])
+ indices[count++] = i + 4;
+ }
+
+
+ workingReg.id = m_module.opVectorShuffle(getVectorTypeId(workingReg.type),
+ workingReg.id, indexVal.id, 4, indices.data());
+ }
+
+ // Ie. 0 or 1 for diffuse and specular color
+ // and for Shader Model 1 or 2
+ // (because those have dedicated color registers
+ // where this rule applies)
+ if (elem.semantic.usage == DxsoUsage::Color &&
+ elem.semantic.usageIndex < 2 &&
+ m_programInfo.majorVersion() < 3)
+ workingReg = emitSaturate(workingReg);
+
+ m_module.opStore(outputPtr.id, workingReg.id);
+ }
+
+ auto OutputDefault = [&](DxsoSemantic semantic) {
+ DxsoRegisterInfo info;
+ info.type.ctype = DxsoScalarType::Float32;
+ info.type.ccount = 4;
+ info.type.alength = 1;
+ info.sclass = spv::StorageClassOutput;
+
+ uint32_t slot = RegisterLinkerSlot(semantic);
+
+ uint32_t value = semantic == DxsoSemantic{ DxsoUsage::Color, 0 }
+ ? m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f)
+ : m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f);
+
+
+ uint32_t outputPtr = emitNewVariableDefault(info, value);
+
+ m_module.decorateLocation(outputPtr, slot);
+
+ std::string name =
+ str::format("out_", semantic.usage, semantic.usageIndex, "_default");
+
+ m_module.setDebugName(outputPtr, name.c_str());
+
+ m_interfaceSlots.outputSlots |= 1u << slot;
+ m_entryPointInterfaces.push_back(outputPtr);
+ };
+
+ if (!outputtedColor0)
+ OutputDefault(DxsoSemantic{ DxsoUsage::Color, 0 });
+
+ if (!outputtedColor1)
+ OutputDefault(DxsoSemantic{ DxsoUsage::Color, 1 });
+
+ auto pointInfo = GetPointSizeInfoVS(m_module, m_vs.oPos.id, 0, 0, m_rsBlock, false);
+
+ if (m_vs.oPSize.id == 0) {
+ m_vs.oPSize = this->emitRegisterPtr(
+ "oPSize", DxsoScalarType::Float32, 1, 0,
+ spv::StorageClassOutput, spv::BuiltInPointSize);
+
+ uint32_t pointSize = m_module.opFClamp(m_module.defFloatType(32), pointInfo.defaultValue, pointInfo.min, pointInfo.max);
+
+ m_module.opStore(m_vs.oPSize.id, pointSize);
+ }
+ else {
+ uint32_t float_t = m_module.defFloatType(32);
+ uint32_t pointSize = m_module.opFClamp(m_module.defFloatType(32), m_module.opLoad(float_t, m_vs.oPSize.id), pointInfo.min, pointInfo.max);
+ m_module.opStore(m_vs.oPSize.id, pointSize);
+ }
+ }
+
+
+ void DxsoCompiler::emitVsClipping() {
+ uint32_t clipPlaneCountId = m_module.constu32(caps::MaxClipPlanes);
+
+ uint32_t floatType = m_module.defFloatType(32);
+ uint32_t vec4Type = m_module.defVectorType(floatType, 4);
+
+ // Declare uniform buffer containing clip planes
+ uint32_t clipPlaneArray = m_module.defArrayTypeUnique(vec4Type, clipPlaneCountId);
+ uint32_t clipPlaneStruct = m_module.defStructTypeUnique(1, &clipPlaneArray);
+ uint32_t clipPlaneBlock = m_module.newVar(
+ m_module.defPointerType(clipPlaneStruct, spv::StorageClassUniform),
+ spv::StorageClassUniform);
+
+ m_module.decorateArrayStride (clipPlaneArray, 16);
+
+ m_module.setDebugName (clipPlaneStruct, "clip_info_t");
+ m_module.setDebugMemberName (clipPlaneStruct, 0, "clip_planes");
+ m_module.decorate (clipPlaneStruct, spv::DecorationBlock);
+ m_module.memberDecorateOffset (clipPlaneStruct, 0, 0);
+
+ uint32_t bindingId = computeResourceSlotId(
+ m_programInfo.type(), DxsoBindingType::ConstantBuffer,
+ DxsoConstantBuffers::VSClipPlanes);
+
+ m_module.setDebugName (clipPlaneBlock, "clip_info");
+ m_module.decorateDescriptorSet(clipPlaneBlock, 0);
+ m_module.decorateBinding (clipPlaneBlock, bindingId);
+
+ DxvkResourceSlot resource;
+ resource.slot = bindingId;
+ resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
+ resource.access = VK_ACCESS_UNIFORM_READ_BIT;
+ m_resourceSlots.push_back(resource);
+
+ // Declare output array for clip distances
+ uint32_t clipDistArray = m_module.newVar(
+ m_module.defPointerType(
+ m_module.defArrayType(floatType, clipPlaneCountId),
+ spv::StorageClassOutput),
+ spv::StorageClassOutput);
+
+ m_module.decorateBuiltIn(clipDistArray, spv::BuiltInClipDistance);
+ m_entryPointInterfaces.push_back(clipDistArray);
+
+ if (m_moduleInfo.options.invariantPosition)
+ m_module.decorate(m_vs.oPos.id, spv::DecorationInvariant);
+
+ const uint32_t positionPtr = m_vs.oPos.id;
+
+ // We generated a bad shader, let's not make it even worse.
+ if (positionPtr == 0) {
+ Logger::warn("Shader without Position output. Something is likely wrong here.");
+ return;
+ }
+
+ // Compute clip distances
+ uint32_t positionId = m_module.opLoad(vec4Type, positionPtr);
+
+ for (uint32_t i = 0; i < caps::MaxClipPlanes; i++) {
+ std::array<uint32_t, 2> blockMembers = {{
+ m_module.constu32(0),
+ m_module.constu32(i),
+ }};
+
+ uint32_t planeId = m_module.opLoad(vec4Type,
+ m_module.opAccessChain(
+ m_module.defPointerType(vec4Type, spv::StorageClassUniform),
+ clipPlaneBlock, blockMembers.size(), blockMembers.data()));
+
+ uint32_t distId = m_module.opDot(floatType, positionId, planeId);
+
+ m_module.opStore(
+ m_module.opAccessChain(
+ m_module.defPointerType(floatType, spv::StorageClassOutput),
+ clipDistArray, 1, &blockMembers[1]),
+ distId);
+ }
+ }
+
+
+ void DxsoCompiler::setupRenderStateInfo() {
+ uint32_t count;
+
+ // Only need alpha ref for PS 3.
+ // No FF fog component.
+ if (m_programInfo.type() == DxsoProgramType::PixelShader) {
+ if (m_programInfo.majorVersion() == 3) {
+ m_interfaceSlots.pushConstOffset = offsetof(D3D9RenderStateInfo, alphaRef);
+ m_interfaceSlots.pushConstSize = sizeof(float);
+ }
+ else {
+ m_interfaceSlots.pushConstOffset = 0;
+ m_interfaceSlots.pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
+ }
+
+ count = 5;
+ }
+ else {
+ m_interfaceSlots.pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
+ // Point scale never triggers on programmable
+ m_interfaceSlots.pushConstSize = sizeof(float) * 3;
+ count = 8;
+ }
+
+ m_rsBlock = SetupRenderStateBlock(m_module, count);
+ }
+
+
+ void DxsoCompiler::emitFog() {
+ DxsoRegister color0;
+ color0.id = DxsoRegisterId{ DxsoRegisterType::ColorOut, 0 };
+ auto oColor0Ptr = this->emitGetOperandPtr(color0);
+
+ DxsoRegister vFog;
+ vFog.id = DxsoRegisterId{ DxsoRegisterType::RasterizerOut, RasterOutFog };
+ auto vFogPtr = this->emitGetOperandPtr(vFog);
+
+ DxsoRegister vPos;
+ vPos.id = DxsoRegisterId{ DxsoRegisterType::MiscType, DxsoMiscTypeIndices::MiscTypePosition };
+ auto vPosPtr = this->emitGetOperandPtr(vPos);
+
+ D3D9FogContext fogCtx;
+ fogCtx.IsPixel = true;
+ fogCtx.RangeFog = false;
+ fogCtx.RenderState = m_rsBlock;
+ fogCtx.vPos = m_module.opLoad(getVectorTypeId(vPosPtr.type), vPosPtr.id);
+ fogCtx.vFog = m_module.opLoad(getVectorTypeId(vFogPtr.type), vFogPtr.id);
+ fogCtx.oColor = m_module.opLoad(getVectorTypeId(oColor0Ptr.type), oColor0Ptr.id);
+ fogCtx.IsFixedFunction = false;
+ fogCtx.IsPositionT = false;
+ fogCtx.HasSpecular = false;
+ fogCtx.Specular = 0;
+
+ m_module.opStore(oColor0Ptr.id, DoFixedFunctionFog(m_module, fogCtx));
+ }
+
+
+ void DxsoCompiler::emitPsProcessing() {
+ uint32_t boolType = m_module.defBoolType();
+ uint32_t floatType = m_module.defFloatType(32);
+ uint32_t floatPtr = m_module.defPointerType(floatType, spv::StorageClassPushConstant);
+
+ uint32_t alphaFuncId = m_module.specConst32(m_module.defIntType(32, 0), 0);
+ m_module.setDebugName (alphaFuncId, "alpha_func");
+ m_module.decorateSpecId (alphaFuncId, getSpecId(D3D9SpecConstantId::AlphaCompareOp));
+
+ // Implement alpha test and fog
+ DxsoRegister color0;
+ color0.id = DxsoRegisterId{ DxsoRegisterType::ColorOut, 0 };
+ auto oC0 = this->emitGetOperandPtr(color0);
+
+ if (oC0.id) {
+ if (m_programInfo.majorVersion() < 3)
+ emitFog();
+
+ // Labels for the alpha test
+ std::array<SpirvSwitchCaseLabel, 8> atestCaseLabels = {{
+ { uint32_t(VK_COMPARE_OP_NEVER), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_LESS), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_LESS_OR_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_GREATER), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_NOT_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_GREATER_OR_EQUAL), m_module.allocateId() },
+ { uint32_t(VK_COMPARE_OP_ALWAYS), m_module.allocateId() },
+ }};
+
+ uint32_t atestBeginLabel = m_module.allocateId();
+ uint32_t atestTestLabel = m_module.allocateId();
+ uint32_t atestDiscardLabel = m_module.allocateId();
+ uint32_t atestKeepLabel = m_module.allocateId();
+ uint32_t atestSkipLabel = m_module.allocateId();
+
+ // if (alpha_func != ALWAYS) { ... }
+ uint32_t isNotAlways = m_module.opINotEqual(boolType, alphaFuncId, m_module.constu32(VK_COMPARE_OP_ALWAYS));
+ m_module.opSelectionMerge(atestSkipLabel, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(isNotAlways, atestBeginLabel, atestSkipLabel);
+ m_module.opLabel(atestBeginLabel);
+
+ // Load alpha component
+ uint32_t alphaComponentId = 3;
+ uint32_t alphaId = m_module.opCompositeExtract(floatType,
+ m_module.opLoad(m_module.defVectorType(floatType, 4), oC0.id),
+ 1, &alphaComponentId);
+
+ if (m_moduleInfo.options.alphaTestWiggleRoom) {
+ // NV has wonky interpolation of all 1's in a VS -> PS going to 0.999999...
+ // This causes garbage-looking graphics on people's clothing in EverQuest 2 as it does alpha == 1.0.
+
+ // My testing shows the alpha test has a precision of 1/256 for all A8 and below formats,
+ // and around 1 / 2048 for A32F formats and 1 / 4096 for A16F formats (It makes no sense to me too)
+ // so anyway, we're just going to round this to a precision of 1 / 4096 and hopefully this should make things happy
+ // everywhere.
+ const uint32_t alphaSizeId = m_module.constf32(4096.0f);
+
+ alphaId = m_module.opFMul(floatType, alphaId, alphaSizeId);
+ alphaId = m_module.opRound(floatType, alphaId);
+ alphaId = m_module.opFDiv(floatType, alphaId, alphaSizeId);
+ }
+
+ // Load alpha reference
+ uint32_t alphaRefMember = m_module.constu32(uint32_t(D3D9RenderStateItem::AlphaRef));
+ uint32_t alphaRefId = m_module.opLoad(floatType,
+ m_module.opAccessChain(floatPtr, m_rsBlock, 1, &alphaRefMember));
+
+ // switch (alpha_func) { ... }
+ m_module.opSelectionMerge(atestTestLabel, spv::SelectionControlMaskNone);
+ m_module.opSwitch(alphaFuncId,
+ atestCaseLabels[uint32_t(VK_COMPARE_OP_ALWAYS)].labelId,
+ atestCaseLabels.size(),
+ atestCaseLabels.data());
+
+ std::array<SpirvPhiLabel, 8> atestVariables;
+
+ for (uint32_t i = 0; i < atestCaseLabels.size(); i++) {
+ m_module.opLabel(atestCaseLabels[i].labelId);
+
+ atestVariables[i].labelId = atestCaseLabels[i].labelId;
+ atestVariables[i].varId = [&] {
+ switch (VkCompareOp(atestCaseLabels[i].literal)) {
+ case VK_COMPARE_OP_NEVER: return m_module.constBool(false);
+ case VK_COMPARE_OP_LESS: return m_module.opFOrdLessThan (boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_EQUAL: return m_module.opFOrdEqual (boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_LESS_OR_EQUAL: return m_module.opFOrdLessThanEqual (boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_GREATER: return m_module.opFOrdGreaterThan (boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_NOT_EQUAL: return m_module.opFOrdNotEqual (boolType, alphaId, alphaRefId);
+ case VK_COMPARE_OP_GREATER_OR_EQUAL: return m_module.opFOrdGreaterThanEqual(boolType, alphaId, alphaRefId);
+ default:
+ case VK_COMPARE_OP_ALWAYS: return m_module.constBool(true);
+ }
+ }();
+
+ m_module.opBranch(atestTestLabel);
+ }
+
+ // end switch
+ m_module.opLabel(atestTestLabel);
+
+ uint32_t atestResult = m_module.opPhi(boolType,
+ atestVariables.size(),
+ atestVariables.data());
+ uint32_t atestDiscard = m_module.opLogicalNot(boolType, atestResult);
+
+ // if (do_discard) { ... }
+ m_module.opSelectionMerge(atestKeepLabel, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(atestDiscard, atestDiscardLabel, atestKeepLabel);
+
+ m_module.opLabel(atestDiscardLabel);
+ m_module.opKill();
+
+ // end if (do_discard)
+ m_module.opLabel(atestKeepLabel);
+ m_module.opBranch(atestSkipLabel);
+
+ // end if (alpha_test)
+ m_module.opLabel(atestSkipLabel);
+ }
+ }
+
+ void DxsoCompiler::emitOutputDepthClamp() {
+ // HACK: Some drivers do not clamp FragDepth to [minDepth..maxDepth]
+ // before writing to the depth attachment, but we do not have acccess
+ // to those. Clamp to [0..1] instead.
+
+ if (m_ps.oDepth.id != 0) {
+ auto result = emitValueLoad(m_ps.oDepth);
+
+ result = emitSaturate(result);
+
+ m_module.opStore(
+ m_ps.oDepth.id,
+ result.id);
+ }
+}
+
+
+ void DxsoCompiler::emitVsFinalize() {
+ this->emitMainFunctionBegin();
+
+ this->emitInputSetup();
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_vs.functionId, 0, nullptr);
+ this->emitLinkerOutputSetup();
+
+ this->emitVsClipping();
+
+ this->emitFunctionEnd();
+ }
+
+ void DxsoCompiler::emitPsFinalize() {
+ this->emitMainFunctionBegin();
+
+ this->emitInputSetup();
+
+ bool canUsePixelFog = m_programInfo.majorVersion() < 3;
+
+ if (canUsePixelFog) {
+ // Look up vPos so it gets initted.
+ DxsoRegister vPos;
+ vPos.id = DxsoRegisterId{ DxsoRegisterType::MiscType, DxsoMiscTypeIndices::MiscTypePosition };
+ this->emitGetOperandPtr(vPos);
+ }
+
+ if (m_ps.vPos.id != 0) {
+ DxsoRegisterPointer fragCoord = this->emitRegisterPtr(
+ "ps_frag_coord", DxsoScalarType::Float32, 4, 0,
+ spv::StorageClassInput, spv::BuiltInFragCoord);
+
+ DxsoRegisterValue val = this->emitValueLoad(fragCoord);
+ val.id = m_module.opFSub(
+ getVectorTypeId(val.type), val.id,
+ m_module.constvec4f32(0.5f, 0.5f, 0.0f, 0.0f));
+
+ m_module.opStore(m_ps.vPos.id, val.id);
+ }
+
+ if (m_ps.vFace.id != 0) {
+ DxsoRegisterPointer faceBool = this->emitRegisterPtr(
+ "ps_is_front_face", DxsoScalarType::Bool, 1, 0,
+ spv::StorageClassInput, spv::BuiltInFrontFacing);
+
+ DxsoRegisterValue frontFace = emitValueLoad(faceBool);
+ DxsoRegisterValue selectOp = emitRegisterExtend(frontFace, 4);
+
+ m_module.opStore(
+ m_ps.vFace.id,
+ m_module.opSelect(getVectorTypeId(m_ps.vFace.type), selectOp.id,
+ m_module.constvec4f32( 1.0f, 1.0f, 1.0f, 1.0f),
+ m_module.constvec4f32(-1.0f, -1.0f, -1.0f, -1.0f)));
+ }
+
+ m_module.opFunctionCall(
+ m_module.defVoidType(),
+ m_ps.functionId, 0, nullptr);
+
+ if (m_ps.killState != 0) {
+ uint32_t labelIf = m_module.allocateId();
+ uint32_t labelEnd = m_module.allocateId();
+
+ uint32_t killTest = m_module.opLoad(m_module.defBoolType(), m_ps.killState);
+
+ m_module.opSelectionMerge(labelEnd, spv::SelectionControlMaskNone);
+ m_module.opBranchConditional(killTest, labelIf, labelEnd);
+
+ m_module.opLabel(labelIf);
+ m_module.opKill();
+
+ m_module.opLabel(labelEnd);
+ }
+
+ // r0 in PS1 is the colour output register. Move r0 -> cO0 here.
+ if (m_programInfo.majorVersion() == 1
+ && m_programInfo.type() == DxsoProgramTypes::PixelShader) {
+ DxsoRegister r0;
+ r0.id = { DxsoRegisterType::Temp, 0 };
+
+ DxsoRegister c0;
+ c0.id = { DxsoRegisterType::ColorOut, 0 };
+
+ DxsoRegisterValue val = emitRegisterLoadRaw(r0, nullptr);
+ DxsoRegisterPointer out = emitGetOperandPtr(c0);
+ m_module.opStore(out.id, val.id);
+ }
+
+ // No need to setup output here as it's non-indexable
+ // everything has already gone to the right place!
+
+ this->emitPsProcessing();
+ this->emitOutputDepthClamp();
+ this->emitFunctionEnd();
+ }
+
+
+
+ uint32_t DxsoCompiler::getScalarTypeId(DxsoScalarType type) {
+ switch (type) {
+ case DxsoScalarType::Uint32: return m_module.defIntType(32, 0);
+ case DxsoScalarType::Sint32: return m_module.defIntType(32, 1);
+ case DxsoScalarType::Float32: return m_module.defFloatType(32);
+ case DxsoScalarType::Bool: return m_module.defBoolType();
+ }
+
+ throw DxvkError("DxsoCompiler: Invalid scalar type");
+ }
+
+
+ uint32_t DxsoCompiler::getVectorTypeId(const DxsoVectorType& type) {
+ uint32_t typeId = this->getScalarTypeId(type.ctype);
+
+ if (type.ccount > 1)
+ typeId = m_module.defVectorType(typeId, type.ccount);
+
+ return typeId;
+ }
+
+
+ uint32_t DxsoCompiler::getArrayTypeId(const DxsoArrayType& type) {
+ DxsoVectorType vtype;
+ vtype.ctype = type.ctype;
+ vtype.ccount = type.ccount;
+
+ uint32_t typeId = this->getVectorTypeId(vtype);
+
+ if (type.alength > 1) {
+ typeId = m_module.defArrayType(typeId,
+ m_module.constu32(type.alength));
+ }
+
+ return typeId;
+ }
+
+
+ uint32_t DxsoCompiler::getPointerTypeId(const DxsoRegisterInfo& type) {
+ return m_module.defPointerType(
+ this->getArrayTypeId(type.type),
+ type.sclass);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.h
new file mode 100644
index 00000000..a8257102
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_compiler.h
@@ -0,0 +1,683 @@
+#pragma once
+
+#include "dxso_decoder.h"
+#include "dxso_header.h"
+#include "dxso_modinfo.h"
+#include "dxso_isgn.h"
+
+#include "../d3d9/d3d9_constant_layout.h"
+#include "../d3d9/d3d9_shader_permutations.h"
+#include "../spirv/spirv_module.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Scalar value type
+ *
+ * Enumerates possible register component
+ * types. Scalar types are represented as
+ * a one-component vector type.
+ */
+ enum class DxsoScalarType : uint32_t {
+ Uint32 = 0,
+ Sint32 = 1,
+ Float32 = 2,
+ Bool = 3,
+ };
+
+ /**
+ * \brief Vector type
+ *
+ * Convenience struct that stores a scalar
+ * type and a component count. The compiler
+ * can use this to generate SPIR-V types.
+ */
+ struct DxsoVectorType {
+ DxsoScalarType ctype;
+ uint32_t ccount;
+ };
+
+
+ /**
+ * \brief Array type
+ *
+ * Convenience struct that stores a scalar type, a
+ * component count and an array size. An array of
+ * length 0 will be evaluated to a vector type. The
+ * compiler can use this to generate SPIR-V types.
+ */
+ struct DxsoArrayType {
+ DxsoScalarType ctype;
+ uint32_t ccount;
+ uint32_t alength;
+ };
+
+
+ /**
+ * \brief Register info
+ *
+ * Stores the array type of a register and
+ * its storage class. The compiler can use
+ * this to generate SPIR-V pointer types.
+ */
+ struct DxsoRegisterInfo {
+ DxsoArrayType type;
+ spv::StorageClass sclass;
+ };
+
+
+ /**
+ * \brief Register value
+ *
+ * Stores a vector type and a SPIR-V ID that
+ * represents an intermediate value. This is
+ * used to track the type of such values.
+ */
+ struct DxsoRegisterValue {
+ DxsoVectorType type;
+ uint32_t id;
+ };
+
+
+ /**
+ * \brief Register pointer
+ *
+ * Stores a vector type and a SPIR-V ID that
+ * represents a pointer to such a vector. This
+ * can be used to load registers conveniently.
+ */
+ struct DxsoRegisterPointer {
+ DxsoVectorType type;
+ uint32_t id = 0;
+ };
+
+ /**
+ * \brief Sampler info
+ *
+ * Stores a vector type and a SPIR-V ID that
+ * represents a pointer to such a vector. This
+ * can be used to load registers conveniently.
+ */
+ struct DxsoSamplerInfo {
+ uint32_t dimensions = 0;
+
+ uint32_t varId = 0;
+ uint32_t typeId = 0;
+
+ uint32_t imageTypeId = 0;
+ };
+
+ enum DxsoSamplerType : uint32_t {
+ SamplerTypeTexture2D = 0,
+ SamplerTypeTexture3D = 1,
+ SamplerTypeTextureCube,
+
+ SamplerTypeCount
+ };
+
+ inline auto SamplerTypeFromTextureType(DxsoTextureType type) {
+ switch (type) {
+ default:
+ case DxsoTextureType::Texture2D: return SamplerTypeTexture2D; break;
+ case DxsoTextureType::Texture3D: return SamplerTypeTexture3D; break;
+ case DxsoTextureType::TextureCube: return SamplerTypeTextureCube; break;
+ }
+ }
+
+ struct DxsoSampler {
+ DxsoSamplerInfo color[SamplerTypeCount];
+ DxsoSamplerInfo depth[SamplerTypeCount];
+
+ uint32_t boundConst;
+
+ DxsoTextureType type;
+ };
+
+ struct DxsoAnalysisInfo;
+
+ /**
+ * \brief Vertex shader-specific structure
+ */
+ struct DxsoCompilerVsPart {
+ uint32_t functionId = 0;
+
+ ////////////////////
+ // Address register
+ DxsoRegisterPointer addr;
+
+ //////////////////////////////
+ // Rasterizer output registers
+ DxsoRegisterPointer oPos;
+ DxsoRegisterPointer oPSize;
+ };
+
+ /**
+ * \brief Pixel shader-specific structure
+ */
+ struct DxsoCompilerPsPart {
+ uint32_t functionId = 0;
+ uint32_t samplerTypeSpec = 0;
+ uint32_t projectionSpec = 0;
+ uint32_t fetch4Spec = 0;
+
+ //////////////
+ // Misc Types
+ DxsoRegisterPointer vPos;
+ DxsoRegisterPointer vFace;
+
+ ///////////////////
+ // Colour Outputs
+ std::array<DxsoRegisterPointer, 4> oColor;
+
+ ////////////////
+ // Depth output
+ DxsoRegisterPointer oDepth;
+
+ ////////////////
+ // Shared State
+ uint32_t sharedState = 0;
+
+ uint32_t killState = 0;
+ uint32_t builtinLaneId = 0;
+
+ uint32_t diffuseColorIn = 0;
+ uint32_t specularColorIn = 0;
+ };
+
+ struct DxsoCfgBlockIf {
+ uint32_t ztestId;
+ uint32_t labelIf;
+ uint32_t labelElse;
+ uint32_t labelEnd;
+ size_t headerPtr;
+ };
+
+ struct DxsoCfgBlockLoop {
+ uint32_t labelHeader;
+ uint32_t labelBegin;
+ uint32_t labelContinue;
+ uint32_t labelBreak;
+ uint32_t iteratorPtr;
+
+ uint32_t strideVar;
+ uint32_t countBackup;
+ };
+
+ enum class DxsoCfgBlockType : uint32_t {
+ If, Loop
+ };
+
+ struct DxsoCfgBlock {
+ DxsoCfgBlockType type;
+
+ union {
+ DxsoCfgBlockIf b_if;
+ DxsoCfgBlockLoop b_loop;
+ };
+ };
+
+ using DxsoSrcArray = std::array<DxsoRegisterValue, DxsoMaxOperandCount>;
+
+ class DxsoCompiler {
+
+ public:
+
+ DxsoCompiler(
+ const std::string& fileName,
+ const DxsoModuleInfo& moduleInfo,
+ const DxsoProgramInfo& programInfo,
+ const DxsoAnalysisInfo& analysis,
+ const D3D9ConstantLayout& layout);
+
+ /**
+ * \brief Processes a single instruction
+ * \param [in] ins The instruction
+ */
+ void processInstruction(
+ const DxsoInstructionContext& ctx,
+ uint32_t currentCoissueIdx = 0);
+
+ /**
+ * \brief Finalizes the shader
+ */
+ void finalize();
+
+ /**
+ * \brief Compiles the shader
+ * \returns The final shader objects
+ */
+ DxsoPermutations compile();
+
+ const DxsoIsgn& isgn() { return m_isgn; }
+ const DxsoIsgn& osgn() { return m_osgn; }
+
+ const DxsoShaderMetaInfo& meta() { return m_meta; }
+ const DxsoDefinedConstants& constants() { return m_constants; }
+ uint32_t usedSamplers() const { return m_usedSamplers; }
+ uint32_t usedRTs() const { return m_usedRTs; }
+
+ private:
+
+ DxsoModuleInfo m_moduleInfo;
+ DxsoProgramInfo m_programInfo;
+ const DxsoAnalysisInfo* m_analysis;
+ const D3D9ConstantLayout* m_layout;
+
+ DxsoShaderMetaInfo m_meta;
+ DxsoDefinedConstants m_constants;
+
+ SpirvModule m_module;
+
+ uint32_t m_boolSpecConstant;
+ uint32_t m_depthSpecConstant;
+
+ ///////////////////////////////////////////////////////
+ // Resource slot description for the shader. This will
+ // be used to map D3D9 bindings to DXVK bindings.
+ std::vector<DxvkResourceSlot> m_resourceSlots;
+
+ ////////////////////////////////////////////////
+ // Temporary r# vector registers with immediate
+ // indexing, and x# vector array registers.
+ std::array<
+ DxsoRegisterPointer,
+ DxsoMaxTempRegs> m_rRegs;
+
+ ////////////////////////////////////////////////
+ // Predicate registers
+ std::array<
+ DxsoRegisterPointer,
+ 1> m_pRegs;
+
+ //////////////////////////////////////////////////////////////////
+ // Array of input values. Since v# and o# registers are indexable
+ // in DXSO, we need to copy them into an array first.
+ uint32_t m_vArray = 0;
+ uint32_t m_oArray = 0;
+
+ ////////////////////////////////
+ // Input and output signatures
+ DxsoIsgn m_isgn;
+ DxsoIsgn m_osgn;
+
+ ////////////////////////////////////
+ // Ptr to the constant buffer array
+ uint32_t m_cBuffer;
+
+ ////////////////////////////////////////
+ // Constant buffer deffed mappings
+ std::array<uint32_t, caps::MaxFloatConstantsSoftware> m_cFloat;
+ std::array<uint32_t, caps::MaxOtherConstantsSoftware> m_cInt;
+ std::array<uint32_t, caps::MaxOtherConstantsSoftware> m_cBool;
+
+ //////////////////////
+ // Loop counter
+ DxsoRegisterPointer m_loopCounter;
+
+ ///////////////////////////////////
+ // Working tex/coord registers (PS)
+ std::array<
+ DxsoRegisterPointer,
+ DxsoMaxTextureRegs> m_tRegs;
+
+ ///////////////////////////////////////////////
+ // Control flow information. Stores labels for
+ // currently active if-else blocks and loops.
+ std::vector<DxsoCfgBlock> m_controlFlowBlocks;
+
+ //////////////////////////////////////////////
+ // Function state tracking. Required in order
+ // to properly end functions in some cases.
+ bool m_insideFunction = false;
+
+ ////////////
+ // Samplers
+ std::array<DxsoSampler, 17> m_samplers;
+
+ ////////////////////////////////////////////
+ // What io regswe need to
+ // NOT generate semantics for
+ uint16_t m_explicitInputs = 0;
+ uint16_t m_explicitOutputs = 0;
+
+ ///////////////////////////////////////////////////
+ // Entry point description - we'll need to declare
+ // the function ID and all input/output variables.
+ std::vector<uint32_t> m_entryPointInterfaces;
+ uint32_t m_entryPointId = 0;
+
+ ////////////////////////////////////////////
+ // Inter-stage shader interface slots. Also
+ // covers vertex input and fragment output.
+ DxvkInterfaceSlots m_interfaceSlots;
+
+ ///////////////////////////////////
+ // Shader-specific data structures
+ DxsoCompilerVsPart m_vs;
+ DxsoCompilerPsPart m_ps;
+
+ DxsoRegisterPointer m_fog;
+
+ //////////////////////////////////////////
+ // Bit masks containing used samplers
+ // and render targets for hazard tracking
+ uint32_t m_usedSamplers;
+ uint32_t m_usedRTs;
+
+ uint32_t m_rsBlock = 0;
+ uint32_t m_mainFuncLabel = 0;
+
+ //////////////////////////////////////
+ // Common function definition methods
+ void emitInit();
+
+ //////////////////////
+ // Common shader dcls
+ void emitDclConstantBuffer();
+
+ void emitDclInputArray();
+ void emitDclOutputArray();
+
+ /////////////////////////////////
+ // Shader initialization methods
+ void emitVsInit();
+
+ void emitPsSharedConstants();
+ void emitPsInit();
+
+ void emitFunctionBegin(
+ uint32_t entryPoint,
+ uint32_t returnType,
+ uint32_t funcType);
+
+ void emitFunctionEnd();
+
+ uint32_t emitFunctionLabel();
+
+ void emitMainFunctionBegin();
+
+ ///////////////////////////////
+ // Variable definition methods
+ uint32_t emitNewVariable(
+ const DxsoRegisterInfo& info);
+
+ uint32_t emitNewVariableDefault(
+ const DxsoRegisterInfo& info,
+ uint32_t value);
+
+ uint32_t emitNewBuiltinVariable(
+ const DxsoRegisterInfo& info,
+ spv::BuiltIn builtIn,
+ const char* name,
+ uint32_t value);
+
+ DxsoCfgBlock* cfgFindBlock(
+ const std::initializer_list<DxsoCfgBlockType>& types);
+
+ void emitDclInterface(
+ bool input,
+ uint32_t regNumber,
+ DxsoSemantic semantic,
+ DxsoRegMask mask,
+ bool centroid);
+
+ void emitDclSampler(
+ uint32_t idx,
+ DxsoTextureType type);
+
+ bool defineInput(uint32_t idx) {
+ bool alreadyDefined = m_interfaceSlots.inputSlots & 1u << idx;
+ m_interfaceSlots.inputSlots |= 1u << idx;
+ return alreadyDefined;
+ }
+
+ bool defineOutput(uint32_t idx) {
+ bool alreadyDefined = m_interfaceSlots.outputSlots & 1u << idx;
+ m_interfaceSlots.outputSlots |= 1u << idx;
+ return alreadyDefined;
+ }
+
+ uint32_t emitArrayIndex(
+ uint32_t idx,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterPointer emitInputPtr(
+ bool texture,
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterPointer emitRegisterPtr(
+ const char* name,
+ DxsoScalarType ctype,
+ uint32_t ccount,
+ uint32_t defaultVal,
+ spv::StorageClass storageClass = spv::StorageClassPrivate,
+ spv::BuiltIn builtIn = spv::BuiltInMax);
+
+ DxsoRegisterValue emitLoadConstant(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterPointer emitOutputPtr(
+ bool texcrdOut,
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterPointer emitGetOperandPtr(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterPointer emitGetOperandPtr(
+ const DxsoRegister& reg) {
+ return this->emitGetOperandPtr(
+ reg,
+ reg.hasRelative ? &reg.relative : nullptr);
+ }
+
+ uint32_t emitBoolComparison(DxsoVectorType type, DxsoComparison cmp, uint32_t a, uint32_t b);
+
+ DxsoRegisterValue emitValueLoad(
+ DxsoRegisterPointer ptr);
+
+ void emitDstStore(
+ DxsoRegisterPointer ptr,
+ DxsoRegisterValue value,
+ DxsoRegMask writeMask,
+ bool saturate,
+ DxsoRegisterValue predicate,
+ int8_t shift,
+ DxsoRegisterId regId) {
+ if (regId.type == DxsoRegisterType::RasterizerOut && regId.num == RasterOutFog)
+ saturate = true;
+
+ if (value.type.ctype == DxsoScalarType::Float32) {
+ const uint32_t typeId = getVectorTypeId(value.type);
+
+ // There doesn't seem to be a nice float bitshift method for float vectors
+ // in Spirv that I can see... Resorting to multiplication.
+ if (shift != 0) {
+ float shiftAmount = shift < 0
+ ? 1.0f / (1 << -shift)
+ : float(1 << shift);
+
+ uint32_t shiftConst = m_module.constf32(shiftAmount);
+
+ if (value.type.ccount == 1)
+ value.id = m_module.opFMul(typeId, value.id, shiftConst);
+ else
+ value.id = m_module.opVectorTimesScalar(typeId, value.id, shiftConst);
+ }
+
+ // Saturating only makes sense on floats
+ if (saturate) {
+ value.id = m_module.opNClamp(
+ typeId, value.id,
+ m_module.constfReplicant(0.0f, value.type.ccount),
+ m_module.constfReplicant(1.0f, value.type.ccount));
+ }
+ }
+
+ this->emitValueStore(ptr, value, writeMask, predicate);
+ }
+
+ DxsoRegisterValue applyPredicate(DxsoRegisterValue pred, DxsoRegisterValue dst, DxsoRegisterValue src);
+
+ void emitValueStore(
+ DxsoRegisterPointer ptr,
+ DxsoRegisterValue value,
+ DxsoRegMask writeMask,
+ DxsoRegisterValue predicate);
+
+ DxsoRegisterValue emitClampBoundReplicant(
+ DxsoRegisterValue srcValue,
+ float lb,
+ float ub);
+
+ DxsoRegisterValue emitSaturate(
+ DxsoRegisterValue srcValue);
+
+ DxsoRegisterValue emitDot(
+ DxsoRegisterValue a,
+ DxsoRegisterValue b);
+
+ DxsoRegisterValue emitRegisterInsert(
+ DxsoRegisterValue dstValue,
+ DxsoRegisterValue srcValue,
+ DxsoRegMask srcMask);
+
+ DxsoRegisterValue emitRegisterLoadRaw(
+ const DxsoBaseRegister& reg,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterValue emitRegisterExtend(
+ DxsoRegisterValue value,
+ uint32_t size);
+
+ DxsoRegisterValue emitSrcOperandPreSwizzleModifiers(
+ DxsoRegisterValue value,
+ DxsoRegModifier modifier);
+
+ DxsoRegisterValue emitSrcOperandPostSwizzleModifiers(
+ DxsoRegisterValue value,
+ DxsoRegModifier modifier);
+
+ DxsoRegisterValue emitRegisterSwizzle(
+ DxsoRegisterValue value,
+ DxsoRegSwizzle swizzle,
+ DxsoRegMask writeMask);
+
+ DxsoRegisterValue emitRegisterLoad(
+ const DxsoBaseRegister& reg,
+ DxsoRegMask writeMask,
+ const DxsoBaseRegister* relative);
+
+ DxsoRegisterValue emitRegisterLoad(
+ const DxsoRegister& reg,
+ DxsoRegMask writeMask) {
+ return this->emitRegisterLoad(
+ reg, writeMask,
+ reg.hasRelative ? &reg.relative : nullptr);
+ }
+
+ DxsoRegisterValue emitPredicateLoad(const DxsoInstructionContext& ctx) {
+ if (!ctx.instruction.predicated)
+ return DxsoRegisterValue();
+
+ return emitRegisterLoad(ctx.pred, IdentityWriteMask);
+ }
+
+ DxsoRegisterValue emitRegisterLoadTexcoord(
+ const DxsoRegister& reg,
+ DxsoRegMask writeMask) {
+ DxsoRegister lookup = reg;
+ if (reg.id.type == DxsoRegisterType::Texture)
+ lookup.id.type = DxsoRegisterType::PixelTexcoord;
+
+ return this->emitRegisterLoad(lookup, writeMask);
+ }
+
+ Rc<DxvkShader> compileShader();
+
+ ///////////////////////////////
+ // Handle shader ops
+ void emitDcl(const DxsoInstructionContext& ctx);
+
+ void emitDef(const DxsoInstructionContext& ctx);
+ void emitDefF(const DxsoInstructionContext& ctx);
+ void emitDefI(const DxsoInstructionContext& ctx);
+ void emitDefB(const DxsoInstructionContext& ctx);
+
+ bool isScalarRegister(DxsoRegisterId id);
+
+ void emitMov(const DxsoInstructionContext& ctx);
+ void emitPredicateOp(const DxsoInstructionContext& ctx);
+ void emitVectorAlu(const DxsoInstructionContext& ctx);
+ void emitMatrixAlu(const DxsoInstructionContext& ctx);
+
+ void emitControlFlowGenericLoop(
+ bool count,
+ uint32_t initialVar,
+ uint32_t strideVar,
+ uint32_t iterationCountVar);
+
+ void emitControlFlowGenericLoopEnd();
+
+ void emitControlFlowRep(const DxsoInstructionContext& ctx);
+ void emitControlFlowEndRep(const DxsoInstructionContext& ctx);
+
+ void emitControlFlowLoop(const DxsoInstructionContext& ctx);
+ void emitControlFlowEndLoop(const DxsoInstructionContext& ctx);
+
+ void emitControlFlowBreak(const DxsoInstructionContext& ctx);
+ void emitControlFlowBreakC(const DxsoInstructionContext& ctx);
+
+ void emitControlFlowIf(const DxsoInstructionContext& ctx);
+ void emitControlFlowElse(const DxsoInstructionContext& ctx);
+ void emitControlFlowEndIf(const DxsoInstructionContext& ctx);
+
+ void emitTexCoord(const DxsoInstructionContext& ctx);
+ void emitTextureSample(const DxsoInstructionContext& ctx);
+ void emitTextureKill(const DxsoInstructionContext& ctx);
+ void emitTextureDepth(const DxsoInstructionContext& ctx);
+
+ uint32_t emitSample(
+ bool projected,
+ uint32_t resultType,
+ DxsoSamplerInfo& samplerInfo,
+ DxsoRegisterValue coordinates,
+ uint32_t reference,
+ uint32_t fetch4,
+ const SpirvImageOperands& operands);
+
+ ///////////////////////////////
+ // Shader finalization methods
+ void emitInputSetup();
+
+ void emitVsClipping();
+ void setupRenderStateInfo();
+ void emitFog();
+ void emitPsProcessing();
+ void emitOutputDepthClamp();
+
+ void emitLinkerOutputSetup();
+
+ void emitVsFinalize();
+ void emitPsFinalize();
+
+ ///////////////////////////
+ // Type definition methods
+ uint32_t getScalarTypeId(
+ DxsoScalarType type);
+
+ uint32_t getVectorTypeId(
+ const DxsoVectorType& type);
+
+ uint32_t getArrayTypeId(
+ const DxsoArrayType& type);
+
+ uint32_t getPointerTypeId(
+ const DxsoRegisterInfo& type);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.cpp
new file mode 100644
index 00000000..880c7ead
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.cpp
@@ -0,0 +1,19 @@
+#include "dxso_ctab.h"
+
+namespace dxvk {
+
+ DxsoCtab::DxsoCtab(DxsoReader& reader, uint32_t commentTokenCount) {
+ m_size = reader.readu32();
+
+ if (m_size != sizeof(DxsoCtab))
+ throw DxvkError("DxsoCtab: ctab size invalid");
+
+ m_creator = reader.readu32();
+ m_version = reader.readu32();
+ m_constants = reader.readu32();
+ m_constantInfo = reader.readu32();
+ m_flags = reader.readu32();
+ m_target = reader.readu32();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.h
new file mode 100644
index 00000000..56f4f945
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_ctab.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "dxso_common.h"
+
+#include "dxso_reader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXSO CTAB
+ *
+ * Stores meta information about the shader
+ */
+ class DxsoCtab : public RcObject {
+
+ public:
+
+ DxsoCtab(DxsoReader& reader, uint32_t commentTokenCount);
+
+ private:
+
+ uint32_t m_size;
+ uint32_t m_creator;
+ uint32_t m_version;
+ uint32_t m_constants;
+ uint32_t m_constantInfo;
+ uint32_t m_flags;
+ uint32_t m_target;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.cpp
new file mode 100644
index 00000000..42d8d64b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.cpp
@@ -0,0 +1,280 @@
+#include "dxso_decoder.h"
+
+#include "dxso_tables.h"
+
+namespace dxvk {
+
+ bool DxsoSemantic::operator== (const DxsoSemantic& b) const {
+ return usage == b.usage && usageIndex == b.usageIndex;
+ }
+
+ bool DxsoSemantic::operator!= (const DxsoSemantic& b) const {
+ return usage != b.usage || usageIndex != b.usageIndex;
+ }
+
+ uint32_t DxsoDecodeContext::decodeInstructionLength(uint32_t token) {
+ auto opcode = m_ctx.instruction.opcode;
+
+ uint32_t length = 0;
+ const auto& info = this->getProgramInfo();
+
+ // Comment ops have their own system for getting length.
+ if (opcode == DxsoOpcode::Comment)
+ return (token & 0x7fff0000) >> 16;
+
+ if (opcode == DxsoOpcode::End)
+ return 0;
+
+ // SM2.0 and above has the length of the op in instruction count baked into it.
+ // SM1.4 and below have fixed lengths and run off expectation.
+ // Phase does not respect the following rules. :shrug:
+ if (opcode != DxsoOpcode::Phase) {
+ if (info.majorVersion() >= 2)
+ length = (token & 0x0f000000) >> 24;
+ else
+ length = DxsoGetDefaultOpcodeLength(opcode);
+ }
+
+ // We've already logged this...
+ if (length == InvalidOpcodeLength)
+ return 0;
+
+ // SM 1.4 has an extra param on Tex and TexCoord
+ // As stated before, it also doesn't have the length of the op baked into the opcode
+ if (info.majorVersion() == 1
+ && info.minorVersion() == 4) {
+ switch (opcode) {
+ case DxsoOpcode::TexCoord:
+ case DxsoOpcode::Tex: length += 1;
+ default: break;
+ }
+ }
+
+ return length;
+ }
+
+ bool DxsoDecodeContext::relativeAddressingUsesToken(
+ DxsoInstructionArgumentType type) {
+ auto& info = this->getProgramInfo();
+
+ return (info.majorVersion() >= 2 && type == DxsoInstructionArgumentType::Source)
+ || (info.majorVersion() >= 3 && type == DxsoInstructionArgumentType::Destination);
+ }
+
+ void DxsoDecodeContext::decodeDeclaration(DxsoCodeIter& iter) {
+ uint32_t dclToken = iter.read();
+
+ m_ctx.dcl.textureType = static_cast<DxsoTextureType>((dclToken & 0x78000000) >> 27);
+ m_ctx.dcl.semantic.usage = static_cast<DxsoUsage>(dclToken & 0x0000000f);
+ m_ctx.dcl.semantic.usageIndex = (dclToken & 0x000f0000) >> 16;
+ }
+
+ void DxsoDecodeContext::decodeDefinition(DxsoOpcode opcode, DxsoCodeIter& iter) {
+ const uint32_t instructionLength = std::min(m_ctx.instruction.tokenLength - 1, 4u);
+
+ for (uint32_t i = 0; i < instructionLength; i++)
+ m_ctx.def.uint32[i] = iter.read();
+ }
+
+ void DxsoDecodeContext::decodeBaseRegister(
+ DxsoBaseRegister& reg,
+ uint32_t token) {
+ reg.id.type = static_cast<DxsoRegisterType>(
+ ((token & 0x00001800) >> 8)
+ | ((token & 0x70000000) >> 28));
+
+ reg.id.num = token & 0x000007ff;
+ }
+
+ void DxsoDecodeContext::decodeGenericRegister(
+ DxsoRegister& reg,
+ uint32_t token) {
+ this->decodeBaseRegister(reg, token);
+
+ reg.hasRelative = (token & (1 << 13)) == 8192;
+ reg.relative.id = DxsoRegisterId {
+ DxsoRegisterType::Addr, 0 };
+ reg.relative.swizzle = IdentitySwizzle;
+
+ reg.centroid = token & (4 << 20);
+ reg.partialPrecision = token & (2 << 20);
+ }
+
+ void DxsoDecodeContext::decodeRelativeRegister(
+ DxsoBaseRegister& reg,
+ uint32_t token) {
+ this->decodeBaseRegister(reg, token);
+
+ reg.swizzle = DxsoRegSwizzle(
+ uint8_t((token & 0x00ff0000) >> 16));
+ }
+
+ bool DxsoDecodeContext::decodeDestinationRegister(DxsoCodeIter& iter) {
+ uint32_t token = iter.read();
+
+ this->decodeGenericRegister(m_ctx.dst, token);
+
+ m_ctx.dst.mask = DxsoRegMask(
+ uint8_t((token & 0x000f0000) >> 16));
+
+ m_ctx.dst.saturate = (token & (1 << 20)) != 0;
+
+ m_ctx.dst.shift = (token & 0x0f000000) >> 24;
+ m_ctx.dst.shift = (m_ctx.dst.shift & 0x7) - (m_ctx.dst.shift & 0x8);
+
+ const bool extraToken =
+ relativeAddressingUsesToken(DxsoInstructionArgumentType::Destination);
+
+ if (m_ctx.dst.hasRelative && extraToken) {
+ this->decodeRelativeRegister(m_ctx.dst.relative, iter.read());
+ return true;
+ }
+
+ return false;
+ }
+
+ bool DxsoDecodeContext::decodeSourceRegister(uint32_t i, DxsoCodeIter& iter) {
+ if (i >= m_ctx.src.size())
+ throw DxvkError("DxsoDecodeContext::decodeSourceRegister: source register out of range.");
+
+ uint32_t token = iter.read();
+
+ this->decodeGenericRegister(m_ctx.src[i], token);
+
+ m_ctx.src[i].swizzle = DxsoRegSwizzle(
+ uint8_t((token & 0x00ff0000) >> 16));
+
+ m_ctx.src[i].modifier = static_cast<DxsoRegModifier>(
+ (token & 0x0f000000) >> 24);
+
+ const bool extraToken =
+ relativeAddressingUsesToken(DxsoInstructionArgumentType::Source);
+
+ if (m_ctx.src[i].hasRelative && extraToken) {
+ this->decodeRelativeRegister(m_ctx.src[i].relative, iter.read());
+ return true;
+ }
+
+ return false;
+ }
+
+
+ void DxsoDecodeContext::decodePredicateRegister(DxsoCodeIter& iter) {
+ uint32_t token = iter.read();
+
+ this->decodeGenericRegister(m_ctx.pred, token);
+
+ m_ctx.pred.swizzle = DxsoRegSwizzle(
+ uint8_t((token & 0x00ff0000) >> 16));
+
+ m_ctx.pred.modifier = static_cast<DxsoRegModifier>(
+ (token & 0x0f000000) >> 24);
+ }
+
+
+ bool DxsoDecodeContext::decodeInstruction(DxsoCodeIter& iter) {
+ uint32_t token = iter.read();
+
+ m_ctx.instructionIdx++;
+
+ m_ctx.instruction.opcode = static_cast<DxsoOpcode>(
+ token & 0x0000ffff);
+
+ m_ctx.instruction.predicated = token & (1 << 28);
+
+ m_ctx.instruction.coissue = token & 0x40000000;
+
+ m_ctx.instruction.specificData.uint32 =
+ (token & 0x00ff0000) >> 16;
+
+ m_ctx.instruction.tokenLength =
+ this->decodeInstructionLength(token);
+
+ uint32_t tokenLength =
+ m_ctx.instruction.tokenLength;
+
+ switch (m_ctx.instruction.opcode) {
+ case DxsoOpcode::If:
+ case DxsoOpcode::Ifc:
+ case DxsoOpcode::Rep:
+ case DxsoOpcode::Loop:
+ case DxsoOpcode::BreakC:
+ case DxsoOpcode::BreakP: {
+ uint32_t sourceIdx = 0;
+ for (uint32_t i = 0; i < tokenLength; i++) {
+ if (this->decodeSourceRegister(sourceIdx, iter))
+ i++;
+
+ sourceIdx++;
+ }
+ return true;
+ }
+
+ case DxsoOpcode::Dcl:
+ this->decodeDeclaration(iter);
+ this->decodeDestinationRegister(iter);
+ return true;
+
+ case DxsoOpcode::Def:
+ case DxsoOpcode::DefI:
+ case DxsoOpcode::DefB:
+ this->decodeDestinationRegister(iter);
+ this->decodeDefinition(
+ m_ctx.instruction.opcode, iter);
+ return true;
+
+ case DxsoOpcode::Comment:
+ iter = iter.skip(tokenLength);
+ return true;
+
+ default: {
+ uint32_t sourceIdx = 0;
+ for (uint32_t i = 0; i < tokenLength; i++) {
+ if (i == 0) {
+ if (this->decodeDestinationRegister(iter))
+ i++;
+ }
+ else if (i == 1 && m_ctx.instruction.predicated) {
+ // Relative addressing makes no sense
+ // for predicate registers.
+ this->decodePredicateRegister(iter);
+ }
+ else {
+ if (this->decodeSourceRegister(sourceIdx, iter))
+ i++;
+
+ sourceIdx++;
+ }
+ }
+ return true;
+ }
+
+ case DxsoOpcode::End:
+ return false;
+ }
+ }
+
+ std::ostream& operator << (std::ostream& os, DxsoUsage usage) {
+ switch (usage) {
+ case DxsoUsage::Position: os << "Position"; break;
+ case DxsoUsage::BlendWeight: os << "BlendWeight"; break;
+ case DxsoUsage::BlendIndices: os << "BlendIndices"; break;
+ case DxsoUsage::Normal: os << "Normal"; break;
+ case DxsoUsage::PointSize: os << "PointSize"; break;
+ case DxsoUsage::Texcoord: os << "Texcoord"; break;
+ case DxsoUsage::Tangent: os << "Tangent"; break;
+ case DxsoUsage::Binormal: os << "Binormal"; break;
+ case DxsoUsage::TessFactor: os << "TessFactor"; break;
+ case DxsoUsage::PositionT: os << "PositionT"; break;
+ case DxsoUsage::Color: os << "Color"; break;
+ case DxsoUsage::Fog: os << "Fog"; break;
+ case DxsoUsage::Depth: os << "Depth"; break;
+ case DxsoUsage::Sample: os << "Sample"; break;
+ default:
+ os << "Invalid Format (" << static_cast<uint32_t>(usage) << ")"; break;
+ }
+
+ return os;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.h
new file mode 100644
index 00000000..178f8075
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_decoder.h
@@ -0,0 +1,276 @@
+#pragma once
+
+#include "dxso_common.h"
+#include "dxso_enums.h"
+#include "dxso_code.h"
+
+namespace dxvk {
+
+ constexpr size_t DxsoMaxTempRegs = 32;
+ constexpr size_t DxsoMaxTextureRegs = 10;
+ constexpr size_t DxsoMaxInterfaceRegs = 16;
+ constexpr size_t DxsoMaxOperandCount = 8;
+
+ constexpr uint32_t DxsoRegModifierShift = 24;
+
+ class DxsoDecodeContext;
+
+ /**
+ * \brief Source operand modifiers
+ *
+ * These are applied after loading
+ * an operand register.
+ */
+ enum class DxsoRegModifier : uint32_t {
+ None = 0, // r
+ Neg = 1, // -r
+ Bias = 2, // r - 0.5
+ BiasNeg = 3, // -(r - 0.5)
+ Sign = 4, // fma(r, 2.0f, -1.0f)
+ SignNeg = 5, // -fma(r, 2.0f, -1.0f)
+ Comp = 6, // 1 - r
+ X2 = 7, // r * 2
+ X2Neg = 8, // -r * 2
+ Dz = 9, // r / r.z
+ Dw = 10, // r / r.w
+ Abs = 11, // abs(r)
+ AbsNeg = 12, // -abs(r)
+ Not = 13, // !r
+ };
+
+ enum class DxsoInstructionArgumentType : uint16_t {
+ Source,
+ Destination
+ };
+
+ enum class DxsoComparison : uint32_t {
+ // < = >
+ Never = 0, // 0 0 0
+ GreaterThan = 1, // 0 0 1
+ Equal = 2, // 0 1 0
+ GreaterEqual = 3, // 0 1 1
+ LessThan = 4, // 1 0 0
+ NotEqual = 5, // 1 0 1
+ LessEqual = 6, // 1 1 0
+ Always = 7 // 1 1 1
+ };
+
+ enum class DxsoTexLdMode : uint32_t {
+ Regular = 0,
+ Project = 1,
+ Bias = 2
+ };
+
+ union DxsoOpcodeSpecificData {
+ DxsoComparison comparison;
+ DxsoTexLdMode texld;
+
+ uint32_t uint32;
+ };
+
+ struct DxsoShaderInstruction {
+ DxsoOpcode opcode;
+ bool predicated;
+ bool coissue;
+ DxsoOpcodeSpecificData specificData;
+
+ uint32_t tokenLength;
+ };
+
+ struct DxsoRegisterId {
+ DxsoRegisterType type;
+ uint32_t num;
+
+ bool operator == (const DxsoRegisterId& other) const { return type == other.type && num == other.num; }
+ bool operator != (const DxsoRegisterId& other) const { return type != other.type || num != other.num; }
+ };
+
+ class DxsoRegMask {
+
+ public:
+
+ DxsoRegMask(uint8_t mask)
+ : m_mask(mask) { }
+
+ DxsoRegMask(bool x, bool y, bool z, bool w)
+ : m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
+ | (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
+
+ bool operator [] (uint32_t id) const {
+ return ((m_mask & (1u << id)) != 0);
+ }
+
+ uint32_t popCount() const {
+ const uint8_t n[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ return n[m_mask & 0xF];
+ }
+
+ uint32_t firstSet() const {
+ const uint8_t n[16] = { 4, 0, 1, 0, 2, 0, 1, 0,
+ 3, 0, 1, 0, 2, 0, 1, 0 };
+ return n[m_mask & 0xF];
+ }
+
+ uint32_t minComponents() const {
+ const uint8_t n[16] = { 0, 1, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4 };
+ return n[m_mask & 0xF];
+ }
+
+ bool operator == (const DxsoRegMask& other) const { return m_mask == other.m_mask; }
+ bool operator != (const DxsoRegMask& other) const { return m_mask != other.m_mask; }
+
+ private:
+
+ uint8_t m_mask;
+
+ };
+
+ const DxsoRegMask IdentityWriteMask = DxsoRegMask(true, true, true, true);
+
+ class DxsoRegSwizzle {
+
+ public:
+
+ DxsoRegSwizzle(uint8_t mask)
+ : m_mask(mask) { }
+
+ DxsoRegSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
+ : m_mask((x << 0) | (y << 2) | (z << 4) | (w << 6)) {}
+
+ uint32_t operator [] (uint32_t id) const {
+ return (m_mask >> (id + id)) & 0x3;
+ }
+
+ bool operator == (const DxsoRegSwizzle& other) const { return m_mask == other.m_mask; }
+ bool operator != (const DxsoRegSwizzle& other) const { return m_mask != other.m_mask; }
+
+ private:
+
+ uint8_t m_mask;
+
+ };
+
+ const DxsoRegSwizzle IdentitySwizzle{ 0, 1, 2, 3 };
+
+ struct DxsoBaseRegister {
+ DxsoRegisterId id = { DxsoRegisterType::Temp, 0 };
+ bool centroid = false;
+ bool partialPrecision = false;
+ bool saturate = false;
+ DxsoRegModifier modifier = DxsoRegModifier::None;
+ DxsoRegMask mask = IdentityWriteMask;
+ DxsoRegSwizzle swizzle = IdentitySwizzle;
+ int8_t shift = 0;
+ };
+
+ struct DxsoRegister : public DxsoBaseRegister {
+ bool hasRelative = false;
+ DxsoBaseRegister relative;
+ };
+
+ struct DxsoSemantic {
+ DxsoUsage usage;
+ uint32_t usageIndex;
+
+ bool operator== (const DxsoSemantic& b) const;
+ bool operator!= (const DxsoSemantic& b) const;
+ };
+
+ struct DxsoDeclaration {
+ DxsoSemantic semantic;
+
+ DxsoTextureType textureType;
+ };
+
+ union DxsoDefinition {
+ float float32[4];
+ int32_t int32[4];
+
+ // Not a type we actually use in compiler, but used for decoding.
+ uint32_t uint32[4];
+ };
+
+ struct DxsoInstructionContext {
+ uint32_t instructionIdx;
+
+ DxsoShaderInstruction instruction;
+
+ DxsoRegister pred;
+
+ DxsoRegister dst;
+ std::array<
+ DxsoRegister,
+ DxsoMaxOperandCount> src;
+
+ DxsoDefinition def;
+
+ DxsoDeclaration dcl;
+ };
+
+ class DxsoDecodeContext {
+
+ public:
+
+ DxsoDecodeContext(const DxsoProgramInfo& programInfo)
+ : m_programInfo( programInfo ) {
+ m_ctx.instructionIdx = 0;
+ }
+
+ /**
+ * \brief Retrieves current instruction context
+ *
+ * This is only valid after a call to \ref decode.
+ * \returns Reference to last decoded instruction & its context
+ */
+ const DxsoInstructionContext& getInstructionContext() const {
+ return m_ctx;
+ }
+
+ const DxsoProgramInfo& getProgramInfo() const {
+ return m_programInfo;
+ }
+
+ /**
+ * \brief Decodes an instruction
+ *
+ * This also advances the given code slice by the
+ * number of dwords consumed by the instruction.
+ * \param [in] code Code slice
+ */
+ bool decodeInstruction(DxsoCodeIter& iter);
+
+ private:
+
+ uint32_t decodeInstructionLength(uint32_t token);
+
+ void decodeBaseRegister(
+ DxsoBaseRegister& reg,
+ uint32_t token);
+ void decodeGenericRegister(
+ DxsoRegister& reg,
+ uint32_t token);
+ void decodeRelativeRegister(
+ DxsoBaseRegister& reg,
+ uint32_t token);
+
+ // Returns whether an extra token was read.
+ bool decodeDestinationRegister(DxsoCodeIter& iter);
+ bool decodeSourceRegister(uint32_t i, DxsoCodeIter& iter);
+ void decodePredicateRegister(DxsoCodeIter& iter);
+
+ void decodeDeclaration(DxsoCodeIter& iter);
+ void decodeDefinition(DxsoOpcode opcode, DxsoCodeIter& iter);
+
+ bool relativeAddressingUsesToken(DxsoInstructionArgumentType type);
+
+ const DxsoProgramInfo& m_programInfo;
+
+ DxsoInstructionContext m_ctx;
+
+ };
+
+ std::ostream& operator << (std::ostream& os, DxsoUsage usage);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.cpp
new file mode 100644
index 00000000..fc966c29
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.cpp
@@ -0,0 +1,101 @@
+#include "dxso_enums.h"
+
+namespace dxvk {
+
+ std::ostream& operator << (std::ostream& os, DxsoOpcode opcode) {
+ switch (opcode) {
+ case DxsoOpcode::Nop: os << "Nop"; break;
+ case DxsoOpcode::Mov: os << "Mov"; break;
+ case DxsoOpcode::Add: os << "Add"; break;
+ case DxsoOpcode::Sub: os << "Sub"; break;
+ case DxsoOpcode::Mad: os << "Mad"; break;
+ case DxsoOpcode::Mul: os << "Mul"; break;
+ case DxsoOpcode::Rcp: os << "Rcp"; break;
+ case DxsoOpcode::Rsq: os << "Rsq"; break;
+ case DxsoOpcode::Dp3: os << "Dp3"; break;
+ case DxsoOpcode::Dp4: os << "Dp4"; break;
+ case DxsoOpcode::Min: os << "Min"; break;
+ case DxsoOpcode::Max: os << "Max"; break;
+ case DxsoOpcode::Slt: os << "Slt"; break;
+ case DxsoOpcode::Sge: os << "Sge"; break;
+ case DxsoOpcode::Exp: os << "Exp"; break;
+ case DxsoOpcode::Log: os << "Log"; break;
+ case DxsoOpcode::Lit: os << "Lit"; break;
+ case DxsoOpcode::Dst: os << "Dst"; break;
+ case DxsoOpcode::Lrp: os << "Lrp"; break;
+ case DxsoOpcode::Frc: os << "Frc"; break;
+ case DxsoOpcode::M4x4: os << "M4x4"; break;
+ case DxsoOpcode::M4x3: os << "M4x3"; break;
+ case DxsoOpcode::M3x4: os << "M3x4"; break;
+ case DxsoOpcode::M3x3: os << "M3x3"; break;
+ case DxsoOpcode::M3x2: os << "M3x2"; break;
+ case DxsoOpcode::Call: os << "Call"; break;
+ case DxsoOpcode::CallNz: os << "CallNz"; break;
+ case DxsoOpcode::Loop: os << "Loop"; break;
+ case DxsoOpcode::Ret: os << "Ret"; break;
+ case DxsoOpcode::EndLoop: os << "EndLoop"; break;
+ case DxsoOpcode::Label: os << "Label"; break;
+ case DxsoOpcode::Dcl: os << "Dcl"; break;
+ case DxsoOpcode::Pow: os << "Pow"; break;
+ case DxsoOpcode::Crs: os << "Crs"; break;
+ case DxsoOpcode::Sgn: os << "Sgn"; break;
+ case DxsoOpcode::Abs: os << "Abs"; break;
+ case DxsoOpcode::Nrm: os << "Nrm"; break;
+ case DxsoOpcode::SinCos: os << "SinCos"; break;
+ case DxsoOpcode::Rep: os << "Rep"; break;
+ case DxsoOpcode::EndRep: os << "EndRep"; break;
+ case DxsoOpcode::If: os << "If"; break;
+ case DxsoOpcode::Ifc: os << "Ifc"; break;
+ case DxsoOpcode::Else: os << "Else"; break;
+ case DxsoOpcode::EndIf: os << "EndIf"; break;
+ case DxsoOpcode::Break: os << "Break"; break;
+ case DxsoOpcode::BreakC: os << "BreakC"; break;
+ case DxsoOpcode::Mova: os << "Mova"; break;
+ case DxsoOpcode::DefB: os << "DefB"; break;
+ case DxsoOpcode::DefI: os << "DefI"; break;
+
+ case DxsoOpcode::TexCoord: os << "TexCoord"; break;
+ case DxsoOpcode::TexKill: os << "TexKill"; break;
+ case DxsoOpcode::Tex: os << "Tex"; break;
+ case DxsoOpcode::TexBem: os << "TexBem"; break;
+ case DxsoOpcode::TexBemL: os << "TexBemL"; break;
+ case DxsoOpcode::TexReg2Ar: os << "TexReg2Ar"; break;
+ case DxsoOpcode::TexReg2Gb: os << "TexReg2Gb"; break;
+ case DxsoOpcode::TexM3x2Pad: os << "TexM3x2Pad"; break;
+ case DxsoOpcode::TexM3x2Tex: os << "TexM3x2Tex"; break;
+ case DxsoOpcode::TexM3x3Pad: os << "TexM3x3Pad"; break;
+ case DxsoOpcode::TexM3x3Tex: os << "TexM3x3Tex"; break;
+ case DxsoOpcode::Reserved0: os << "Reserved0"; break;
+ case DxsoOpcode::TexM3x3Spec: os << "TexM3x3Spec"; break;
+ case DxsoOpcode::TexM3x3VSpec: os << "TexM3x3VSpec"; break;
+ case DxsoOpcode::ExpP: os << "ExpP"; break;
+ case DxsoOpcode::LogP: os << "LogP"; break;
+ case DxsoOpcode::Cnd: os << "Cnd"; break;
+ case DxsoOpcode::Def: os << "Def"; break;
+ case DxsoOpcode::TexReg2Rgb: os << "TexReg2Rgb"; break;
+ case DxsoOpcode::TexDp3Tex: os << "TexDp3Tex"; break;
+ case DxsoOpcode::TexM3x2Depth: os << "TexM3x2Depth"; break;
+ case DxsoOpcode::TexDp3: os << "TexDp3"; break;
+ case DxsoOpcode::TexM3x3: os << "TexM3x3"; break;
+ case DxsoOpcode::TexDepth: os << "TexDepth"; break;
+ case DxsoOpcode::Cmp: os << "Cmp"; break;
+ case DxsoOpcode::Bem: os << "Bem"; break;
+ case DxsoOpcode::Dp2Add: os << "Dp2Add"; break;
+ case DxsoOpcode::DsX: os << "DsX"; break;
+ case DxsoOpcode::DsY: os << "DsY"; break;
+ case DxsoOpcode::TexLdd: os << "TexLdd"; break;
+ case DxsoOpcode::SetP: os << "SetP"; break;
+ case DxsoOpcode::TexLdl: os << "TexLdl"; break;
+ case DxsoOpcode::BreakP: os << "BreakP"; break;
+
+ case DxsoOpcode::Phase: os << "Phase"; break;
+ case DxsoOpcode::Comment: os << "Comment"; break;
+ case DxsoOpcode::End: os << "End"; break;
+ default:
+ os << "Invalid Opcode (" << static_cast<uint32_t>(opcode) << ")"; break;
+ }
+
+ return os;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.h
new file mode 100644
index 00000000..84f2e5b7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_enums.h
@@ -0,0 +1,164 @@
+#pragma once
+
+#include "dxso_include.h"
+
+#include <cstdint>
+
+namespace dxvk {
+
+ /**
+ * \brief Instruction code listing
+ */
+ enum class DxsoOpcode : uint32_t {
+ Nop = 0,
+ Mov ,
+ Add ,
+ Sub ,
+ Mad ,
+ Mul ,
+ Rcp ,
+ Rsq ,
+ Dp3 ,
+ Dp4 ,
+ Min ,
+ Max ,
+ Slt ,
+ Sge ,
+ Exp ,
+ Log ,
+ Lit ,
+ Dst ,
+ Lrp ,
+ Frc ,
+ M4x4 ,
+ M4x3 ,
+ M3x4 ,
+ M3x3 ,
+ M3x2 ,
+ Call ,
+ CallNz ,
+ Loop ,
+ Ret ,
+ EndLoop ,
+ Label ,
+ Dcl ,
+ Pow ,
+ Crs ,
+ Sgn ,
+ Abs ,
+ Nrm ,
+ SinCos ,
+ Rep ,
+ EndRep ,
+ If ,
+ Ifc ,
+ Else ,
+ EndIf ,
+ Break ,
+ BreakC ,
+ Mova ,
+ DefB ,
+ DefI ,
+
+ TexCoord = 64,
+ TexKill ,
+ Tex ,
+ TexBem ,
+ TexBemL ,
+ TexReg2Ar ,
+ TexReg2Gb ,
+ TexM3x2Pad ,
+ TexM3x2Tex ,
+ TexM3x3Pad ,
+ TexM3x3Tex ,
+ Reserved0 ,
+ TexM3x3Spec ,
+ TexM3x3VSpec ,
+ ExpP ,
+ LogP ,
+ Cnd ,
+ Def ,
+ TexReg2Rgb ,
+ TexDp3Tex ,
+ TexM3x2Depth ,
+ TexDp3 ,
+ TexM3x3 ,
+ TexDepth ,
+ Cmp ,
+ Bem ,
+ Dp2Add ,
+ DsX ,
+ DsY ,
+ TexLdd ,
+ SetP ,
+ TexLdl ,
+ BreakP ,
+
+ Phase = 0xfffd,
+ Comment = 0xfffe,
+ End = 0xffff
+ };
+
+ std::ostream& operator << (std::ostream& os, DxsoOpcode opcode);
+
+ enum class DxsoRegisterType : uint32_t {
+ Temp = 0, // Temporary Register File
+ Input = 1, // Input Register File
+ Const = 2, // Constant Register File
+ Addr = 3, // Address Register (VS)
+ Texture = 3, // Texture Register File (PS)
+ RasterizerOut = 4, // Rasterizer Register File
+ AttributeOut = 5, // Attribute Output Register File
+ TexcoordOut = 6, // Texture Coordinate Output Register File
+ Output = 6, // Output register file for VS3.0+
+ ConstInt = 7, // Constant Integer Vector Register File
+ ColorOut = 8, // Color Output Register File
+ DepthOut = 9, // Depth Output Register File
+ Sampler = 10, // Sampler State Register File
+ Const2 = 11, // Constant Register File 2048 - 4095
+ Const3 = 12, // Constant Register File 4096 - 6143
+ Const4 = 13, // Constant Register File 6144 - 8191
+ ConstBool = 14, // Constant Boolean register file
+ Loop = 15, // Loop counter register file
+ TempFloat16 = 16, // 16-bit float temp register file
+ MiscType = 17, // Miscellaneous (single) registers.
+ Label = 18, // Label
+ Predicate = 19, // Predicate register
+ PixelTexcoord = 20
+ };
+
+ enum class DxsoUsage : uint32_t {
+ Position = 0,
+ BlendWeight, // 1
+ BlendIndices, // 2
+ Normal, // 3
+ PointSize, // 4
+ Texcoord, // 5
+ Tangent, // 6
+ Binormal, // 7
+ TessFactor, // 8
+ PositionT, // 9
+ Color, // 10
+ Fog, // 11
+ Depth, // 12
+ Sample, // 13
+ };
+
+ enum class DxsoTextureType : uint32_t {
+ Texture2D = 2,
+ TextureCube = 3,
+ Texture3D = 4
+ };
+
+ enum DxsoReasterizerOutIndices : uint32_t {
+ RasterOutPosition = 0,
+ RasterOutFog = 1,
+ RasterOutPointSize = 2
+ };
+
+ enum DxsoMiscTypeIndices : uint32_t {
+ MiscTypePosition,
+ MiscTypeFace,
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.cpp
new file mode 100644
index 00000000..81077c95
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.cpp
@@ -0,0 +1,24 @@
+#include "dxso_header.h"
+
+namespace dxvk {
+
+ DxsoHeader::DxsoHeader(DxsoReader& reader) {
+ uint32_t headerToken = reader.readu32();
+
+ uint32_t headerTypeMask = headerToken & 0xffff0000;
+
+ DxsoProgramType programType;
+ if (headerTypeMask == 0xffff0000)
+ programType = DxsoProgramTypes::PixelShader;
+ else if (headerTypeMask == 0xfffe0000)
+ programType = DxsoProgramTypes::VertexShader;
+ else
+ throw DxvkError("DxsoHeader: invalid header - invalid version");
+
+ const uint32_t majorVersion = (headerToken >> 8) & 0xff;
+ const uint32_t minorVersion = headerToken & 0xff;
+
+ m_info = DxsoProgramInfo{ programType, minorVersion, majorVersion };
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.h
new file mode 100644
index 00000000..3a7f4bd3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_header.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "dxso_common.h"
+
+#include "dxso_reader.h"
+
+namespace dxvk {
+
+/**
+ * \brief DXSO header
+ *
+ * Stores meta information about the shader such
+ * as the version and the type.
+ */
+ class DxsoHeader {
+
+ public:
+
+ DxsoHeader(DxsoReader& reader);
+
+ const DxsoProgramInfo& info() const {
+ return m_info;
+ }
+
+ private:
+
+ DxsoProgramInfo m_info;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_helpers.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_helpers.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_helpers.h
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_include.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_include.h
new file mode 100644
index 00000000..2f41e784
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_include.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "../dxvk/dxvk_shader.h"
+
+#include "../util/com/com_guid.h"
+#include "../util/com/com_object.h"
+#include "../util/com/com_pointer.h"
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#include "../util/util_bit.h"
+#include "../util/util_enum.h"
+#include "../util/util_error.h"
+#include "../util/util_string.h" \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_isgn.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_isgn.h
new file mode 100644
index 00000000..2faa04ef
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_isgn.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "dxso_decoder.h"
+
+namespace dxvk {
+
+ struct DxsoIsgnEntry {
+ uint32_t regNumber = 0;
+ uint32_t slot = 0;
+ DxsoSemantic semantic = DxsoSemantic{ DxsoUsage::Position, 0 };
+ DxsoRegMask mask = IdentityWriteMask;
+ bool centroid = false;
+ };
+
+ struct DxsoIsgn {
+ std::array<
+ DxsoIsgnEntry,
+ 2 * DxsoMaxInterfaceRegs> elems;
+ uint32_t elemCount = 0;
+ };
+
+ struct DxsoDefinedConstant {
+ uint32_t uboIdx;
+
+ // Only float constants may be indexed.
+ // So that's the only ones we care about putting in the UBO.
+ float float32[4];
+ };
+
+ using DxsoDefinedConstants = std::vector<DxsoDefinedConstant>;
+
+ struct DxsoShaderMetaInfo {
+ bool needsConstantCopies = false;
+ uint32_t maxConstIndexF = 0;
+ uint32_t maxConstIndexI = 0;
+ uint32_t maxConstIndexB = 0;
+
+ uint32_t boolConstantMask = 0;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_modinfo.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_modinfo.h
new file mode 100644
index 00000000..410c90f3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_modinfo.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "dxso_options.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Shader module info
+ *
+ * Stores information which may affect shader compilation.
+ * This data can be supplied by the client API implementation.
+ */
+ struct DxsoModuleInfo {
+ DxsoOptions options;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.cpp
new file mode 100644
index 00000000..43f9fda9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.cpp
@@ -0,0 +1,86 @@
+#include "dxso_module.h"
+
+#include "dxso_code.h"
+#include "dxso_compiler.h"
+
+#include <memory>
+
+namespace dxvk {
+
+ DxsoModule::DxsoModule(DxsoReader& reader)
+ : m_header( reader )
+ , m_code ( reader ) { }
+
+ DxsoAnalysisInfo DxsoModule::analyze() {
+ DxsoAnalysisInfo info;
+
+ DxsoAnalyzer analyzer(info);
+
+ this->runAnalyzer(analyzer, m_code.iter());
+
+ return info;
+ }
+
+ DxsoPermutations DxsoModule::compile(
+ const DxsoModuleInfo& moduleInfo,
+ const std::string& fileName,
+ const DxsoAnalysisInfo& analysis,
+ const D3D9ConstantLayout& layout) {
+ auto compiler = std::make_unique<DxsoCompiler>(
+ fileName, moduleInfo,
+ m_header.info(), analysis,
+ layout);
+
+ this->runCompiler(*compiler, m_code.iter());
+ m_isgn = compiler->isgn();
+
+ m_meta = compiler->meta();
+ m_constants = compiler->constants();
+ m_usedSamplers = compiler->usedSamplers();
+ m_usedRTs = compiler->usedRTs();
+
+ compiler->finalize();
+
+ return compiler->compile();
+ }
+
+ void DxsoModule::runAnalyzer(
+ DxsoAnalyzer& analyzer,
+ DxsoCodeIter iter) const {
+ DxsoCodeIter start = iter;
+
+ DxsoDecodeContext decoder(m_header.info());
+
+ while (decoder.decodeInstruction(iter))
+ analyzer.processInstruction(
+ decoder.getInstructionContext());
+
+ size_t tokenCount = size_t(iter.ptrAt(0) - start.ptrAt(0));
+
+ // We need to account for the header token in the bytecode size...
+
+ // At this point, start is offset by the header due to us this being
+ // a *code* iterator, and not the general reader class.
+ // [start token] ^(start caret)^ [frog rendering code] [end token] ^(end caret)^
+ // where the tokenCount above is inbetween the start and end carets.
+
+ // We need to account for this otherwise it will show up as us not
+ // accounting for the *end* token in GetFunction due to the total size being
+ // offset by -1.
+ // [start token] [frog rendering code] (end of tokenCount) [end token]
+ tokenCount += 1;
+
+ analyzer.finalize(tokenCount);
+ }
+
+ void DxsoModule::runCompiler(
+ DxsoCompiler& compiler,
+ DxsoCodeIter iter) const {
+ DxsoDecodeContext decoder(m_header.info());
+
+ while (decoder.decodeInstruction(iter))
+ compiler.processInstruction(
+ decoder.getInstructionContext());
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.h
new file mode 100644
index 00000000..1f5cda85
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_module.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "dxso_reader.h"
+#include "dxso_code.h"
+#include "dxso_header.h"
+#include "dxso_ctab.h"
+
+#include "dxso_isgn.h"
+#include "dxso_analysis.h"
+
+#include "../d3d9/d3d9_constant_layout.h"
+#include "../d3d9/d3d9_shader_permutations.h"
+
+#include <vector>
+
+namespace dxvk {
+
+ class DxsoCompiler;
+ class DxsoCode;
+ struct DxsoModuleInfo;
+
+ /**
+ * \brief DXSO shader module, a d3d9 shader object.
+ */
+ class DxsoModule {
+
+ public:
+
+ DxsoModule(DxsoReader& reader);
+
+ const DxsoProgramInfo& info() {
+ return m_header.info();
+ }
+
+ DxsoAnalysisInfo analyze();
+
+ /**
+ * \brief Compiles DXSO shader to SPIR-V module
+ *
+ * \param [in] moduleInfo DXSO module info
+ * \param [in] fileName File name, will be added to
+ * the compiled SPIR-V for debugging purposes.
+ * \returns The compiled shader object
+ */
+ DxsoPermutations compile(
+ const DxsoModuleInfo& moduleInfo,
+ const std::string& fileName,
+ const DxsoAnalysisInfo& analysis,
+ const D3D9ConstantLayout& layout);
+
+ const DxsoIsgn& isgn() {
+ return m_isgn;
+ }
+
+ const DxsoShaderMetaInfo& meta() { return m_meta; }
+
+ const DxsoDefinedConstants& constants() { return m_constants; }
+
+ uint32_t usedSamplers() { return m_usedSamplers; }
+
+ uint32_t usedRTs() { return m_usedRTs; }
+
+ private:
+
+ void runCompiler(
+ DxsoCompiler& compiler,
+ DxsoCodeIter iter) const;
+
+ void runAnalyzer(
+ DxsoAnalyzer& analyzer,
+ DxsoCodeIter iter) const;
+
+ DxsoHeader m_header;
+ DxsoCode m_code;
+
+ DxsoIsgn m_isgn;
+ uint32_t m_usedSamplers;
+ uint32_t m_usedRTs;
+
+ DxsoShaderMetaInfo m_meta;
+ DxsoDefinedConstants m_constants;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.cpp
new file mode 100644
index 00000000..a06f25b3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.cpp
@@ -0,0 +1,48 @@
+#include "dxso_options.h"
+
+#include "../d3d9/d3d9_device.h"
+
+namespace dxvk {
+
+ DxsoOptions::DxsoOptions() {}
+
+ DxsoOptions::DxsoOptions(D3D9DeviceEx* pDevice, const D3D9Options& options) {
+ const Rc<DxvkDevice> device = pDevice->GetDXVKDevice();
+
+ const Rc<DxvkAdapter> adapter = device->adapter();
+
+ const DxvkDeviceFeatures& devFeatures = device->features();
+ const DxvkDeviceInfo& devInfo = adapter->devicePropertiesExt();
+
+ useDemoteToHelperInvocation
+ = (devFeatures.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation);
+
+ useSubgroupOpsForEarlyDiscard
+ = (devInfo.coreSubgroup.subgroupSize >= 4)
+ && (devInfo.coreSubgroup.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT)
+ && (devInfo.coreSubgroup.supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
+
+ // Disable early discard on Nvidia because it may hurt performance
+ if (adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0))
+ useSubgroupOpsForEarlyDiscard = false;
+
+ // Apply shader-related options
+ strictConstantCopies = options.strictConstantCopies;
+
+ strictPow = options.strictPow;
+ d3d9FloatEmulation = options.d3d9FloatEmulation;
+
+ shaderModel = options.shaderModel;
+
+ invariantPosition = options.invariantPosition;
+
+ forceSamplerTypeSpecConstants = options.forceSamplerTypeSpecConstants;
+
+ vertexConstantBufferAsSSBO = pDevice->GetVertexConstantLayout().totalSize() > devInfo.core.properties.limits.maxUniformBufferRange;
+
+ longMad = options.longMad;
+
+ alphaTestWiggleRoom = options.alphaTestWiggleRoom;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.h
new file mode 100644
index 00000000..24ca4264
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_options.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+#include "../d3d9/d3d9_options.h"
+
+namespace dxvk {
+
+ class D3D9DeviceEx;
+ struct D3D9Options;
+
+ struct DxsoOptions {
+ DxsoOptions();
+ DxsoOptions(D3D9DeviceEx* pDevice, const D3D9Options& options);
+
+ /// Use a SPIR-V extension to implement D3D-style discards
+ bool useDemoteToHelperInvocation = false;
+
+ /// Use subgroup operations to discard fragment
+ /// shader invocations if derivatives remain valid.
+ bool useSubgroupOpsForEarlyDiscard = false;
+
+ /// True: Copy our constant set into UBO if we are relative indexing ever.
+ /// False: Copy our constant set into UBO if we are relative indexing at the start of a defined constant
+ /// Why?: In theory, FXC should never generate code where this would be an issue.
+ bool strictConstantCopies;
+
+ /// Whether to emulate d3d9 float behaviour using clampps
+ /// True: Perform emulation to emulate behaviour (ie. anything * 0 = 0)
+ /// False: Don't do anything.
+ bool d3d9FloatEmulation;
+
+ /// Whether or not we should care about pow(0, 0) = 1
+ bool strictPow;
+
+ /// Max version of shader to support
+ uint32_t shaderModel;
+
+ /// Work around a NV driver quirk
+ /// Fixes flickering/z-fighting in some games.
+ bool invariantPosition;
+
+ /// Always use a spec constant to determine sampler type (instead of just in PS 1.x)
+ /// Works around a game bug in Halo CE where it gives cube textures to 2d/volume samplers
+ bool forceSamplerTypeSpecConstants;
+
+ /// Should the VS constant buffer be an SSBO (swvp on NV)
+ bool vertexConstantBufferAsSSBO;
+
+ /// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
+ /// This solves some rendering bugs in games that have z-pass shaders which
+ /// don't match entirely to the regular vertex shader in this way.
+ bool longMad;
+
+ /// Workaround for games using alpha test == 1.0, etc due to wonky interpolation or
+ /// misc. imprecision on some vendors
+ bool alphaTestWiggleRoom;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.cpp
new file mode 100644
index 00000000..ab47f283
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.cpp
@@ -0,0 +1,26 @@
+#include "dxso_reader.h"
+
+#include <cstring>
+
+namespace dxvk {
+
+ DxbcTag DxsoReader::readTag() {
+ DxbcTag tag;
+ this->read(&tag, 4);
+ return tag;
+ }
+
+ void DxsoReader::read(void* dst, size_t n) {
+ std::memcpy(dst, m_data + m_pos, n);
+ m_pos += n;
+ }
+
+ void DxsoReader::skip(size_t n) {
+ m_pos += n;
+ }
+
+ void DxsoReader::store(std::ostream && stream, size_t size) const {
+ stream.write(m_data, size);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.h
new file mode 100644
index 00000000..fa650bb8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_reader.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "dxso_include.h"
+
+#include "../dxbc/dxbc_tag.h"
+
+#include <cstdint>
+
+namespace dxvk {
+
+ /**
+ * \brief DXSO (d3d9) bytecode reader
+ *
+ * Holds references to the shader byte code and
+ * provides methods to read
+ */
+ class DxsoReader {
+
+ public:
+
+ DxsoReader(const char* data)
+ : DxsoReader(data, 0) { }
+
+ size_t pos() {
+ return m_pos;
+ }
+
+ auto readu32() { return this->readNum<uint32_t> (); }
+ auto readf32() { return this->readNum<float> (); }
+
+ DxbcTag readTag();
+
+ void read(void* dst, size_t n);
+
+ void skip(size_t n);
+
+ void store(std::ostream&& stream, size_t size) const;
+
+ const char* currentPtr() {
+ return m_data + m_pos;
+ }
+
+ private:
+
+ DxsoReader(const char* data, size_t pos)
+ : m_data(data), m_pos(pos) { }
+
+ const char* m_data = nullptr;
+ size_t m_pos = 0;
+
+ template<typename T>
+ T readNum() {
+ T result;
+ this->read(&result, sizeof(result));
+ return result;
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.cpp
new file mode 100644
index 00000000..5b8ab91f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.cpp
@@ -0,0 +1,93 @@
+#include "dxso_tables.h"
+
+namespace dxvk {
+
+ uint32_t DxsoGetDefaultOpcodeLength(DxsoOpcode opcode) {
+
+ switch (opcode) {
+ case DxsoOpcode::Nop: return 0;
+ case DxsoOpcode::Mov: return 2;
+ case DxsoOpcode::Add: return 3;
+ case DxsoOpcode::Sub: return 3;
+ case DxsoOpcode::Mad: return 4;
+ case DxsoOpcode::Mul: return 3;
+ case DxsoOpcode::Rcp: return 2;
+ case DxsoOpcode::Rsq: return 2;
+ case DxsoOpcode::Dp3: return 3;
+ case DxsoOpcode::Dp4: return 3;
+ case DxsoOpcode::Min: return 3;
+ case DxsoOpcode::Max: return 3;
+ case DxsoOpcode::Slt: return 3;
+ case DxsoOpcode::Sge: return 3;
+ case DxsoOpcode::Exp: return 2;
+ case DxsoOpcode::Log: return 2;
+ case DxsoOpcode::Lit: return 2;
+ case DxsoOpcode::Dst: return 3;
+ case DxsoOpcode::Lrp: return 4;
+ case DxsoOpcode::Frc: return 2;
+ case DxsoOpcode::M4x4: return 3;
+ case DxsoOpcode::M4x3: return 3;
+ case DxsoOpcode::M3x4: return 3;
+ case DxsoOpcode::M3x3: return 3;
+ case DxsoOpcode::M3x2: return 3;
+ case DxsoOpcode::Call: return 1;
+ case DxsoOpcode::CallNz: return 2;
+ case DxsoOpcode::Loop: return 2;
+ case DxsoOpcode::Ret: return 0;
+ case DxsoOpcode::EndLoop: return 0;
+ case DxsoOpcode::Label: return 1;
+ case DxsoOpcode::Dcl: return 2;
+ case DxsoOpcode::Pow: return 3;
+ case DxsoOpcode::Crs: return 3;
+ case DxsoOpcode::Sgn: return 4;
+ case DxsoOpcode::Abs: return 2;
+ case DxsoOpcode::Nrm: return 2;
+ case DxsoOpcode::SinCos: return 4;
+ case DxsoOpcode::Rep: return 1;
+ case DxsoOpcode::EndRep: return 0;
+ case DxsoOpcode::If: return 1;
+ case DxsoOpcode::Ifc: return 2;
+ case DxsoOpcode::Else: return 0;
+ case DxsoOpcode::EndIf: return 0;
+ case DxsoOpcode::Break: return 0;
+ case DxsoOpcode::BreakC: return 2;
+ case DxsoOpcode::Mova: return 2;
+ case DxsoOpcode::DefB: return 2;
+ case DxsoOpcode::DefI: return 5;
+ case DxsoOpcode::TexCoord: return 1;
+ case DxsoOpcode::TexKill: return 1;
+ case DxsoOpcode::Tex: return 1;
+ case DxsoOpcode::TexBem: return 2;
+ case DxsoOpcode::TexBemL: return 2;
+ case DxsoOpcode::TexReg2Ar: return 2;
+ case DxsoOpcode::TexReg2Gb: return 2;
+ case DxsoOpcode::TexM3x2Pad: return 2;
+ case DxsoOpcode::TexM3x2Tex: return 2;
+ case DxsoOpcode::TexM3x3Pad: return 2;
+ case DxsoOpcode::TexM3x3Tex: return 2;
+ case DxsoOpcode::TexM3x3Spec: return 3;
+ case DxsoOpcode::TexM3x3VSpec: return 2;
+ case DxsoOpcode::ExpP: return 2;
+ case DxsoOpcode::LogP: return 2;
+ case DxsoOpcode::Cnd: return 4;
+ case DxsoOpcode::Def: return 5;
+ case DxsoOpcode::TexReg2Rgb: return 2;
+ case DxsoOpcode::TexDp3Tex: return 2;
+ case DxsoOpcode::TexM3x2Depth: return 2;
+ case DxsoOpcode::TexDp3: return 2;
+ case DxsoOpcode::TexM3x3: return 2;
+ case DxsoOpcode::TexDepth: return 1;
+ case DxsoOpcode::Cmp: return 4;
+ case DxsoOpcode::Bem: return 3;
+ case DxsoOpcode::Dp2Add: return 4;
+ case DxsoOpcode::DsX: return 2;
+ case DxsoOpcode::DsY: return 2;
+ case DxsoOpcode::TexLdd: return 5;
+ case DxsoOpcode::SetP: return 3;
+ case DxsoOpcode::TexLdl: return 3;
+ case DxsoOpcode::BreakP: return 2;
+ default: Logger::warn("DxsoGetDefaultOpcodeLength: unknown opcode to get default length for."); return UINT32_MAX;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.h
new file mode 100644
index 00000000..73e3801d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_tables.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "dxso_enums.h"
+
+namespace dxvk {
+
+ constexpr uint32_t InvalidOpcodeLength = UINT32_MAX;
+
+ uint32_t DxsoGetDefaultOpcodeLength(DxsoOpcode opcode);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.cpp b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.cpp
new file mode 100644
index 00000000..16a75082
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.cpp
@@ -0,0 +1,34 @@
+#include "dxso_util.h"
+
+#include "dxso_include.h"
+
+namespace dxvk {
+
+ dxvk::mutex g_linkerSlotMutex;
+ uint32_t g_linkerSlotCount = 0;
+ std::array<DxsoSemantic, 32> g_linkerSlots;
+
+ uint32_t RegisterLinkerSlot(DxsoSemantic semantic) {
+ // Lock, because games could be trying
+ // to make multiple shaders at a time.
+ std::lock_guard<dxvk::mutex> lock(g_linkerSlotMutex);
+
+ // Need to chose a slot that maps nicely and similarly
+ // between vertex and pixel shaders
+
+ // Find or map a slot.
+ uint32_t slot = g_linkerSlotCount;
+ for (uint32_t j = 0; j < g_linkerSlotCount; j++) {
+ if (g_linkerSlots[j] == semantic) {
+ slot = j;
+ break;
+ }
+ }
+
+ if (slot == g_linkerSlotCount)
+ g_linkerSlots[g_linkerSlotCount++] = semantic;
+
+ return slot;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.h b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.h
new file mode 100644
index 00000000..fac03d73
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/dxso_util.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <cstdint>
+
+#include "dxso_common.h"
+#include "dxso_decoder.h"
+
+namespace dxvk {
+
+ enum class DxsoBindingType : uint32_t {
+ ConstantBuffer,
+ Image,
+ };
+
+ enum DxsoConstantBuffers : uint32_t {
+ VSConstantBuffer = 0,
+ VSClipPlanes = 1,
+ VSFixedFunction = 2,
+ VSVertexBlendData = 3,
+ VSCount,
+
+ PSConstantBuffer = 0,
+ PSFixedFunction = 1,
+ PSShared = 2,
+ PSCount
+ };
+
+ constexpr uint32_t computeResourceSlotId(
+ DxsoProgramType shaderStage,
+ DxsoBindingType bindingType,
+ uint32_t bindingIndex) {
+ const uint32_t stageOffset = 8 * uint32_t(shaderStage);
+
+ if (bindingType == DxsoBindingType::ConstantBuffer)
+ return bindingIndex + stageOffset;
+ else // if (bindingType == DxsoBindingType::Image)
+ return bindingIndex + stageOffset + (shaderStage == DxsoProgramType::PixelShader ? PSCount : VSCount);
+ }
+
+ // TODO: Intergrate into compute resource slot ID/refactor all of this?
+ constexpr uint32_t getSWVPBufferSlot() {
+ return 27; // From last pixel shader slot, above.
+ }
+
+ uint32_t RegisterLinkerSlot(DxsoSemantic semantic);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxso/meson.build b/src/libs/dxvk-native-1.9.2a/src/dxso/meson.build
new file mode 100644
index 00000000..392b7409
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxso/meson.build
@@ -0,0 +1,23 @@
+dxso_src = files([
+ 'dxso_common.cpp',
+ 'dxso_options.cpp',
+ 'dxso_module.cpp',
+ 'dxso_reader.cpp',
+ 'dxso_header.cpp',
+ 'dxso_ctab.cpp',
+ 'dxso_util.cpp',
+ 'dxso_code.cpp',
+ 'dxso_tables.cpp',
+ 'dxso_decoder.cpp',
+ 'dxso_analysis.cpp',
+ 'dxso_compiler.cpp',
+ 'dxso_enums.cpp'
+])
+
+dxso_lib = static_library('dxso', dxso_src,
+ include_directories : [ dxvk_include_path ],
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+dxso_dep = declare_dependency(
+ link_with : [ dxso_lib ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.cpp
new file mode 100644
index 00000000..9db50ae4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.cpp
@@ -0,0 +1,802 @@
+#include <cstring>
+#include <unordered_set>
+
+#include "dxvk_adapter.h"
+#include "dxvk_device.h"
+#include "dxvk_instance.h"
+
+namespace dxvk {
+
+ DxvkAdapter::DxvkAdapter(
+ const Rc<vk::InstanceFn>& vki,
+ VkPhysicalDevice handle)
+ : m_vki (vki),
+ m_handle (handle) {
+ this->initHeapAllocInfo();
+ this->queryExtensions();
+ this->queryDeviceInfo();
+ this->queryDeviceFeatures();
+ this->queryDeviceQueues();
+
+ m_hasMemoryBudget = m_deviceExtensions.supports(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
+ }
+
+
+ DxvkAdapter::~DxvkAdapter() {
+
+ }
+
+
+ DxvkAdapterMemoryInfo DxvkAdapter::getMemoryHeapInfo() const {
+ VkPhysicalDeviceMemoryBudgetPropertiesEXT memBudget = { };
+ memBudget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
+ memBudget.pNext = nullptr;
+
+ VkPhysicalDeviceMemoryProperties2 memProps = { };
+ memProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
+ memProps.pNext = m_hasMemoryBudget ? &memBudget : nullptr;
+
+ m_vki->vkGetPhysicalDeviceMemoryProperties2(m_handle, &memProps);
+
+ DxvkAdapterMemoryInfo info = { };
+ info.heapCount = memProps.memoryProperties.memoryHeapCount;
+
+ for (uint32_t i = 0; i < info.heapCount; i++) {
+ info.heaps[i].heapFlags = memProps.memoryProperties.memoryHeaps[i].flags;
+
+ if (m_hasMemoryBudget) {
+ info.heaps[i].memoryBudget = memBudget.heapBudget[i];
+ info.heaps[i].memoryAllocated = memBudget.heapUsage[i];
+ } else {
+ info.heaps[i].memoryBudget = memProps.memoryProperties.memoryHeaps[i].size;
+ info.heaps[i].memoryAllocated = m_heapAlloc[i].load();
+ }
+ }
+
+ return info;
+ }
+
+
+ VkPhysicalDeviceMemoryProperties DxvkAdapter::memoryProperties() const {
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+ m_vki->vkGetPhysicalDeviceMemoryProperties(m_handle, &memoryProperties);
+ return memoryProperties;
+ }
+
+
+ VkFormatProperties DxvkAdapter::formatProperties(VkFormat format) const {
+ VkFormatProperties formatProperties;
+ m_vki->vkGetPhysicalDeviceFormatProperties(m_handle, format, &formatProperties);
+ return formatProperties;
+ }
+
+
+ VkResult DxvkAdapter::imageFormatProperties(
+ VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags,
+ VkImageFormatProperties& properties) const {
+ return m_vki->vkGetPhysicalDeviceImageFormatProperties(
+ m_handle, format, type, tiling, usage, flags, &properties);
+ }
+
+
+ DxvkAdapterQueueIndices DxvkAdapter::findQueueFamilies() const {
+ uint32_t graphicsQueue = findQueueFamily(
+ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
+
+ uint32_t computeQueue = findQueueFamily(
+ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
+ VK_QUEUE_COMPUTE_BIT);
+
+ if (computeQueue == VK_QUEUE_FAMILY_IGNORED)
+ computeQueue = graphicsQueue;
+
+ uint32_t transferQueue = findQueueFamily(
+ VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
+ VK_QUEUE_TRANSFER_BIT);
+
+ if (transferQueue == VK_QUEUE_FAMILY_IGNORED)
+ transferQueue = computeQueue;
+
+ DxvkAdapterQueueIndices queues;
+ queues.graphics = graphicsQueue;
+ queues.transfer = transferQueue;
+ return queues;
+ }
+
+
+ bool DxvkAdapter::checkFeatureSupport(const DxvkDeviceFeatures& required) const {
+ return (m_deviceFeatures.core.features.robustBufferAccess
+ || !required.core.features.robustBufferAccess)
+ && (m_deviceFeatures.core.features.fullDrawIndexUint32
+ || !required.core.features.fullDrawIndexUint32)
+ && (m_deviceFeatures.core.features.imageCubeArray
+ || !required.core.features.imageCubeArray)
+ && (m_deviceFeatures.core.features.independentBlend
+ || !required.core.features.independentBlend)
+ && (m_deviceFeatures.core.features.geometryShader
+ || !required.core.features.geometryShader)
+ && (m_deviceFeatures.core.features.tessellationShader
+ || !required.core.features.tessellationShader)
+ && (m_deviceFeatures.core.features.sampleRateShading
+ || !required.core.features.sampleRateShading)
+ && (m_deviceFeatures.core.features.dualSrcBlend
+ || !required.core.features.dualSrcBlend)
+ && (m_deviceFeatures.core.features.logicOp
+ || !required.core.features.logicOp)
+ && (m_deviceFeatures.core.features.multiDrawIndirect
+ || !required.core.features.multiDrawIndirect)
+ && (m_deviceFeatures.core.features.drawIndirectFirstInstance
+ || !required.core.features.drawIndirectFirstInstance)
+ && (m_deviceFeatures.core.features.depthClamp
+ || !required.core.features.depthClamp)
+ && (m_deviceFeatures.core.features.depthBiasClamp
+ || !required.core.features.depthBiasClamp)
+ && (m_deviceFeatures.core.features.fillModeNonSolid
+ || !required.core.features.fillModeNonSolid)
+ && (m_deviceFeatures.core.features.depthBounds
+ || !required.core.features.depthBounds)
+ && (m_deviceFeatures.core.features.wideLines
+ || !required.core.features.wideLines)
+ && (m_deviceFeatures.core.features.largePoints
+ || !required.core.features.largePoints)
+ && (m_deviceFeatures.core.features.alphaToOne
+ || !required.core.features.alphaToOne)
+ && (m_deviceFeatures.core.features.multiViewport
+ || !required.core.features.multiViewport)
+ && (m_deviceFeatures.core.features.samplerAnisotropy
+ || !required.core.features.samplerAnisotropy)
+ && (m_deviceFeatures.core.features.textureCompressionETC2
+ || !required.core.features.textureCompressionETC2)
+ && (m_deviceFeatures.core.features.textureCompressionASTC_LDR
+ || !required.core.features.textureCompressionASTC_LDR)
+ && (m_deviceFeatures.core.features.textureCompressionBC
+ || !required.core.features.textureCompressionBC)
+ && (m_deviceFeatures.core.features.occlusionQueryPrecise
+ || !required.core.features.occlusionQueryPrecise)
+ && (m_deviceFeatures.core.features.pipelineStatisticsQuery
+ || !required.core.features.pipelineStatisticsQuery)
+ && (m_deviceFeatures.core.features.vertexPipelineStoresAndAtomics
+ || !required.core.features.vertexPipelineStoresAndAtomics)
+ && (m_deviceFeatures.core.features.fragmentStoresAndAtomics
+ || !required.core.features.fragmentStoresAndAtomics)
+ && (m_deviceFeatures.core.features.shaderTessellationAndGeometryPointSize
+ || !required.core.features.shaderTessellationAndGeometryPointSize)
+ && (m_deviceFeatures.core.features.shaderImageGatherExtended
+ || !required.core.features.shaderImageGatherExtended)
+ && (m_deviceFeatures.core.features.shaderStorageImageExtendedFormats
+ || !required.core.features.shaderStorageImageExtendedFormats)
+ && (m_deviceFeatures.core.features.shaderStorageImageMultisample
+ || !required.core.features.shaderStorageImageMultisample)
+ && (m_deviceFeatures.core.features.shaderStorageImageReadWithoutFormat
+ || !required.core.features.shaderStorageImageReadWithoutFormat)
+ && (m_deviceFeatures.core.features.shaderStorageImageWriteWithoutFormat
+ || !required.core.features.shaderStorageImageWriteWithoutFormat)
+ && (m_deviceFeatures.core.features.shaderUniformBufferArrayDynamicIndexing
+ || !required.core.features.shaderUniformBufferArrayDynamicIndexing)
+ && (m_deviceFeatures.core.features.shaderSampledImageArrayDynamicIndexing
+ || !required.core.features.shaderSampledImageArrayDynamicIndexing)
+ && (m_deviceFeatures.core.features.shaderStorageBufferArrayDynamicIndexing
+ || !required.core.features.shaderStorageBufferArrayDynamicIndexing)
+ && (m_deviceFeatures.core.features.shaderStorageImageArrayDynamicIndexing
+ || !required.core.features.shaderStorageImageArrayDynamicIndexing)
+ && (m_deviceFeatures.core.features.shaderClipDistance
+ || !required.core.features.shaderClipDistance)
+ && (m_deviceFeatures.core.features.shaderCullDistance
+ || !required.core.features.shaderCullDistance)
+ && (m_deviceFeatures.core.features.shaderFloat64
+ || !required.core.features.shaderFloat64)
+ && (m_deviceFeatures.core.features.shaderInt64
+ || !required.core.features.shaderInt64)
+ && (m_deviceFeatures.core.features.shaderInt16
+ || !required.core.features.shaderInt16)
+ && (m_deviceFeatures.core.features.shaderResourceResidency
+ || !required.core.features.shaderResourceResidency)
+ && (m_deviceFeatures.core.features.shaderResourceMinLod
+ || !required.core.features.shaderResourceMinLod)
+ && (m_deviceFeatures.core.features.sparseBinding
+ || !required.core.features.sparseBinding)
+ && (m_deviceFeatures.core.features.sparseResidencyBuffer
+ || !required.core.features.sparseResidencyBuffer)
+ && (m_deviceFeatures.core.features.sparseResidencyImage2D
+ || !required.core.features.sparseResidencyImage2D)
+ && (m_deviceFeatures.core.features.sparseResidencyImage3D
+ || !required.core.features.sparseResidencyImage3D)
+ && (m_deviceFeatures.core.features.sparseResidency2Samples
+ || !required.core.features.sparseResidency2Samples)
+ && (m_deviceFeatures.core.features.sparseResidency4Samples
+ || !required.core.features.sparseResidency4Samples)
+ && (m_deviceFeatures.core.features.sparseResidency8Samples
+ || !required.core.features.sparseResidency8Samples)
+ && (m_deviceFeatures.core.features.sparseResidency16Samples
+ || !required.core.features.sparseResidency16Samples)
+ && (m_deviceFeatures.core.features.sparseResidencyAliased
+ || !required.core.features.sparseResidencyAliased)
+ && (m_deviceFeatures.core.features.variableMultisampleRate
+ || !required.core.features.variableMultisampleRate)
+ && (m_deviceFeatures.core.features.inheritedQueries
+ || !required.core.features.inheritedQueries)
+ && (m_deviceFeatures.shaderDrawParameters.shaderDrawParameters
+ || !required.shaderDrawParameters.shaderDrawParameters)
+ && (m_deviceFeatures.ext4444Formats.formatA4R4G4B4
+ || !required.ext4444Formats.formatA4R4G4B4)
+ && (m_deviceFeatures.ext4444Formats.formatA4B4G4R4
+ || !required.ext4444Formats.formatA4B4G4R4)
+ && (m_deviceFeatures.extCustomBorderColor.customBorderColors
+ || !required.extCustomBorderColor.customBorderColors)
+ && (m_deviceFeatures.extCustomBorderColor.customBorderColorWithoutFormat
+ || !required.extCustomBorderColor.customBorderColorWithoutFormat)
+ && (m_deviceFeatures.extDepthClipEnable.depthClipEnable
+ || !required.extDepthClipEnable.depthClipEnable)
+ && (m_deviceFeatures.extExtendedDynamicState.extendedDynamicState
+ || !required.extExtendedDynamicState.extendedDynamicState)
+ && (m_deviceFeatures.extHostQueryReset.hostQueryReset
+ || !required.extHostQueryReset.hostQueryReset)
+ && (m_deviceFeatures.extMemoryPriority.memoryPriority
+ || !required.extMemoryPriority.memoryPriority)
+ && (m_deviceFeatures.extRobustness2.robustBufferAccess2
+ || !required.extRobustness2.robustBufferAccess2)
+ && (m_deviceFeatures.extRobustness2.robustImageAccess2
+ || !required.extRobustness2.robustImageAccess2)
+ && (m_deviceFeatures.extRobustness2.nullDescriptor
+ || !required.extRobustness2.nullDescriptor)
+ && (m_deviceFeatures.extTransformFeedback.transformFeedback
+ || !required.extTransformFeedback.transformFeedback)
+ && (m_deviceFeatures.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor
+ || !required.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor)
+ && (m_deviceFeatures.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor
+ || !required.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor);
+ }
+
+
+ void DxvkAdapter::enableExtensions(const DxvkNameSet& extensions) {
+ m_extraExtensions.merge(extensions);
+ }
+
+
+ Rc<DxvkDevice> DxvkAdapter::createDevice(
+ const Rc<DxvkInstance>& instance,
+ DxvkDeviceFeatures enabledFeatures) {
+ DxvkDeviceExtensions devExtensions;
+
+ std::array<DxvkExt*, 28> devExtensionList = {{
+ &devExtensions.amdMemoryOverallocationBehaviour,
+ &devExtensions.amdShaderFragmentMask,
+ &devExtensions.ext4444Formats,
+ &devExtensions.extConservativeRasterization,
+ &devExtensions.extCustomBorderColor,
+ &devExtensions.extDepthClipEnable,
+ &devExtensions.extExtendedDynamicState,
+ &devExtensions.extFullScreenExclusive,
+ &devExtensions.extHostQueryReset,
+ &devExtensions.extMemoryBudget,
+ &devExtensions.extMemoryPriority,
+ &devExtensions.extRobustness2,
+ &devExtensions.extShaderDemoteToHelperInvocation,
+ &devExtensions.extShaderStencilExport,
+ &devExtensions.extShaderViewportIndexLayer,
+ &devExtensions.extTransformFeedback,
+ &devExtensions.extVertexAttributeDivisor,
+ &devExtensions.khrBufferDeviceAddress,
+ &devExtensions.khrCreateRenderPass2,
+ &devExtensions.khrDepthStencilResolve,
+ &devExtensions.khrDrawIndirectCount,
+ &devExtensions.khrDriverProperties,
+ &devExtensions.khrImageFormatList,
+ &devExtensions.khrSamplerMirrorClampToEdge,
+ &devExtensions.khrShaderFloatControls,
+ &devExtensions.khrSwapchain,
+ &devExtensions.nvxBinaryImport,
+ &devExtensions.nvxImageViewHandle,
+ }};
+
+ // Only enable Cuda interop extensions in 64-bit builds in
+ // order to avoid potential driver or address space issues.
+ // VK_KHR_buffer_device_address is expensive on some drivers.
+ bool enableCudaInterop = !env::is32BitHostPlatform() &&
+ m_deviceExtensions.supports(devExtensions.nvxBinaryImport.name()) &&
+ m_deviceExtensions.supports(devExtensions.nvxImageViewHandle.name()) &&
+ m_deviceFeatures.khrBufferDeviceAddress.bufferDeviceAddress;
+
+ if (enableCudaInterop) {
+ devExtensions.nvxBinaryImport.setMode(DxvkExtMode::Optional);
+ devExtensions.nvxImageViewHandle.setMode(DxvkExtMode::Optional);
+ devExtensions.khrBufferDeviceAddress.setMode(DxvkExtMode::Optional);
+
+ enabledFeatures.khrBufferDeviceAddress.bufferDeviceAddress = VK_TRUE;
+ }
+
+ DxvkNameSet extensionsEnabled;
+
+ if (!m_deviceExtensions.enableExtensions(
+ devExtensionList.size(),
+ devExtensionList.data(),
+ extensionsEnabled))
+ throw DxvkError("DxvkAdapter: Failed to create device");
+
+ // Enable additional extensions if necessary
+ extensionsEnabled.merge(m_extraExtensions);
+ DxvkNameList extensionNameList = extensionsEnabled.toNameList();
+
+ // Enable additional device features if supported
+ enabledFeatures.extExtendedDynamicState.extendedDynamicState = m_deviceFeatures.extExtendedDynamicState.extendedDynamicState;
+
+ enabledFeatures.ext4444Formats.formatA4B4G4R4 = m_deviceFeatures.ext4444Formats.formatA4B4G4R4;
+ enabledFeatures.ext4444Formats.formatA4R4G4B4 = m_deviceFeatures.ext4444Formats.formatA4R4G4B4;
+
+ Logger::info(str::format("Device properties:"
+ "\n Device name: : ", m_deviceInfo.core.properties.deviceName,
+ "\n Driver version : ",
+ VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
+ VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
+ VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
+
+ Logger::info("Enabled device extensions:");
+ this->logNameList(extensionNameList);
+ this->logFeatures(enabledFeatures);
+
+ // Create pNext chain for additional device features
+ enabledFeatures.core.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
+ enabledFeatures.core.pNext = nullptr;
+
+ enabledFeatures.shaderDrawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
+ enabledFeatures.shaderDrawParameters.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.shaderDrawParameters);
+
+ if (devExtensions.ext4444Formats) {
+ enabledFeatures.ext4444Formats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT;
+ enabledFeatures.ext4444Formats.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.ext4444Formats);
+ }
+
+ if (devExtensions.extCustomBorderColor) {
+ enabledFeatures.extCustomBorderColor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
+ enabledFeatures.extCustomBorderColor.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extCustomBorderColor);
+ }
+
+ if (devExtensions.extDepthClipEnable) {
+ enabledFeatures.extDepthClipEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT;
+ enabledFeatures.extDepthClipEnable.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extDepthClipEnable);
+ }
+
+ if (devExtensions.extExtendedDynamicState) {
+ enabledFeatures.extExtendedDynamicState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
+ enabledFeatures.extExtendedDynamicState.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extExtendedDynamicState);
+ }
+
+ if (devExtensions.extHostQueryReset) {
+ enabledFeatures.extHostQueryReset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT;
+ enabledFeatures.extHostQueryReset.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extHostQueryReset);
+ }
+
+ if (devExtensions.extMemoryPriority) {
+ enabledFeatures.extMemoryPriority.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT;
+ enabledFeatures.extMemoryPriority.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extMemoryPriority);
+ }
+
+ if (devExtensions.extShaderDemoteToHelperInvocation) {
+ enabledFeatures.extShaderDemoteToHelperInvocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
+ enabledFeatures.extShaderDemoteToHelperInvocation.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extShaderDemoteToHelperInvocation);
+ }
+
+ if (devExtensions.extRobustness2) {
+ enabledFeatures.extRobustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
+ enabledFeatures.extRobustness2.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extRobustness2);
+ }
+
+ if (devExtensions.extTransformFeedback) {
+ enabledFeatures.extTransformFeedback.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
+ enabledFeatures.extTransformFeedback.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extTransformFeedback);
+ }
+
+ if (devExtensions.extVertexAttributeDivisor.revision() >= 3) {
+ enabledFeatures.extVertexAttributeDivisor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+ enabledFeatures.extVertexAttributeDivisor.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extVertexAttributeDivisor);
+ }
+
+ if (devExtensions.khrBufferDeviceAddress) {
+ enabledFeatures.khrBufferDeviceAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
+ enabledFeatures.khrBufferDeviceAddress.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrBufferDeviceAddress);
+ }
+
+ // Report the desired overallocation behaviour to the driver
+ VkDeviceMemoryOverallocationCreateInfoAMD overallocInfo;
+ overallocInfo.sType = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD;
+ overallocInfo.pNext = nullptr;
+ overallocInfo.overallocationBehavior = VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD;
+
+ // Create the requested queues
+ float queuePriority = 1.0f;
+ std::vector<VkDeviceQueueCreateInfo> queueInfos;
+
+ std::unordered_set<uint32_t> queueFamiliySet;
+
+ DxvkAdapterQueueIndices queueFamilies = findQueueFamilies();
+ queueFamiliySet.insert(queueFamilies.graphics);
+ queueFamiliySet.insert(queueFamilies.transfer);
+ this->logQueueFamilies(queueFamilies);
+
+ for (uint32_t family : queueFamiliySet) {
+ VkDeviceQueueCreateInfo graphicsQueue;
+ graphicsQueue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ graphicsQueue.pNext = nullptr;
+ graphicsQueue.flags = 0;
+ graphicsQueue.queueFamilyIndex = family;
+ graphicsQueue.queueCount = 1;
+ graphicsQueue.pQueuePriorities = &queuePriority;
+ queueInfos.push_back(graphicsQueue);
+ }
+
+ VkDeviceCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ info.pNext = enabledFeatures.core.pNext;
+ info.flags = 0;
+ info.queueCreateInfoCount = queueInfos.size();
+ info.pQueueCreateInfos = queueInfos.data();
+ info.enabledLayerCount = 0;
+ info.ppEnabledLayerNames = nullptr;
+ info.enabledExtensionCount = extensionNameList.count();
+ info.ppEnabledExtensionNames = extensionNameList.names();
+ info.pEnabledFeatures = &enabledFeatures.core.features;
+
+ if (devExtensions.amdMemoryOverallocationBehaviour)
+ overallocInfo.pNext = std::exchange(info.pNext, &overallocInfo);
+
+ VkDevice device = VK_NULL_HANDLE;
+ VkResult vr = m_vki->vkCreateDevice(m_handle, &info, nullptr, &device);
+
+ if (vr != VK_SUCCESS && enableCudaInterop) {
+ // Enabling certain Vulkan extensions can cause device creation to fail on
+ // Nvidia drivers if a certain kernel module isn't loaded, but we cannot know
+ // that in advance since the extensions are reported as supported anyway.
+ Logger::err("DxvkAdapter: Failed to create device, retrying without CUDA interop extensions");
+
+ extensionsEnabled.disableExtension(devExtensions.khrBufferDeviceAddress);
+ extensionsEnabled.disableExtension(devExtensions.nvxBinaryImport);
+ extensionsEnabled.disableExtension(devExtensions.nvxImageViewHandle);
+
+ enabledFeatures.khrBufferDeviceAddress.bufferDeviceAddress = VK_FALSE;
+
+ vk::removeStructFromPNextChain(&enabledFeatures.core.pNext,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR);
+
+ extensionNameList = extensionsEnabled.toNameList();
+ info.enabledExtensionCount = extensionNameList.count();
+ info.ppEnabledExtensionNames = extensionNameList.names();
+
+ vr = m_vki->vkCreateDevice(m_handle, &info, nullptr, &device);
+ }
+
+ if (vr != VK_SUCCESS)
+ throw DxvkError("DxvkAdapter: Failed to create device");
+
+ Rc<DxvkDevice> result = new DxvkDevice(instance, this,
+ new vk::DeviceFn(true, m_vki->instance(), device),
+ devExtensions, enabledFeatures);
+ result->initResources();
+ return result;
+ }
+
+
+ void DxvkAdapter::notifyHeapMemoryAlloc(
+ uint32_t heap,
+ VkDeviceSize bytes) {
+ if (!m_hasMemoryBudget)
+ m_heapAlloc[heap] += bytes;
+ }
+
+
+ void DxvkAdapter::notifyHeapMemoryFree(
+ uint32_t heap,
+ VkDeviceSize bytes) {
+ if (!m_hasMemoryBudget)
+ m_heapAlloc[heap] -= bytes;
+ }
+
+
+ bool DxvkAdapter::matchesDriver(
+ DxvkGpuVendor vendor,
+ VkDriverIdKHR driver,
+ uint32_t minVer,
+ uint32_t maxVer) const {
+ bool driverMatches = m_deviceInfo.khrDeviceDriverProperties.driverID
+ ? driver == m_deviceInfo.khrDeviceDriverProperties.driverID
+ : vendor == DxvkGpuVendor(m_deviceInfo.core.properties.vendorID);
+
+ if (minVer) driverMatches &= m_deviceInfo.core.properties.driverVersion >= minVer;
+ if (maxVer) driverMatches &= m_deviceInfo.core.properties.driverVersion < maxVer;
+
+ return driverMatches;
+ }
+
+
+ void DxvkAdapter::logAdapterInfo() const {
+ VkPhysicalDeviceProperties deviceInfo = this->deviceProperties();
+ VkPhysicalDeviceMemoryProperties memoryInfo = this->memoryProperties();
+
+ Logger::info(str::format(deviceInfo.deviceName, ":"));
+ Logger::info(str::format(" Driver: ",
+ VK_VERSION_MAJOR(deviceInfo.driverVersion), ".",
+ VK_VERSION_MINOR(deviceInfo.driverVersion), ".",
+ VK_VERSION_PATCH(deviceInfo.driverVersion)));
+ Logger::info(str::format(" Vulkan: ",
+ VK_VERSION_MAJOR(deviceInfo.apiVersion), ".",
+ VK_VERSION_MINOR(deviceInfo.apiVersion), ".",
+ VK_VERSION_PATCH(deviceInfo.apiVersion)));
+
+ for (uint32_t i = 0; i < memoryInfo.memoryHeapCount; i++) {
+ constexpr VkDeviceSize mib = 1024 * 1024;
+
+ Logger::info(str::format(" Memory Heap[", i, "]: "));
+ Logger::info(str::format(" Size: ", memoryInfo.memoryHeaps[i].size / mib, " MiB"));
+ Logger::info(str::format(" Flags: ", "0x", std::hex, memoryInfo.memoryHeaps[i].flags));
+
+ for (uint32_t j = 0; j < memoryInfo.memoryTypeCount; j++) {
+ if (memoryInfo.memoryTypes[j].heapIndex == i) {
+ Logger::info(str::format(
+ " Memory Type[", j, "]: ",
+ "Property Flags = ", "0x", std::hex, memoryInfo.memoryTypes[j].propertyFlags));
+ }
+ }
+ }
+ }
+
+
+ bool DxvkAdapter::isUnifiedMemoryArchitecture() const {
+ auto memory = this->memoryProperties();
+ bool result = true;
+
+ for (uint32_t i = 0; i < memory.memoryHeapCount; i++)
+ result &= memory.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+
+ return result;
+ }
+
+
+ void DxvkAdapter::initHeapAllocInfo() {
+ for (uint32_t i = 0; i < m_heapAlloc.size(); i++)
+ m_heapAlloc[i] = 0;
+ }
+
+
+ void DxvkAdapter::queryExtensions() {
+ m_deviceExtensions = DxvkNameSet::enumDeviceExtensions(m_vki, m_handle);
+ }
+
+
+ void DxvkAdapter::queryDeviceInfo() {
+ m_deviceInfo = DxvkDeviceInfo();
+ m_deviceInfo.core.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ m_deviceInfo.core.pNext = nullptr;
+
+ // Query info now so that we have basic device properties available
+ m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
+
+ m_deviceInfo.coreDeviceId.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+ m_deviceInfo.coreDeviceId.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.coreDeviceId);
+
+ m_deviceInfo.coreSubgroup.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ m_deviceInfo.coreSubgroup.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.coreSubgroup);
+
+ if (m_deviceExtensions.supports(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
+ m_deviceInfo.extConservativeRasterization.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
+ m_deviceInfo.extConservativeRasterization.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.extConservativeRasterization);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME)) {
+ m_deviceInfo.extCustomBorderColor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT;
+ m_deviceInfo.extCustomBorderColor.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.extCustomBorderColor);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
+ m_deviceInfo.extRobustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT;
+ m_deviceInfo.extRobustness2.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.extRobustness2);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME)) {
+ m_deviceInfo.extTransformFeedback.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
+ m_deviceInfo.extTransformFeedback.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.extTransformFeedback);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
+ m_deviceInfo.extVertexAttributeDivisor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
+ m_deviceInfo.extVertexAttributeDivisor.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.extVertexAttributeDivisor);
+ }
+
+ if (m_deviceExtensions.supports(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
+ m_deviceInfo.khrDepthStencilResolve.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR;
+ m_deviceInfo.khrDepthStencilResolve.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.khrDepthStencilResolve);
+ }
+
+ if (m_deviceExtensions.supports(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) {
+ m_deviceInfo.khrDeviceDriverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
+ m_deviceInfo.khrDeviceDriverProperties.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.khrDeviceDriverProperties);
+ }
+
+ if (m_deviceExtensions.supports(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)) {
+ m_deviceInfo.khrShaderFloatControls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR;
+ m_deviceInfo.khrShaderFloatControls.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.khrShaderFloatControls);
+ }
+
+ // Query full device properties for all enabled extensions
+ m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
+
+ // Nvidia reports the driver version in a slightly different format
+ if (DxvkGpuVendor(m_deviceInfo.core.properties.vendorID) == DxvkGpuVendor::Nvidia) {
+ m_deviceInfo.core.properties.driverVersion = VK_MAKE_VERSION(
+ VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion),
+ VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion >> 0) >> 2,
+ VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion >> 2) >> 4);
+ }
+ }
+
+
+ void DxvkAdapter::queryDeviceFeatures() {
+ m_deviceFeatures = DxvkDeviceFeatures();
+ m_deviceFeatures.core.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ m_deviceFeatures.core.pNext = nullptr;
+
+ m_deviceFeatures.shaderDrawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
+ m_deviceFeatures.shaderDrawParameters.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.shaderDrawParameters);
+
+ if (m_deviceExtensions.supports(VK_EXT_4444_FORMATS_EXTENSION_NAME)) {
+ m_deviceFeatures.ext4444Formats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT;
+ m_deviceFeatures.ext4444Formats.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.ext4444Formats);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME)) {
+ m_deviceFeatures.extCustomBorderColor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
+ m_deviceFeatures.extCustomBorderColor.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extCustomBorderColor);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME)) {
+ m_deviceFeatures.extDepthClipEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT;
+ m_deviceFeatures.extDepthClipEnable.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extDepthClipEnable);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME)) {
+ m_deviceFeatures.extExtendedDynamicState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
+ m_deviceFeatures.extExtendedDynamicState.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extExtendedDynamicState);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME)) {
+ m_deviceFeatures.extHostQueryReset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT;
+ m_deviceFeatures.extHostQueryReset.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extHostQueryReset);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) {
+ m_deviceFeatures.extMemoryPriority.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT;
+ m_deviceFeatures.extMemoryPriority.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extMemoryPriority);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
+ m_deviceFeatures.extRobustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
+ m_deviceFeatures.extRobustness2.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extRobustness2);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME)) {
+ m_deviceFeatures.extShaderDemoteToHelperInvocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
+ m_deviceFeatures.extShaderDemoteToHelperInvocation.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extShaderDemoteToHelperInvocation);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME)) {
+ m_deviceFeatures.extTransformFeedback.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
+ m_deviceFeatures.extTransformFeedback.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extTransformFeedback);
+ }
+
+ if (m_deviceExtensions.supports(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) >= 3) {
+ m_deviceFeatures.extVertexAttributeDivisor.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
+ m_deviceFeatures.extVertexAttributeDivisor.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extVertexAttributeDivisor);
+ }
+
+ if (m_deviceExtensions.supports(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) {
+ m_deviceFeatures.khrBufferDeviceAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
+ m_deviceFeatures.khrBufferDeviceAddress.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrBufferDeviceAddress);
+ }
+
+ m_vki->vkGetPhysicalDeviceFeatures2(m_handle, &m_deviceFeatures.core);
+ }
+
+
+ void DxvkAdapter::queryDeviceQueues() {
+ uint32_t numQueueFamilies = 0;
+ m_vki->vkGetPhysicalDeviceQueueFamilyProperties(
+ m_handle, &numQueueFamilies, nullptr);
+
+ m_queueFamilies.resize(numQueueFamilies);
+ m_vki->vkGetPhysicalDeviceQueueFamilyProperties(
+ m_handle, &numQueueFamilies, m_queueFamilies.data());
+ }
+
+
+ uint32_t DxvkAdapter::findQueueFamily(
+ VkQueueFlags mask,
+ VkQueueFlags flags) const {
+ for (uint32_t i = 0; i < m_queueFamilies.size(); i++) {
+ if ((m_queueFamilies[i].queueFlags & mask) == flags)
+ return i;
+ }
+
+ return VK_QUEUE_FAMILY_IGNORED;
+ }
+
+
+ void DxvkAdapter::logNameList(const DxvkNameList& names) {
+ for (uint32_t i = 0; i < names.count(); i++)
+ Logger::info(str::format(" ", names.name(i)));
+ }
+
+
+ void DxvkAdapter::logFeatures(const DxvkDeviceFeatures& features) {
+ Logger::info(str::format("Device features:",
+ "\n robustBufferAccess : ", features.core.features.robustBufferAccess ? "1" : "0",
+ "\n fullDrawIndexUint32 : ", features.core.features.fullDrawIndexUint32 ? "1" : "0",
+ "\n imageCubeArray : ", features.core.features.imageCubeArray ? "1" : "0",
+ "\n independentBlend : ", features.core.features.independentBlend ? "1" : "0",
+ "\n geometryShader : ", features.core.features.geometryShader ? "1" : "0",
+ "\n tessellationShader : ", features.core.features.tessellationShader ? "1" : "0",
+ "\n sampleRateShading : ", features.core.features.sampleRateShading ? "1" : "0",
+ "\n dualSrcBlend : ", features.core.features.dualSrcBlend ? "1" : "0",
+ "\n logicOp : ", features.core.features.logicOp ? "1" : "0",
+ "\n multiDrawIndirect : ", features.core.features.multiDrawIndirect ? "1" : "0",
+ "\n drawIndirectFirstInstance : ", features.core.features.drawIndirectFirstInstance ? "1" : "0",
+ "\n depthClamp : ", features.core.features.depthClamp ? "1" : "0",
+ "\n depthBiasClamp : ", features.core.features.depthBiasClamp ? "1" : "0",
+ "\n fillModeNonSolid : ", features.core.features.fillModeNonSolid ? "1" : "0",
+ "\n depthBounds : ", features.core.features.depthBounds ? "1" : "0",
+ "\n multiViewport : ", features.core.features.multiViewport ? "1" : "0",
+ "\n samplerAnisotropy : ", features.core.features.samplerAnisotropy ? "1" : "0",
+ "\n textureCompressionBC : ", features.core.features.textureCompressionBC ? "1" : "0",
+ "\n occlusionQueryPrecise : ", features.core.features.occlusionQueryPrecise ? "1" : "0",
+ "\n pipelineStatisticsQuery : ", features.core.features.pipelineStatisticsQuery ? "1" : "0",
+ "\n vertexPipelineStoresAndAtomics : ", features.core.features.vertexPipelineStoresAndAtomics ? "1" : "0",
+ "\n fragmentStoresAndAtomics : ", features.core.features.fragmentStoresAndAtomics ? "1" : "0",
+ "\n shaderImageGatherExtended : ", features.core.features.shaderImageGatherExtended ? "1" : "0",
+ "\n shaderStorageImageExtendedFormats : ", features.core.features.shaderStorageImageExtendedFormats ? "1" : "0",
+ "\n shaderStorageImageReadWithoutFormat : ", features.core.features.shaderStorageImageReadWithoutFormat ? "1" : "0",
+ "\n shaderStorageImageWriteWithoutFormat : ", features.core.features.shaderStorageImageWriteWithoutFormat ? "1" : "0",
+ "\n shaderClipDistance : ", features.core.features.shaderClipDistance ? "1" : "0",
+ "\n shaderCullDistance : ", features.core.features.shaderCullDistance ? "1" : "0",
+ "\n shaderFloat64 : ", features.core.features.shaderFloat64 ? "1" : "0",
+ "\n shaderInt64 : ", features.core.features.shaderInt64 ? "1" : "0",
+ "\n variableMultisampleRate : ", features.core.features.variableMultisampleRate ? "1" : "0",
+ "\n", VK_EXT_4444_FORMATS_EXTENSION_NAME,
+ "\n formatA4R4G4B4 : ", features.ext4444Formats.formatA4R4G4B4 ? "1" : "0",
+ "\n formatA4B4G4R4 : ", features.ext4444Formats.formatA4B4G4R4 ? "1" : "0",
+ "\n", VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME,
+ "\n customBorderColors : ", features.extCustomBorderColor.customBorderColors ? "1" : "0",
+ "\n customBorderColorWithoutFormat : ", features.extCustomBorderColor.customBorderColorWithoutFormat ? "1" : "0",
+ "\n", VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,
+ "\n depthClipEnable : ", features.extDepthClipEnable.depthClipEnable ? "1" : "0",
+ "\n", VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME,
+ "\n extendedDynamicState : ", features.extExtendedDynamicState.extendedDynamicState ? "1" : "0",
+ "\n", VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
+ "\n hostQueryReset : ", features.extHostQueryReset.hostQueryReset ? "1" : "0",
+ "\n", VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME,
+ "\n memoryPriority : ", features.extMemoryPriority.memoryPriority ? "1" : "0",
+ "\n", VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
+ "\n robustBufferAccess2 : ", features.extRobustness2.robustBufferAccess2 ? "1" : "0",
+ "\n robustImageAccess2 : ", features.extRobustness2.robustImageAccess2 ? "1" : "0",
+ "\n nullDescriptor : ", features.extRobustness2.nullDescriptor ? "1" : "0",
+ "\n", VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
+ "\n shaderDemoteToHelperInvocation : ", features.extShaderDemoteToHelperInvocation.shaderDemoteToHelperInvocation ? "1" : "0",
+ "\n", VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME,
+ "\n transformFeedback : ", features.extTransformFeedback.transformFeedback ? "1" : "0",
+ "\n geometryStreams : ", features.extTransformFeedback.geometryStreams ? "1" : "0",
+ "\n", VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
+ "\n vertexAttributeInstanceRateDivisor : ", features.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor ? "1" : "0",
+ "\n vertexAttributeInstanceRateZeroDivisor : ", features.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor ? "1" : "0",
+ "\n", VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
+ "\n bufferDeviceAddress : ", features.khrBufferDeviceAddress.bufferDeviceAddress));
+ }
+
+
+ void DxvkAdapter::logQueueFamilies(const DxvkAdapterQueueIndices& queues) {
+ Logger::info(str::format("Queue families:",
+ "\n Graphics : ", queues.graphics,
+ "\n Transfer : ", queues.transfer));
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.h
new file mode 100644
index 00000000..f2fb1f0a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_adapter.h
@@ -0,0 +1,291 @@
+#pragma once
+
+#include "dxvk_device_info.h"
+#include "dxvk_extensions.h"
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+ class DxvkInstance;
+
+ /**
+ * \brief GPU vendors
+ * Based on PCIe IDs.
+ */
+ enum class DxvkGpuVendor : uint16_t {
+ Amd = 0x1002,
+ Nvidia = 0x10de,
+ Intel = 0x8086,
+ };
+
+ /**
+ * \brief Adapter memory heap info
+ *
+ * Stores info about a heap, and the amount
+ * of memory allocated from it by the app.
+ */
+ struct DxvkAdapterMemoryHeapInfo {
+ VkMemoryHeapFlags heapFlags;
+ VkDeviceSize memoryBudget;
+ VkDeviceSize memoryAllocated;
+ };
+
+ /**
+ * \brief Adapter memory info
+ *
+ * Stores properties and allocation
+ * info of each available heap.
+ */
+ struct DxvkAdapterMemoryInfo {
+ uint32_t heapCount;
+ DxvkAdapterMemoryHeapInfo heaps[VK_MAX_MEMORY_HEAPS];
+ };
+
+ /**
+ * \brief Retrieves queue indices
+ */
+ struct DxvkAdapterQueueIndices {
+ uint32_t graphics;
+ uint32_t transfer;
+ };
+
+ /**
+ * \brief DXVK adapter
+ *
+ * Corresponds to a physical device in Vulkan. Provides
+ * all kinds of information about the device itself and
+ * the supported feature set.
+ */
+ class DxvkAdapter : public RcObject {
+
+ public:
+
+ DxvkAdapter(
+ const Rc<vk::InstanceFn>& vki,
+ VkPhysicalDevice handle);
+ ~DxvkAdapter();
+
+ /**
+ * \brief Vulkan instance functions
+ * \returns Vulkan instance functions
+ */
+ Rc<vk::InstanceFn> vki() const {
+ return m_vki;
+ }
+
+ /**
+ * \brief Physical device handle
+ * \returns The adapter handle
+ */
+ VkPhysicalDevice handle() const {
+ return m_handle;
+ }
+
+ /**
+ * \brief Physical device properties
+ *
+ * Returns a read-only reference to the core
+ * properties of the Vulkan physical device.
+ * \returns Physical device core properties
+ */
+ const VkPhysicalDeviceProperties& deviceProperties() const {
+ return m_deviceInfo.core.properties;
+ }
+
+ /**
+ * \brief Device info
+ *
+ * Returns a read-only reference to the full
+ * device info structure, including extended
+ * properties.
+ * \returns Device info struct
+ */
+ const DxvkDeviceInfo& devicePropertiesExt() const {
+ return m_deviceInfo;
+ }
+
+ /**
+ * \brief Supportred device features
+ *
+ * Queries the supported device features.
+ * \returns Device features
+ */
+ const DxvkDeviceFeatures& features() const {
+ return m_deviceFeatures;
+ }
+
+ /**
+ * \brief Retrieves memory heap info
+ *
+ * Returns properties of all available memory heaps,
+ * both device-local and non-local heaps, and the
+ * amount of memory allocated from those heaps by
+ * logical devices.
+ * \returns Memory heap info
+ */
+ DxvkAdapterMemoryInfo getMemoryHeapInfo() const;
+
+ /**
+ * \brief Memory properties
+ *
+ * Queries the memory types and memory heaps of
+ * the device. This is useful for memory allocators.
+ * \returns Device memory properties
+ */
+ VkPhysicalDeviceMemoryProperties memoryProperties() const;
+
+ /**
+ * \brief Queries format support
+ *
+ * \param [in] format The format to query
+ * \returns Format support info
+ */
+ VkFormatProperties formatProperties(
+ VkFormat format) const;
+
+ /**
+ * \brief Queries image format support
+ *
+ * \param [in] format Format to query
+ * \param [in] type Image type
+ * \param [in] tiling Image tiling
+ * \param [in] usage Image usage flags
+ * \param [in] flags Image create flags
+ * \param [out] properties Format properties
+ * \returns \c VK_SUCCESS or \c VK_ERROR_FORMAT_NOT_SUPPORTED
+ */
+ VkResult imageFormatProperties(
+ VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags,
+ VkImageFormatProperties& properties) const;
+
+ /**
+ * \brief Retrieves queue family indices
+ * \returns Indices for all queue families
+ */
+ DxvkAdapterQueueIndices findQueueFamilies() const;
+
+ /**
+ * \brief Tests whether all required features are supported
+ *
+ * \param [in] features Required device features
+ * \returns \c true if all features are supported
+ */
+ bool checkFeatureSupport(
+ const DxvkDeviceFeatures& required) const;
+
+ /**
+ * \brief Enables extensions for this adapter
+ *
+ * When creating a device, all extensions that
+ * are added using this method will be enabled
+ * in addition to the ones required by DXVK.
+ * This is used for OpenVR support.
+ */
+ void enableExtensions(
+ const DxvkNameSet& extensions);
+
+ /**
+ * \brief Creates a DXVK device
+ *
+ * Creates a logical device for this adapter.
+ * \param [in] instance Parent instance
+ * \param [in] enabledFeatures Device features
+ * \returns Device handle
+ */
+ Rc<DxvkDevice> createDevice(
+ const Rc<DxvkInstance>& instance,
+ DxvkDeviceFeatures enabledFeatures);
+
+ /**
+ * \brief Registers memory allocation
+ *
+ * Updates memory alloc info accordingly.
+ * \param [in] heap Memory heap index
+ * \param [in] bytes Allocation size
+ */
+ void notifyHeapMemoryAlloc(
+ uint32_t heap,
+ VkDeviceSize bytes);
+
+ /**
+ * \brief Registers memory deallocation
+ *
+ * Updates memory alloc info accordingly.
+ * \param [in] heap Memory heap index
+ * \param [in] bytes Allocation size
+ */
+ void notifyHeapMemoryFree(
+ uint32_t heap,
+ VkDeviceSize bytes);
+
+ /**
+ * \brief Tests if the driver matches certain criteria
+ *
+ * \param [in] vendor GPU vendor
+ * \param [in] driver Driver. Ignored when the
+ * driver properties extension is not supported.
+ * \param [in] minVer Match versions starting with this one
+ * \param [in] maxVer Match versions lower than this one
+ * \returns \c True if the driver matches these criteria
+ */
+ bool matchesDriver(
+ DxvkGpuVendor vendor,
+ VkDriverIdKHR driver,
+ uint32_t minVer,
+ uint32_t maxVer) const;
+
+ /**
+ * \brief Logs DXVK adapter info
+ *
+ * May be useful for bug reports
+ * and general troubleshooting.
+ */
+ void logAdapterInfo() const;
+
+ /**
+ * \brief Checks whether this is a UMA system
+ *
+ * Basically tests whether all heaps are device-local.
+ * Can be used for various optimizations in client APIs.
+ * \returns \c true if the system has unified memory.
+ */
+ bool isUnifiedMemoryArchitecture() const;
+
+ private:
+
+ Rc<vk::InstanceFn> m_vki;
+ VkPhysicalDevice m_handle;
+
+ DxvkNameSet m_extraExtensions;
+ DxvkNameSet m_deviceExtensions;
+ DxvkDeviceInfo m_deviceInfo;
+ DxvkDeviceFeatures m_deviceFeatures;
+
+ bool m_hasMemoryBudget;
+
+ std::vector<VkQueueFamilyProperties> m_queueFamilies;
+
+ std::array<std::atomic<VkDeviceSize>, VK_MAX_MEMORY_HEAPS> m_heapAlloc;
+
+ void initHeapAllocInfo();
+ void queryExtensions();
+ void queryDeviceInfo();
+ void queryDeviceFeatures();
+ void queryDeviceQueues();
+
+ uint32_t findQueueFamily(
+ VkQueueFlags mask,
+ VkQueueFlags flags) const;
+
+ static void logNameList(const DxvkNameList& names);
+ static void logFeatures(const DxvkDeviceFeatures& features);
+ static void logQueueFamilies(const DxvkAdapterQueueIndices& queues);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.cpp
new file mode 100644
index 00000000..b0be24d0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.cpp
@@ -0,0 +1,288 @@
+#include "dxvk_barrier.h"
+
+namespace dxvk {
+
+ DxvkBarrierSet:: DxvkBarrierSet(DxvkCmdBuffer cmdBuffer)
+ : m_cmdBuffer(cmdBuffer) {
+
+ }
+
+
+ DxvkBarrierSet::~DxvkBarrierSet() {
+
+ }
+
+
+ void DxvkBarrierSet::accessMemory(
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ m_srcStages |= srcStages;
+ m_dstStages |= dstStages;
+
+ m_srcAccess |= srcAccess;
+ m_dstAccess |= dstAccess;
+ }
+
+
+ void DxvkBarrierSet::accessBuffer(
+ const DxvkBufferSliceHandle& bufSlice,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ DxvkAccessFlags access = this->getAccessTypes(srcAccess);
+
+ if (srcStages == VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
+ || dstStages == VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT)
+ access.set(DxvkAccess::Write);
+
+ m_srcStages |= srcStages;
+ m_dstStages |= dstStages;
+
+ m_srcAccess |= srcAccess;
+ m_dstAccess |= dstAccess;
+
+ m_bufSlices.insert(bufSlice.handle,
+ DxvkBarrierBufferSlice(bufSlice.offset, bufSlice.length, access));
+ }
+
+
+ void DxvkBarrierSet::accessImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout srcLayout,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ DxvkAccessFlags access = this->getAccessTypes(srcAccess);
+
+ if (srcStages == VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT
+ || dstStages == VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
+ || srcLayout != dstLayout)
+ access.set(DxvkAccess::Write);
+
+ m_srcStages |= srcStages;
+ m_dstStages |= dstStages;
+
+ if (srcLayout == dstLayout) {
+ m_srcAccess |= srcAccess;
+ m_dstAccess |= dstAccess;
+ } else {
+ VkImageMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.srcAccessMask = srcAccess;
+ barrier.dstAccessMask = dstAccess;
+ barrier.oldLayout = srcLayout;
+ barrier.newLayout = dstLayout;
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.image = image->handle();
+ barrier.subresourceRange = subresources;
+ barrier.subresourceRange.aspectMask = image->formatInfo()->aspectMask;
+ m_imgBarriers.push_back(barrier);
+ }
+
+ m_imgSlices.insert(image->handle(),
+ DxvkBarrierImageSlice(subresources, access));
+ }
+
+
+ void DxvkBarrierSet::releaseBuffer(
+ DxvkBarrierSet& acquire,
+ const DxvkBufferSliceHandle& bufSlice,
+ uint32_t srcQueue,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ uint32_t dstQueue,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ auto& release = *this;
+
+ release.m_srcStages |= srcStages;
+ acquire.m_dstStages |= dstStages;
+
+ VkBufferMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.srcAccessMask = srcAccess;
+ barrier.dstAccessMask = 0;
+ barrier.srcQueueFamilyIndex = srcQueue;
+ barrier.dstQueueFamilyIndex = dstQueue;
+ barrier.buffer = bufSlice.handle;
+ barrier.offset = bufSlice.offset;
+ barrier.size = bufSlice.length;
+ release.m_bufBarriers.push_back(barrier);
+
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = dstAccess;
+ acquire.m_bufBarriers.push_back(barrier);
+
+ DxvkAccessFlags access(DxvkAccess::Read, DxvkAccess::Write);
+ release.m_bufSlices.insert(bufSlice.handle,
+ DxvkBarrierBufferSlice(bufSlice.offset, bufSlice.length, access));
+ acquire.m_bufSlices.insert(bufSlice.handle,
+ DxvkBarrierBufferSlice(bufSlice.offset, bufSlice.length, access));
+ }
+
+
+ void DxvkBarrierSet::releaseImage(
+ DxvkBarrierSet& acquire,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ uint32_t srcQueue,
+ VkImageLayout srcLayout,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ uint32_t dstQueue,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ auto& release = *this;
+
+ release.m_srcStages |= srcStages;
+ acquire.m_dstStages |= dstStages;
+
+ VkImageMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.srcAccessMask = srcAccess;
+ barrier.dstAccessMask = 0;
+ barrier.oldLayout = srcLayout;
+ barrier.newLayout = dstLayout;
+ barrier.srcQueueFamilyIndex = srcQueue;
+ barrier.dstQueueFamilyIndex = dstQueue;
+ barrier.image = image->handle();
+ barrier.subresourceRange = subresources;
+ barrier.subresourceRange.aspectMask = image->formatInfo()->aspectMask;
+ release.m_imgBarriers.push_back(barrier);
+
+ if (srcQueue == dstQueue)
+ barrier.oldLayout = dstLayout;
+
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = dstAccess;
+ acquire.m_imgBarriers.push_back(barrier);
+
+ DxvkAccessFlags access(DxvkAccess::Read, DxvkAccess::Write);
+ release.m_imgSlices.insert(image->handle(),
+ DxvkBarrierImageSlice(subresources, access));
+ acquire.m_imgSlices.insert(image->handle(),
+ DxvkBarrierImageSlice(subresources, access));
+ }
+
+
+ bool DxvkBarrierSet::isBufferDirty(
+ const DxvkBufferSliceHandle& bufSlice,
+ DxvkAccessFlags bufAccess) {
+ return m_bufSlices.isDirty(bufSlice.handle,
+ DxvkBarrierBufferSlice(bufSlice.offset, bufSlice.length, bufAccess));
+ }
+
+
+ bool DxvkBarrierSet::isImageDirty(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& imgSubres,
+ DxvkAccessFlags imgAccess) {
+ return m_imgSlices.isDirty(image->handle(),
+ DxvkBarrierImageSlice(imgSubres, imgAccess));
+ }
+
+
+ DxvkAccessFlags DxvkBarrierSet::getBufferAccess(
+ const DxvkBufferSliceHandle& bufSlice) {
+ return m_bufSlices.getAccess(bufSlice.handle,
+ DxvkBarrierBufferSlice(bufSlice.offset, bufSlice.length, 0));
+ }
+
+
+ DxvkAccessFlags DxvkBarrierSet::getImageAccess(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& imgSubres) {
+ return m_imgSlices.getAccess(image->handle(),
+ DxvkBarrierImageSlice(imgSubres, 0));
+ }
+
+
+ void DxvkBarrierSet::recordCommands(const Rc<DxvkCommandList>& commandList) {
+ if (m_srcStages | m_dstStages) {
+ VkPipelineStageFlags srcFlags = m_srcStages;
+ VkPipelineStageFlags dstFlags = m_dstStages;
+
+ if (!srcFlags) srcFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ if (!dstFlags) dstFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+
+ VkMemoryBarrier memBarrier;
+ memBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ memBarrier.pNext = nullptr;
+ memBarrier.srcAccessMask = m_srcAccess;
+ memBarrier.dstAccessMask = m_dstAccess;
+
+ VkMemoryBarrier* pMemBarrier = nullptr;
+ if (m_srcAccess | m_dstAccess)
+ pMemBarrier = &memBarrier;
+
+ commandList->cmdPipelineBarrier(
+ m_cmdBuffer, srcFlags, dstFlags, 0,
+ pMemBarrier ? 1 : 0, pMemBarrier,
+ m_bufBarriers.size(),
+ m_bufBarriers.data(),
+ m_imgBarriers.size(),
+ m_imgBarriers.data());
+
+ this->reset();
+ }
+ }
+
+
+ void DxvkBarrierSet::reset() {
+ m_srcStages = 0;
+ m_dstStages = 0;
+
+ m_srcAccess = 0;
+ m_dstAccess = 0;
+
+ m_bufBarriers.resize(0);
+ m_imgBarriers.resize(0);
+
+ m_bufSlices.clear();
+ m_imgSlices.clear();
+ }
+
+
+ DxvkAccessFlags DxvkBarrierSet::getAccessTypes(VkAccessFlags flags) {
+ const VkAccessFlags rflags
+ = VK_ACCESS_INDIRECT_COMMAND_READ_BIT
+ | VK_ACCESS_INDEX_READ_BIT
+ | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
+ | VK_ACCESS_UNIFORM_READ_BIT
+ | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
+ | VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT
+ | VK_ACCESS_HOST_READ_BIT
+ | VK_ACCESS_MEMORY_READ_BIT
+ | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
+
+ const VkAccessFlags wflags
+ = VK_ACCESS_SHADER_WRITE_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+ | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_HOST_WRITE_BIT
+ | VK_ACCESS_MEMORY_WRITE_BIT
+ | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT
+ | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
+
+ DxvkAccessFlags result;
+ if (flags & rflags) result.set(DxvkAccess::Read);
+ if (flags & wflags) result.set(DxvkAccess::Write);
+ return result;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.h
new file mode 100644
index 00000000..f3629fa9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_barrier.h
@@ -0,0 +1,572 @@
+#pragma once
+
+#include <utility>
+#include <vector>
+
+#include "dxvk_buffer.h"
+#include "dxvk_cmdlist.h"
+#include "dxvk_image.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Buffer slice for barrier tracking
+ *
+ * Stores the offset and length of a buffer slice,
+ * as well as access flags for the given range.
+ */
+ class DxvkBarrierBufferSlice {
+
+ public:
+
+ DxvkBarrierBufferSlice()
+ : m_offset(0), m_length(0), m_access(0) { }
+
+ DxvkBarrierBufferSlice(VkDeviceSize offset, VkDeviceSize length, DxvkAccessFlags access)
+ : m_offset(offset), m_length(length), m_access(access) { }
+
+ /**
+ * \brief Checks whether two slices overlap
+ *
+ * \param [in] slice The other buffer slice to check
+ * \returns \c true if the two slices overlap
+ */
+ bool overlaps(const DxvkBarrierBufferSlice& slice) const {
+ return m_offset + m_length > slice.m_offset
+ && m_offset < slice.m_offset + slice.m_length;
+ }
+
+ /**
+ * \brief Checks whether a given slice is dirty
+ *
+ * \param [in] slice The buffer slice to check
+ * \returns \c true if the two slices overlap, and if
+ * at least one of the two slices have write access.
+ */
+ bool isDirty(const DxvkBarrierBufferSlice& slice) const {
+ return (slice.m_access | m_access).test(DxvkAccess::Write) && overlaps(slice);
+ }
+
+ /**
+ * \brief Checks whether two slices can be merged
+ *
+ * Two buffer slices can be merged if they overlap or are adjacent
+ * and if the access flags are the same, or alternatively, if the
+ * offset and size are the same and only the access flags differ.
+ * \param [in] slice The other buffer slice to check
+ * \returns \c true if the slices can be merged.
+ */
+ bool canMerge(const DxvkBarrierBufferSlice& slice) const {
+ if (m_access == slice.m_access) {
+ return m_offset + m_length >= slice.m_offset
+ && m_offset <= slice.m_offset + slice.m_length;
+ } else {
+ return m_offset == slice.m_offset
+ && m_length == slice.m_length;
+ }
+ }
+
+ /**
+ * \brief Merges two buffer slices
+ *
+ * The resulting slice is guaranteed to fully contain both slices,
+ * including their access flags. If called when \c canMerge would
+ * return \c false, this will be a strict superset of both slices.
+ * \param [in] slice The slice to merge
+ */
+ void merge(const DxvkBarrierBufferSlice& slice) {
+ VkDeviceSize end = std::max(m_offset + m_length, slice.m_offset + slice.m_length);
+
+ m_offset = std::min(m_offset, slice.m_offset);
+ m_length = end - m_offset;
+ m_access.set(slice.m_access);
+ }
+
+ /**
+ * \brief Queries access flags
+ * \returns Access flags
+ */
+ DxvkAccessFlags getAccess() const {
+ return m_access;
+ }
+
+ private:
+
+ VkDeviceSize m_offset;
+ VkDeviceSize m_length;
+ DxvkAccessFlags m_access;
+
+ };
+
+
+ /**
+ * \brief Image slice for barrier tracking
+ *
+ * Stores an image subresource range, as well as
+ * access flags for the given image subresources.
+ */
+ class DxvkBarrierImageSlice {
+
+ public:
+
+ DxvkBarrierImageSlice()
+ : m_range(VkImageSubresourceRange()), m_access(0) { }
+
+ DxvkBarrierImageSlice(VkImageSubresourceRange range, DxvkAccessFlags access)
+ : m_range(range), m_access(access) { }
+
+ /**
+ * \brief Checks whether two slices overlap
+ *
+ * \param [in] slice The other image slice to check
+ * \returns \c true if the two slices overlap
+ */
+ bool overlaps(const DxvkBarrierImageSlice& slice) const {
+ return (m_range.aspectMask & slice.m_range.aspectMask)
+ && (m_range.baseArrayLayer < slice.m_range.baseArrayLayer + slice.m_range.layerCount)
+ && (m_range.baseArrayLayer + m_range.layerCount > slice.m_range.baseArrayLayer)
+ && (m_range.baseMipLevel < slice.m_range.baseMipLevel + slice.m_range.levelCount)
+ && (m_range.baseMipLevel + m_range.levelCount > slice.m_range.baseMipLevel);
+ }
+
+ /**
+ * \brief Checks whether a given slice is dirty
+ *
+ * \param [in] slice The image slice to check
+ * \returns \c true if the two slices overlap, and if
+ * at least one of the two slices have write access.
+ */
+ bool isDirty(const DxvkBarrierImageSlice& slice) const {
+ return (slice.m_access | m_access).test(DxvkAccess::Write) && overlaps(slice);
+ }
+
+ /**
+ * \brief Checks whether two slices can be merged
+ *
+ * This is a simplified implementation that does not check for
+ * adjacent or overlapping layers or levels, and instead only
+ * returns \c true if both slices contain the same mip levels
+ * and array layers. Access flags and image aspects may differ.
+ * \param [in] slice The other image slice to check
+ * \returns \c true if the slices can be merged.
+ */
+ bool canMerge(const DxvkBarrierImageSlice& slice) const {
+ return m_range.baseMipLevel == slice.m_range.baseMipLevel
+ && m_range.levelCount == slice.m_range.levelCount
+ && m_range.baseArrayLayer == slice.m_range.baseArrayLayer
+ && m_range.layerCount == slice.m_range.layerCount;
+ }
+
+ /**
+ * \brief Merges two image slices
+ *
+ * The resulting slice is guaranteed to fully contain both slices,
+ * including their access flags. If called when \c canMerge would
+ * return \c false, this will be a strict superset of both slices.
+ * \param [in] slice The slice to merge
+ */
+ void merge(const DxvkBarrierImageSlice& slice) {
+ uint32_t maxMipLevel = std::max(m_range.baseMipLevel + m_range.levelCount,
+ slice.m_range.baseMipLevel + slice.m_range.levelCount);
+ uint32_t maxArrayLayer = std::max(m_range.baseArrayLayer + m_range.layerCount,
+ slice.m_range.baseArrayLayer + slice.m_range.layerCount);
+ m_range.aspectMask |= slice.m_range.aspectMask;
+ m_range.baseMipLevel = std::min(m_range.baseMipLevel, slice.m_range.baseMipLevel);
+ m_range.levelCount = maxMipLevel - m_range.baseMipLevel;
+ m_range.baseArrayLayer = std::min(m_range.baseMipLevel, slice.m_range.baseArrayLayer);
+ m_range.layerCount = maxArrayLayer - m_range.baseArrayLayer;
+ m_access.set(slice.m_access);
+ }
+
+ /**
+ * \brief Queries access flags
+ * \returns Access flags
+ */
+ DxvkAccessFlags getAccess() const {
+ return m_access;
+ }
+
+ private:
+
+ VkImageSubresourceRange m_range;
+ DxvkAccessFlags m_access;
+
+ };
+
+
+ /**
+ * \brief Resource slice set for barrier tracking
+ *
+ * Implements a versioned hash table for fast resource
+ * lookup, with a single-linked list accurately storing
+ * each accessed slice if necessary.
+ * \tparam K Resource handle type
+ * \tparam T Resource slice type
+ */
+ template<typename K, typename T>
+ class DxvkBarrierSubresourceSet {
+ constexpr static uint32_t NoEntry = ~0u;
+ public:
+
+ /**
+ * \brief Queries access flags of a given resource slice
+ *
+ * \param [in] resource Resource handle
+ * \param [in] slice Resource slice
+ * \returns Or'd access flags of all known slices
+ * that overlap with the given slice.
+ */
+ DxvkAccessFlags getAccess(K resource, const T& slice) {
+ HashEntry* entry = findHashEntry(resource);
+
+ if (!entry)
+ return DxvkAccessFlags();
+
+ // Exit early if we know that there are no overlapping
+ // slices, or if there is only one slice to check anyway.
+ if (!entry->data.overlaps(slice))
+ return DxvkAccessFlags();
+
+ ListEntry* list = getListEntry(entry->next);
+
+ if (!list)
+ return entry->data.getAccess();
+
+ // The early out condition just checks whether there are
+ // any access flags left that may potentially get added
+ DxvkAccessFlags access;
+
+ while (list && access != entry->data.getAccess()) {
+ if (list->data.overlaps(slice))
+ access.set(list->data.getAccess());
+
+ list = getListEntry(list->next);
+ }
+
+ return access;
+ }
+
+ /**
+ * \brief Checks whether a given resource slice is dirty
+ *
+ * \param [in] resource Resourece handle
+ * \param [in] slice Resource slice
+ * \returns \c true if there is at least one slice that
+ * overlaps with the given slice, and either slice has
+ * the \c DxvkAccess::Write flag set.
+ */
+ bool isDirty(K resource, const T& slice) {
+ HashEntry* entry = findHashEntry(resource);
+
+ if (!entry)
+ return false;
+
+ // Exit early if there are no overlapping slices, or
+ // if none of the slices have the write flag set.
+ if (!entry->data.isDirty(slice))
+ return false;
+
+ // We know that some subresources are dirty, so if
+ // there is no list, the given slice must be dirty.
+ ListEntry* list = getListEntry(entry->next);
+
+ if (!list)
+ return true;
+
+ // Exit earlier if we find one dirty slice
+ bool dirty = false;
+
+ while (list && !dirty) {
+ dirty = list->data.isDirty(slice);
+ list = getListEntry(list->next);
+ }
+
+ return dirty;
+ }
+
+ /**
+ * \brief Inserts a given resource slice
+ *
+ * This will attempt to deduplicate and merge entries if
+ * possible, so that lookup and further insertions remain
+ * reasonably fast.
+ * \param [in] resource Resource handle
+ * \param [in] slice Resource slice
+ */
+ void insert(K resource, const T& slice) {
+ HashEntry* hashEntry = insertHashEntry(resource, slice);
+
+ if (hashEntry) {
+ ListEntry* listEntry = getListEntry(hashEntry->next);
+
+ // Only create the linear list if absolutely necessary
+ if (!listEntry && !hashEntry->data.canMerge(slice))
+ listEntry = insertListEntry(hashEntry->data, hashEntry);
+
+ if (listEntry) {
+ while (listEntry) {
+ // Avoid adding new list entries if possible
+ if (listEntry->data.canMerge(slice)) {
+ listEntry->data.merge(slice);
+ break;
+ }
+
+ listEntry = getListEntry(listEntry->next);
+ }
+
+ if (!listEntry)
+ insertListEntry(slice, hashEntry);
+ }
+
+ // Merge hash entry data so that it stores
+ // a superset of all slices in the list.
+ hashEntry->data.merge(slice);
+ }
+ }
+
+ /**
+ * \brief Removes all resources from the set
+ */
+ void clear() {
+ m_used = 0;
+ m_version += 1;
+ m_list.clear();
+ }
+
+ private:
+
+ struct ListEntry {
+ T data;
+ uint32_t next;
+ };
+
+ struct HashEntry {
+ uint64_t version;
+ K key;
+ T data;
+ uint32_t next;
+ };
+
+ uint64_t m_version = 1ull;
+ uint64_t m_used = 0ull;
+
+ std::vector<ListEntry> m_list;
+ std::vector<HashEntry> m_hashMap;
+
+ static size_t computeHash(K key) {
+ return size_t(reinterpret_cast<uint64_t>(key));
+ }
+
+ size_t computeIndex(K key) const {
+ return computeHash(key) % m_hashMap.size();
+ }
+
+ size_t advanceIndex(size_t index) const {
+ size_t size = m_hashMap.size();
+ size_t next = index + 1;
+ return next < size ? next : 0;
+ }
+
+ HashEntry* findHashEntry(K key) {
+ if (!m_used)
+ return nullptr;
+
+ size_t index = computeIndex(key);
+
+ while (m_hashMap[index].version == m_version) {
+ if (m_hashMap[index].key == key)
+ return &m_hashMap[index];
+
+ index = advanceIndex(index);
+ }
+
+ return nullptr;
+ }
+
+ HashEntry* insertHashEntry(K key, const T& data) {
+ growHashMapBeforeInsert();
+
+ // If we already have an entry for the given key, return
+ // the old one and let the caller deal with it
+ size_t index = computeIndex(key);
+
+ while (m_hashMap[index].version == m_version) {
+ if (m_hashMap[index].key == key)
+ return &m_hashMap[index];
+
+ index = advanceIndex(index);
+ }
+
+ HashEntry* entry = &m_hashMap[index];
+ entry->version = m_version;
+ entry->key = key;
+ entry->data = data;
+ entry->next = NoEntry;
+
+ m_used += 1;
+ return nullptr;
+ }
+
+ void growHashMap(size_t newSize) {
+ size_t oldSize = m_hashMap.size();
+ m_hashMap.resize(newSize);
+
+ // Relocate hash entries in place
+ for (size_t i = 0; i < oldSize; i++) {
+ HashEntry entry = m_hashMap[i];
+ m_hashMap[i].version = 0;
+
+ while (entry.version == m_version) {
+ size_t index = computeIndex(entry.key);
+ entry.version = m_version + 1;
+
+ while (m_hashMap[index].version > m_version)
+ index = advanceIndex(index);
+
+ std::swap(entry, m_hashMap[index]);
+ }
+ }
+
+ m_version += 1;
+ }
+
+ void growHashMapBeforeInsert() {
+ // Allow a load factor of 0.7 for performance reasons
+ size_t oldSize = m_hashMap.size();
+
+ if (10 * m_used >= 7 * oldSize) {
+ size_t newSize = oldSize ? (oldSize * 2 + 5) : 37;
+ growHashMap(newSize);
+ }
+ }
+
+ ListEntry* getListEntry(uint32_t index) {
+ return index < NoEntry ? &m_list[index] : nullptr;
+ }
+
+ ListEntry* insertListEntry(const T& subresource, HashEntry* head) {
+ uint32_t newIndex = uint32_t(m_list.size());
+ m_list.push_back({ subresource, head->next });
+ head->next = newIndex;
+ return &m_list[newIndex];
+ }
+
+ };
+
+ /**
+ * \brief Barrier set
+ *
+ * Accumulates memory barriers and provides a
+ * method to record all those barriers into a
+ * command buffer at once.
+ */
+ class DxvkBarrierSet {
+
+ public:
+
+ DxvkBarrierSet(DxvkCmdBuffer cmdBuffer);
+ ~DxvkBarrierSet();
+
+ void accessMemory(
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ void accessBuffer(
+ const DxvkBufferSliceHandle& bufSlice,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ void accessImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout srcLayout,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ void releaseBuffer(
+ DxvkBarrierSet& acquire,
+ const DxvkBufferSliceHandle& bufSlice,
+ uint32_t srcQueue,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ uint32_t dstQueue,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ void releaseImage(
+ DxvkBarrierSet& acquire,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ uint32_t srcQueue,
+ VkImageLayout srcLayout,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ uint32_t dstQueue,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ bool isBufferDirty(
+ const DxvkBufferSliceHandle& bufSlice,
+ DxvkAccessFlags bufAccess);
+
+ bool isImageDirty(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& imgSubres,
+ DxvkAccessFlags imgAccess);
+
+ DxvkAccessFlags getBufferAccess(
+ const DxvkBufferSliceHandle& bufSlice);
+
+ DxvkAccessFlags getImageAccess(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& imgSubres);
+
+ VkPipelineStageFlags getSrcStages() {
+ return m_srcStages;
+ }
+
+ void recordCommands(
+ const Rc<DxvkCommandList>& commandList);
+
+ void reset();
+
+ static DxvkAccessFlags getAccessTypes(VkAccessFlags flags);
+
+ private:
+
+ struct BufSlice {
+ DxvkBufferSliceHandle slice;
+ DxvkAccessFlags access;
+ };
+
+ struct ImgSlice {
+ VkImage image;
+ VkImageSubresourceRange subres;
+ DxvkAccessFlags access;
+ };
+
+ DxvkCmdBuffer m_cmdBuffer;
+
+ VkPipelineStageFlags m_srcStages = 0;
+ VkPipelineStageFlags m_dstStages = 0;
+
+ VkAccessFlags m_srcAccess = 0;
+ VkAccessFlags m_dstAccess = 0;
+
+ std::vector<VkBufferMemoryBarrier> m_bufBarriers;
+ std::vector<VkImageMemoryBarrier> m_imgBarriers;
+
+ DxvkBarrierSubresourceSet<VkBuffer, DxvkBarrierBufferSlice> m_bufSlices;
+ DxvkBarrierSubresourceSet<VkImage, DxvkBarrierImageSlice> m_imgSlices;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_bind_mask.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_bind_mask.h
new file mode 100644
index 00000000..b45b9b66
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_bind_mask.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "dxvk_buffer.h"
+#include "dxvk_descriptor.h"
+#include "dxvk_image.h"
+#include "dxvk_limits.h"
+#include "dxvk_sampler.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Binding mask
+ *
+ * Used to track which resource slots have a compatible
+ * binding and which ones don't. This is used to set up
+ * binding-related specialization constants in shaders.
+ * \tparam N Number of binding slots
+ */
+ template<uint32_t BindingCount>
+ class DxvkBindingSet {
+ constexpr static uint32_t BitCount = 32;
+ constexpr static uint32_t IntCount = (BindingCount + BitCount - 1) / BitCount;
+ public:
+
+ /**
+ * \brief Tests whether a binding is active
+ *
+ * \param [in] slot The binding ID
+ * \returns \c true if the binding is active
+ */
+ bool test(uint32_t slot) const {
+ const uint32_t intId = slot / BitCount;
+ const uint32_t bitId = slot % BitCount;
+ const uint32_t bitMask = 1u << bitId;
+ return (m_slots[intId] & bitMask) != 0;
+ }
+
+ /**
+ * \brief Changes a single binding
+ *
+ * \param [in] slot The binding ID
+ * \param [in] value New binding state
+ * \returns \c true if the state has changed
+ */
+ bool set(uint32_t slot, bool value) {
+ const uint32_t intId = slot / BitCount;
+ const uint32_t bitId = slot % BitCount;
+ const uint32_t bitMask = 1u << bitId;
+
+ const uint32_t prev = m_slots[intId];
+ const uint32_t next = value
+ ? prev | bitMask
+ : prev & ~bitMask;
+ m_slots[intId] = next;
+ return prev != next;
+ }
+
+ /**
+ * \brief Marks a binding as active
+ *
+ * \param [in] slot The binding ID
+ * \returns \c true if the state has changed
+ */
+ bool set(uint32_t slot) {
+ return set(slot, true);
+ }
+
+ /**
+ * \brief Marks a binding as inactive
+ *
+ * \param [in] slot The binding ID
+ * \returns \c true if the state has changed
+ */
+ bool clr(uint32_t slot) {
+ return set(slot, false);
+ }
+
+ /**
+ * \brief Clears binding state
+ *
+ * Useful to zero out any bindings
+ * that are not used by a pipeline.
+ */
+ void clear() {
+ for (uint32_t i = 0; i < IntCount; i++)
+ m_slots[i] = 0;
+ }
+
+ /**
+ * \brief Enables multiple bindings
+ * \param [in] n Number of bindings
+ */
+ void setFirst(uint32_t n) {
+ for (uint32_t i = 0; i < IntCount; i++) {
+ m_slots[i] = n >= BitCount ? ~0u : ~(~0u << n);
+ n = n >= BitCount ? n - BitCount : 0;
+ }
+ }
+
+ /**
+ * \brief Finds next set binding
+ *
+ * \param [in] first Fist bit to consider
+ * \returns Binding ID, or -1 if none was found
+ */
+ int32_t findNext(uint32_t first) const {
+ if (unlikely(first >= BindingCount))
+ return -1;
+
+ uint32_t intId = first / BitCount;
+ uint32_t bitId = first % BitCount;
+
+ auto mask = m_slots[intId] & ~((1 << bitId) - 1);
+
+ while (!mask && ++intId < IntCount)
+ mask = m_slots[intId];
+
+ if (!mask)
+ return -1;
+
+ return BitCount * intId + bit::tzcnt(mask);
+ }
+
+ bool operator == (const DxvkBindingSet& other) const {
+ bool eq = true;
+ for (uint32_t i = 0; i < IntCount; i++)
+ eq &= m_slots[i] == other.m_slots[i];
+ return eq;
+ }
+
+ bool operator != (const DxvkBindingSet& other) const {
+ return !this->operator == (other);
+ }
+
+ private:
+
+ uint32_t m_slots[IntCount];
+
+ };
+
+ using DxvkBindingMask = DxvkBindingSet<MaxNumActiveBindings>;
+
+
+ /**
+ * \brief Bound shader resources
+ *
+ * Stores the resources bound to a binding
+ * slot in DXVK. These are used to create
+ * descriptor sets.
+ */
+ struct DxvkShaderResourceSlot {
+ Rc<DxvkSampler> sampler;
+ Rc<DxvkImageView> imageView;
+ Rc<DxvkBufferView> bufferView;
+ DxvkBufferSlice bufferSlice;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.cpp
new file mode 100644
index 00000000..b7e3c447
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.cpp
@@ -0,0 +1,237 @@
+#include "dxvk_buffer.h"
+#include "dxvk_device.h"
+
+#include <algorithm>
+
+namespace dxvk {
+
+ DxvkBuffer::DxvkBuffer(
+ DxvkDevice* device,
+ const DxvkBufferCreateInfo& createInfo,
+ DxvkMemoryAllocator& memAlloc,
+ VkMemoryPropertyFlags memFlags)
+ : m_device (device),
+ m_info (createInfo),
+ m_memAlloc (&memAlloc),
+ m_memFlags (memFlags) {
+ // Align slices so that we don't violate any alignment
+ // requirements imposed by the Vulkan device/driver
+ VkDeviceSize sliceAlignment = computeSliceAlignment();
+ m_physSliceLength = createInfo.size;
+ m_physSliceStride = align(createInfo.size, sliceAlignment);
+ m_physSliceCount = std::max<VkDeviceSize>(1, 256 / m_physSliceStride);
+
+ // Limit size of multi-slice buffers to reduce fragmentation
+ constexpr VkDeviceSize MaxBufferSize = 4 << 20;
+
+ m_physSliceMaxCount = MaxBufferSize >= m_physSliceStride
+ ? MaxBufferSize / m_physSliceStride
+ : 1;
+
+ // Allocate the initial set of buffer slices
+ m_buffer = allocBuffer(m_physSliceCount);
+
+ DxvkBufferSliceHandle slice;
+ slice.handle = m_buffer.buffer;
+ slice.offset = 0;
+ slice.length = m_physSliceLength;
+ slice.mapPtr = m_buffer.memory.mapPtr(0);
+
+ m_physSlice = slice;
+ m_lazyAlloc = m_physSliceCount > 1;
+ }
+
+
+ DxvkBuffer::~DxvkBuffer() {
+ auto vkd = m_device->vkd();
+
+ for (const auto& buffer : m_buffers)
+ vkd->vkDestroyBuffer(vkd->device(), buffer.buffer, nullptr);
+ vkd->vkDestroyBuffer(vkd->device(), m_buffer.buffer, nullptr);
+ }
+
+
+ DxvkBufferHandle DxvkBuffer::allocBuffer(VkDeviceSize sliceCount) const {
+ auto vkd = m_device->vkd();
+
+ VkBufferCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.size = m_physSliceStride * sliceCount;
+ info.usage = m_info.usage;
+ info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ info.queueFamilyIndexCount = 0;
+ info.pQueueFamilyIndices = nullptr;
+
+ DxvkBufferHandle handle;
+
+ if (vkd->vkCreateBuffer(vkd->device(),
+ &info, nullptr, &handle.buffer) != VK_SUCCESS) {
+ throw DxvkError(str::format(
+ "DxvkBuffer: Failed to create buffer:"
+ "\n size: ", info.size,
+ "\n usage: ", info.usage));
+ }
+
+ VkMemoryDedicatedRequirements dedicatedRequirements;
+ dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+ dedicatedRequirements.pNext = VK_NULL_HANDLE;
+ dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE;
+ dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE;
+
+ VkMemoryRequirements2 memReq;
+ memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ memReq.pNext = &dedicatedRequirements;
+
+ VkBufferMemoryRequirementsInfo2 memReqInfo;
+ memReqInfo.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2;
+ memReqInfo.buffer = handle.buffer;
+ memReqInfo.pNext = VK_NULL_HANDLE;
+
+ VkMemoryDedicatedAllocateInfo dedMemoryAllocInfo;
+ dedMemoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+ dedMemoryAllocInfo.pNext = VK_NULL_HANDLE;
+ dedMemoryAllocInfo.buffer = handle.buffer;
+ dedMemoryAllocInfo.image = VK_NULL_HANDLE;
+
+ vkd->vkGetBufferMemoryRequirements2(
+ vkd->device(), &memReqInfo, &memReq);
+
+ // Use high memory priority for GPU-writable resources
+ bool isGpuWritable = (m_info.access & (
+ VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT)) != 0;
+ float priority = isGpuWritable ? 1.0f : 0.5f;
+
+ // Ask driver whether we should be using a dedicated allocation
+ handle.memory = m_memAlloc->alloc(&memReq.memoryRequirements,
+ dedicatedRequirements, dedMemoryAllocInfo, m_memFlags, priority);
+
+ if (vkd->vkBindBufferMemory(vkd->device(), handle.buffer,
+ handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS)
+ throw DxvkError("DxvkBuffer: Failed to bind device memory");
+
+ return handle;
+ }
+
+
+ VkDeviceSize DxvkBuffer::computeSliceAlignment() const {
+ const auto& devInfo = m_device->properties().core.properties;
+
+ VkDeviceSize result = sizeof(uint32_t);
+
+ if (m_info.usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
+ result = std::max(result, devInfo.limits.minUniformBufferOffsetAlignment);
+
+ if (m_info.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
+ result = std::max(result, devInfo.limits.minStorageBufferOffsetAlignment);
+
+ if (m_info.usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) {
+ result = std::max(result, devInfo.limits.minTexelBufferOffsetAlignment);
+ result = std::max(result, VkDeviceSize(16));
+ }
+
+ if (m_info.usage & (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
+ && m_info.size > (devInfo.limits.optimalBufferCopyOffsetAlignment / 2))
+ result = std::max(result, devInfo.limits.optimalBufferCopyOffsetAlignment);
+
+ // For some reason, Warhammer Chaosbane breaks otherwise
+ if (m_info.usage & (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT))
+ result = std::max(result, VkDeviceSize(256));
+
+ if (m_memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ result = std::max(result, devInfo.limits.nonCoherentAtomSize);
+ result = std::max(result, VkDeviceSize(64));
+ }
+
+ return result;
+ }
+
+
+
+
+ DxvkBufferView::DxvkBufferView(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferViewCreateInfo& info)
+ : m_vkd(vkd), m_info(info), m_buffer(buffer),
+ m_bufferSlice (getSliceHandle()),
+ m_bufferView (createBufferView(m_bufferSlice)) {
+
+ }
+
+
+ DxvkBufferView::~DxvkBufferView() {
+ if (m_views.empty()) {
+ m_vkd->vkDestroyBufferView(
+ m_vkd->device(), m_bufferView, nullptr);
+ } else {
+ for (const auto& pair : m_views) {
+ m_vkd->vkDestroyBufferView(
+ m_vkd->device(), pair.second, nullptr);
+ }
+ }
+ }
+
+
+ VkBufferView DxvkBufferView::createBufferView(
+ const DxvkBufferSliceHandle& slice) {
+ VkBufferViewCreateInfo viewInfo;
+ viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
+ viewInfo.pNext = nullptr;
+ viewInfo.flags = 0;
+ viewInfo.buffer = slice.handle;
+ viewInfo.format = m_info.format;
+ viewInfo.offset = slice.offset;
+ viewInfo.range = slice.length;
+
+ VkBufferView result = VK_NULL_HANDLE;
+
+ if (m_vkd->vkCreateBufferView(m_vkd->device(),
+ &viewInfo, nullptr, &result) != VK_SUCCESS) {
+ throw DxvkError(str::format(
+ "DxvkBufferView: Failed to create buffer view:",
+ "\n Offset: ", viewInfo.offset,
+ "\n Range: ", viewInfo.range,
+ "\n Format: ", viewInfo.format));
+ }
+
+ return result;
+ }
+
+
+ void DxvkBufferView::updateBufferView(
+ const DxvkBufferSliceHandle& slice) {
+ if (m_views.empty())
+ m_views.insert({ m_bufferSlice, m_bufferView });
+
+ m_bufferSlice = slice;
+
+ auto entry = m_views.find(slice);
+ if (entry != m_views.end()) {
+ m_bufferView = entry->second;
+ } else {
+ m_bufferView = createBufferView(m_bufferSlice);
+ m_views.insert({ m_bufferSlice, m_bufferView });
+ }
+ }
+
+
+ DxvkBufferTracker:: DxvkBufferTracker() { }
+ DxvkBufferTracker::~DxvkBufferTracker() { }
+
+
+ void DxvkBufferTracker::reset() {
+ std::sort(m_entries.begin(), m_entries.end(),
+ [] (const Entry& a, const Entry& b) {
+ return a.slice.handle < b.slice.handle;
+ });
+
+ for (const auto& e : m_entries)
+ e.buffer->freeSlice(e.slice);
+
+ m_entries.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.h
new file mode 100644
index 00000000..f17abba2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_buffer.h
@@ -0,0 +1,688 @@
+#pragma once
+
+#include <unordered_map>
+#include <vector>
+
+#include "dxvk_descriptor.h"
+#include "dxvk_format.h"
+#include "dxvk_hash.h"
+#include "dxvk_memory.h"
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Buffer create info
+ *
+ * The properties of a buffer that are
+ * passed to \ref DxvkDevice::createBuffer
+ */
+ struct DxvkBufferCreateInfo {
+ /// Size of the buffer, in bytes
+ VkDeviceSize size;
+
+ /// Buffer usage flags
+ VkBufferUsageFlags usage;
+
+ /// Pipeline stages that can access
+ /// the contents of the buffer.
+ VkPipelineStageFlags stages;
+
+ /// Allowed access patterns
+ VkAccessFlags access;
+ };
+
+
+ /**
+ * \brief Buffer view create info
+ *
+ * The properties of a buffer view that
+ * are to \ref DxvkDevice::createBufferView
+ */
+ struct DxvkBufferViewCreateInfo {
+ /// Buffer data format, like image data
+ VkFormat format;
+
+ /// Offset of the buffer region to include in the view
+ VkDeviceSize rangeOffset;
+
+ /// Size of the buffer region to include in the view
+ VkDeviceSize rangeLength;
+ };
+
+
+ /**
+ * \brief Buffer info
+ *
+ * Stores a Vulkan buffer handle and the
+ * memory object that is bound to the buffer.
+ */
+ struct DxvkBufferHandle {
+ VkBuffer buffer = VK_NULL_HANDLE;
+ DxvkMemory memory;
+ };
+
+
+ /**
+ * \brief Buffer slice info
+ *
+ * Stores the Vulkan buffer handle, offset
+ * and length of the slice, and a pointer
+ * to the mapped region..
+ */
+ struct DxvkBufferSliceHandle {
+ VkBuffer handle;
+ VkDeviceSize offset;
+ VkDeviceSize length;
+ void* mapPtr;
+
+ bool eq(const DxvkBufferSliceHandle& other) const {
+ return handle == other.handle
+ && offset == other.offset
+ && length == other.length;
+ }
+
+ size_t hash() const {
+ DxvkHashState result;
+ result.add(std::hash<VkBuffer>()(handle));
+ result.add(std::hash<VkDeviceSize>()(offset));
+ result.add(std::hash<VkDeviceSize>()(length));
+ return result;
+ }
+ };
+
+
+ /**
+ * \brief Virtual buffer resource
+ *
+ * A simple buffer resource that stores linear,
+ * unformatted data. Can be accessed by the host
+ * if allocated on an appropriate memory type.
+ */
+ class DxvkBuffer : public DxvkResource {
+ friend class DxvkBufferView;
+ public:
+
+ DxvkBuffer(
+ DxvkDevice* device,
+ const DxvkBufferCreateInfo& createInfo,
+ DxvkMemoryAllocator& memAlloc,
+ VkMemoryPropertyFlags memFlags);
+
+ ~DxvkBuffer();
+
+ /**
+ * \brief Buffer properties
+ * \returns Buffer properties
+ */
+ const DxvkBufferCreateInfo& info() const {
+ return m_info;
+ }
+
+ /**
+ * \brief Memory type flags
+ *
+ * Use this to determine whether a
+ * buffer is mapped to host memory.
+ * \returns Vulkan memory flags
+ */
+ VkMemoryPropertyFlags memFlags() const {
+ return m_memFlags;
+ }
+
+ /**
+ * \brief Map pointer
+ *
+ * If the buffer has been created on a host-visible
+ * memory type, the buffer memory is mapped and can
+ * be accessed by the host.
+ * \param [in] offset Byte offset into mapped region
+ * \returns Pointer to mapped memory region
+ */
+ void* mapPtr(VkDeviceSize offset) const {
+ return reinterpret_cast<char*>(m_physSlice.mapPtr) + offset;
+ }
+
+ /**
+ * \brief Retrieves slice handle
+ * \returns Buffer slice handle
+ */
+ DxvkBufferSliceHandle getSliceHandle() const {
+ return m_physSlice;
+ }
+
+ /**
+ * \brief Retrieves sub slice handle
+ *
+ * \param [in] offset Offset into buffer
+ * \param [in] length Sub slice length
+ * \returns Buffer slice handle
+ */
+ DxvkBufferSliceHandle getSliceHandle(VkDeviceSize offset, VkDeviceSize length) const {
+ DxvkBufferSliceHandle result;
+ result.handle = m_physSlice.handle;
+ result.offset = m_physSlice.offset + offset;
+ result.length = length;
+ result.mapPtr = mapPtr(offset);
+ return result;
+ }
+
+ /**
+ * \brief Retrieves descriptor info
+ *
+ * \param [in] offset Buffer slice offset
+ * \param [in] length Buffer slice length
+ * \returns Buffer slice descriptor
+ */
+ DxvkDescriptorInfo getDescriptor(VkDeviceSize offset, VkDeviceSize length) const {
+ DxvkDescriptorInfo result;
+ result.buffer.buffer = m_physSlice.handle;
+ result.buffer.offset = m_physSlice.offset + offset;
+ result.buffer.range = length;
+ return result;
+ }
+
+ /**
+ * \brief Retrieves dynamic offset
+ *
+ * \param [in] offset Offset into the buffer
+ * \returns Offset for dynamic descriptors
+ */
+ VkDeviceSize getDynamicOffset(VkDeviceSize offset) const {
+ return m_physSlice.offset + offset;
+ }
+
+ /**
+ * \brief Replaces backing resource
+ *
+ * Replaces the underlying buffer and implicitly marks
+ * any buffer views using this resource as dirty. Do
+ * not call this directly as this is called implicitly
+ * by the context's \c invalidateBuffer method.
+ * \param [in] slice The new backing resource
+ * \returns Previous buffer slice
+ */
+ DxvkBufferSliceHandle rename(const DxvkBufferSliceHandle& slice) {
+ return std::exchange(m_physSlice, slice);
+ }
+
+ /**
+ * \brief Transform feedback vertex stride
+ *
+ * Used when drawing after transform feedback,
+ * \returns The current xfb vertex stride
+ */
+ uint32_t getXfbVertexStride() const {
+ return m_vertexStride;
+ }
+
+ /**
+ * \brief Set transform feedback vertex stride
+ *
+ * When the buffer is used as a transform feedback
+ * buffer, this will be set to the vertex stride
+ * defined by the geometry shader.
+ * \param [in] stride Vertex stride
+ */
+ void setXfbVertexStride(uint32_t stride) {
+ m_vertexStride = stride;
+ }
+
+ /**
+ * \brief Allocates new buffer slice
+ * \returns The new buffer slice
+ */
+ DxvkBufferSliceHandle allocSlice() {
+ std::unique_lock<sync::Spinlock> freeLock(m_freeMutex);
+
+ // If no slices are available, swap the two free lists.
+ if (unlikely(m_freeSlices.empty())) {
+ std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
+ std::swap(m_freeSlices, m_nextSlices);
+ }
+
+ // If there are still no slices available, create a new
+ // backing buffer and add all slices to the free list.
+ if (unlikely(m_freeSlices.empty())) {
+ if (likely(!m_lazyAlloc)) {
+ DxvkBufferHandle handle = allocBuffer(m_physSliceCount);
+
+ for (uint32_t i = 0; i < m_physSliceCount; i++)
+ pushSlice(handle, i);
+
+ m_buffers.push_back(std::move(handle));
+ m_physSliceCount = std::min(m_physSliceCount * 2, m_physSliceMaxCount);
+ } else {
+ for (uint32_t i = 1; i < m_physSliceCount; i++)
+ pushSlice(m_buffer, i);
+
+ m_lazyAlloc = false;
+ }
+ }
+
+ // Take the first slice from the queue
+ DxvkBufferSliceHandle result = m_freeSlices.back();
+ m_freeSlices.pop_back();
+ return result;
+ }
+
+ /**
+ * \brief Frees a buffer slice
+ *
+ * Marks the slice as free so that it can be used for
+ * subsequent allocations. Called automatically when
+ * the slice is no longer needed by the GPU.
+ * \param [in] slice The buffer slice to free
+ */
+ void freeSlice(const DxvkBufferSliceHandle& slice) {
+ // Add slice to a separate free list to reduce lock contention.
+ std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
+ m_nextSlices.push_back(slice);
+ }
+
+ private:
+
+ DxvkDevice* m_device;
+ DxvkBufferCreateInfo m_info;
+ DxvkMemoryAllocator* m_memAlloc;
+ VkMemoryPropertyFlags m_memFlags;
+
+ DxvkBufferHandle m_buffer;
+ DxvkBufferSliceHandle m_physSlice;
+
+ uint32_t m_vertexStride = 0;
+ uint32_t m_lazyAlloc = false;
+
+ sync::Spinlock m_freeMutex;
+ sync::Spinlock m_swapMutex;
+
+ std::vector<DxvkBufferHandle> m_buffers;
+ std::vector<DxvkBufferSliceHandle> m_freeSlices;
+ std::vector<DxvkBufferSliceHandle> m_nextSlices;
+
+ VkDeviceSize m_physSliceLength = 0;
+ VkDeviceSize m_physSliceStride = 0;
+ VkDeviceSize m_physSliceCount = 1;
+ VkDeviceSize m_physSliceMaxCount = 1;
+
+ void pushSlice(const DxvkBufferHandle& handle, uint32_t index) {
+ DxvkBufferSliceHandle slice;
+ slice.handle = handle.buffer;
+ slice.length = m_physSliceLength;
+ slice.offset = m_physSliceStride * index;
+ slice.mapPtr = handle.memory.mapPtr(slice.offset);
+ m_freeSlices.push_back(slice);
+ }
+
+ DxvkBufferHandle allocBuffer(
+ VkDeviceSize sliceCount) const;
+
+ VkDeviceSize computeSliceAlignment() const;
+
+ };
+
+
+ /**
+ * \brief Buffer slice
+ *
+ * Stores the buffer and a sub-range of the buffer.
+ * Slices are considered equal if the buffer and
+ * the buffer range are the same.
+ */
+ class DxvkBufferSlice {
+
+ public:
+
+ DxvkBufferSlice() { }
+
+ DxvkBufferSlice(
+ const Rc<DxvkBuffer>& buffer,
+ VkDeviceSize rangeOffset,
+ VkDeviceSize rangeLength)
+ : m_buffer(buffer),
+ m_offset(rangeOffset),
+ m_length(rangeLength) { }
+
+ explicit DxvkBufferSlice(const Rc<DxvkBuffer>& buffer)
+ : DxvkBufferSlice(buffer, 0, buffer->info().size) { }
+
+ DxvkBufferSlice(const DxvkBufferSlice& ) = default;
+ DxvkBufferSlice( DxvkBufferSlice&&) = default;
+
+ DxvkBufferSlice& operator = (const DxvkBufferSlice& other) {
+ if (m_buffer != other.m_buffer)
+ m_buffer = other.m_buffer;
+ m_offset = other.m_offset;
+ m_length = other.m_length;
+ return *this;
+ }
+
+ DxvkBufferSlice& operator = (DxvkBufferSlice&&) = default;
+
+ /**
+ * \brief Buffer slice offset and length
+ * \returns Buffer slice offset and length
+ */
+ size_t offset() const { return m_offset; }
+ size_t length() const { return m_length; }
+
+ /**
+ * \brief Underlying buffer
+ * \returns The virtual buffer
+ */
+ const Rc<DxvkBuffer>& buffer() const {
+ return m_buffer;
+ }
+
+ /**
+ * \brief Buffer info
+ *
+ * Retrieves the properties of the underlying
+ * virtual buffer. Should not be used directly
+ * by client APIs.
+ * \returns Buffer properties
+ */
+ const DxvkBufferCreateInfo& bufferInfo() const {
+ return m_buffer->info();
+ }
+
+ /**
+ * \brief Buffer sub slice
+ *
+ * Takes a sub slice from this slice.
+ * \param [in] offset Sub slice offset
+ * \param [in] length Sub slice length
+ * \returns The sub slice object
+ */
+ DxvkBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
+ return DxvkBufferSlice(m_buffer, m_offset + offset, length);
+ }
+
+ /**
+ * \brief Checks whether the slice is valid
+ *
+ * A buffer slice that does not point to any virtual
+ * buffer object is considered undefined and cannot
+ * be used for any operations.
+ * \returns \c true if the slice is defined
+ */
+ bool defined() const {
+ return m_buffer != nullptr;
+ }
+
+ /**
+ * \brief Retrieves buffer slice handle
+ *
+ * Returns the buffer handle and offset
+ * \returns Buffer slice handle
+ */
+ DxvkBufferSliceHandle getSliceHandle() const {
+ return m_buffer != nullptr
+ ? m_buffer->getSliceHandle(m_offset, m_length)
+ : DxvkBufferSliceHandle();
+ }
+
+ /**
+ * \brief Retrieves sub slice handle
+ *
+ * \param [in] offset Offset into buffer
+ * \param [in] length Sub slice length
+ * \returns Buffer slice handle
+ */
+ DxvkBufferSliceHandle getSliceHandle(VkDeviceSize offset, VkDeviceSize length) const {
+ return m_buffer != nullptr
+ ? m_buffer->getSliceHandle(m_offset + offset, length)
+ : DxvkBufferSliceHandle();
+ }
+
+ /**
+ * \brief Retrieves descriptor info
+ * \returns Buffer slice descriptor
+ */
+ DxvkDescriptorInfo getDescriptor() const {
+ return m_buffer->getDescriptor(m_offset, m_length);
+ }
+
+ /**
+ * \brief Retrieves dynamic offset
+ *
+ * Used for descriptor set binding.
+ * \returns Buffer slice offset
+ */
+ VkDeviceSize getDynamicOffset() const {
+ return m_buffer->getDynamicOffset(m_offset);
+ }
+
+ /**
+ * \brief Pointer to mapped memory region
+ *
+ * \param [in] offset Offset into the slice
+ * \returns Pointer into mapped buffer memory
+ */
+ void* mapPtr(VkDeviceSize offset) const {
+ return m_buffer != nullptr
+ ? m_buffer->mapPtr(m_offset + offset)
+ : nullptr;
+ }
+
+ /**
+ * \brief Checks whether two slices are equal
+ *
+ * Two slices are considered equal if they point to
+ * the same memory region within the same buffer.
+ * \param [in] other The slice to compare to
+ * \returns \c true if the two slices are the same
+ */
+ bool matches(const DxvkBufferSlice& other) const {
+ return this->m_buffer == other.m_buffer
+ && this->m_offset == other.m_offset
+ && this->m_length == other.m_length;
+ }
+
+ /**
+ * \brief Checks whether two slices are from the same buffer
+ *
+ * This returns \c true if the two slices are taken
+ * from the same buffer, but may have different ranges.
+ * \param [in] other The slice to compare to
+ * \returns \c true if the buffer objects are the same
+ */
+ bool matchesBuffer(const DxvkBufferSlice& other) const {
+ return this->m_buffer == other.m_buffer;
+ }
+
+ /**
+ * \brief Checks whether two slices have the same range
+ *
+ * This returns \c true if the two slices have the same
+ * offset and size, even if the buffers are different.
+ * May be useful if the buffers are know to be the same.
+ * \param [in] other The slice to compare to
+ * \returns \c true if the buffer objects are the same
+ */
+ bool matchesRange(const DxvkBufferSlice& other) const {
+ return this->m_offset == other.m_offset
+ && this->m_length == other.m_length;
+ }
+
+ private:
+
+ Rc<DxvkBuffer> m_buffer = nullptr;
+ VkDeviceSize m_offset = 0;
+ VkDeviceSize m_length = 0;
+
+ };
+
+
+ /**
+ * \brief Buffer view
+ *
+ * Allows the application to interpret buffer
+ * contents like formatted pixel data. These
+ * buffer views are used as texel buffers.
+ */
+ class DxvkBufferView : public DxvkResource {
+
+ public:
+
+ DxvkBufferView(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferViewCreateInfo& info);
+
+ ~DxvkBufferView();
+
+ /**
+ * \brief Buffer view handle
+ * \returns Buffer view handle
+ */
+ VkBufferView handle() const {
+ return m_bufferView;
+ }
+
+ /**
+ * \brief Element cound
+ *
+ * Number of typed elements contained
+ * in the buffer view. Depends on the
+ * buffer view format.
+ * \returns Element count
+ */
+ VkDeviceSize elementCount() const {
+ auto format = imageFormatInfo(m_info.format);
+ return m_info.rangeLength / format->elementSize;
+ }
+
+ /**
+ * \brief Buffer view properties
+ * \returns Buffer view properties
+ */
+ const DxvkBufferViewCreateInfo& info() const {
+ return m_info;
+ }
+
+ /**
+ * \brief Underlying buffer object
+ * \returns Underlying buffer object
+ */
+ const Rc<DxvkBuffer>& buffer() const {
+ return m_buffer;
+ }
+
+ /**
+ * \brief Underlying buffer info
+ * \returns Underlying buffer info
+ */
+ const DxvkBufferCreateInfo& bufferInfo() const {
+ return m_buffer->info();
+ }
+
+ /**
+ * \brief View format info
+ * \returns View format info
+ */
+ const DxvkFormatInfo* formatInfo() const {
+ return imageFormatInfo(m_info.format);
+ }
+
+ /**
+ * \brief Retrieves buffer slice handle
+ * \returns Buffer slice handle
+ */
+ DxvkBufferSliceHandle getSliceHandle() const {
+ return m_buffer->getSliceHandle(
+ m_info.rangeOffset,
+ m_info.rangeLength);
+ }
+
+ /**
+ * \brief Underlying buffer slice
+ * \returns Slice backing the view
+ */
+ DxvkBufferSlice slice() const {
+ return DxvkBufferSlice(m_buffer,
+ m_info.rangeOffset,
+ m_info.rangeLength);
+ }
+
+ /**
+ * \brief Updates the buffer view
+ *
+ * If the buffer has been invalidated ever since
+ * the view was created, the view is invalid as
+ * well and needs to be re-created. Call this
+ * prior to using the buffer view handle.
+ */
+ void updateView() {
+ DxvkBufferSliceHandle slice = getSliceHandle();
+
+ if (!m_bufferSlice.eq(slice))
+ this->updateBufferView(slice);
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkBufferViewCreateInfo m_info;
+ Rc<DxvkBuffer> m_buffer;
+
+ DxvkBufferSliceHandle m_bufferSlice;
+ VkBufferView m_bufferView;
+
+ std::unordered_map<
+ DxvkBufferSliceHandle,
+ VkBufferView,
+ DxvkHash, DxvkEq> m_views;
+
+ VkBufferView createBufferView(
+ const DxvkBufferSliceHandle& slice);
+
+ void updateBufferView(
+ const DxvkBufferSliceHandle& slice);
+
+ };
+
+
+ /**
+ * \brief Buffer slice tracker
+ *
+ * Stores a list of buffer slices that can be
+ * freed. Useful when buffers have been renamed
+ * and the original slice is no longer needed.
+ */
+ class DxvkBufferTracker {
+
+ public:
+
+ DxvkBufferTracker();
+ ~DxvkBufferTracker();
+
+ /**
+ * \brief Add buffer slice for tracking
+ *
+ * The slice will be returned to the
+ * buffer on the next call to \c reset.
+ * \param [in] buffer The parent buffer
+ * \param [in] slice The buffer slice
+ */
+ void freeBufferSlice(const Rc<DxvkBuffer>& buffer, const DxvkBufferSliceHandle& slice) {
+ m_entries.push_back({ buffer, slice });
+ }
+
+ /**
+ * \brief Returns tracked buffer slices
+ */
+ void reset();
+
+ private:
+
+ struct Entry {
+ Rc<DxvkBuffer> buffer;
+ DxvkBufferSliceHandle slice;
+ };
+
+ std::vector<Entry> m_entries;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.cpp
new file mode 100644
index 00000000..edda53db
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.cpp
@@ -0,0 +1,221 @@
+#include "dxvk_cmdlist.h"
+#include "dxvk_device.h"
+
+namespace dxvk {
+
+ DxvkCommandList::DxvkCommandList(DxvkDevice* device)
+ : m_device (device),
+ m_vkd (device->vkd()),
+ m_vki (device->instance()->vki()),
+ m_cmdBuffersUsed(0),
+ m_descriptorPoolTracker(device) {
+ const auto& graphicsQueue = m_device->queues().graphics;
+ const auto& transferQueue = m_device->queues().transfer;
+
+ VkFenceCreateInfo fenceInfo;
+ fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fenceInfo.pNext = nullptr;
+ fenceInfo.flags = 0;
+
+ if (m_vkd->vkCreateFence(m_vkd->device(), &fenceInfo, nullptr, &m_fence) != VK_SUCCESS)
+ throw DxvkError("DxvkCommandList: Failed to create fence");
+
+ VkCommandPoolCreateInfo poolInfo;
+ poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ poolInfo.pNext = nullptr;
+ poolInfo.flags = 0;
+ poolInfo.queueFamilyIndex = graphicsQueue.queueFamily;
+
+ if (m_vkd->vkCreateCommandPool(m_vkd->device(), &poolInfo, nullptr, &m_graphicsPool) != VK_SUCCESS)
+ throw DxvkError("DxvkCommandList: Failed to create graphics command pool");
+
+ if (m_device->hasDedicatedTransferQueue()) {
+ poolInfo.queueFamilyIndex = transferQueue.queueFamily;
+
+ if (m_vkd->vkCreateCommandPool(m_vkd->device(), &poolInfo, nullptr, &m_transferPool) != VK_SUCCESS)
+ throw DxvkError("DxvkCommandList: Failed to create transfer command pool");
+ }
+
+ VkCommandBufferAllocateInfo cmdInfoGfx;
+ cmdInfoGfx.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ cmdInfoGfx.pNext = nullptr;
+ cmdInfoGfx.commandPool = m_graphicsPool;
+ cmdInfoGfx.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ cmdInfoGfx.commandBufferCount = 1;
+
+ VkCommandBufferAllocateInfo cmdInfoDma;
+ cmdInfoDma.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ cmdInfoDma.pNext = nullptr;
+ cmdInfoDma.commandPool = m_transferPool ? m_transferPool : m_graphicsPool;
+ cmdInfoDma.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ cmdInfoDma.commandBufferCount = 1;
+
+ if (m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfoGfx, &m_execBuffer) != VK_SUCCESS
+ || m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfoGfx, &m_initBuffer) != VK_SUCCESS
+ || m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfoDma, &m_sdmaBuffer) != VK_SUCCESS)
+ throw DxvkError("DxvkCommandList: Failed to allocate command buffer");
+
+ if (m_device->hasDedicatedTransferQueue()) {
+ VkSemaphoreCreateInfo semInfo;
+ semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semInfo.pNext = nullptr;
+ semInfo.flags = 0;
+
+ if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semInfo, nullptr, &m_sdmaSemaphore) != VK_SUCCESS)
+ throw DxvkError("DxvkCommandList: Failed to create semaphore");
+ }
+ }
+
+
+ DxvkCommandList::~DxvkCommandList() {
+ this->reset();
+
+ m_vkd->vkDestroySemaphore(m_vkd->device(), m_sdmaSemaphore, nullptr);
+
+ m_vkd->vkDestroyCommandPool(m_vkd->device(), m_graphicsPool, nullptr);
+ m_vkd->vkDestroyCommandPool(m_vkd->device(), m_transferPool, nullptr);
+
+ m_vkd->vkDestroyFence(m_vkd->device(), m_fence, nullptr);
+ }
+
+
+ VkResult DxvkCommandList::submit(
+ VkSemaphore waitSemaphore,
+ VkSemaphore wakeSemaphore) {
+ const auto& graphics = m_device->queues().graphics;
+ const auto& transfer = m_device->queues().transfer;
+
+ DxvkQueueSubmission info = DxvkQueueSubmission();
+
+ if (m_cmdBuffersUsed.test(DxvkCmdBuffer::SdmaBuffer)) {
+ info.cmdBuffers[info.cmdBufferCount++] = m_sdmaBuffer;
+
+ if (m_device->hasDedicatedTransferQueue()) {
+ info.wakeSync[info.wakeCount++] = m_sdmaSemaphore;
+ VkResult status = submitToQueue(transfer.queueHandle, VK_NULL_HANDLE, info);
+
+ if (status != VK_SUCCESS)
+ return status;
+
+ info = DxvkQueueSubmission();
+ info.waitSync[info.waitCount] = m_sdmaSemaphore;
+ info.waitMask[info.waitCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ info.waitCount += 1;
+ }
+ }
+
+ if (m_cmdBuffersUsed.test(DxvkCmdBuffer::InitBuffer))
+ info.cmdBuffers[info.cmdBufferCount++] = m_initBuffer;
+ if (m_cmdBuffersUsed.test(DxvkCmdBuffer::ExecBuffer))
+ info.cmdBuffers[info.cmdBufferCount++] = m_execBuffer;
+
+ if (waitSemaphore) {
+ info.waitSync[info.waitCount] = waitSemaphore;
+ info.waitMask[info.waitCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ info.waitCount += 1;
+ }
+
+ if (wakeSemaphore)
+ info.wakeSync[info.wakeCount++] = wakeSemaphore;
+
+ return submitToQueue(graphics.queueHandle, m_fence, info);
+ }
+
+
+ VkResult DxvkCommandList::synchronize() {
+ VkResult status = VK_TIMEOUT;
+
+ while (status == VK_TIMEOUT) {
+ status = m_vkd->vkWaitForFences(
+ m_vkd->device(), 1, &m_fence, VK_FALSE,
+ 1'000'000'000ull);
+ }
+
+ return status;
+ }
+
+
+ void DxvkCommandList::beginRecording() {
+ VkCommandBufferBeginInfo info;
+ info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ info.pNext = nullptr;
+ info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+ info.pInheritanceInfo = nullptr;
+
+ if ((m_graphicsPool && m_vkd->vkResetCommandPool(m_vkd->device(), m_graphicsPool, 0) != VK_SUCCESS)
+ || (m_transferPool && m_vkd->vkResetCommandPool(m_vkd->device(), m_transferPool, 0) != VK_SUCCESS))
+ Logger::err("DxvkCommandList: Failed to reset command buffer");
+
+ if (m_vkd->vkBeginCommandBuffer(m_execBuffer, &info) != VK_SUCCESS
+ || m_vkd->vkBeginCommandBuffer(m_initBuffer, &info) != VK_SUCCESS
+ || m_vkd->vkBeginCommandBuffer(m_sdmaBuffer, &info) != VK_SUCCESS)
+ Logger::err("DxvkCommandList: Failed to begin command buffer");
+
+ if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence) != VK_SUCCESS)
+ Logger::err("DxvkCommandList: Failed to reset fence");
+
+ // Unconditionally mark the exec buffer as used. There
+ // is virtually no use case where this isn't correct.
+ m_cmdBuffersUsed = DxvkCmdBuffer::ExecBuffer;
+ }
+
+
+ void DxvkCommandList::endRecording() {
+ if (m_vkd->vkEndCommandBuffer(m_execBuffer) != VK_SUCCESS
+ || m_vkd->vkEndCommandBuffer(m_initBuffer) != VK_SUCCESS
+ || m_vkd->vkEndCommandBuffer(m_sdmaBuffer) != VK_SUCCESS)
+ Logger::err("DxvkCommandList::endRecording: Failed to record command buffer");
+ }
+
+
+ void DxvkCommandList::reset() {
+ // Signal resources and events to
+ // avoid stalling main thread
+ m_signalTracker.reset();
+ m_resources.reset();
+
+ // Recycle heavy Vulkan objects
+ m_descriptorPoolTracker.reset();
+
+ // Return buffer memory slices
+ m_bufferTracker.reset();
+
+ // Return query and event handles
+ m_gpuQueryTracker.reset();
+ m_gpuEventTracker.reset();
+
+ // Less important stuff
+ m_statCounters.reset();
+ }
+
+
+ VkResult DxvkCommandList::submitToQueue(
+ VkQueue queue,
+ VkFence fence,
+ const DxvkQueueSubmission& info) {
+ VkSubmitInfo submitInfo;
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.pNext = nullptr;
+ submitInfo.waitSemaphoreCount = info.waitCount;
+ submitInfo.pWaitSemaphores = info.waitSync;
+ submitInfo.pWaitDstStageMask = info.waitMask;
+ submitInfo.commandBufferCount = info.cmdBufferCount;
+ submitInfo.pCommandBuffers = info.cmdBuffers;
+ submitInfo.signalSemaphoreCount = info.wakeCount;
+ submitInfo.pSignalSemaphores = info.wakeSync;
+
+ return m_vkd->vkQueueSubmit(queue, 1, &submitInfo, fence);
+ }
+
+ void DxvkCommandList::cmdBeginDebugUtilsLabel(VkDebugUtilsLabelEXT *pLabelInfo) {
+ m_vki->vkCmdBeginDebugUtilsLabelEXT(m_execBuffer, pLabelInfo);
+ }
+
+ void DxvkCommandList::cmdEndDebugUtilsLabel() {
+ m_vki->vkCmdEndDebugUtilsLabelEXT(m_execBuffer);
+ }
+
+ void DxvkCommandList::cmdInsertDebugUtilsLabel(VkDebugUtilsLabelEXT *pLabelInfo) {
+ m_vki->vkCmdInsertDebugUtilsLabelEXT(m_execBuffer, pLabelInfo);
+ }
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.h
new file mode 100644
index 00000000..5dda8dbf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cmdlist.h
@@ -0,0 +1,814 @@
+#pragma once
+
+#include <limits>
+
+#include "dxvk_bind_mask.h"
+#include "dxvk_buffer.h"
+#include "dxvk_descriptor.h"
+#include "dxvk_gpu_event.h"
+#include "dxvk_gpu_query.h"
+#include "dxvk_lifetime.h"
+#include "dxvk_limits.h"
+#include "dxvk_pipelayout.h"
+#include "dxvk_signal.h"
+#include "dxvk_staging.h"
+#include "dxvk_stats.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Command buffer flags
+ *
+ * A set of flags used to specify which of
+ * the command buffers need to be submitted.
+ */
+ enum class DxvkCmdBuffer : uint32_t {
+ InitBuffer = 0,
+ ExecBuffer = 1,
+ SdmaBuffer = 2,
+ };
+
+ using DxvkCmdBufferFlags = Flags<DxvkCmdBuffer>;
+
+ /**
+ * \brief Queue submission info
+ *
+ * Convenience struct that holds data for
+ * actual command submissions. Internal use
+ * only, array sizes are based on need.
+ */
+ struct DxvkQueueSubmission {
+ uint32_t waitCount;
+ VkSemaphore waitSync[2];
+ VkPipelineStageFlags waitMask[2];
+ uint32_t wakeCount;
+ VkSemaphore wakeSync[2];
+ uint32_t cmdBufferCount;
+ VkCommandBuffer cmdBuffers[4];
+ };
+
+ /**
+ * \brief DXVK command list
+ *
+ * Stores a command buffer that a context can use to record Vulkan
+ * commands. The command list shall also reference the resources
+ * used by the recorded commands for automatic lifetime tracking.
+ * When the command list has completed execution, resources that
+ * are no longer used may get destroyed.
+ */
+ class DxvkCommandList : public RcObject {
+
+ public:
+
+ DxvkCommandList(DxvkDevice* device);
+ ~DxvkCommandList();
+
+ /**
+ * \brief Submits command list
+ *
+ * \param [in] queue Device queue
+ * \param [in] waitSemaphore Semaphore to wait on
+ * \param [in] wakeSemaphore Semaphore to signal
+ * \returns Submission status
+ */
+ VkResult submit(
+ VkSemaphore waitSemaphore,
+ VkSemaphore wakeSemaphore);
+
+ /**
+ * \brief Synchronizes command buffer execution
+ *
+ * Waits for the fence associated with
+ * this command buffer to get signaled.
+ * \returns Synchronization status
+ */
+ VkResult synchronize();
+
+ /**
+ * \brief Stat counters
+ *
+ * Retrieves some info about per-command list
+ * statistics, such as the number of draw calls
+ * or the number of pipelines compiled.
+ * \returns Reference to stat counters
+ */
+ DxvkStatCounters& statCounters() {
+ return m_statCounters;
+ }
+
+ /**
+ * \brief Increments a stat counter value
+ *
+ * \param [in] ctr The counter to increment
+ * \param [in] val The value to add
+ */
+ void addStatCtr(DxvkStatCounter ctr, uint32_t val) {
+ m_statCounters.addCtr(ctr, val);
+ }
+
+ /**
+ * \brief Begins recording
+ *
+ * Resets the command buffer and
+ * begins command buffer recording.
+ */
+ void beginRecording();
+
+ /**
+ * \brief Ends recording
+ *
+ * Ends command buffer recording, making
+ * the command list ready for submission.
+ * \param [in] stats Stat counters
+ */
+ void endRecording();
+
+ /**
+ * \brief Frees buffer slice
+ *
+ * After the command buffer execution has finished,
+ * the given buffer slice will be released to the
+ * virtual buffer object so that it can be reused.
+ * \param [in] buffer The virtual buffer object
+ * \param [in] slice The buffer slice handle
+ */
+ void freeBufferSlice(
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferSliceHandle& slice) {
+ m_bufferTracker.freeBufferSlice(buffer, slice);
+ }
+
+ /**
+ * \brief Adds a resource to track
+ *
+ * Adds a resource to the internal resource tracker.
+ * Resources will be kept alive and "in use" until
+ * the device can guarantee that the submission has
+ * completed.
+ */
+ template<DxvkAccess Access>
+ void trackResource(Rc<DxvkResource> rc) {
+ m_resources.trackResource<Access>(std::move(rc));
+ }
+
+ /**
+ * \brief Tracks a descriptor pool
+ * \param [in] pool The descriptor pool
+ */
+ void trackDescriptorPool(Rc<DxvkDescriptorPool> pool) {
+ m_descriptorPoolTracker.trackDescriptorPool(pool);
+ }
+
+ /**
+ * \brief Tracks a GPU event
+ *
+ * The event will be returned to its event pool
+ * after the command buffer has finished executing.
+ * \param [in] handle Event handle
+ */
+ void trackGpuEvent(DxvkGpuEventHandle handle) {
+ m_gpuEventTracker.trackEvent(handle);
+ }
+
+ /**
+ * \brief Tracks a GPU query
+ *
+ * The query handle will be returned to its allocator
+ * after the command buffer has finished executing.
+ * \param [in] handle Event handle
+ */
+ void trackGpuQuery(DxvkGpuQueryHandle handle) {
+ m_gpuQueryTracker.trackQuery(handle);
+ }
+
+ /**
+ * \brief Queues signal
+ *
+ * The signal will be notified once the command
+ * buffer has finished executing on the GPU.
+ * \param [in] signal The signal
+ * \param [in] value Signal value
+ */
+ void queueSignal(const Rc<sync::Signal>& signal, uint64_t value) {
+ m_signalTracker.add(signal, value);
+ }
+
+ /**
+ * \brief Notifies signals
+ */
+ void notifySignals() {
+ m_signalTracker.notify();
+ }
+
+ /**
+ * \brief Resets the command list
+ *
+ * Resets the internal command buffer of the command list and
+ * marks all tracked resources as unused. When submitting the
+ * command list to the device, this method will be called once
+ * the command list completes execution.
+ */
+ void reset();
+
+ void updateDescriptorSets(
+ uint32_t descriptorWriteCount,
+ const VkWriteDescriptorSet* pDescriptorWrites) {
+ m_vkd->vkUpdateDescriptorSets(m_vkd->device(),
+ descriptorWriteCount, pDescriptorWrites,
+ 0, nullptr);
+ }
+
+
+ void updateDescriptorSetWithTemplate(
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplate descriptorTemplate,
+ const void* data) {
+ m_vkd->vkUpdateDescriptorSetWithTemplate(m_vkd->device(),
+ descriptorSet, descriptorTemplate, data);
+ }
+
+
+ void cmdBeginConditionalRendering(
+ const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin) {
+ m_vkd->vkCmdBeginConditionalRenderingEXT(
+ m_execBuffer, pConditionalRenderingBegin);
+ }
+
+
+ void cmdEndConditionalRendering() {
+ m_vkd->vkCmdEndConditionalRenderingEXT(m_execBuffer);
+ }
+
+
+
+ void cmdBeginQuery(
+ VkQueryPool queryPool,
+ uint32_t query,
+ VkQueryControlFlags flags) {
+ m_vkd->vkCmdBeginQuery(m_execBuffer,
+ queryPool, query, flags);
+ }
+
+
+ void cmdBeginQueryIndexed(
+ VkQueryPool queryPool,
+ uint32_t query,
+ VkQueryControlFlags flags,
+ uint32_t index) {
+ m_vkd->vkCmdBeginQueryIndexedEXT(
+ m_execBuffer, queryPool, query, flags, index);
+ }
+
+
+ void cmdBeginRenderPass(
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ VkSubpassContents contents) {
+ m_vkd->vkCmdBeginRenderPass(m_execBuffer,
+ pRenderPassBegin, contents);
+ }
+
+
+ void cmdBeginTransformFeedback(
+ uint32_t firstBuffer,
+ uint32_t bufferCount,
+ const VkBuffer* counterBuffers,
+ const VkDeviceSize* counterOffsets) {
+ m_vkd->vkCmdBeginTransformFeedbackEXT(m_execBuffer,
+ firstBuffer, bufferCount, counterBuffers, counterOffsets);
+ }
+
+
+ void cmdBindDescriptorSet(
+ VkPipelineBindPoint pipeline,
+ VkPipelineLayout pipelineLayout,
+ VkDescriptorSet descriptorSet,
+ uint32_t dynamicOffsetCount,
+ const uint32_t* pDynamicOffsets) {
+ m_vkd->vkCmdBindDescriptorSets(m_execBuffer,
+ pipeline, pipelineLayout, 0, 1,
+ &descriptorSet, dynamicOffsetCount, pDynamicOffsets);
+ }
+
+
+ void cmdBindIndexBuffer(
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkIndexType indexType) {
+ m_vkd->vkCmdBindIndexBuffer(m_execBuffer,
+ buffer, offset, indexType);
+ }
+
+
+ void cmdBindPipeline(
+ VkPipelineBindPoint pipelineBindPoint,
+ VkPipeline pipeline) {
+ m_vkd->vkCmdBindPipeline(m_execBuffer,
+ pipelineBindPoint, pipeline);
+ }
+
+
+ void cmdBindTransformFeedbackBuffers(
+ uint32_t firstBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets,
+ const VkDeviceSize* pSizes) {
+ m_vkd->vkCmdBindTransformFeedbackBuffersEXT(m_execBuffer,
+ firstBinding, bindingCount, pBuffers, pOffsets, pSizes);
+ }
+
+
+ void cmdBindVertexBuffers(
+ uint32_t firstBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets) {
+ m_vkd->vkCmdBindVertexBuffers(m_execBuffer,
+ firstBinding, bindingCount, pBuffers, pOffsets);
+ }
+
+
+ void cmdBindVertexBuffers2(
+ uint32_t firstBinding,
+ uint32_t bindingCount,
+ const VkBuffer* pBuffers,
+ const VkDeviceSize* pOffsets,
+ const VkDeviceSize* pSizes,
+ const VkDeviceSize* pStrides) {
+ m_vkd->vkCmdBindVertexBuffers2EXT(m_execBuffer,
+ firstBinding, bindingCount, pBuffers, pOffsets,
+ pSizes, pStrides);
+ }
+
+ void cmdLaunchCuKernel(VkCuLaunchInfoNVX launchInfo) {
+ m_vkd->vkCmdCuLaunchKernelNVX(m_execBuffer, &launchInfo);
+ }
+
+ void cmdBlitImage(
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageBlit* pRegions,
+ VkFilter filter) {
+ m_vkd->vkCmdBlitImage(m_execBuffer,
+ srcImage, srcImageLayout,
+ dstImage, dstImageLayout,
+ regionCount, pRegions, filter);
+ }
+
+
+ void cmdClearAttachments(
+ uint32_t attachmentCount,
+ const VkClearAttachment* pAttachments,
+ uint32_t rectCount,
+ const VkClearRect* pRects) {
+ m_vkd->vkCmdClearAttachments(m_execBuffer,
+ attachmentCount, pAttachments,
+ rectCount, pRects);
+ }
+
+
+ void cmdClearColorImage(
+ VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearColorValue* pColor,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange* pRanges) {
+ m_vkd->vkCmdClearColorImage(m_execBuffer,
+ image, imageLayout, pColor,
+ rangeCount, pRanges);
+ }
+
+
+ void cmdClearDepthStencilImage(
+ VkImage image,
+ VkImageLayout imageLayout,
+ const VkClearDepthStencilValue* pDepthStencil,
+ uint32_t rangeCount,
+ const VkImageSubresourceRange* pRanges) {
+ m_vkd->vkCmdClearDepthStencilImage(m_execBuffer,
+ image, imageLayout, pDepthStencil,
+ rangeCount, pRanges);
+ }
+
+
+ void cmdCopyBuffer(
+ DxvkCmdBuffer cmdBuffer,
+ VkBuffer srcBuffer,
+ VkBuffer dstBuffer,
+ uint32_t regionCount,
+ const VkBufferCopy* pRegions) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdCopyBuffer(getCmdBuffer(cmdBuffer),
+ srcBuffer, dstBuffer,
+ regionCount, pRegions);
+ }
+
+
+ void cmdCopyBufferToImage(
+ DxvkCmdBuffer cmdBuffer,
+ VkBuffer srcBuffer,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkBufferImageCopy* pRegions) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdCopyBufferToImage(getCmdBuffer(cmdBuffer),
+ srcBuffer, dstImage, dstImageLayout,
+ regionCount, pRegions);
+ }
+
+
+ void cmdCopyImage(
+ DxvkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageCopy* pRegions) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdCopyImage(getCmdBuffer(cmdBuffer),
+ srcImage, srcImageLayout,
+ dstImage, dstImageLayout,
+ regionCount, pRegions);
+ }
+
+
+ void cmdCopyImageToBuffer(
+ DxvkCmdBuffer cmdBuffer,
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkBuffer dstBuffer,
+ uint32_t regionCount,
+ const VkBufferImageCopy* pRegions) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdCopyImageToBuffer(getCmdBuffer(cmdBuffer),
+ srcImage, srcImageLayout, dstBuffer,
+ regionCount, pRegions);
+ }
+
+
+ void cmdCopyQueryPoolResults(
+ VkQueryPool queryPool,
+ uint32_t firstQuery,
+ uint32_t queryCount,
+ VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize stride,
+ VkQueryResultFlags flags) {
+ m_vkd->vkCmdCopyQueryPoolResults(m_execBuffer,
+ queryPool, firstQuery, queryCount,
+ dstBuffer, dstOffset, stride, flags);
+ }
+
+
+ void cmdDispatch(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z) {
+ m_vkd->vkCmdDispatch(m_execBuffer, x, y, z);
+ }
+
+
+ void cmdDispatchIndirect(
+ VkBuffer buffer,
+ VkDeviceSize offset) {
+ m_vkd->vkCmdDispatchIndirect(
+ m_execBuffer, buffer, offset);
+ }
+
+
+ void cmdDraw(
+ uint32_t vertexCount,
+ uint32_t instanceCount,
+ uint32_t firstVertex,
+ uint32_t firstInstance) {
+ m_vkd->vkCmdDraw(m_execBuffer,
+ vertexCount, instanceCount,
+ firstVertex, firstInstance);
+ }
+
+
+ void cmdDrawIndirect(
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ uint32_t drawCount,
+ uint32_t stride) {
+ m_vkd->vkCmdDrawIndirect(m_execBuffer,
+ buffer, offset, drawCount, stride);
+ }
+
+
+ void cmdDrawIndirectCount(
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countOffset,
+ uint32_t maxDrawCount,
+ uint32_t stride) {
+ m_vkd->vkCmdDrawIndirectCountKHR(m_execBuffer,
+ buffer, offset, countBuffer, countOffset, maxDrawCount, stride);
+ }
+
+
+ void cmdDrawIndexed(
+ uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ uint32_t vertexOffset,
+ uint32_t firstInstance) {
+ m_vkd->vkCmdDrawIndexed(m_execBuffer,
+ indexCount, instanceCount,
+ firstIndex, vertexOffset,
+ firstInstance);
+ }
+
+
+ void cmdDrawIndexedIndirect(
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ uint32_t drawCount,
+ uint32_t stride) {
+ m_vkd->vkCmdDrawIndexedIndirect(m_execBuffer,
+ buffer, offset, drawCount, stride);
+ }
+
+
+ void cmdDrawIndexedIndirectCount(
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countOffset,
+ uint32_t maxDrawCount,
+ uint32_t stride) {
+ m_vkd->vkCmdDrawIndexedIndirectCountKHR(m_execBuffer,
+ buffer, offset, countBuffer, countOffset, maxDrawCount, stride);
+ }
+
+
+ void cmdDrawIndirectVertexCount(
+ uint32_t instanceCount,
+ uint32_t firstInstance,
+ VkBuffer counterBuffer,
+ VkDeviceSize counterBufferOffset,
+ uint32_t counterOffset,
+ uint32_t vertexStride) {
+ m_vkd->vkCmdDrawIndirectByteCountEXT(m_execBuffer,
+ instanceCount, firstInstance, counterBuffer,
+ counterBufferOffset, counterOffset, vertexStride);
+ }
+
+
+ void cmdEndQuery(
+ VkQueryPool queryPool,
+ uint32_t query) {
+ m_vkd->vkCmdEndQuery(m_execBuffer, queryPool, query);
+ }
+
+
+ void cmdEndQueryIndexed(
+ VkQueryPool queryPool,
+ uint32_t query,
+ uint32_t index) {
+ m_vkd->vkCmdEndQueryIndexedEXT(
+ m_execBuffer, queryPool, query, index);
+ }
+
+
+ void cmdEndRenderPass() {
+ m_vkd->vkCmdEndRenderPass(m_execBuffer);
+ }
+
+
+ void cmdEndTransformFeedback(
+ uint32_t firstBuffer,
+ uint32_t bufferCount,
+ const VkBuffer* counterBuffers,
+ const VkDeviceSize* counterOffsets) {
+ m_vkd->vkCmdEndTransformFeedbackEXT(m_execBuffer,
+ firstBuffer, bufferCount, counterBuffers, counterOffsets);
+ }
+
+
+ void cmdFillBuffer(
+ VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize size,
+ uint32_t data) {
+ m_vkd->vkCmdFillBuffer(m_execBuffer,
+ dstBuffer, dstOffset, size, data);
+ }
+
+
+ void cmdPipelineBarrier(
+ DxvkCmdBuffer cmdBuffer,
+ VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ VkDependencyFlags dependencyFlags,
+ uint32_t memoryBarrierCount,
+ const VkMemoryBarrier* pMemoryBarriers,
+ uint32_t bufferMemoryBarrierCount,
+ const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+ uint32_t imageMemoryBarrierCount,
+ const VkImageMemoryBarrier* pImageMemoryBarriers) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdPipelineBarrier(getCmdBuffer(cmdBuffer),
+ srcStageMask, dstStageMask, dependencyFlags,
+ memoryBarrierCount, pMemoryBarriers,
+ bufferMemoryBarrierCount, pBufferMemoryBarriers,
+ imageMemoryBarrierCount, pImageMemoryBarriers);
+ }
+
+
+ void cmdPushConstants(
+ VkPipelineLayout layout,
+ VkShaderStageFlags stageFlags,
+ uint32_t offset,
+ uint32_t size,
+ const void* pValues) {
+ m_vkd->vkCmdPushConstants(m_execBuffer,
+ layout, stageFlags, offset, size, pValues);
+ }
+
+
+ void cmdResetQuery(
+ VkQueryPool queryPool,
+ uint32_t queryId,
+ VkEvent event) {
+ if (event == VK_NULL_HANDLE) {
+ m_vkd->vkResetQueryPoolEXT(
+ m_vkd->device(), queryPool, queryId, 1);
+ } else {
+ m_cmdBuffersUsed.set(DxvkCmdBuffer::InitBuffer);
+
+ m_vkd->vkResetEvent(
+ m_vkd->device(), event);
+
+ m_vkd->vkCmdResetQueryPool(
+ m_initBuffer, queryPool, queryId, 1);
+
+ m_vkd->vkCmdSetEvent(m_initBuffer,
+ event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
+ }
+ }
+
+
+ void cmdResetQueryPool(
+ VkQueryPool queryPool,
+ uint32_t firstQuery,
+ uint32_t queryCount) {
+ m_cmdBuffersUsed.set(DxvkCmdBuffer::InitBuffer);
+
+ m_vkd->vkCmdResetQueryPool(m_initBuffer,
+ queryPool, firstQuery, queryCount);
+ }
+
+
+ void cmdResolveImage(
+ VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageResolve* pRegions) {
+ m_vkd->vkCmdResolveImage(m_execBuffer,
+ srcImage, srcImageLayout,
+ dstImage, dstImageLayout,
+ regionCount, pRegions);
+ }
+
+
+ void cmdUpdateBuffer(
+ DxvkCmdBuffer cmdBuffer,
+ VkBuffer dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize dataSize,
+ const void* pData) {
+ m_cmdBuffersUsed.set(cmdBuffer);
+
+ m_vkd->vkCmdUpdateBuffer(getCmdBuffer(cmdBuffer),
+ dstBuffer, dstOffset, dataSize, pData);
+ }
+
+
+ void cmdSetBlendConstants(const float blendConstants[4]) {
+ m_vkd->vkCmdSetBlendConstants(m_execBuffer, blendConstants);
+ }
+
+
+ void cmdSetDepthBias(
+ float depthBiasConstantFactor,
+ float depthBiasClamp,
+ float depthBiasSlopeFactor) {
+ m_vkd->vkCmdSetDepthBias(m_execBuffer,
+ depthBiasConstantFactor,
+ depthBiasClamp,
+ depthBiasSlopeFactor);
+ }
+
+
+ void cmdSetDepthBounds(
+ float minDepthBounds,
+ float maxDepthBounds) {
+ m_vkd->vkCmdSetDepthBounds(m_execBuffer,
+ minDepthBounds,
+ maxDepthBounds);
+ }
+
+
+ void cmdSetEvent(
+ VkEvent event,
+ VkPipelineStageFlags stages) {
+ m_vkd->vkCmdSetEvent(m_execBuffer, event, stages);
+ }
+
+
+ void cmdSetScissor(
+ uint32_t firstScissor,
+ uint32_t scissorCount,
+ const VkRect2D* scissors) {
+ m_vkd->vkCmdSetScissor(m_execBuffer,
+ firstScissor, scissorCount, scissors);
+ }
+
+
+ void cmdSetStencilReference(
+ VkStencilFaceFlags faceMask,
+ uint32_t reference) {
+ m_vkd->vkCmdSetStencilReference(m_execBuffer,
+ faceMask, reference);
+ }
+
+
+ void cmdSetViewport(
+ uint32_t firstViewport,
+ uint32_t viewportCount,
+ const VkViewport* viewports) {
+ m_vkd->vkCmdSetViewport(m_execBuffer,
+ firstViewport, viewportCount, viewports);
+ }
+
+
+ void cmdWriteTimestamp(
+ VkPipelineStageFlagBits pipelineStage,
+ VkQueryPool queryPool,
+ uint32_t query) {
+ m_vkd->vkCmdWriteTimestamp(m_execBuffer,
+ pipelineStage, queryPool, query);
+ }
+
+ void cmdBeginDebugUtilsLabel(VkDebugUtilsLabelEXT *pLabelInfo);
+
+ void cmdEndDebugUtilsLabel();
+
+ void cmdInsertDebugUtilsLabel(VkDebugUtilsLabelEXT *pLabelInfo);
+
+ private:
+
+ DxvkDevice* m_device;
+ Rc<vk::DeviceFn> m_vkd;
+ Rc<vk::InstanceFn> m_vki;
+
+ VkFence m_fence;
+
+ VkCommandPool m_graphicsPool = VK_NULL_HANDLE;
+ VkCommandPool m_transferPool = VK_NULL_HANDLE;
+
+ VkCommandBuffer m_execBuffer = VK_NULL_HANDLE;
+ VkCommandBuffer m_initBuffer = VK_NULL_HANDLE;
+ VkCommandBuffer m_sdmaBuffer = VK_NULL_HANDLE;
+
+ VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
+
+ DxvkCmdBufferFlags m_cmdBuffersUsed;
+ DxvkLifetimeTracker m_resources;
+ DxvkDescriptorPoolTracker m_descriptorPoolTracker;
+ DxvkSignalTracker m_signalTracker;
+ DxvkGpuEventTracker m_gpuEventTracker;
+ DxvkGpuQueryTracker m_gpuQueryTracker;
+ DxvkBufferTracker m_bufferTracker;
+ DxvkStatCounters m_statCounters;
+
+ VkCommandBuffer getCmdBuffer(DxvkCmdBuffer cmdBuffer) const {
+ if (cmdBuffer == DxvkCmdBuffer::ExecBuffer) return m_execBuffer;
+ if (cmdBuffer == DxvkCmdBuffer::InitBuffer) return m_initBuffer;
+ if (cmdBuffer == DxvkCmdBuffer::SdmaBuffer) return m_sdmaBuffer;
+ return VK_NULL_HANDLE;
+ }
+
+ VkResult submitToQueue(
+ VkQueue queue,
+ VkFence fence,
+ const DxvkQueueSubmission& info);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.cpp
new file mode 100644
index 00000000..86985890
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.cpp
@@ -0,0 +1,162 @@
+#include <cstring>
+
+#include "../util/util_time.h"
+
+#include "dxvk_compute.h"
+#include "dxvk_device.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_spec_const.h"
+#include "dxvk_state_cache.h"
+
+namespace dxvk {
+
+ DxvkComputePipeline::DxvkComputePipeline(
+ DxvkPipelineManager* pipeMgr,
+ DxvkComputePipelineShaders shaders)
+ : m_vkd(pipeMgr->m_device->vkd()), m_pipeMgr(pipeMgr),
+ m_shaders(std::move(shaders)) {
+ m_shaders.cs->defineResourceSlots(m_slotMapping);
+
+ m_slotMapping.makeDescriptorsDynamic(
+ m_pipeMgr->m_device->options().maxNumDynamicUniformBuffers,
+ m_pipeMgr->m_device->options().maxNumDynamicStorageBuffers);
+
+ m_layout = new DxvkPipelineLayout(m_vkd,
+ m_slotMapping, VK_PIPELINE_BIND_POINT_COMPUTE);
+ }
+
+
+ DxvkComputePipeline::~DxvkComputePipeline() {
+ for (const auto& instance : m_pipelines)
+ this->destroyPipeline(instance.pipeline());
+ }
+
+
+ VkPipeline DxvkComputePipeline::getPipelineHandle(
+ const DxvkComputePipelineStateInfo& state) {
+ DxvkComputePipelineInstance* instance = nullptr;
+
+ { std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ instance = this->findInstance(state);
+
+ if (instance)
+ return instance->pipeline();
+
+ // If no pipeline instance exists with the given state
+ // vector, create a new one and add it to the list.
+ instance = this->createInstance(state);
+ }
+
+ if (!instance)
+ return VK_NULL_HANDLE;
+
+ this->writePipelineStateToCache(state);
+ return instance->pipeline();
+ }
+
+
+ void DxvkComputePipeline::compilePipeline(
+ const DxvkComputePipelineStateInfo& state) {
+ std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ if (!this->findInstance(state))
+ this->createInstance(state);
+ }
+
+
+ DxvkComputePipelineInstance* DxvkComputePipeline::createInstance(
+ const DxvkComputePipelineStateInfo& state) {
+ VkPipeline newPipelineHandle = this->createPipeline(state);
+
+ m_pipeMgr->m_numComputePipelines += 1;
+ return &m_pipelines.emplace_back(state, newPipelineHandle);
+ }
+
+
+ DxvkComputePipelineInstance* DxvkComputePipeline::findInstance(
+ const DxvkComputePipelineStateInfo& state) {
+ for (auto& instance : m_pipelines) {
+ if (instance.isCompatible(state))
+ return &instance;
+ }
+
+ return nullptr;
+ }
+
+
+ VkPipeline DxvkComputePipeline::createPipeline(
+ const DxvkComputePipelineStateInfo& state) const {
+ std::vector<VkDescriptorSetLayoutBinding> bindings;
+
+ if (Logger::logLevel() <= LogLevel::Debug) {
+ Logger::debug("Compiling compute pipeline...");
+ Logger::debug(str::format(" cs : ", m_shaders.cs->debugName()));
+ }
+
+ DxvkSpecConstants specData;
+ for (uint32_t i = 0; i < m_layout->bindingCount(); i++)
+ specData.set(i, state.bsBindingMask.test(i), true);
+
+ for (uint32_t i = 0; i < MaxNumSpecConstants; i++)
+ specData.set(getSpecId(i), state.sc.specConstants[i], 0u);
+
+ VkSpecializationInfo specInfo = specData.getSpecInfo();
+
+ DxvkShaderModuleCreateInfo moduleInfo;
+ moduleInfo.fsDualSrcBlend = false;
+
+ auto csm = m_shaders.cs->createShaderModule(m_vkd, m_slotMapping, moduleInfo);
+
+ VkComputePipelineCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.stage = csm.stageInfo(&specInfo);
+ info.layout = m_layout->pipelineLayout();
+ info.basePipelineHandle = VK_NULL_HANDLE;
+ info.basePipelineIndex = -1;
+
+ // Time pipeline compilation for debugging purposes
+ dxvk::high_resolution_clock::time_point t0, t1;
+
+ if (Logger::logLevel() <= LogLevel::Debug)
+ t0 = dxvk::high_resolution_clock::now();
+
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateComputePipelines(m_vkd->device(),
+ m_pipeMgr->m_cache->handle(), 1, &info, nullptr, &pipeline) != VK_SUCCESS) {
+ Logger::err("DxvkComputePipeline: Failed to compile pipeline");
+ Logger::err(str::format(" cs : ", m_shaders.cs->debugName()));
+ return VK_NULL_HANDLE;
+ }
+
+ if (Logger::logLevel() <= LogLevel::Debug) {
+ t1 = dxvk::high_resolution_clock::now();
+ auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
+ Logger::debug(str::format("DxvkComputePipeline: Finished in ", td.count(), " ms"));
+ }
+
+ return pipeline;
+ }
+
+
+ void DxvkComputePipeline::destroyPipeline(VkPipeline pipeline) {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), pipeline, nullptr);
+ }
+
+
+ void DxvkComputePipeline::writePipelineStateToCache(
+ const DxvkComputePipelineStateInfo& state) const {
+ if (m_pipeMgr->m_stateCache == nullptr)
+ return;
+
+ DxvkStateCacheKey key;
+
+ if (m_shaders.cs != nullptr)
+ key.cs = m_shaders.cs->getShaderKey();
+
+ m_pipeMgr->m_stateCache->addComputePipeline(key, state);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.h
new file mode 100644
index 00000000..5be89d6c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_compute.h
@@ -0,0 +1,166 @@
+#pragma once
+
+#include <atomic>
+#include <vector>
+
+#include "dxvk_bind_mask.h"
+#include "dxvk_graphics_state.h"
+#include "dxvk_pipecache.h"
+#include "dxvk_pipelayout.h"
+#include "dxvk_resource.h"
+#include "dxvk_shader.h"
+#include "dxvk_stats.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+ class DxvkPipelineManager;
+
+ /**
+ * \brief Shaders used in compute pipelines
+ */
+ struct DxvkComputePipelineShaders {
+ Rc<DxvkShader> cs;
+
+ bool eq(const DxvkComputePipelineShaders& other) const {
+ return cs == other.cs;
+ }
+
+ size_t hash() const {
+ return DxvkShader::getHash(cs);
+ }
+ };
+
+
+ /**
+ * \brief Compute pipeline instance
+ */
+ class DxvkComputePipelineInstance {
+
+ public:
+
+ DxvkComputePipelineInstance()
+ : m_stateVector (),
+ m_pipeline (VK_NULL_HANDLE) { }
+
+ DxvkComputePipelineInstance(
+ const DxvkComputePipelineStateInfo& state,
+ VkPipeline pipe)
+ : m_stateVector (state),
+ m_pipeline (pipe) { }
+
+ /**
+ * \brief Checks for matching pipeline state
+ *
+ * \param [in] stateVector Graphics pipeline state
+ * \param [in] renderPass Render pass handle
+ * \returns \c true if the specialization is compatible
+ */
+ bool isCompatible(const DxvkComputePipelineStateInfo& state) const {
+ return m_stateVector == state;
+ }
+
+ /**
+ * \brief Retrieves pipeline
+ * \returns The pipeline handle
+ */
+ VkPipeline pipeline() const {
+ return m_pipeline;
+ }
+
+ private:
+
+ DxvkComputePipelineStateInfo m_stateVector;
+ VkPipeline m_pipeline;
+
+ };
+
+
+ /**
+ * \brief Compute pipeline
+ *
+ * Stores a compute pipeline object and the corresponding
+ * pipeline layout. Unlike graphics pipelines, compute
+ * pipelines do not need to be recompiled against any sort
+ * of pipeline state.
+ */
+ class DxvkComputePipeline {
+
+ public:
+
+ DxvkComputePipeline(
+ DxvkPipelineManager* pipeMgr,
+ DxvkComputePipelineShaders shaders);
+
+ ~DxvkComputePipeline();
+
+ /**
+ * \brief Shaders used by the pipeline
+ * \returns Shaders used by the pipeline
+ */
+ const DxvkComputePipelineShaders& shaders() const {
+ return m_shaders;
+ }
+
+ /**
+ * \brief Pipeline layout
+ *
+ * Stores the pipeline layout and the descriptor set
+ * layout, as well as information on the resource
+ * slots used by the pipeline.
+ * \returns Pipeline layout
+ */
+ DxvkPipelineLayout* layout() const {
+ return m_layout.ptr();
+ }
+
+ /**
+ * \brief Retrieves pipeline handle
+ *
+ * \param [in] state Pipeline state
+ * \returns Pipeline handle
+ */
+ VkPipeline getPipelineHandle(
+ const DxvkComputePipelineStateInfo& state);
+
+ /**
+ * \brief Compiles a pipeline
+ *
+ * Asynchronously compiles the given pipeline
+ * and stores the result for future use.
+ * \param [in] state Pipeline state
+ */
+ void compilePipeline(
+ const DxvkComputePipelineStateInfo& state);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkPipelineManager* m_pipeMgr;
+
+ DxvkComputePipelineShaders m_shaders;
+ DxvkDescriptorSlotMapping m_slotMapping;
+
+ Rc<DxvkPipelineLayout> m_layout;
+
+ sync::Spinlock m_mutex;
+ std::vector<DxvkComputePipelineInstance> m_pipelines;
+
+ DxvkComputePipelineInstance* createInstance(
+ const DxvkComputePipelineStateInfo& state);
+
+ DxvkComputePipelineInstance* findInstance(
+ const DxvkComputePipelineStateInfo& state);
+
+ VkPipeline createPipeline(
+ const DxvkComputePipelineStateInfo& state) const;
+
+ void destroyPipeline(
+ VkPipeline pipeline);
+
+ void writePipelineStateToCache(
+ const DxvkComputePipelineStateInfo& state) const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_constant_state.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_constant_state.h
new file mode 100644
index 00000000..b17dd9b5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_constant_state.h
@@ -0,0 +1,208 @@
+#pragma once
+
+#include "dxvk_buffer.h"
+#include "dxvk_framebuffer.h"
+#include "dxvk_limits.h"
+#include "dxvk_resource.h"
+#include "dxvk_shader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Blend constants
+ *
+ * Stores a blend factor
+ * as an RGBA color value.
+ */
+ struct DxvkBlendConstants {
+ float r, g, b, a;
+
+ bool operator == (const DxvkBlendConstants& other) const {
+ return this->r == other.r && this->g == other.g
+ && this->b == other.b && this->a == other.a;
+ }
+
+ bool operator != (const DxvkBlendConstants& other) const {
+ return this->r != other.r || this->g != other.g
+ || this->b != other.b || this->a != other.a;
+ }
+ };
+
+
+ /**
+ * \brief Depth bias
+ *
+ * Stores depth bias values.
+ */
+ struct DxvkDepthBias {
+ float depthBiasConstant;
+ float depthBiasSlope;
+ float depthBiasClamp;
+
+ bool operator == (const DxvkDepthBias& other) const {
+ return depthBiasConstant == other.depthBiasConstant
+ && depthBiasSlope == other.depthBiasSlope
+ && depthBiasClamp == other.depthBiasClamp;
+ }
+
+ bool operator != (const DxvkDepthBias& other) const {
+ return depthBiasConstant != other.depthBiasConstant
+ || depthBiasSlope != other.depthBiasSlope
+ || depthBiasClamp != other.depthBiasClamp;
+ }
+ };
+
+
+ /**
+ * \brief Depth bounds
+ *
+ * Stores depth bounds values.
+ */
+ struct DxvkDepthBounds {
+ VkBool32 enableDepthBounds;
+ float minDepthBounds;
+ float maxDepthBounds;
+
+ bool operator == (const DxvkDepthBounds& other) const {
+ return enableDepthBounds == other.enableDepthBounds
+ && minDepthBounds == other.minDepthBounds
+ && maxDepthBounds == other.maxDepthBounds;
+ }
+
+ bool operator != (const DxvkDepthBounds& other) const {
+ return enableDepthBounds != other.enableDepthBounds
+ || minDepthBounds != other.minDepthBounds
+ || maxDepthBounds != other.maxDepthBounds;
+ }
+ };
+
+
+ /**
+ * \brief Input assembly state
+ *
+ * Stores the primitive topology and
+ * whether or not primitive restart
+ * is enabled.
+ */
+ struct DxvkInputAssemblyState {
+ VkPrimitiveTopology primitiveTopology;
+ VkBool32 primitiveRestart;
+ uint32_t patchVertexCount;
+ };
+
+
+ /**
+ * \brief Rasterizer state
+ *
+ * Stores the operating mode of the
+ * rasterizer, including the depth bias.
+ */
+ struct DxvkRasterizerState {
+ VkPolygonMode polygonMode;
+ VkCullModeFlags cullMode;
+ VkFrontFace frontFace;
+ VkBool32 depthClipEnable;
+ VkBool32 depthBiasEnable;
+ VkConservativeRasterizationModeEXT conservativeMode;
+ VkSampleCountFlags sampleCount;
+ };
+
+
+ /**
+ * \brief Multisample state
+ *
+ * Defines how to handle certain
+ * aspects of multisampling.
+ */
+ struct DxvkMultisampleState {
+ uint32_t sampleMask;
+ VkBool32 enableAlphaToCoverage;
+ };
+
+
+ /**
+ * \brief Depth-stencil state
+ *
+ * Defines the depth test and stencil
+ * operations for the graphics pipeline.
+ */
+ struct DxvkDepthStencilState {
+ VkBool32 enableDepthTest;
+ VkBool32 enableDepthWrite;
+ VkBool32 enableStencilTest;
+ VkCompareOp depthCompareOp;
+ VkStencilOpState stencilOpFront;
+ VkStencilOpState stencilOpBack;
+ };
+
+
+ /**
+ * \brief Logic op state
+ * Defines a logic op.
+ */
+ struct DxvkLogicOpState {
+ VkBool32 enableLogicOp;
+ VkLogicOp logicOp;
+ };
+
+
+ /**
+ * \brief Blend mode for a single attachment
+ *
+ * Stores the blend state for a single color attachment.
+ * Blend modes can be set separately for each attachment.
+ */
+ struct DxvkBlendMode {
+ VkBool32 enableBlending;
+ VkBlendFactor colorSrcFactor;
+ VkBlendFactor colorDstFactor;
+ VkBlendOp colorBlendOp;
+ VkBlendFactor alphaSrcFactor;
+ VkBlendFactor alphaDstFactor;
+ VkBlendOp alphaBlendOp;
+ VkColorComponentFlags writeMask;
+ };
+
+
+ /**
+ * \brief Vertex attribute description
+ *
+ * Stores information about a
+ * single vertex attribute.
+ */
+ struct DxvkVertexAttribute {
+ uint32_t location;
+ uint32_t binding;
+ VkFormat format;
+ uint32_t offset;
+ };
+
+
+ /**
+ * \brief Vertex binding description
+ *
+ * Stores information about a
+ * single vertex binding slot.
+ */
+ struct DxvkVertexBinding {
+ uint32_t binding;
+ uint32_t fetchRate;
+ VkVertexInputRate inputRate;
+ };
+
+
+ /**
+ * \brief Input layout
+ *
+ * Stores the description of all active
+ * vertex attributes and vertex bindings.
+ */
+ struct DxvkInputLayout {
+ uint32_t numAttributes;
+ uint32_t numBindings;
+
+ std::array<DxvkVertexAttribute, DxvkLimits::MaxNumVertexAttributes> attributes;
+ std::array<DxvkVertexBinding, DxvkLimits::MaxNumVertexBindings> bindings;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.cpp
new file mode 100644
index 00000000..a1c67a90
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.cpp
@@ -0,0 +1,5370 @@
+#include <cstring>
+#include <vector>
+#include <utility>
+
+#include "dxvk_device.h"
+#include "dxvk_context.h"
+#include "dxvk_main.h"
+
+namespace dxvk {
+
+ DxvkContext::DxvkContext(const Rc<DxvkDevice>& device)
+ : m_device (device),
+ m_common (&device->m_objects),
+ m_sdmaAcquires(DxvkCmdBuffer::SdmaBuffer),
+ m_sdmaBarriers(DxvkCmdBuffer::SdmaBuffer),
+ m_initBarriers(DxvkCmdBuffer::InitBuffer),
+ m_execAcquires(DxvkCmdBuffer::ExecBuffer),
+ m_execBarriers(DxvkCmdBuffer::ExecBuffer),
+ m_gfxBarriers (DxvkCmdBuffer::ExecBuffer),
+ m_queryManager(m_common->queryPool()),
+ m_staging (device) {
+ if (m_device->features().extRobustness2.nullDescriptor)
+ m_features.set(DxvkContextFeature::NullDescriptors);
+ if (m_device->features().extExtendedDynamicState.extendedDynamicState)
+ m_features.set(DxvkContextFeature::ExtendedDynamicState);
+ }
+
+
+ DxvkContext::~DxvkContext() {
+
+ }
+
+
+ void DxvkContext::beginRecording(const Rc<DxvkCommandList>& cmdList) {
+ m_cmd = cmdList;
+ m_cmd->beginRecording();
+
+ // Mark all resources as untracked
+ m_vbTracked.clear();
+ m_rcTracked.clear();
+
+ // The current state of the internal command buffer is
+ // undefined, so we have to bind and set up everything
+ // before any draw or dispatch command is recorded.
+ m_flags.clr(
+ DxvkContextFlag::GpRenderPassBound,
+ DxvkContextFlag::GpXfbActive);
+
+ m_flags.set(
+ DxvkContextFlag::GpDirtyFramebuffer,
+ DxvkContextFlag::GpDirtyPipeline,
+ DxvkContextFlag::GpDirtyPipelineState,
+ DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::GpDirtyVertexBuffers,
+ DxvkContextFlag::GpDirtyIndexBuffer,
+ DxvkContextFlag::GpDirtyXfbBuffers,
+ DxvkContextFlag::GpDirtyBlendConstants,
+ DxvkContextFlag::GpDirtyStencilRef,
+ DxvkContextFlag::GpDirtyViewport,
+ DxvkContextFlag::GpDirtyDepthBias,
+ DxvkContextFlag::GpDirtyDepthBounds,
+ DxvkContextFlag::CpDirtyPipeline,
+ DxvkContextFlag::CpDirtyPipelineState,
+ DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::DirtyDrawBuffer);
+ }
+
+
+ Rc<DxvkCommandList> DxvkContext::endRecording() {
+ this->spillRenderPass(true);
+ this->flushSharedImages();
+
+ m_sdmaBarriers.recordCommands(m_cmd);
+ m_initBarriers.recordCommands(m_cmd);
+ m_execBarriers.recordCommands(m_cmd);
+
+ m_cmd->endRecording();
+ return std::exchange(m_cmd, nullptr);
+ }
+
+
+ void DxvkContext::flushCommandList() {
+ m_device->submitCommandList(
+ this->endRecording(),
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE);
+
+ this->beginRecording(
+ m_device->createCommandList());
+ }
+
+
+ void DxvkContext::beginQuery(const Rc<DxvkGpuQuery>& query) {
+ m_queryManager.enableQuery(m_cmd, query);
+ }
+
+
+ void DxvkContext::endQuery(const Rc<DxvkGpuQuery>& query) {
+ m_queryManager.disableQuery(m_cmd, query);
+ }
+
+
+ void DxvkContext::bindRenderTargets(
+ const DxvkRenderTargets& targets) {
+ // Set up default render pass ops
+ m_state.om.renderTargets = targets;
+
+ this->resetRenderPassOps(
+ m_state.om.renderTargets,
+ m_state.om.renderPassOps);
+
+ if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->hasTargets(targets)) {
+ // Create a new framebuffer object next
+ // time we start rendering something
+ m_flags.set(DxvkContextFlag::GpDirtyFramebuffer);
+ } else {
+ // Don't redundantly spill the render pass if
+ // the same render targets are bound again
+ m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
+ }
+ }
+
+
+ void DxvkContext::bindDrawBuffers(
+ const DxvkBufferSlice& argBuffer,
+ const DxvkBufferSlice& cntBuffer) {
+ m_state.id.argBuffer = argBuffer;
+ m_state.id.cntBuffer = cntBuffer;
+
+ m_flags.set(DxvkContextFlag::DirtyDrawBuffer);
+ }
+
+
+ void DxvkContext::bindIndexBuffer(
+ const DxvkBufferSlice& buffer,
+ VkIndexType indexType) {
+ if (!m_state.vi.indexBuffer.matchesBuffer(buffer))
+ m_vbTracked.clr(MaxNumVertexBindings);
+
+ m_state.vi.indexBuffer = buffer;
+ m_state.vi.indexType = indexType;
+
+ m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
+ }
+
+
+ void DxvkContext::bindResourceBuffer(
+ uint32_t slot,
+ const DxvkBufferSlice& buffer) {
+ bool needsUpdate = !m_rc[slot].bufferSlice.matchesBuffer(buffer);
+
+ if (likely(needsUpdate))
+ m_rcTracked.clr(slot);
+ else
+ needsUpdate = m_rc[slot].bufferSlice.length() != buffer.length();
+
+ if (likely(needsUpdate)) {
+ m_flags.set(
+ DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::GpDirtyResources);
+ } else {
+ m_flags.set(
+ DxvkContextFlag::CpDirtyDescriptorBinding,
+ DxvkContextFlag::GpDirtyDescriptorBinding);
+ }
+
+ m_rc[slot].bufferSlice = buffer;
+ }
+
+
+ void DxvkContext::bindResourceView(
+ uint32_t slot,
+ const Rc<DxvkImageView>& imageView,
+ const Rc<DxvkBufferView>& bufferView) {
+ m_rc[slot].imageView = imageView;
+ m_rc[slot].bufferView = bufferView;
+ m_rc[slot].bufferSlice = bufferView != nullptr
+ ? bufferView->slice()
+ : DxvkBufferSlice();
+ m_rcTracked.clr(slot);
+
+ m_flags.set(
+ DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::GpDirtyResources);
+ }
+
+
+ void DxvkContext::bindResourceSampler(
+ uint32_t slot,
+ const Rc<DxvkSampler>& sampler) {
+ m_rc[slot].sampler = sampler;
+ m_rcTracked.clr(slot);
+
+ m_flags.set(
+ DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::GpDirtyResources);
+ }
+
+
+ void DxvkContext::bindShader(
+ VkShaderStageFlagBits stage,
+ const Rc<DxvkShader>& shader) {
+ Rc<DxvkShader>* shaderStage;
+
+ switch (stage) {
+ case VK_SHADER_STAGE_VERTEX_BIT: shaderStage = &m_state.gp.shaders.vs; break;
+ case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: shaderStage = &m_state.gp.shaders.tcs; break;
+ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: shaderStage = &m_state.gp.shaders.tes; break;
+ case VK_SHADER_STAGE_GEOMETRY_BIT: shaderStage = &m_state.gp.shaders.gs; break;
+ case VK_SHADER_STAGE_FRAGMENT_BIT: shaderStage = &m_state.gp.shaders.fs; break;
+ case VK_SHADER_STAGE_COMPUTE_BIT: shaderStage = &m_state.cp.shaders.cs; break;
+ default: return;
+ }
+
+ *shaderStage = shader;
+
+ if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
+ m_flags.set(
+ DxvkContextFlag::CpDirtyPipeline,
+ DxvkContextFlag::CpDirtyPipelineState,
+ DxvkContextFlag::CpDirtyResources);
+ } else {
+ m_flags.set(
+ DxvkContextFlag::GpDirtyPipeline,
+ DxvkContextFlag::GpDirtyPipelineState,
+ DxvkContextFlag::GpDirtyResources);
+ }
+ }
+
+
+ void DxvkContext::bindVertexBuffer(
+ uint32_t binding,
+ const DxvkBufferSlice& buffer,
+ uint32_t stride) {
+ if (!m_state.vi.vertexBuffers[binding].matchesBuffer(buffer))
+ m_vbTracked.clr(binding);
+
+ m_state.vi.vertexBuffers[binding] = buffer;
+ m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
+
+ if (unlikely(!buffer.defined())
+ && unlikely(!m_features.test(DxvkContextFeature::NullDescriptors)))
+ stride = 0;
+
+ if (unlikely(m_state.vi.vertexStrides[binding] != stride)) {
+ m_state.vi.vertexStrides[binding] = stride;
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+ }
+
+
+ void DxvkContext::bindXfbBuffer(
+ uint32_t binding,
+ const DxvkBufferSlice& buffer,
+ const DxvkBufferSlice& counter) {
+ if (!m_state.xfb.buffers [binding].matches(buffer)
+ || !m_state.xfb.counters[binding].matches(counter)) {
+ m_state.xfb.buffers [binding] = buffer;
+ m_state.xfb.counters[binding] = counter;
+
+ m_flags.set(DxvkContextFlag::GpDirtyXfbBuffers);
+ }
+ }
+
+
+ void DxvkContext::blitImage(
+ const Rc<DxvkImage>& dstImage,
+ const VkComponentMapping& dstMapping,
+ const Rc<DxvkImage>& srcImage,
+ const VkComponentMapping& srcMapping,
+ const VkImageBlit& region,
+ VkFilter filter) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(region.dstSubresource));
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(region.srcSubresource));
+
+ auto mapping = util::resolveSrcComponentMapping(dstMapping, srcMapping);
+
+ bool canUseFb = (srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)
+ && (dstImage->info().usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ && ((dstImage->info().flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)
+ || (dstImage->info().type != VK_IMAGE_TYPE_3D));
+
+ bool useFb = dstImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT
+ || !util::isIdentityMapping(mapping);
+
+ if (!useFb) {
+ this->blitImageHw(
+ dstImage, srcImage,
+ region, filter);
+ } else if (canUseFb) {
+ this->blitImageFb(
+ dstImage, srcImage,
+ region, mapping, filter);
+ } else {
+ Logger::err("DxvkContext: Unsupported blit operation");
+ }
+ }
+
+
+ void DxvkContext::changeImageLayout(
+ const Rc<DxvkImage>& image,
+ VkImageLayout layout) {
+ if (image->info().layout != layout) {
+ this->spillRenderPass(true);
+
+ VkImageSubresourceRange subresources = image->getAvailableSubresources();
+
+ this->prepareImage(m_execBarriers, image, subresources);
+
+ if (m_execBarriers.isImageDirty(image, subresources, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ m_execBarriers.accessImage(image, subresources,
+ image->info().layout,
+ image->info().stages, 0,
+ layout,
+ image->info().stages,
+ image->info().access);
+
+ image->setLayout(layout);
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+ }
+
+
+ void DxvkContext::clearBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ uint32_t value) {
+ this->spillRenderPass(true);
+
+ length = align(length, sizeof(uint32_t));
+ auto slice = buffer->getSliceHandle(offset, length);
+
+ if (m_execBarriers.isBufferDirty(slice, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ m_cmd->cmdFillBuffer(
+ slice.handle,
+ slice.offset,
+ slice.length,
+ value);
+
+ m_execBarriers.accessBuffer(slice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ buffer->info().stages,
+ buffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(buffer);
+ }
+
+
+ void DxvkContext::clearBufferView(
+ const Rc<DxvkBufferView>& bufferView,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ VkClearColorValue value) {
+ this->spillRenderPass(true);
+ this->unbindComputePipeline();
+
+ // The view range might have been invalidated, so
+ // we need to make sure the handle is up to date
+ bufferView->updateView();
+
+ auto bufferSlice = bufferView->getSliceHandle();
+
+ if (m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Query pipeline objects to use for this clear operation
+ DxvkMetaClearPipeline pipeInfo = m_common->metaClear().getClearBufferPipeline(
+ imageFormatInfo(bufferView->info().format)->flags);
+
+ // Create a descriptor set pointing to the view
+ VkBufferView viewObject = bufferView->handle();
+
+ VkDescriptorSet descriptorSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstSet = descriptorSet;
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+ descriptorWrite.pImageInfo = nullptr;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = &viewObject;
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+
+ // Prepare shader arguments
+ DxvkMetaClearArgs pushArgs = { };
+ pushArgs.clearValue = value;
+ pushArgs.offset = VkOffset3D { int32_t(offset), 0, 0 };
+ pushArgs.extent = VkExtent3D { uint32_t(length), 1, 1 };
+
+ VkExtent3D workgroups = util::computeBlockCount(
+ pushArgs.extent, pipeInfo.workgroupSize);
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeline);
+ m_cmd->cmdBindDescriptorSet(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeLayout, descriptorSet,
+ 0, nullptr);
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(pushArgs), &pushArgs);
+ m_cmd->cmdDispatch(
+ workgroups.width,
+ workgroups.height,
+ workgroups.depth);
+
+ m_execBarriers.accessBuffer(bufferSlice,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_WRITE_BIT,
+ bufferView->bufferInfo().stages,
+ bufferView->bufferInfo().access);
+
+ m_cmd->trackResource<DxvkAccess::None>(bufferView);
+ m_cmd->trackResource<DxvkAccess::Write>(bufferView->buffer());
+ }
+
+
+ void DxvkContext::clearColorImage(
+ const Rc<DxvkImage>& image,
+ const VkClearColorValue& value,
+ const VkImageSubresourceRange& subresources) {
+ this->spillRenderPass(false);
+
+ VkImageLayout imageLayoutClear = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ this->initializeImage(image, subresources,
+ imageLayoutClear,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ m_cmd->cmdClearColorImage(image->handle(),
+ imageLayoutClear, &value, 1, &subresources);
+
+ m_execBarriers.accessImage(image, subresources,
+ imageLayoutClear,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::clearDepthStencilImage(
+ const Rc<DxvkImage>& image,
+ const VkClearDepthStencilValue& value,
+ const VkImageSubresourceRange& subresources) {
+ this->spillRenderPass(false);
+
+ m_execBarriers.recordCommands(m_cmd);
+
+ VkImageLayout imageLayoutClear = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ this->initializeImage(image, subresources,
+ imageLayoutClear,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ m_cmd->cmdClearDepthStencilImage(image->handle(),
+ imageLayoutClear, &value, 1, &subresources);
+
+ m_execBarriers.accessImage(
+ image, subresources,
+ imageLayoutClear,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::clearCompressedColorImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources) {
+ this->spillRenderPass(false);
+
+ VkImageLayout layout = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ this->initializeImage(image, subresources, layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ auto formatInfo = image->formatInfo();
+
+ for (auto aspects = formatInfo->aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto extent = image->mipLevelExtent(subresources.baseMipLevel);
+ auto elementSize = formatInfo->elementSize;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ extent.width /= plane->blockSize.width;
+ extent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ // Allocate enough staging buffer memory to fit one
+ // single subresource, then dispatch multiple copies
+ VkExtent3D blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
+ VkDeviceSize dataSize = util::flattenImageExtent(blockCount) * elementSize;
+
+ auto zeroBuffer = createZeroBuffer(dataSize);
+ auto zeroHandle = zeroBuffer->getSliceHandle();
+
+ for (uint32_t level = 0; level < subresources.levelCount; level++) {
+ VkOffset3D offset = VkOffset3D { 0, 0, 0 };
+ VkExtent3D extent = image->mipLevelExtent(subresources.baseMipLevel + level);
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ extent.width /= plane->blockSize.width;
+ extent.height /= plane->blockSize.height;
+ }
+
+ for (uint32_t layer = 0; layer < subresources.layerCount; layer++) {
+ VkBufferImageCopy region;
+ region.bufferOffset = zeroHandle.offset;
+ region.bufferRowLength = 0;
+ region.bufferImageHeight = 0;
+ region.imageSubresource = vk::makeSubresourceLayers(
+ vk::pickSubresource(subresources, level, layer));
+ region.imageSubresource.aspectMask = aspect;
+ region.imageOffset = offset;
+ region.imageExtent = extent;
+
+ m_cmd->cmdCopyBufferToImage(DxvkCmdBuffer::ExecBuffer,
+ zeroHandle.handle, image->handle(), layout, 1, &region);
+ }
+ }
+
+ m_cmd->trackResource<DxvkAccess::Read>(zeroBuffer);
+ }
+
+ m_execBarriers.accessImage(
+ image, subresources, layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::clearRenderTarget(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue) {
+ // Make sure the color components are ordered correctly
+ if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
+ clearValue.color = util::swizzleClearColor(clearValue.color,
+ util::invertComponentMapping(imageView->info().swizzle));
+ }
+
+ // Check whether the render target view is an attachment
+ // of the current framebuffer and is included entirely.
+ // If not, we need to create a temporary framebuffer.
+ int32_t attachmentIndex = -1;
+
+ if (m_state.om.framebuffer != nullptr
+ && m_state.om.framebuffer->isFullSize(imageView))
+ attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
+
+ if (attachmentIndex < 0) {
+ // Suspend works here because we'll end up with one of these scenarios:
+ // 1) The render pass gets ended for good, in which case we emit barriers
+ // 2) The clear gets folded into render pass ops, so the layout is correct
+ // 3) The clear gets executed separately, in which case updateFramebuffer
+ // will indirectly emit barriers for the given render target.
+ // If there is overlap, we need to explicitly transition affected attachments.
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, imageView->image(), imageView->subresources(), false);
+ } else if (!m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects)) {
+ // We cannot inline clears if the clear aspects are not writable
+ this->spillRenderPass(true);
+ }
+
+ if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
+ uint32_t colorIndex = std::max(0, m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex));
+
+ VkClearAttachment clearInfo;
+ clearInfo.aspectMask = clearAspects;
+ clearInfo.colorAttachment = colorIndex;
+ clearInfo.clearValue = clearValue;
+
+ VkClearRect clearRect;
+ clearRect.rect.offset.x = 0;
+ clearRect.rect.offset.y = 0;
+ clearRect.rect.extent.width = imageView->mipLevelExtent(0).width;
+ clearRect.rect.extent.height = imageView->mipLevelExtent(0).height;
+ clearRect.baseArrayLayer = 0;
+ clearRect.layerCount = imageView->info().numLayers;
+
+ m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
+ } else
+ this->deferClear(imageView, clearAspects, clearValue);
+ }
+
+
+ void DxvkContext::clearImageView(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkImageAspectFlags aspect,
+ VkClearValue value) {
+ const VkImageUsageFlags viewUsage = imageView->info().usage;
+
+ if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
+ value.color = util::swizzleClearColor(value.color,
+ util::invertComponentMapping(imageView->info().swizzle));
+ }
+
+ if (viewUsage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
+ this->clearImageViewFb(imageView, offset, extent, aspect, value);
+ else if (viewUsage & VK_IMAGE_USAGE_STORAGE_BIT)
+ this->clearImageViewCs(imageView, offset, extent, value);
+ }
+
+
+ void DxvkContext::copyBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcOffset,
+ VkDeviceSize numBytes) {
+ if (numBytes == 0)
+ return;
+
+ this->spillRenderPass(true);
+
+ auto dstSlice = dstBuffer->getSliceHandle(dstOffset, numBytes);
+ auto srcSlice = srcBuffer->getSliceHandle(srcOffset, numBytes);
+
+ if (m_execBarriers.isBufferDirty(srcSlice, DxvkAccess::Read)
+ || m_execBarriers.isBufferDirty(dstSlice, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ VkBufferCopy bufferRegion;
+ bufferRegion.srcOffset = srcSlice.offset;
+ bufferRegion.dstOffset = dstSlice.offset;
+ bufferRegion.size = dstSlice.length;
+
+ m_cmd->cmdCopyBuffer(DxvkCmdBuffer::ExecBuffer,
+ srcSlice.handle, dstSlice.handle, 1, &bufferRegion);
+
+ m_execBarriers.accessBuffer(srcSlice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcBuffer->info().stages,
+ srcBuffer->info().access);
+
+ m_execBarriers.accessBuffer(dstSlice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstBuffer->info().stages,
+ dstBuffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstBuffer);
+ m_cmd->trackResource<DxvkAccess::Read>(srcBuffer);
+ }
+
+
+ void DxvkContext::copyBufferRegion(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize srcOffset,
+ VkDeviceSize numBytes) {
+ VkDeviceSize loOvl = std::max(dstOffset, srcOffset);
+ VkDeviceSize hiOvl = std::min(dstOffset, srcOffset) + numBytes;
+
+ if (hiOvl > loOvl) {
+ DxvkBufferCreateInfo bufInfo;
+ bufInfo.size = numBytes;
+ bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ bufInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT;
+
+ auto tmpBuffer = m_device->createBuffer(
+ bufInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ VkDeviceSize tmpOffset = 0;
+
+ this->copyBuffer(tmpBuffer, tmpOffset, dstBuffer, srcOffset, numBytes);
+ this->copyBuffer(dstBuffer, dstOffset, tmpBuffer, tmpOffset, numBytes);
+ } else {
+ this->copyBuffer(dstBuffer, dstOffset, dstBuffer, srcOffset, numBytes);
+ }
+ }
+
+
+ void DxvkContext::copyBufferToImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkExtent3D dstExtent,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcOffset,
+ VkDeviceSize rowAlignment,
+ VkDeviceSize sliceAlignment) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(dstSubresource));
+
+ auto srcSlice = srcBuffer->getSliceHandle(srcOffset, 0);
+
+ // We may copy to only one aspect at a time, but pipeline
+ // barriers need to have all available aspect bits set
+ auto dstFormatInfo = dstImage->formatInfo();
+
+ auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource);
+ dstSubresourceRange.aspectMask = dstFormatInfo->aspectMask;
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isBufferDirty(srcSlice, DxvkAccess::Read))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Initialize the image if the entire subresource is covered
+ VkImageLayout dstImageLayoutInitial = dstImage->info().layout;
+ VkImageLayout dstImageLayoutTransfer = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ if (dstImage->isFullSubresource(dstSubresource, dstExtent))
+ dstImageLayoutInitial = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ if (dstImageLayoutTransfer != dstImageLayoutInitial) {
+ m_execAcquires.accessImage(
+ dstImage, dstSubresourceRange,
+ dstImageLayoutInitial,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ dstImageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ this->copyImageBufferData<true>(DxvkCmdBuffer::ExecBuffer, dstImage, dstSubresource,
+ dstOffset, dstExtent, dstImageLayoutTransfer, srcSlice, rowAlignment, sliceAlignment);
+
+ m_execBarriers.accessImage(
+ dstImage, dstSubresourceRange,
+ dstImageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_execBarriers.accessBuffer(srcSlice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcBuffer->info().stages,
+ srcBuffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcBuffer);
+ }
+
+
+ void DxvkContext::copyImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent) {
+ this->spillRenderPass(true);
+
+ if (this->copyImageClear(dstImage, dstSubresource, dstOffset, extent, srcImage, srcSubresource))
+ return;
+
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(dstSubresource));
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(srcSubresource));
+
+ bool useFb = dstSubresource.aspectMask != srcSubresource.aspectMask;
+
+ if (m_device->perfHints().preferFbDepthStencilCopy) {
+ useFb |= (dstSubresource.aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
+ && (dstImage->info().usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
+ && (srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT);
+ }
+
+ if (!useFb) {
+ this->copyImageHw(
+ dstImage, dstSubresource, dstOffset,
+ srcImage, srcSubresource, srcOffset,
+ extent);
+ } else {
+ this->copyImageFb(
+ dstImage, dstSubresource, dstOffset,
+ srcImage, srcSubresource, srcOffset,
+ extent);
+ }
+ }
+
+
+ void DxvkContext::copyImageRegion(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkOffset3D srcOffset,
+ VkExtent3D extent) {
+ VkOffset3D loOvl = {
+ std::max(dstOffset.x, srcOffset.x),
+ std::max(dstOffset.y, srcOffset.y),
+ std::max(dstOffset.z, srcOffset.z) };
+
+ VkOffset3D hiOvl = {
+ std::min(dstOffset.x, srcOffset.x) + int32_t(extent.width),
+ std::min(dstOffset.y, srcOffset.y) + int32_t(extent.height),
+ std::min(dstOffset.z, srcOffset.z) + int32_t(extent.depth) };
+
+ bool overlap = hiOvl.x > loOvl.x
+ && hiOvl.y > loOvl.y
+ && hiOvl.z > loOvl.z;
+
+ if (overlap) {
+ DxvkImageCreateInfo imgInfo;
+ imgInfo.type = dstImage->info().type;
+ imgInfo.format = dstImage->info().format;
+ imgInfo.flags = 0;
+ imgInfo.sampleCount = dstImage->info().sampleCount;
+ imgInfo.extent = extent;
+ imgInfo.numLayers = dstSubresource.layerCount;
+ imgInfo.mipLevels = 1;
+ imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ imgInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ imgInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT;
+ imgInfo.tiling = dstImage->info().tiling;
+ imgInfo.layout = VK_IMAGE_LAYOUT_GENERAL;
+
+ auto tmpImage = m_device->createImage(
+ imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ VkImageSubresourceLayers tmpSubresource;
+ tmpSubresource.aspectMask = dstSubresource.aspectMask;
+ tmpSubresource.mipLevel = 0;
+ tmpSubresource.baseArrayLayer = 0;
+ tmpSubresource.layerCount = dstSubresource.layerCount;
+
+ VkOffset3D tmpOffset = { 0, 0, 0 };
+
+ this->copyImage(
+ tmpImage, tmpSubresource, tmpOffset,
+ dstImage, dstSubresource, srcOffset,
+ extent);
+
+ this->copyImage(
+ dstImage, dstSubresource, dstOffset,
+ tmpImage, tmpSubresource, tmpOffset,
+ extent);
+ } else {
+ this->copyImage(
+ dstImage, dstSubresource, dstOffset,
+ dstImage, dstSubresource, srcOffset,
+ extent);
+ }
+ }
+
+
+ void DxvkContext::copyImageToBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize rowAlignment,
+ VkDeviceSize sliceAlignment,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D srcExtent) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(srcSubresource));
+
+ auto dstSlice = dstBuffer->getSliceHandle(dstOffset, 0);
+
+ // We may copy to only one aspect of a depth-stencil image,
+ // but pipeline barriers need to have all aspect bits set
+ auto srcFormatInfo = srcImage->formatInfo();
+
+ auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresource);
+ srcSubresourceRange.aspectMask = srcFormatInfo->aspectMask;
+
+ if (m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isBufferDirty(dstSlice, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Select a suitable image layout for the transfer op
+ VkImageLayout srcImageLayoutTransfer = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ srcImageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ this->copyImageBufferData<false>(DxvkCmdBuffer::ExecBuffer, srcImage, srcSubresource,
+ srcOffset, srcExtent, srcImageLayoutTransfer, dstSlice, rowAlignment, sliceAlignment);
+
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_execBarriers.accessBuffer(dstSlice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstBuffer->info().stages,
+ dstBuffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstBuffer);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ }
+
+
+ void DxvkContext::copyDepthStencilImageToPackedBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstBufferOffset,
+ VkOffset2D dstOffset,
+ VkExtent2D dstExtent,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset2D srcOffset,
+ VkExtent2D srcExtent,
+ VkFormat format) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(srcSubresource));
+
+ this->unbindComputePipeline();
+
+ // Retrieve compute pipeline for the given format
+ auto pipeInfo = m_common->metaPack().getPackPipeline(format);
+
+ if (!pipeInfo.pipeHandle)
+ return;
+
+ // Create one depth view and one stencil view
+ DxvkImageViewCreateInfo dViewInfo;
+ dViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ dViewInfo.format = srcImage->info().format;
+ dViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ dViewInfo.aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
+ dViewInfo.minLevel = srcSubresource.mipLevel;
+ dViewInfo.numLevels = 1;
+ dViewInfo.minLayer = srcSubresource.baseArrayLayer;
+ dViewInfo.numLayers = srcSubresource.layerCount;
+
+ DxvkImageViewCreateInfo sViewInfo = dViewInfo;
+ sViewInfo.aspect = VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ Rc<DxvkImageView> dView = m_device->createImageView(srcImage, dViewInfo);
+ Rc<DxvkImageView> sView = m_device->createImageView(srcImage, sViewInfo);
+
+ // Create a descriptor set for the pack operation
+ VkImageLayout layout = srcImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
+
+ DxvkMetaPackDescriptors descriptors;
+ descriptors.dstBuffer = dstBuffer->getDescriptor(dstBufferOffset, VK_WHOLE_SIZE).buffer;
+ descriptors.srcDepth = dView->getDescriptor(VK_IMAGE_VIEW_TYPE_2D_ARRAY, layout).image;
+ descriptors.srcStencil = sView->getDescriptor(VK_IMAGE_VIEW_TYPE_2D_ARRAY, layout).image;
+
+ VkDescriptorSet dset = allocateDescriptorSet(pipeInfo.dsetLayout);
+ m_cmd->updateDescriptorSetWithTemplate(dset, pipeInfo.dsetTemplate, &descriptors);
+
+ // Since this is a meta operation, the image may be
+ // in a different layout and we have to transition it
+ auto subresourceRange = vk::makeSubresourceRange(srcSubresource);
+
+ if (m_execBarriers.isImageDirty(srcImage, subresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ if (srcImage->info().layout != layout) {
+ m_execAcquires.accessImage(
+ srcImage, subresourceRange,
+ srcImage->info().layout,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
+ layout,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+ }
+
+ // Execute the actual pack operation
+ DxvkMetaPackArgs args;
+ args.srcOffset = srcOffset;
+ args.srcExtent = srcExtent;
+ args.dstOffset = dstOffset;
+ args.dstExtent = dstExtent;
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeHandle);
+
+ m_cmd->cmdBindDescriptorSet(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeLayout, dset,
+ 0, nullptr);
+
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(args), &args);
+
+ m_cmd->cmdDispatch(
+ (srcExtent.width + 7) / 8,
+ (srcExtent.height + 7) / 8,
+ srcSubresource.layerCount);
+
+ m_execBarriers.accessImage(
+ srcImage, subresourceRange, layout,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_execBarriers.accessBuffer(
+ dstBuffer->getSliceHandle(),
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_WRITE_BIT,
+ dstBuffer->info().stages,
+ dstBuffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::None>(dView);
+ m_cmd->trackResource<DxvkAccess::None>(sView);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstBuffer);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ }
+
+
+ void DxvkContext::copyPackedBufferImage(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstBufferOffset,
+ VkOffset3D dstOffset,
+ VkExtent3D dstSize,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcBufferOffset,
+ VkOffset3D srcOffset,
+ VkExtent3D srcSize,
+ VkExtent3D extent,
+ VkDeviceSize elementSize) {
+ this->spillRenderPass(true);
+ this->unbindComputePipeline();
+
+ auto dstBufferSlice = dstBuffer->getSliceHandle(dstBufferOffset, elementSize * util::flattenImageExtent(dstSize));
+ auto srcBufferSlice = srcBuffer->getSliceHandle(srcBufferOffset, elementSize * util::flattenImageExtent(srcSize));
+
+ if (m_execBarriers.isBufferDirty(dstBufferSlice, DxvkAccess::Write)
+ || m_execBarriers.isBufferDirty(srcBufferSlice, DxvkAccess::Read))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // We'll use texel buffer views with an appropriately
+ // sized integer format to perform the copy
+ VkFormat format = VK_FORMAT_UNDEFINED;
+
+ switch (elementSize) {
+ case 1: format = VK_FORMAT_R8_UINT; break;
+ case 2: format = VK_FORMAT_R16_UINT; break;
+ case 4: format = VK_FORMAT_R32_UINT; break;
+ case 8: format = VK_FORMAT_R32G32_UINT; break;
+ case 12: format = VK_FORMAT_R32G32B32_UINT; break;
+ case 16: format = VK_FORMAT_R32G32B32A32_UINT; break;
+ }
+
+ if (!format) {
+ Logger::err(str::format("DxvkContext: copyPackedBufferImage: Unsupported element size ", elementSize));
+ return;
+ }
+
+ DxvkBufferViewCreateInfo viewInfo;
+ viewInfo.format = format;
+ viewInfo.rangeOffset = dstBufferOffset;
+ viewInfo.rangeLength = dstBufferSlice.length;
+ Rc<DxvkBufferView> dstView = m_device->createBufferView(dstBuffer, viewInfo);
+
+ viewInfo.rangeOffset = srcBufferOffset;
+ viewInfo.rangeLength = srcBufferSlice.length;
+ Rc<DxvkBufferView> srcView;
+
+ if (srcBuffer == dstBuffer
+ && srcBufferSlice.offset < dstBufferSlice.offset + dstBufferSlice.length
+ && srcBufferSlice.offset + srcBufferSlice.length > dstBufferSlice.offset) {
+ // Create temporary copy in case of overlapping regions
+ DxvkBufferCreateInfo bufferInfo;
+ bufferInfo.size = srcBufferSlice.length;
+ bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+ bufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ bufferInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ Rc<DxvkBuffer> tmpBuffer = m_device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ auto tmpBufferSlice = tmpBuffer->getSliceHandle();
+
+ VkBufferCopy copyRegion;
+ copyRegion.srcOffset = srcBufferSlice.offset;
+ copyRegion.dstOffset = tmpBufferSlice.offset;
+ copyRegion.size = tmpBufferSlice.length;
+
+ m_cmd->cmdCopyBuffer(DxvkCmdBuffer::ExecBuffer,
+ srcBufferSlice.handle, tmpBufferSlice.handle,
+ 1, &copyRegion);
+
+ emitMemoryBarrier(0,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ viewInfo.rangeOffset = 0;
+ srcView = m_device->createBufferView(tmpBuffer, viewInfo);
+
+ m_cmd->trackResource<DxvkAccess::Write>(tmpBuffer);
+ } else {
+ srcView = m_device->createBufferView(srcBuffer, viewInfo);
+ }
+
+ auto pipeInfo = m_common->metaCopy().getCopyBufferImagePipeline();
+ VkDescriptorSet descriptorSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+
+ std::array<VkWriteDescriptorSet, 2> descriptorWrites;
+
+ std::array<std::pair<VkDescriptorType, VkBufferView>, 2> descriptorInfos = {{
+ { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, dstView->handle() },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, srcView->handle() },
+ }};
+
+ for (uint32_t i = 0; i < descriptorWrites.size(); i++) {
+ auto write = &descriptorWrites[i];
+ auto info = &descriptorInfos[i];
+
+ write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write->pNext = nullptr;
+ write->dstSet = descriptorSet;
+ write->dstBinding = i;
+ write->dstArrayElement = 0;
+ write->descriptorCount = 1;
+ write->descriptorType = info->first;
+ write->pImageInfo = nullptr;
+ write->pBufferInfo = nullptr;
+ write->pTexelBufferView = &info->second;
+ }
+
+ m_cmd->updateDescriptorSets(descriptorWrites.size(), descriptorWrites.data());
+
+ DxvkCopyBufferImageArgs args = { };
+ args.dstOffset = dstOffset;
+ args.srcOffset = srcOffset;
+ args.extent = extent;
+ args.dstSize = { dstSize.width, dstSize.height };
+ args.srcSize = { srcSize.width, srcSize.height };
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeHandle);
+
+ m_cmd->cmdBindDescriptorSet(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeLayout, descriptorSet,
+ 0, nullptr);
+
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(args), &args);
+
+ m_cmd->cmdDispatch(
+ (extent.width + 7) / 8,
+ (extent.height + 7) / 8,
+ extent.depth);
+
+ m_execBarriers.accessBuffer(
+ dstView->getSliceHandle(),
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_WRITE_BIT,
+ dstBuffer->info().stages,
+ dstBuffer->info().access);
+
+ m_execBarriers.accessBuffer(
+ srcView->getSliceHandle(),
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT,
+ srcBuffer->info().stages,
+ srcBuffer->info().access);
+
+ // Track all involved resources
+ m_cmd->trackResource<DxvkAccess::Write>(dstBuffer);
+ m_cmd->trackResource<DxvkAccess::Read>(srcBuffer);
+
+ m_cmd->trackResource<DxvkAccess::None>(dstView);
+ m_cmd->trackResource<DxvkAccess::None>(srcView);
+ }
+
+
+ void DxvkContext::copyPackedBufferToDepthStencilImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset2D dstOffset,
+ VkExtent2D dstExtent,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcBufferOffset,
+ VkOffset2D srcOffset,
+ VkExtent2D srcExtent,
+ VkFormat format) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(dstSubresource));
+
+ this->unbindComputePipeline();
+
+ if (m_execBarriers.isBufferDirty(srcBuffer->getSliceHandle(), DxvkAccess::Read)
+ || m_execBarriers.isImageDirty(dstImage, vk::makeSubresourceRange(dstSubresource), DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Retrieve compute pipeline for the given format
+ auto pipeInfo = m_common->metaPack().getUnpackPipeline(dstImage->info().format, format);
+
+ if (!pipeInfo.pipeHandle) {
+ Logger::err(str::format(
+ "DxvkContext: copyPackedBufferToDepthStencilImage: Unhandled formats"
+ "\n dstFormat = ", dstImage->info().format,
+ "\n srcFormat = ", format));
+ return;
+ }
+
+ // Pick depth and stencil data formats
+ VkFormat dataFormatD = VK_FORMAT_UNDEFINED;
+ VkFormat dataFormatS = VK_FORMAT_UNDEFINED;
+
+ const std::array<std::tuple<VkFormat, VkFormat, VkFormat>, 2> formats = {{
+ { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_UINT },
+ { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R8_UINT },
+ }};
+
+ for (const auto& e : formats) {
+ if (std::get<0>(e) == dstImage->info().format) {
+ dataFormatD = std::get<1>(e);
+ dataFormatS = std::get<2>(e);
+ }
+ }
+
+ // Create temporary buffer for depth/stencil data
+ VkDeviceSize pixelCount = dstExtent.width * dstExtent.height * dstSubresource.layerCount;
+ VkDeviceSize dataSizeD = align(pixelCount * imageFormatInfo(dataFormatD)->elementSize, 256);
+ VkDeviceSize dataSizeS = align(pixelCount * imageFormatInfo(dataFormatS)->elementSize, 256);
+
+ DxvkBufferCreateInfo tmpBufferInfo;
+ tmpBufferInfo.size = dataSizeD + dataSizeS;
+ tmpBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ tmpBufferInfo.stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ | VK_PIPELINE_STAGE_TRANSFER_BIT;
+ tmpBufferInfo.access = VK_ACCESS_SHADER_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT;
+
+ auto tmpBuffer = m_device->createBuffer(tmpBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ // Create formatted buffer views
+ DxvkBufferViewCreateInfo tmpViewInfoD;
+ tmpViewInfoD.format = dataFormatD;
+ tmpViewInfoD.rangeOffset = 0;
+ tmpViewInfoD.rangeLength = dataSizeD;
+
+ DxvkBufferViewCreateInfo tmpViewInfoS;
+ tmpViewInfoS.format = dataFormatS;
+ tmpViewInfoS.rangeOffset = dataSizeD;
+ tmpViewInfoS.rangeLength = dataSizeS;
+
+ auto tmpBufferViewD = m_device->createBufferView(tmpBuffer, tmpViewInfoD);
+ auto tmpBufferViewS = m_device->createBufferView(tmpBuffer, tmpViewInfoS);
+
+ // Create descriptor set for the unpack operation
+ DxvkMetaUnpackDescriptors descriptors;
+ descriptors.dstDepth = tmpBufferViewD->handle();
+ descriptors.dstStencil = tmpBufferViewS->handle();
+ descriptors.srcBuffer = srcBuffer->getDescriptor(srcBufferOffset, VK_WHOLE_SIZE).buffer;
+
+ VkDescriptorSet dset = allocateDescriptorSet(pipeInfo.dsetLayout);
+ m_cmd->updateDescriptorSetWithTemplate(dset, pipeInfo.dsetTemplate, &descriptors);
+
+ // Unpack the source buffer to temporary buffers
+ DxvkMetaPackArgs args;
+ args.srcOffset = srcOffset;
+ args.srcExtent = srcExtent;
+ args.dstOffset = VkOffset2D { 0, 0 };
+ args.dstExtent = dstExtent;
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeHandle);
+
+ m_cmd->cmdBindDescriptorSet(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeLayout, dset,
+ 0, nullptr);
+
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(args), &args);
+
+ m_cmd->cmdDispatch(
+ (dstExtent.width + 63) / 64,
+ dstExtent.height,
+ dstSubresource.layerCount);
+
+ m_execBarriers.accessBuffer(
+ tmpBuffer->getSliceHandle(),
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_WRITE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT);
+
+ m_execBarriers.accessBuffer(
+ srcBuffer->getSliceHandle(),
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT,
+ srcBuffer->info().stages,
+ srcBuffer->info().access);
+
+ // Prepare image for the data transfer operation
+ VkOffset3D dstOffset3D = { dstOffset.x, dstOffset.y, 0 };
+ VkExtent3D dstExtent3D = { dstExtent.width, dstExtent.height, 1 };
+
+ VkImageLayout initialImageLayout = dstImage->info().layout;
+
+ if (dstImage->isFullSubresource(dstSubresource, dstExtent3D))
+ initialImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ m_execBarriers.accessImage(
+ dstImage, vk::makeSubresourceRange(dstSubresource),
+ initialImageLayout,
+ dstImage->info().stages,
+ dstImage->info().access,
+ dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Copy temporary buffer data to depth-stencil image
+ VkImageSubresourceLayers dstSubresourceD = dstSubresource;
+ dstSubresourceD.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+
+ VkImageSubresourceLayers dstSubresourceS = dstSubresource;
+ dstSubresourceS.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ std::array<VkBufferImageCopy, 2> copyRegions = {{
+ { tmpBufferViewD->info().rangeOffset, 0, 0, dstSubresourceD, dstOffset3D, dstExtent3D },
+ { tmpBufferViewS->info().rangeOffset, 0, 0, dstSubresourceS, dstOffset3D, dstExtent3D },
+ }};
+
+ m_cmd->cmdCopyBufferToImage(DxvkCmdBuffer::ExecBuffer,
+ tmpBuffer->getSliceHandle().handle,
+ dstImage->handle(),
+ dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ copyRegions.size(),
+ copyRegions.data());
+
+ m_execBarriers.accessImage(
+ dstImage, vk::makeSubresourceRange(dstSubresource),
+ dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ // Track all involved resources
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcBuffer);
+
+ m_cmd->trackResource<DxvkAccess::None>(tmpBufferViewD);
+ m_cmd->trackResource<DxvkAccess::None>(tmpBufferViewS);
+ }
+
+
+ void DxvkContext::discardBuffer(
+ const Rc<DxvkBuffer>& buffer) {
+ if (buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ return;
+
+ if (m_execBarriers.isBufferDirty(buffer->getSliceHandle(), DxvkAccess::Write))
+ this->invalidateBuffer(buffer, buffer->allocSlice());
+ }
+
+
+ void DxvkContext::discardImageView(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags discardAspects) {
+ VkImageUsageFlags viewUsage = imageView->info().usage;
+
+ // Ignore non-render target views since there's likely no good use case for
+ // discarding those. Also, force reinitialization even if the image is bound
+ // as a render target, which may have niche use cases for depth buffers.
+ if (viewUsage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ this->spillRenderPass(true);
+ this->deferDiscard(imageView, discardAspects);
+ }
+ }
+
+
+ void DxvkContext::dispatch(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z) {
+ if (this->commitComputeState()) {
+ this->commitComputeInitBarriers();
+
+ m_queryManager.beginQueries(m_cmd,
+ VK_QUERY_TYPE_PIPELINE_STATISTICS);
+
+ m_cmd->cmdDispatch(x, y, z);
+
+ m_queryManager.endQueries(m_cmd,
+ VK_QUERY_TYPE_PIPELINE_STATISTICS);
+
+ this->commitComputePostBarriers();
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDispatchCalls, 1);
+ }
+
+
+ void DxvkContext::dispatchIndirect(
+ VkDeviceSize offset) {
+ auto bufferSlice = m_state.id.argBuffer.getSliceHandle(
+ offset, sizeof(VkDispatchIndirectCommand));
+
+ if (m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Read))
+ m_execBarriers.recordCommands(m_cmd);
+
+ if (this->commitComputeState()) {
+ this->commitComputeInitBarriers();
+
+ m_queryManager.beginQueries(m_cmd,
+ VK_QUERY_TYPE_PIPELINE_STATISTICS);
+
+ m_cmd->cmdDispatchIndirect(
+ bufferSlice.handle,
+ bufferSlice.offset);
+
+ m_queryManager.endQueries(m_cmd,
+ VK_QUERY_TYPE_PIPELINE_STATISTICS);
+
+ this->commitComputePostBarriers();
+
+ m_execBarriers.accessBuffer(bufferSlice,
+ VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
+ VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
+ m_state.id.argBuffer.bufferInfo().stages,
+ m_state.id.argBuffer.bufferInfo().access);
+
+ this->trackDrawBuffer();
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDispatchCalls, 1);
+ }
+
+
+ void DxvkContext::draw(
+ uint32_t vertexCount,
+ uint32_t instanceCount,
+ uint32_t firstVertex,
+ uint32_t firstInstance) {
+ if (this->commitGraphicsState<false, false>()) {
+ m_cmd->cmdDraw(
+ vertexCount, instanceCount,
+ firstVertex, firstInstance);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndirect(
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride) {
+ if (this->commitGraphicsState<false, true>()) {
+ auto descriptor = m_state.id.argBuffer.getDescriptor();
+
+ m_cmd->cmdDrawIndirect(
+ descriptor.buffer.buffer,
+ descriptor.buffer.offset + offset,
+ count, stride);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndirectCount(
+ VkDeviceSize offset,
+ VkDeviceSize countOffset,
+ uint32_t maxCount,
+ uint32_t stride) {
+ if (this->commitGraphicsState<false, true>()) {
+ auto argDescriptor = m_state.id.argBuffer.getDescriptor();
+ auto cntDescriptor = m_state.id.cntBuffer.getDescriptor();
+
+ m_cmd->cmdDrawIndirectCount(
+ argDescriptor.buffer.buffer,
+ argDescriptor.buffer.offset + offset,
+ cntDescriptor.buffer.buffer,
+ cntDescriptor.buffer.offset + countOffset,
+ maxCount, stride);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndexed(
+ uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ uint32_t vertexOffset,
+ uint32_t firstInstance) {
+ if (this->commitGraphicsState<true, false>()) {
+ m_cmd->cmdDrawIndexed(
+ indexCount, instanceCount,
+ firstIndex, vertexOffset,
+ firstInstance);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndexedIndirect(
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride) {
+ if (this->commitGraphicsState<true, true>()) {
+ auto descriptor = m_state.id.argBuffer.getDescriptor();
+
+ m_cmd->cmdDrawIndexedIndirect(
+ descriptor.buffer.buffer,
+ descriptor.buffer.offset + offset,
+ count, stride);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndexedIndirectCount(
+ VkDeviceSize offset,
+ VkDeviceSize countOffset,
+ uint32_t maxCount,
+ uint32_t stride) {
+ if (this->commitGraphicsState<true, true>()) {
+ auto argDescriptor = m_state.id.argBuffer.getDescriptor();
+ auto cntDescriptor = m_state.id.cntBuffer.getDescriptor();
+
+ m_cmd->cmdDrawIndexedIndirectCount(
+ argDescriptor.buffer.buffer,
+ argDescriptor.buffer.offset + offset,
+ cntDescriptor.buffer.buffer,
+ cntDescriptor.buffer.offset + countOffset,
+ maxCount, stride);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::drawIndirectXfb(
+ const DxvkBufferSlice& counterBuffer,
+ uint32_t counterDivisor,
+ uint32_t counterBias) {
+ if (this->commitGraphicsState<false, false>()) {
+ auto physSlice = counterBuffer.getSliceHandle();
+
+ m_cmd->cmdDrawIndirectVertexCount(1, 0,
+ physSlice.handle,
+ physSlice.offset,
+ counterBias,
+ counterDivisor);
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
+ }
+
+
+ void DxvkContext::emitRenderTargetReadbackBarrier() {
+ if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
+ emitMemoryBarrier(VK_DEPENDENCY_BY_REGION_BIT,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+ }
+ }
+
+
+ void DxvkContext::initImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout initialLayout) {
+ m_execBarriers.accessImage(image, subresources,
+ initialLayout, 0, 0,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+
+ (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+ ? m_cmd->trackResource<DxvkAccess::None> (image)
+ : m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::generateMipmaps(
+ const Rc<DxvkImageView>& imageView,
+ VkFilter filter) {
+ if (imageView->info().numLevels <= 1)
+ return;
+
+ this->spillRenderPass(false);
+
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Create the a set of framebuffers and image views
+ const Rc<DxvkMetaMipGenRenderPass> mipGenerator
+ = new DxvkMetaMipGenRenderPass(m_device->vkd(), imageView);
+
+ // Common descriptor set properties that we use to
+ // bind the source image view to the fragment shader
+ VkDescriptorImageInfo descriptorImage;
+ descriptorImage.sampler = m_common->metaBlit().getSampler(filter);
+ descriptorImage.imageView = VK_NULL_HANDLE;
+ descriptorImage.imageLayout = imageView->imageInfo().layout;
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstSet = VK_NULL_HANDLE;
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrite.pImageInfo = &descriptorImage;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+
+ // Common render pass info
+ VkRenderPassBeginInfo passInfo;
+ passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ passInfo.pNext = nullptr;
+ passInfo.renderPass = mipGenerator->renderPass();
+ passInfo.framebuffer = VK_NULL_HANDLE;
+ passInfo.renderArea = VkRect2D { };
+ passInfo.clearValueCount = 0;
+ passInfo.pClearValues = nullptr;
+
+ // Retrieve a compatible pipeline to use for rendering
+ DxvkMetaBlitPipeline pipeInfo = m_common->metaBlit().getPipeline(
+ mipGenerator->viewType(), imageView->info().format, VK_SAMPLE_COUNT_1_BIT);
+
+ for (uint32_t i = 0; i < mipGenerator->passCount(); i++) {
+ DxvkMetaBlitPass pass = mipGenerator->pass(i);
+
+ // Width, height and layer count for the current pass
+ VkExtent3D passExtent = mipGenerator->passExtent(i);
+
+ // Create descriptor set with the current source view
+ descriptorImage.imageView = pass.srcView;
+ descriptorWrite.dstSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+
+ // Set up viewport and scissor rect
+ VkViewport viewport;
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = float(passExtent.width);
+ viewport.height = float(passExtent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { 0, 0 };
+ scissor.extent = { passExtent.width, passExtent.height };
+
+ // Set up render pass info
+ passInfo.framebuffer = pass.framebuffer;
+ passInfo.renderArea = scissor;
+
+ // Set up push constants
+ DxvkMetaBlitPushConstants pushConstants = { };
+ pushConstants.srcCoord0 = { 0.0f, 0.0f, 0.0f };
+ pushConstants.srcCoord1 = { 1.0f, 1.0f, 1.0f };
+ pushConstants.layerCount = passExtent.depth;
+
+ m_cmd->cmdBeginRenderPass(&passInfo, VK_SUBPASS_CONTENTS_INLINE);
+ m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
+ m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr);
+
+ m_cmd->cmdSetViewport(0, 1, &viewport);
+ m_cmd->cmdSetScissor (0, 1, &scissor);
+
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, sizeof(pushConstants),
+ &pushConstants);
+
+ m_cmd->cmdDraw(3, passExtent.depth, 0, 0);
+ m_cmd->cmdEndRenderPass();
+ }
+
+ m_cmd->trackResource<DxvkAccess::None>(mipGenerator);
+ m_cmd->trackResource<DxvkAccess::Write>(imageView->image());
+ }
+
+
+ void DxvkContext::invalidateBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferSliceHandle& slice) {
+ // Allocate new backing resource
+ DxvkBufferSliceHandle prevSlice = buffer->rename(slice);
+ m_cmd->freeBufferSlice(buffer, prevSlice);
+
+ // We also need to update all bindings that the buffer
+ // may be bound to either directly or through views.
+ VkBufferUsageFlags usage = buffer->info().usage &
+ ~(VK_BUFFER_USAGE_TRANSFER_DST_BIT |
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
+
+ if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
+ m_flags.set(prevSlice.handle == slice.handle
+ ? DxvkContextFlags(DxvkContextFlag::GpDirtyDescriptorBinding,
+ DxvkContextFlag::CpDirtyDescriptorBinding)
+ : DxvkContextFlags(DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::CpDirtyResources));
+ }
+
+ // Fast early-out for uniform buffers, very common
+ if (likely(usage == VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT))
+ return;
+
+ if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
+ m_flags.set(DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::CpDirtyResources);
+ }
+
+ if (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
+ m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
+
+ if (usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
+ m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
+
+ if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT)
+ m_flags.set(DxvkContextFlag::DirtyDrawBuffer);
+
+ if (usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT)
+ m_flags.set(DxvkContextFlag::GpDirtyXfbBuffers);
+ }
+
+
+ void DxvkContext::pushConstants(
+ uint32_t offset,
+ uint32_t size,
+ const void* data) {
+ std::memcpy(&m_state.pc.data[offset], data, size);
+
+ m_flags.set(DxvkContextFlag::DirtyPushConstants);
+ }
+
+
+ void DxvkContext::resolveImage(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkFormat format) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(region.dstSubresource));
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(region.srcSubresource));
+
+ if (format == VK_FORMAT_UNDEFINED)
+ format = srcImage->info().format;
+
+ bool useFb = srcImage->info().format != format
+ || dstImage->info().format != format;
+
+ if (m_device->perfHints().preferFbResolve) {
+ useFb |= (dstImage->info().usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ && (srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT);
+ }
+
+ if (!useFb) {
+ this->resolveImageHw(
+ dstImage, srcImage, region);
+ } else {
+ this->resolveImageFb(
+ dstImage, srcImage, region, format,
+ VK_RESOLVE_MODE_NONE_KHR,
+ VK_RESOLVE_MODE_NONE_KHR);
+ }
+ }
+
+
+ void DxvkContext::resolveDepthStencilImage(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode) {
+ this->spillRenderPass(true);
+ this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(region.dstSubresource));
+ this->prepareImage(m_execBarriers, srcImage, vk::makeSubresourceRange(region.srcSubresource));
+
+ // Technically legal, but no-op
+ if (!depthMode && !stencilMode)
+ return;
+
+ // Subsequent functions expect stencil mode to be None
+ // if either of the images have no stencil aspect
+ if (!(region.dstSubresource.aspectMask
+ & region.srcSubresource.aspectMask
+ & VK_IMAGE_ASPECT_STENCIL_BIT))
+ stencilMode = VK_RESOLVE_MODE_NONE_KHR;
+
+ // We can only use the depth-stencil resolve path if the
+ // extension is supported, if we are resolving a full
+ // subresource, and both images have the same format.
+ bool useFb = !m_device->extensions().khrDepthStencilResolve
+ || !dstImage->isFullSubresource(region.dstSubresource, region.extent)
+ || !srcImage->isFullSubresource(region.srcSubresource, region.extent)
+ || dstImage->info().format != srcImage->info().format;
+
+ if (!useFb) {
+ // Additionally, the given mode combination must be supported.
+ const auto& properties = m_device->properties().khrDepthStencilResolve;
+
+ useFb |= (properties.supportedDepthResolveModes & depthMode) != depthMode
+ || (properties.supportedStencilResolveModes & stencilMode) != stencilMode;
+
+ if (depthMode != stencilMode) {
+ useFb |= (!depthMode || !stencilMode)
+ ? !properties.independentResolveNone
+ : !properties.independentResolve;
+ }
+ }
+
+ if (useFb) {
+ this->resolveImageFb(
+ dstImage, srcImage, region, VK_FORMAT_UNDEFINED,
+ depthMode, stencilMode);
+ } else {
+ this->resolveImageDs(
+ dstImage, srcImage, region,
+ depthMode, stencilMode);
+ }
+ }
+
+
+ void DxvkContext::transformImage(
+ const Rc<DxvkImage>& dstImage,
+ const VkImageSubresourceRange& dstSubresources,
+ VkImageLayout srcLayout,
+ VkImageLayout dstLayout) {
+ this->spillRenderPass(false);
+
+ if (srcLayout != dstLayout) {
+ m_execBarriers.recordCommands(m_cmd);
+
+ m_execBarriers.accessImage(
+ dstImage, dstSubresources,
+ srcLayout,
+ dstImage->info().stages,
+ dstImage->info().access,
+ dstLayout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ }
+ }
+
+
+ void DxvkContext::performClear(
+ const Rc<DxvkImageView>& imageView,
+ int32_t attachmentIndex,
+ VkImageAspectFlags discardAspects,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue) {
+ DxvkColorAttachmentOps colorOp;
+ colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ colorOp.loadLayout = imageView->imageInfo().layout;
+ colorOp.storeLayout = imageView->imageInfo().layout;
+
+ DxvkDepthAttachmentOps depthOp;
+ depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_LOAD;
+ depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
+ depthOp.loadLayout = imageView->imageInfo().layout;
+ depthOp.storeLayout = imageView->imageInfo().layout;
+
+ if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
+ colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
+ colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+
+ if (clearAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
+ depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
+ depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+
+ if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
+ depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
+ depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+
+ if (attachmentIndex >= 0 && !m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects | discardAspects)) {
+ // Do not fold the clear/discard into the render pass if any of the affected aspects
+ // isn't writable. We can only hit this particular path when starting a render pass,
+ // so we can safely manipulate load layouts here.
+ int32_t colorIndex = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex);
+ VkImageLayout renderLayout = m_state.om.framebuffer->getAttachment(attachmentIndex).layout;
+
+ if (colorIndex < 0) {
+ depthOp.loadLayout = m_state.om.renderPassOps.depthOps.loadLayout;
+ depthOp.storeLayout = renderLayout;
+ m_state.om.renderPassOps.depthOps.loadLayout = renderLayout;
+ } else {
+ colorOp.loadLayout = m_state.om.renderPassOps.colorOps[colorIndex].loadLayout;
+ colorOp.storeLayout = renderLayout;
+ m_state.om.renderPassOps.colorOps[colorIndex].loadLayout = renderLayout;
+ }
+
+ attachmentIndex = -1;
+ }
+
+ bool is3D = imageView->imageInfo().type == VK_IMAGE_TYPE_3D;
+
+ if ((clearAspects | discardAspects) == imageView->info().aspect && !is3D) {
+ colorOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ depthOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ if (attachmentIndex < 0) {
+ if (m_execBarriers.isImageDirty(
+ imageView->image(),
+ imageView->imageSubresources(),
+ DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Set up and bind a temporary framebuffer
+ DxvkRenderTargets attachments;
+ DxvkRenderPassOps ops;
+
+ VkPipelineStageFlags clearStages = 0;
+ VkAccessFlags clearAccess = 0;
+
+ if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_COLOR_BIT) {
+ clearStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ clearAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ attachments.color[0].view = imageView;
+ attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ ops.colorOps[0] = colorOp;
+ } else {
+ clearStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ clearAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+
+ attachments.depth.view = imageView;
+ attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ ops.depthOps = depthOp;
+ }
+
+ ops.barrier.srcStages = clearStages;
+ ops.barrier.srcAccess = clearAccess;
+ ops.barrier.dstStages = imageView->imageInfo().stages;
+ ops.barrier.dstAccess = imageView->imageInfo().access;
+
+ this->renderPassBindFramebuffer(
+ m_device->createFramebuffer(attachments),
+ ops, 1, &clearValue);
+ this->renderPassUnbindFramebuffer();
+ } else {
+ // Perform the operation when starting the next render pass
+ if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_COLOR_BIT) {
+ uint32_t colorIndex = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex);
+
+ m_state.om.renderPassOps.colorOps[colorIndex].loadOp = colorOp.loadOp;
+ if (m_state.om.renderPassOps.colorOps[colorIndex].loadOp != VK_ATTACHMENT_LOAD_OP_LOAD && !is3D)
+ m_state.om.renderPassOps.colorOps[colorIndex].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ m_state.om.clearValues[attachmentIndex].color = clearValue.color;
+ }
+
+ if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_DEPTH_BIT) {
+ m_state.om.renderPassOps.depthOps.loadOpD = depthOp.loadOpD;
+ m_state.om.clearValues[attachmentIndex].depthStencil.depth = clearValue.depthStencil.depth;
+ }
+
+ if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_STENCIL_BIT) {
+ m_state.om.renderPassOps.depthOps.loadOpS = depthOp.loadOpS;
+ m_state.om.clearValues[attachmentIndex].depthStencil.stencil = clearValue.depthStencil.stencil;
+ }
+
+ if ((clearAspects | discardAspects) & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ if (m_state.om.renderPassOps.depthOps.loadOpD != VK_ATTACHMENT_LOAD_OP_LOAD
+ && m_state.om.renderPassOps.depthOps.loadOpS != VK_ATTACHMENT_LOAD_OP_LOAD)
+ m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+ }
+ }
+
+
+ void DxvkContext::deferClear(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue) {
+ for (auto& entry : m_deferredClears) {
+ if (entry.imageView->matchesView(imageView)) {
+ entry.imageView = imageView;
+ entry.discardAspects &= ~clearAspects;
+ entry.clearAspects |= clearAspects;
+
+ if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
+ entry.clearValue.color = clearValue.color;
+ if (clearAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
+ entry.clearValue.depthStencil.depth = clearValue.depthStencil.depth;
+ if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
+ entry.clearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
+
+ return;
+ } else if (entry.imageView->checkSubresourceOverlap(imageView)) {
+ this->spillRenderPass(false);
+ break;
+ }
+ }
+
+ m_deferredClears.push_back({ imageView, 0, clearAspects, clearValue });
+ }
+
+
+ void DxvkContext::deferDiscard(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags discardAspects) {
+ for (auto& entry : m_deferredClears) {
+ if (entry.imageView->matchesView(imageView)) {
+ entry.imageView = imageView;
+ entry.discardAspects |= discardAspects;
+ entry.clearAspects &= ~discardAspects;
+ return;
+ } else if (entry.imageView->checkSubresourceOverlap(imageView)) {
+ this->spillRenderPass(false);
+ break;
+ }
+ }
+
+ m_deferredClears.push_back({ imageView, discardAspects });
+ }
+
+
+ void DxvkContext::flushClears(
+ bool useRenderPass) {
+ for (const auto& clear : m_deferredClears) {
+ int32_t attachmentIndex = -1;
+
+ if (useRenderPass && m_state.om.framebuffer->isFullSize(clear.imageView))
+ attachmentIndex = m_state.om.framebuffer->findAttachment(clear.imageView);
+
+ this->performClear(clear.imageView, attachmentIndex,
+ clear.discardAspects, clear.clearAspects, clear.clearValue);
+ }
+
+ m_deferredClears.clear();
+ }
+
+
+ void DxvkContext::flushSharedImages() {
+ for (auto i = m_deferredClears.begin(); i != m_deferredClears.end(); ) {
+ if (i->imageView->imageInfo().shared) {
+ this->performClear(i->imageView, -1, i->discardAspects, i->clearAspects, i->clearValue);
+ i = m_deferredClears.erase(i);
+ } else {
+ i++;
+ }
+ }
+
+ this->transitionRenderTargetLayouts(m_execBarriers, true);
+ }
+
+
+ void DxvkContext::updateBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ VkDeviceSize offset,
+ VkDeviceSize size,
+ const void* data) {
+ bool isHostVisible = buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+ bool replaceBuffer = (size == buffer->info().size)
+ && (size <= (1 << 20))
+ && !isHostVisible;
+
+ DxvkBufferSliceHandle bufferSlice;
+ DxvkCmdBuffer cmdBuffer;
+
+ if (replaceBuffer) {
+ // Suspend render pass so that we don't mess with the
+ // currently bound transform feedback counter buffers
+ if (m_flags.test(DxvkContextFlag::GpXfbActive))
+ this->spillRenderPass(true);
+
+ // As an optimization, allocate a free slice and perform
+ // the copy in the initialization command buffer instead
+ // interrupting the render pass and stalling the pipeline.
+ bufferSlice = buffer->allocSlice();
+ cmdBuffer = DxvkCmdBuffer::InitBuffer;
+
+ this->invalidateBuffer(buffer, bufferSlice);
+ } else {
+ this->spillRenderPass(true);
+
+ bufferSlice = buffer->getSliceHandle(offset, size);
+ cmdBuffer = DxvkCmdBuffer::ExecBuffer;
+
+ if (m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+ }
+
+ // Vulkan specifies that small amounts of data (up to 64kB) can
+ // be copied to a buffer directly if the size is a multiple of
+ // four. Anything else must be copied through a staging buffer.
+ // We'll limit the size to 4kB in order to keep command buffers
+ // reasonably small, we do not know how much data apps may upload.
+ if ((size <= 4096) && ((size & 0x3) == 0) && ((offset & 0x3) == 0)) {
+ m_cmd->cmdUpdateBuffer(
+ cmdBuffer,
+ bufferSlice.handle,
+ bufferSlice.offset,
+ bufferSlice.length,
+ data);
+ } else {
+ auto stagingSlice = m_staging.alloc(CACHE_LINE_SIZE, size);
+ auto stagingHandle = stagingSlice.getSliceHandle();
+
+ std::memcpy(stagingHandle.mapPtr, data, size);
+
+ VkBufferCopy region;
+ region.srcOffset = stagingHandle.offset;
+ region.dstOffset = bufferSlice.offset;
+ region.size = size;
+
+ m_cmd->cmdCopyBuffer(cmdBuffer,
+ stagingHandle.handle, bufferSlice.handle, 1, &region);
+
+ m_cmd->trackResource<DxvkAccess::Read>(stagingSlice.buffer());
+ }
+
+ auto& barriers = replaceBuffer
+ ? m_initBarriers
+ : m_execBarriers;
+
+ barriers.accessBuffer(
+ bufferSlice,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ buffer->info().stages,
+ buffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(buffer);
+ }
+
+
+ void DxvkContext::updateImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer) {
+ this->spillRenderPass(true);
+
+ // Prepare the image layout. If the given extent covers
+ // the entire image, we may discard its previous contents.
+ auto subresourceRange = vk::makeSubresourceRange(subresources);
+ subresourceRange.aspectMask = image->formatInfo()->aspectMask;
+
+ this->prepareImage(m_execBarriers, image, subresourceRange);
+
+ if (m_execBarriers.isImageDirty(image, subresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Initialize the image if the entire subresource is covered
+ VkImageLayout imageLayoutInitial = image->info().layout;
+ VkImageLayout imageLayoutTransfer = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ if (image->isFullSubresource(subresources, imageExtent))
+ imageLayoutInitial = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ if (imageLayoutTransfer != imageLayoutInitial) {
+ m_execAcquires.accessImage(
+ image, subresourceRange,
+ imageLayoutInitial,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ imageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ this->copyImageHostData(DxvkCmdBuffer::ExecBuffer,
+ image, subresources, imageOffset, imageExtent,
+ data, pitchPerRow, pitchPerLayer);
+
+ // Transition image back into its optimal layout
+ m_execBarriers.accessImage(
+ image, subresourceRange,
+ imageLayoutTransfer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::updateDepthStencilImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ VkOffset2D imageOffset,
+ VkExtent2D imageExtent,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer,
+ VkFormat format) {
+ auto formatInfo = imageFormatInfo(format);
+
+ VkExtent3D extent3D;
+ extent3D.width = imageExtent.width;
+ extent3D.height = imageExtent.height;
+ extent3D.depth = subresources.layerCount;
+
+ VkDeviceSize pixelCount = extent3D.width * extent3D.height * extent3D.depth;
+
+ DxvkBufferCreateInfo tmpBufferInfo;
+ tmpBufferInfo.size = pixelCount * formatInfo->elementSize;
+ tmpBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ tmpBufferInfo.stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ tmpBufferInfo.access = VK_ACCESS_SHADER_READ_BIT;
+
+ auto tmpBuffer = m_device->createBuffer(tmpBufferInfo,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ util::packImageData(tmpBuffer->mapPtr(0), data,
+ extent3D, formatInfo->elementSize,
+ pitchPerRow, pitchPerLayer);
+
+ copyPackedBufferToDepthStencilImage(
+ image, subresources, imageOffset, imageExtent,
+ tmpBuffer, 0, VkOffset2D { 0, 0 }, imageExtent,
+ format);
+ }
+
+
+ void DxvkContext::uploadBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ const void* data) {
+ auto bufferSlice = buffer->getSliceHandle();
+
+ auto stagingSlice = m_staging.alloc(CACHE_LINE_SIZE, bufferSlice.length);
+ auto stagingHandle = stagingSlice.getSliceHandle();
+ std::memcpy(stagingHandle.mapPtr, data, bufferSlice.length);
+
+ VkBufferCopy region;
+ region.srcOffset = stagingHandle.offset;
+ region.dstOffset = bufferSlice.offset;
+ region.size = bufferSlice.length;
+
+ m_cmd->cmdCopyBuffer(DxvkCmdBuffer::SdmaBuffer,
+ stagingHandle.handle, bufferSlice.handle, 1, &region);
+
+ m_sdmaBarriers.releaseBuffer(
+ m_initBarriers, bufferSlice,
+ m_device->queues().transfer.queueFamily,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ m_device->queues().graphics.queueFamily,
+ buffer->info().stages,
+ buffer->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Read>(stagingSlice.buffer());
+ m_cmd->trackResource<DxvkAccess::Write>(buffer);
+ }
+
+
+ void DxvkContext::uploadImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer) {
+ VkOffset3D imageOffset = { 0, 0, 0 };
+ VkExtent3D imageExtent = image->mipLevelExtent(subresources.mipLevel);
+
+ DxvkCmdBuffer cmdBuffer = DxvkCmdBuffer::SdmaBuffer;
+ DxvkBarrierSet* barriers = &m_sdmaAcquires;
+
+ if (subresources.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ cmdBuffer = DxvkCmdBuffer::InitBuffer;
+ barriers = &m_initBarriers;
+ }
+
+ // Discard previous subresource contents
+ barriers->accessImage(image,
+ vk::makeSubresourceRange(subresources),
+ VK_IMAGE_LAYOUT_UNDEFINED, 0, 0,
+ image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+
+ barriers->recordCommands(m_cmd);
+
+ this->copyImageHostData(cmdBuffer,
+ image, subresources, imageOffset, imageExtent,
+ data, pitchPerRow, pitchPerLayer);
+
+ // Transfer ownership to graphics queue
+ if (cmdBuffer == DxvkCmdBuffer::SdmaBuffer) {
+ m_sdmaBarriers.releaseImage(m_initBarriers,
+ image, vk::makeSubresourceRange(subresources),
+ m_device->queues().transfer.queueFamily,
+ image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ m_device->queues().graphics.queueFamily,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+ } else {
+ barriers->accessImage(image,
+ vk::makeSubresourceRange(subresources),
+ image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ image->info().layout,
+ image->info().stages,
+ image->info().access);
+ }
+
+ m_cmd->trackResource<DxvkAccess::Write>(image);
+ }
+
+
+ void DxvkContext::setViewports(
+ uint32_t viewportCount,
+ const VkViewport* viewports,
+ const VkRect2D* scissorRects) {
+ if (m_state.gp.state.rs.viewportCount() != viewportCount) {
+ m_state.gp.state.rs.setViewportCount(viewportCount);
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+ for (uint32_t i = 0; i < viewportCount; i++) {
+ m_state.vp.viewports[i] = viewports[i];
+ m_state.vp.scissorRects[i] = scissorRects[i];
+
+ // Vulkan viewports are not allowed to have a width or
+ // height of zero, so we fall back to a dummy viewport
+ // and instead set an empty scissor rect, which is legal.
+ if (viewports[i].width == 0.0f || viewports[i].height == 0.0f) {
+ m_state.vp.viewports[i] = VkViewport {
+ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f };
+ m_state.vp.scissorRects[i] = VkRect2D {
+ VkOffset2D { 0, 0 },
+ VkExtent2D { 0, 0 } };
+ }
+ }
+
+ m_flags.set(DxvkContextFlag::GpDirtyViewport);
+ }
+
+
+ void DxvkContext::setBlendConstants(
+ DxvkBlendConstants blendConstants) {
+ if (m_state.dyn.blendConstants != blendConstants) {
+ m_state.dyn.blendConstants = blendConstants;
+ m_flags.set(DxvkContextFlag::GpDirtyBlendConstants);
+ }
+ }
+
+
+ void DxvkContext::setDepthBias(
+ DxvkDepthBias depthBias) {
+ if (m_state.dyn.depthBias != depthBias) {
+ m_state.dyn.depthBias = depthBias;
+ m_flags.set(DxvkContextFlag::GpDirtyDepthBias);
+ }
+ }
+
+
+ void DxvkContext::setDepthBounds(
+ DxvkDepthBounds depthBounds) {
+ if (m_state.dyn.depthBounds != depthBounds) {
+ m_state.dyn.depthBounds = depthBounds;
+ m_flags.set(DxvkContextFlag::GpDirtyDepthBounds);
+ }
+
+ if (m_state.gp.state.ds.enableDepthBoundsTest() != depthBounds.enableDepthBounds) {
+ m_state.gp.state.ds.setEnableDepthBoundsTest(depthBounds.enableDepthBounds);
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+ }
+
+
+ void DxvkContext::setStencilReference(
+ uint32_t reference) {
+ if (m_state.dyn.stencilReference != reference) {
+ m_state.dyn.stencilReference = reference;
+ m_flags.set(DxvkContextFlag::GpDirtyStencilRef);
+ }
+ }
+
+
+ void DxvkContext::setInputAssemblyState(const DxvkInputAssemblyState& ia) {
+ m_state.gp.state.ia = DxvkIaInfo(
+ ia.primitiveTopology,
+ ia.primitiveRestart,
+ ia.patchVertexCount);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setInputLayout(
+ uint32_t attributeCount,
+ const DxvkVertexAttribute* attributes,
+ uint32_t bindingCount,
+ const DxvkVertexBinding* bindings) {
+ m_flags.set(
+ DxvkContextFlag::GpDirtyPipelineState,
+ DxvkContextFlag::GpDirtyVertexBuffers);
+
+ for (uint32_t i = 0; i < attributeCount; i++) {
+ m_state.gp.state.ilAttributes[i] = DxvkIlAttribute(
+ attributes[i].location, attributes[i].binding,
+ attributes[i].format, attributes[i].offset);
+ }
+
+ for (uint32_t i = attributeCount; i < m_state.gp.state.il.attributeCount(); i++)
+ m_state.gp.state.ilAttributes[i] = DxvkIlAttribute();
+
+ for (uint32_t i = 0; i < bindingCount; i++) {
+ m_state.gp.state.ilBindings[i] = DxvkIlBinding(
+ bindings[i].binding, 0, bindings[i].inputRate,
+ bindings[i].fetchRate);
+ }
+
+ for (uint32_t i = bindingCount; i < m_state.gp.state.il.bindingCount(); i++)
+ m_state.gp.state.ilBindings[i] = DxvkIlBinding();
+
+ m_state.gp.state.il = DxvkIlInfo(attributeCount, bindingCount);
+ }
+
+
+ void DxvkContext::setRasterizerState(const DxvkRasterizerState& rs) {
+ m_state.gp.state.rs = DxvkRsInfo(
+ rs.depthClipEnable,
+ rs.depthBiasEnable,
+ rs.polygonMode,
+ rs.cullMode,
+ rs.frontFace,
+ m_state.gp.state.rs.viewportCount(),
+ rs.sampleCount,
+ rs.conservativeMode);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setMultisampleState(const DxvkMultisampleState& ms) {
+ m_state.gp.state.ms = DxvkMsInfo(
+ m_state.gp.state.ms.sampleCount(),
+ ms.sampleMask,
+ ms.enableAlphaToCoverage);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setDepthStencilState(const DxvkDepthStencilState& ds) {
+ m_state.gp.state.ds = DxvkDsInfo(
+ ds.enableDepthTest,
+ ds.enableDepthWrite,
+ m_state.gp.state.ds.enableDepthBoundsTest(),
+ ds.enableStencilTest,
+ ds.depthCompareOp);
+
+ m_state.gp.state.dsFront = DxvkDsStencilOp(ds.stencilOpFront);
+ m_state.gp.state.dsBack = DxvkDsStencilOp(ds.stencilOpBack);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setLogicOpState(const DxvkLogicOpState& lo) {
+ m_state.gp.state.om = DxvkOmInfo(
+ lo.enableLogicOp,
+ lo.logicOp);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setBlendMode(
+ uint32_t attachment,
+ const DxvkBlendMode& blendMode) {
+ m_state.gp.state.omBlend[attachment] = DxvkOmAttachmentBlend(
+ blendMode.enableBlending,
+ blendMode.colorSrcFactor,
+ blendMode.colorDstFactor,
+ blendMode.colorBlendOp,
+ blendMode.alphaSrcFactor,
+ blendMode.alphaDstFactor,
+ blendMode.alphaBlendOp,
+ blendMode.writeMask);
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+
+
+ void DxvkContext::setSpecConstant(
+ VkPipelineBindPoint pipeline,
+ uint32_t index,
+ uint32_t value) {
+ auto& specConst = pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
+ ? m_state.gp.state.sc.specConstants[index]
+ : m_state.cp.state.sc.specConstants[index];
+
+ if (specConst != value) {
+ specConst = value;
+
+ m_flags.set(pipeline == VK_PIPELINE_BIND_POINT_GRAPHICS
+ ? DxvkContextFlag::GpDirtyPipelineState
+ : DxvkContextFlag::CpDirtyPipelineState);
+ }
+ }
+
+
+ void DxvkContext::setBarrierControl(DxvkBarrierControlFlags control) {
+ m_barrierControl = control;
+ }
+
+
+ void DxvkContext::signalGpuEvent(const Rc<DxvkGpuEvent>& event) {
+ this->spillRenderPass(true);
+
+ DxvkGpuEventHandle handle = m_common->eventPool().allocEvent();
+
+ m_cmd->cmdSetEvent(handle.event,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
+
+ m_cmd->trackGpuEvent(event->reset(handle));
+ m_cmd->trackResource<DxvkAccess::None>(event);
+ }
+
+
+ void DxvkContext::launchCuKernelNVX(
+ const VkCuLaunchInfoNVX& nvxLaunchInfo,
+ const std::vector<std::pair<Rc<DxvkBuffer>, DxvkAccessFlags>>& buffers,
+ const std::vector<std::pair<Rc<DxvkImage>, DxvkAccessFlags>>& images) {
+ // The resources in the std::vectors above are called-out
+ // explicitly in the API for barrier and tracking purposes
+ // since they're being used bindlessly.
+ this->spillRenderPass(true);
+
+ VkPipelineStageFlags srcStages = 0;
+ VkAccessFlags srcAccess = 0;
+
+ for (auto& r : buffers) {
+ srcStages |= r.first->info().stages;
+ srcAccess |= r.first->info().access;
+ }
+
+ for (auto& r : images) {
+ srcStages |= r.first->info().stages;
+ srcAccess |= r.first->info().access;
+
+ this->prepareImage(m_execBarriers, r.first, r.first->getAvailableSubresources());
+ }
+
+ m_execBarriers.accessMemory(srcStages, srcAccess,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
+ m_execBarriers.recordCommands(m_cmd);
+
+ m_cmd->cmdLaunchCuKernel(nvxLaunchInfo);
+
+ for (auto& r : buffers) {
+ VkAccessFlags accessFlags = (r.second.test(DxvkAccess::Read) * VK_ACCESS_SHADER_READ_BIT)
+ | (r.second.test(DxvkAccess::Write) * VK_ACCESS_SHADER_WRITE_BIT);
+ DxvkBufferSliceHandle bufferSlice = r.first->getSliceHandle();
+ m_execBarriers.accessBuffer(bufferSlice,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ accessFlags,
+ r.first->info().stages,
+ r.first->info().access);
+ }
+
+ for (auto& r : images) {
+ VkAccessFlags accessFlags = (r.second.test(DxvkAccess::Read) * VK_ACCESS_SHADER_READ_BIT)
+ | (r.second.test(DxvkAccess::Write) * VK_ACCESS_SHADER_WRITE_BIT);
+ m_execBarriers.accessImage(r.first,
+ r.first->getAvailableSubresources(),
+ r.first->info().layout,
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ accessFlags,
+ r.first->info().layout,
+ r.first->info().stages,
+ r.first->info().access);
+ }
+
+ for (auto& r : images) {
+ if (r.second.test(DxvkAccess::Read)) m_cmd->trackResource<DxvkAccess::Read>(r.first);
+ if (r.second.test(DxvkAccess::Write)) m_cmd->trackResource<DxvkAccess::Write>(r.first);
+ }
+
+ for (auto& r : buffers) {
+ if (r.second.test(DxvkAccess::Read)) m_cmd->trackResource<DxvkAccess::Read>(r.first);
+ if (r.second.test(DxvkAccess::Write)) m_cmd->trackResource<DxvkAccess::Write>(r.first);
+ }
+ }
+
+
+ void DxvkContext::writeTimestamp(const Rc<DxvkGpuQuery>& query) {
+ m_queryManager.writeTimestamp(m_cmd, query);
+ }
+
+
+ void DxvkContext::signal(const Rc<sync::Signal>& signal, uint64_t value) {
+ m_cmd->queueSignal(signal, value);
+ }
+
+
+ void DxvkContext::trimStagingBuffers() {
+ m_staging.trim();
+ }
+
+ void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT *label) {
+ if (!m_device->instance()->extensions().extDebugUtils)
+ return;
+
+ m_cmd->cmdBeginDebugUtilsLabel(label);
+ }
+
+ void DxvkContext::endDebugLabel() {
+ if (!m_device->instance()->extensions().extDebugUtils)
+ return;
+
+ m_cmd->cmdEndDebugUtilsLabel();
+ }
+
+ void DxvkContext::insertDebugLabel(VkDebugUtilsLabelEXT *label) {
+ if (!m_device->instance()->extensions().extDebugUtils)
+ return;
+
+ m_cmd->cmdInsertDebugUtilsLabel(label);
+ }
+
+
+ void DxvkContext::blitImageFb(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ const VkComponentMapping& mapping,
+ VkFilter filter) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ bool isDepthStencil = region.srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
+
+ VkImageLayout srcLayout = srcImage->pickLayout(isDepthStencil
+ ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ if (srcImage->info().layout != srcLayout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ srcImage->info().stages, 0,
+ srcLayout,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+ }
+
+ // Sort out image offsets so that dstOffset[0] points
+ // to the top-left corner of the target area
+ VkOffset3D srcOffsets[2] = { region.srcOffsets[0], region.srcOffsets[1] };
+ VkOffset3D dstOffsets[2] = { region.dstOffsets[0], region.dstOffsets[1] };
+
+ if (dstOffsets[0].x > dstOffsets[1].x) {
+ std::swap(dstOffsets[0].x, dstOffsets[1].x);
+ std::swap(srcOffsets[0].x, srcOffsets[1].x);
+ }
+
+ if (dstOffsets[0].y > dstOffsets[1].y) {
+ std::swap(dstOffsets[0].y, dstOffsets[1].y);
+ std::swap(srcOffsets[0].y, srcOffsets[1].y);
+ }
+
+ if (dstOffsets[0].z > dstOffsets[1].z) {
+ std::swap(dstOffsets[0].z, dstOffsets[1].z);
+ std::swap(srcOffsets[0].z, srcOffsets[1].z);
+ }
+
+ VkExtent3D dstExtent = {
+ uint32_t(dstOffsets[1].x - dstOffsets[0].x),
+ uint32_t(dstOffsets[1].y - dstOffsets[0].y),
+ uint32_t(dstOffsets[1].z - dstOffsets[0].z) };
+
+ // Begin render pass
+ Rc<DxvkMetaBlitRenderPass> pass = new DxvkMetaBlitRenderPass(
+ m_device, dstImage, srcImage, region, mapping);
+ DxvkMetaBlitPass passObjects = pass->pass();
+
+ VkExtent3D imageExtent = dstImage->mipLevelExtent(region.dstSubresource.mipLevel);
+
+ VkRect2D renderArea;
+ renderArea.offset = VkOffset2D { 0, 0 };
+ renderArea.extent = VkExtent2D { imageExtent.width, imageExtent.height };
+
+ VkRenderPassBeginInfo passInfo;
+ passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ passInfo.pNext = nullptr;
+ passInfo.renderPass = passObjects.renderPass;
+ passInfo.framebuffer = passObjects.framebuffer;
+ passInfo.renderArea = renderArea;
+ passInfo.clearValueCount = 0;
+ passInfo.pClearValues = nullptr;
+
+ m_cmd->cmdBeginRenderPass(&passInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Bind pipeline
+ DxvkMetaBlitPipeline pipeInfo = m_common->metaBlit().getPipeline(
+ pass->viewType(), dstImage->info().format, dstImage->info().sampleCount);
+
+ m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
+
+ // Set up viewport
+ VkViewport viewport;
+ viewport.x = float(dstOffsets[0].x);
+ viewport.y = float(dstOffsets[0].y);
+ viewport.width = float(dstExtent.width);
+ viewport.height = float(dstExtent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { dstOffsets[0].x, dstOffsets[0].y };
+ scissor.extent = { dstExtent.width, dstExtent.height };
+
+ m_cmd->cmdSetViewport(0, 1, &viewport);
+ m_cmd->cmdSetScissor (0, 1, &scissor);
+
+ // Bind source image view
+ VkDescriptorImageInfo descriptorImage;
+ descriptorImage.sampler = m_common->metaBlit().getSampler(filter);
+ descriptorImage.imageView = passObjects.srcView;
+ descriptorImage.imageLayout = srcLayout;
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrite.pImageInfo = &descriptorImage;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+ m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr);
+
+ // Compute shader parameters for the operation
+ VkExtent3D srcExtent = srcImage->mipLevelExtent(region.srcSubresource.mipLevel);
+
+ DxvkMetaBlitPushConstants pushConstants = { };
+ pushConstants.srcCoord0 = {
+ float(srcOffsets[0].x) / float(srcExtent.width),
+ float(srcOffsets[0].y) / float(srcExtent.height),
+ float(srcOffsets[0].z) / float(srcExtent.depth) };
+ pushConstants.srcCoord1 = {
+ float(srcOffsets[1].x) / float(srcExtent.width),
+ float(srcOffsets[1].y) / float(srcExtent.height),
+ float(srcOffsets[1].z) / float(srcExtent.depth) };
+ pushConstants.layerCount = pass->framebufferLayerCount();
+
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, sizeof(pushConstants),
+ &pushConstants);
+
+ m_cmd->cmdDraw(3, pushConstants.layerCount, 0, 0);
+ m_cmd->cmdEndRenderPass();
+
+ // Add barriers and track image objects
+ m_execBarriers.accessImage(dstImage,
+ vk::makeSubresourceRange(region.dstSubresource),
+ dstImage->info().layout,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_execBarriers.accessImage(srcImage,
+ vk::makeSubresourceRange(region.srcSubresource),
+ srcLayout,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ m_cmd->trackResource<DxvkAccess::None>(pass);
+ }
+
+
+ void DxvkContext::blitImageHw(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ VkFilter filter) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Prepare the two images for transfer ops if necessary
+ auto dstLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ auto srcLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ if (dstImage->info().layout != dstLayout) {
+ m_execAcquires.accessImage(
+ dstImage, dstSubresourceRange,
+ dstImage->info().layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ dstLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (srcImage->info().layout != srcLayout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ srcLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT);
+ }
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ // Perform the blit operation
+ m_cmd->cmdBlitImage(
+ srcImage->handle(), srcLayout,
+ dstImage->handle(), dstLayout,
+ 1, &region, filter);
+
+ m_execBarriers.accessImage(
+ dstImage, dstSubresourceRange, dstLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange, srcLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ }
+
+
+ template<bool ToImage>
+ void DxvkContext::copyImageBufferData(
+ DxvkCmdBuffer cmd,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& imageSubresource,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ VkImageLayout imageLayout,
+ const DxvkBufferSliceHandle& bufferSlice,
+ VkDeviceSize bufferRowAlignment,
+ VkDeviceSize bufferSliceAlignment) {
+ auto formatInfo = image->formatInfo();
+ auto layers = imageSubresource.layerCount;
+
+ VkDeviceSize bufferOffset = bufferSlice.offset;
+
+ // Do one copy region per layer in case the buffer memory layout is weird
+ if (bufferSliceAlignment || formatInfo->flags.test(DxvkFormatFlag::MultiPlane))
+ layers = 1;
+
+ for (uint32_t i = 0; i < imageSubresource.layerCount; i += layers) {
+ auto aspectOffset = bufferOffset;
+
+ for (auto aspects = imageSubresource.aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto elementSize = formatInfo->elementSize;
+
+ VkBufferImageCopy copyRegion = { };
+ copyRegion.imageSubresource.aspectMask = aspect;
+ copyRegion.imageSubresource.baseArrayLayer = imageSubresource.baseArrayLayer + i;
+ copyRegion.imageSubresource.layerCount = layers;
+ copyRegion.imageSubresource.mipLevel = imageSubresource.mipLevel;
+ copyRegion.imageOffset = imageOffset;
+ copyRegion.imageExtent = imageExtent;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ copyRegion.imageOffset.x /= plane->blockSize.width;
+ copyRegion.imageOffset.y /= plane->blockSize.height;
+ copyRegion.imageExtent.width /= plane->blockSize.width;
+ copyRegion.imageExtent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ // Vulkan can't really express row pitch in the same way that client APIs
+ // may expect, so we'll need to do some heroics here and hope that it works
+ VkExtent3D blockCount = util::computeBlockCount(copyRegion.imageExtent, formatInfo->blockSize);
+ VkDeviceSize rowPitch = blockCount.width * elementSize;
+
+ if (bufferRowAlignment > elementSize)
+ rowPitch = bufferRowAlignment >= rowPitch ? bufferRowAlignment : align(rowPitch, bufferRowAlignment);
+
+ VkDeviceSize slicePitch = blockCount.height * rowPitch;
+
+ if (image->info().type == VK_IMAGE_TYPE_3D && bufferSliceAlignment > elementSize)
+ slicePitch = bufferSliceAlignment >= slicePitch ? bufferSliceAlignment : align(slicePitch, bufferSliceAlignment);
+
+ copyRegion.bufferOffset = aspectOffset;
+ copyRegion.bufferRowLength = formatInfo->blockSize.width * rowPitch / elementSize;
+ copyRegion.bufferImageHeight = formatInfo->blockSize.height * slicePitch / rowPitch;
+
+ // Perform the actual copy
+ if constexpr (ToImage) {
+ m_cmd->cmdCopyBufferToImage(cmd, bufferSlice.handle,
+ image->handle(), imageLayout, 1, &copyRegion);
+ } else {
+ m_cmd->cmdCopyImageToBuffer(cmd, image->handle(), imageLayout,
+ bufferSlice.handle, 1, &copyRegion);
+ }
+
+ aspectOffset += blockCount.depth * slicePitch;
+ }
+
+ // Advance to next layer. This is non-trivial for multi-plane formats
+ // since plane data for each layer is expected to be packed.
+ VkDeviceSize layerPitch = aspectOffset - bufferOffset;
+
+ if (bufferSliceAlignment)
+ layerPitch = bufferSliceAlignment >= layerPitch ? bufferSliceAlignment : align(layerPitch, bufferSliceAlignment);
+
+ bufferOffset += layerPitch;
+ }
+ }
+
+
+ void DxvkContext::copyImageHostData(
+ DxvkCmdBuffer cmd,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& imageSubresource,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ const void* hostData,
+ VkDeviceSize rowPitch,
+ VkDeviceSize slicePitch) {
+ auto formatInfo = image->formatInfo();
+ auto srcData = reinterpret_cast<const char*>(hostData);
+
+ for (uint32_t i = 0; i < imageSubresource.layerCount; i++) {
+ auto layerData = srcData + i * slicePitch;
+
+ for (auto aspects = imageSubresource.aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto extent = imageExtent;
+
+ VkDeviceSize elementSize = formatInfo->elementSize;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ extent.width /= plane->blockSize.width;
+ extent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ auto blockCount = util::computeBlockCount(extent, formatInfo->blockSize);
+ auto stagingSlice = m_staging.alloc(CACHE_LINE_SIZE, elementSize * util::flattenImageExtent(blockCount));
+ auto stagingHandle = stagingSlice.getSliceHandle();
+
+ util::packImageData(stagingHandle.mapPtr, layerData,
+ blockCount, elementSize, rowPitch, slicePitch);
+
+ auto subresource = imageSubresource;
+ subresource.aspectMask = aspect;
+
+ this->copyImageBufferData<true>(cmd,
+ image, subresource, imageOffset, imageExtent,
+ image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
+ stagingHandle, 0, 0);
+
+ layerData += blockCount.height * rowPitch;
+
+ m_cmd->trackResource<DxvkAccess::Read>(stagingSlice.buffer());
+ }
+ }
+ }
+
+
+ void DxvkContext::clearImageViewFb(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkImageAspectFlags aspect,
+ VkClearValue value) {
+ this->updateFramebuffer();
+
+ // Find out if the render target view is currently bound,
+ // so that we can avoid spilling the render pass if it is.
+ int32_t attachmentIndex = -1;
+
+ if (m_state.om.framebuffer != nullptr
+ && m_state.om.framebuffer->isFullSize(imageView))
+ attachmentIndex = m_state.om.framebuffer->findAttachment(imageView);
+
+ if (attachmentIndex >= 0 && !m_state.om.framebuffer->isWritable(attachmentIndex, aspect))
+ attachmentIndex = -1;
+
+ if (attachmentIndex < 0) {
+ this->spillRenderPass(false);
+
+ if (m_execBarriers.isImageDirty(
+ imageView->image(),
+ imageView->imageSubresources(),
+ DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Set up a temporary framebuffer
+ DxvkRenderTargets attachments;
+ DxvkRenderPassOps ops;
+
+ VkPipelineStageFlags clearStages = 0;
+ VkAccessFlags clearAccess = 0;
+
+ if (imageView->info().aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
+ clearStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ clearAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+
+ attachments.color[0].view = imageView;
+ attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ ops.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ ops.colorOps[0].loadLayout = imageView->imageInfo().layout;
+ ops.colorOps[0].storeLayout = imageView->imageInfo().layout;
+ } else {
+ clearStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ clearAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
+ | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+ attachments.depth.view = imageView;
+ attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ ops.depthOps.loadOpD = VK_ATTACHMENT_LOAD_OP_LOAD;
+ ops.depthOps.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
+ ops.depthOps.loadLayout = imageView->imageInfo().layout;
+ ops.depthOps.storeLayout = imageView->imageInfo().layout;
+ }
+
+ ops.barrier.srcStages = clearStages;
+ ops.barrier.srcAccess = clearAccess;
+ ops.barrier.dstStages = imageView->imageInfo().stages;
+ ops.barrier.dstAccess = imageView->imageInfo().access;
+
+ // We cannot leverage render pass clears
+ // because we clear only part of the view
+ this->renderPassBindFramebuffer(
+ m_device->createFramebuffer(attachments),
+ ops, 0, nullptr);
+ } else {
+ // Make sure the render pass is active so
+ // that we can actually perform the clear
+ this->startRenderPass();
+ }
+
+ // Perform the actual clear operation
+ VkClearAttachment clearInfo;
+ clearInfo.aspectMask = aspect;
+ clearInfo.colorAttachment = 0;
+ clearInfo.clearValue = value;
+
+ if ((aspect & VK_IMAGE_ASPECT_COLOR_BIT) && (attachmentIndex >= 0))
+ clearInfo.colorAttachment = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex);
+
+ VkClearRect clearRect;
+ clearRect.rect.offset.x = offset.x;
+ clearRect.rect.offset.y = offset.y;
+ clearRect.rect.extent.width = extent.width;
+ clearRect.rect.extent.height = extent.height;
+ clearRect.baseArrayLayer = 0;
+ clearRect.layerCount = imageView->info().numLayers;
+
+ m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
+
+ // Unbind temporary framebuffer
+ if (attachmentIndex < 0)
+ this->renderPassUnbindFramebuffer();
+ }
+
+
+ void DxvkContext::clearImageViewCs(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkClearValue value) {
+ this->spillRenderPass(false);
+ this->unbindComputePipeline();
+
+ if (m_execBarriers.isImageDirty(
+ imageView->image(),
+ imageView->imageSubresources(),
+ DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Query pipeline objects to use for this clear operation
+ DxvkMetaClearPipeline pipeInfo = m_common->metaClear().getClearImagePipeline(
+ imageView->type(), imageFormatInfo(imageView->info().format)->flags);
+
+ // Create a descriptor set pointing to the view
+ VkDescriptorSet descriptorSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+
+ VkDescriptorImageInfo viewInfo;
+ viewInfo.sampler = VK_NULL_HANDLE;
+ viewInfo.imageView = imageView->handle();
+ viewInfo.imageLayout = imageView->imageInfo().layout;
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstSet = descriptorSet;
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ descriptorWrite.pImageInfo = &viewInfo;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+
+ // Prepare shader arguments
+ DxvkMetaClearArgs pushArgs = { };
+ pushArgs.clearValue = value.color;
+ pushArgs.offset = offset;
+ pushArgs.extent = extent;
+
+ VkExtent3D workgroups = util::computeBlockCount(
+ pushArgs.extent, pipeInfo.workgroupSize);
+
+ if (imageView->type() == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
+ workgroups.height = imageView->subresources().layerCount;
+ else if (imageView->type() == VK_IMAGE_VIEW_TYPE_2D_ARRAY)
+ workgroups.depth = imageView->subresources().layerCount;
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeline);
+ m_cmd->cmdBindDescriptorSet(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipeInfo.pipeLayout, descriptorSet,
+ 0, nullptr);
+ m_cmd->cmdPushConstants(
+ pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ 0, sizeof(pushArgs), &pushArgs);
+ m_cmd->cmdDispatch(
+ workgroups.width,
+ workgroups.height,
+ workgroups.depth);
+
+ m_execBarriers.accessImage(
+ imageView->image(),
+ imageView->imageSubresources(),
+ imageView->imageInfo().layout,
+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ VK_ACCESS_SHADER_WRITE_BIT,
+ imageView->imageInfo().layout,
+ imageView->imageInfo().stages,
+ imageView->imageInfo().access);
+
+ m_cmd->trackResource<DxvkAccess::None>(imageView);
+ m_cmd->trackResource<DxvkAccess::Write>(imageView->image());
+ }
+
+
+ void DxvkContext::copyImageHw(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresource);
+
+ auto dstFormatInfo = dstImage->formatInfo();
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ VkImageLayout dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ VkImageLayout srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ VkImageLayout dstInitImageLayout = dstImage->info().layout;
+
+ if (dstImage->isFullSubresource(dstSubresource, extent))
+ dstInitImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ if (dstImageLayout != dstInitImageLayout) {
+ m_execAcquires.accessImage(
+ dstImage, dstSubresourceRange,
+ dstInitImageLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ dstImageLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (srcImageLayout != srcImage->info().layout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ srcImageLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT);
+ }
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ for (auto aspects = dstSubresource.aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+
+ VkImageCopy imageRegion;
+ imageRegion.srcSubresource = srcSubresource;
+ imageRegion.srcSubresource.aspectMask = aspect;
+ imageRegion.srcOffset = srcOffset;
+ imageRegion.dstSubresource = dstSubresource;
+ imageRegion.dstSubresource.aspectMask = aspect;
+ imageRegion.dstOffset = dstOffset;
+ imageRegion.extent = extent;
+
+ if (dstFormatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &dstFormatInfo->planes[vk::getPlaneIndex(aspect)];
+ imageRegion.srcOffset.x /= plane->blockSize.width;
+ imageRegion.srcOffset.y /= plane->blockSize.height;
+ imageRegion.dstOffset.x /= plane->blockSize.width;
+ imageRegion.dstOffset.y /= plane->blockSize.height;
+ imageRegion.extent.width /= plane->blockSize.width;
+ imageRegion.extent.height /= plane->blockSize.height;
+ }
+
+ m_cmd->cmdCopyImage(DxvkCmdBuffer::ExecBuffer,
+ srcImage->handle(), srcImageLayout,
+ dstImage->handle(), dstImageLayout,
+ 1, &imageRegion);
+ }
+
+ m_execBarriers.accessImage(
+ dstImage, dstSubresourceRange,
+ dstImageLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImageLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ }
+
+
+ void DxvkContext::copyImageFb(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Source image needs to be readable
+ if (!(srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
+ Logger::err("DxvkContext: copyImageFb: Source image not readable");
+ return;
+ }
+
+ // Render target format to use for this copy
+ VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
+ dstSubresource.aspectMask,
+ srcSubresource.aspectMask,
+ srcImage->info().format);
+
+ if (viewFormat == VK_FORMAT_UNDEFINED) {
+ Logger::err("DxvkContext: copyImageFb: Unsupported format");
+ return;
+ }
+
+ // We might have to transition the source image layout
+ VkImageLayout srcLayout = (srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
+ ? srcImage->pickLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
+ : srcImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
+
+ if (srcImage->info().layout != srcLayout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ srcImage->info().stages, 0,
+ srcLayout,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+ }
+
+ // In some cases, we may be able to render to the destination
+ // image directly, which is faster than using a temporary image
+ VkImageUsageFlagBits tgtUsage = (dstSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
+ ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ bool useDirectRender = (dstImage->isViewCompatible(viewFormat))
+ && (dstImage->info().usage & tgtUsage);
+
+ // If needed, create a temporary render target for the copy
+ Rc<DxvkImage> tgtImage;
+ VkImageSubresourceLayers tgtSubresource = dstSubresource;
+ VkOffset3D tgtOffset = dstOffset;
+
+ if (!useDirectRender) {
+ DxvkImageCreateInfo info;
+ info.type = dstImage->info().type;
+ info.format = viewFormat;
+ info.flags = 0;
+ info.sampleCount = dstImage->info().sampleCount;
+ info.extent = extent;
+ info.numLayers = dstSubresource.layerCount;
+ info.mipLevels = 1;
+ info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | tgtUsage;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ info.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+
+ tgtImage = m_device->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ tgtSubresource.mipLevel = 0;
+ tgtSubresource.baseArrayLayer = 0;
+
+ tgtOffset = { 0, 0, 0 };
+ } else {
+ tgtImage = dstImage;
+ }
+
+ // Create source and destination image views
+ VkImageViewType viewType = dstImage->info().type == VK_IMAGE_TYPE_1D
+ ? VK_IMAGE_VIEW_TYPE_1D_ARRAY
+ : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+
+ DxvkImageViewCreateInfo tgtViewInfo;
+ tgtViewInfo.type = viewType;
+ tgtViewInfo.format = viewFormat;
+ tgtViewInfo.usage = tgtUsage;
+ tgtViewInfo.aspect = tgtSubresource.aspectMask;
+ tgtViewInfo.minLevel = tgtSubresource.mipLevel;
+ tgtViewInfo.numLevels = 1;
+ tgtViewInfo.minLayer = tgtSubresource.baseArrayLayer;
+ tgtViewInfo.numLayers = tgtSubresource.layerCount;
+
+ DxvkImageViewCreateInfo srcViewInfo;
+ srcViewInfo.type = viewType;
+ srcViewInfo.format = srcImage->info().format;
+ srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ srcViewInfo.aspect = srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_COLOR_BIT);
+ srcViewInfo.minLevel = srcSubresource.mipLevel;
+ srcViewInfo.numLevels = 1;
+ srcViewInfo.minLayer = srcSubresource.baseArrayLayer;
+ srcViewInfo.numLayers = srcSubresource.layerCount;
+
+ Rc<DxvkImageView> tgtImageView = m_device->createImageView(tgtImage, tgtViewInfo);
+ Rc<DxvkImageView> srcImageView = m_device->createImageView(srcImage, srcViewInfo);
+ Rc<DxvkImageView> srcStencilView;
+
+ if (srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
+ srcViewInfo.aspect = VK_IMAGE_ASPECT_STENCIL_BIT;
+ srcStencilView = m_device->createImageView(srcImage, srcViewInfo);
+ }
+
+ // Create framebuffer and pipeline for the copy
+ Rc<DxvkMetaCopyRenderPass> fb = new DxvkMetaCopyRenderPass(
+ m_device->vkd(), tgtImageView, srcImageView, srcStencilView,
+ tgtImage->isFullSubresource(tgtSubresource, extent));
+
+ auto pipeInfo = m_common->metaCopy().getPipeline(
+ viewType, viewFormat, tgtImage->info().sampleCount);
+
+ VkDescriptorImageInfo descriptorImage;
+ descriptorImage.sampler = VK_NULL_HANDLE;
+ descriptorImage.imageView = srcImageView->handle();
+ descriptorImage.imageLayout = srcLayout;
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrite.pImageInfo = &descriptorImage;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+
+ descriptorWrite.dstSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+
+ if (srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
+ descriptorImage.imageView = srcStencilView->handle();
+ descriptorWrite.dstBinding = 1;
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+ }
+
+ VkViewport viewport;
+ viewport.x = float(tgtOffset.x);
+ viewport.y = float(tgtOffset.y);
+ viewport.width = float(extent.width);
+ viewport.height = float(extent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { tgtOffset.x, tgtOffset.y };
+ scissor.extent = { extent.width, extent.height };
+
+ VkRenderPassBeginInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ info.pNext = nullptr;
+ info.renderPass = fb->renderPass();
+ info.framebuffer = fb->framebuffer();
+ info.renderArea.offset = { 0, 0 };
+ info.renderArea.extent = {
+ tgtImage->mipLevelExtent(tgtSubresource.mipLevel).width,
+ tgtImage->mipLevelExtent(tgtSubresource.mipLevel).height };
+ info.clearValueCount = 0;
+ info.pClearValues = nullptr;
+
+ // Perform the actual copy operation
+ m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
+ m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
+ m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr);
+
+ m_cmd->cmdSetViewport(0, 1, &viewport);
+ m_cmd->cmdSetScissor (0, 1, &scissor);
+
+ VkOffset2D srcCoordOffset = {
+ srcOffset.x - tgtOffset.x,
+ srcOffset.y - tgtOffset.y };
+
+ m_cmd->cmdPushConstants(pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, sizeof(srcCoordOffset),
+ &srcCoordOffset);
+
+ m_cmd->cmdDraw(3, tgtSubresource.layerCount, 0, 0);
+ m_cmd->cmdEndRenderPass();
+
+ if (srcLayout != srcImage->info().layout) {
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange, srcLayout,
+ srcImage->info().stages,
+ srcImage->info().access,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+ }
+
+ m_cmd->trackResource<DxvkAccess::Write>(tgtImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ m_cmd->trackResource<DxvkAccess::None>(fb);
+
+ // If necessary, copy the temporary image
+ // to the original destination image
+ if (!useDirectRender) {
+ this->copyImageHw(
+ dstImage, dstSubresource, dstOffset,
+ tgtImage, tgtSubresource, tgtOffset,
+ extent);
+ }
+ }
+
+
+ bool DxvkContext::copyImageClear(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkExtent3D dstExtent,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource) {
+ // If the source image has a pending deferred clear, we can
+ // implement the copy by clearing the destination image to
+ // the same clear value.
+ const VkImageUsageFlags attachmentUsage
+ = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ if (!(dstImage->info().usage & attachmentUsage)
+ || !(srcImage->info().usage & attachmentUsage))
+ return false;
+
+ // Ignore 3D images since those are complicated to handle
+ if (dstImage->info().type == VK_IMAGE_TYPE_3D
+ || srcImage->info().type == VK_IMAGE_TYPE_3D)
+ return false;
+
+ // Find a pending clear that overlaps with the source image
+ const DxvkDeferredClear* clear = nullptr;
+
+ for (const auto& entry : m_deferredClears) {
+ // Entries in the deferred clear array cannot overlap, so
+ // if we find an entry covering all source subresources,
+ // it's the only one in the list that does.
+ if ((entry.imageView->image() == srcImage) && ((srcSubresource.aspectMask & entry.clearAspects) == srcSubresource.aspectMask)
+ && (vk::checkSubresourceRangeSuperset(entry.imageView->subresources(), vk::makeSubresourceRange(srcSubresource)))) {
+ clear = &entry;
+ break;
+ }
+ }
+
+ if (!clear)
+ return false;
+
+ // Create a view for the destination image with the general
+ // properties ofthe source image view used for the clear
+ DxvkImageViewCreateInfo viewInfo = clear->imageView->info();
+ viewInfo.type = dstImage->info().type == VK_IMAGE_TYPE_1D
+ ? VK_IMAGE_VIEW_TYPE_1D_ARRAY
+ : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ viewInfo.minLevel = dstSubresource.mipLevel;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = dstSubresource.baseArrayLayer;
+ viewInfo.numLayers = dstSubresource.layerCount;
+
+ // That is, if the formats are actually compatible
+ // so that we can safely use the same clear value
+ if (!dstImage->isViewCompatible(viewInfo.format))
+ return false;
+
+ // Ignore mismatched size for now, needs more testing since we'd
+ // need to prepare the image first and then call clearImageViewFb
+ if (dstImage->mipLevelExtent(dstSubresource.mipLevel) != dstExtent)
+ return false;
+
+ auto view = m_device->createImageView(dstImage, viewInfo);
+ this->deferClear(view, srcSubresource.aspectMask, clear->clearValue);
+ return true;
+ }
+
+
+ void DxvkContext::resolveImageHw(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // We only support resolving to the entire image
+ // area, so we might as well discard its contents
+ VkImageLayout dstLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ VkImageLayout srcLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ VkImageLayout initialLayout = dstImage->info().layout;
+
+ if (dstImage->isFullSubresource(region.dstSubresource, region.extent))
+ initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ if (dstLayout != initialLayout) {
+ m_execAcquires.accessImage(
+ dstImage, dstSubresourceRange, initialLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ dstLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT);
+ }
+
+ if (srcLayout != srcImage->info().layout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
+ srcLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT);
+ }
+
+ m_execAcquires.recordCommands(m_cmd);
+
+ m_cmd->cmdResolveImage(
+ srcImage->handle(), srcLayout,
+ dstImage->handle(), dstLayout,
+ 1, &region);
+
+ m_execBarriers.accessImage(
+ dstImage, dstSubresourceRange, dstLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ dstImage->info().layout,
+ dstImage->info().stages,
+ dstImage->info().access);
+
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange, srcLayout,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ }
+
+
+ void DxvkContext::resolveImageDs(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // Create image views covering the requested subresourcs
+ DxvkImageViewCreateInfo dstViewInfo;
+ dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ dstViewInfo.format = dstImage->info().format;
+ dstViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ dstViewInfo.aspect = region.dstSubresource.aspectMask;
+ dstViewInfo.minLevel = region.dstSubresource.mipLevel;
+ dstViewInfo.numLevels = 1;
+ dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer;
+ dstViewInfo.numLayers = region.dstSubresource.layerCount;
+
+ DxvkImageViewCreateInfo srcViewInfo;
+ srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ srcViewInfo.format = srcImage->info().format;
+ srcViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ srcViewInfo.aspect = region.srcSubresource.aspectMask;
+ srcViewInfo.minLevel = region.srcSubresource.mipLevel;
+ srcViewInfo.numLevels = 1;
+ srcViewInfo.minLayer = region.srcSubresource.baseArrayLayer;
+ srcViewInfo.numLayers = region.srcSubresource.layerCount;
+
+ Rc<DxvkImageView> dstImageView = m_device->createImageView(dstImage, dstViewInfo);
+ Rc<DxvkImageView> srcImageView = m_device->createImageView(srcImage, srcViewInfo);
+
+ // Create a framebuffer for the resolve op
+ VkExtent3D passExtent = dstImageView->mipLevelExtent(0);
+
+ Rc<DxvkMetaResolveRenderPass> fb = new DxvkMetaResolveRenderPass(
+ m_device->vkd(), dstImageView, srcImageView, depthMode, stencilMode);
+
+ VkRenderPassBeginInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ info.pNext = nullptr;
+ info.renderPass = fb->renderPass();
+ info.framebuffer = fb->framebuffer();
+ info.renderArea.offset = { 0, 0 };
+ info.renderArea.extent = { passExtent.width, passExtent.height };
+ info.clearValueCount = 0;
+ info.pClearValues = nullptr;
+
+ m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
+ m_cmd->cmdEndRenderPass();
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ m_cmd->trackResource<DxvkAccess::None>(fb);
+ }
+
+
+ void DxvkContext::resolveImageFb(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkFormat format,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode) {
+ auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
+ auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
+
+ if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
+ || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ // We might have to transition the source image layout
+ VkImageLayout srcLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ if (srcImage->info().layout != srcLayout) {
+ m_execAcquires.accessImage(
+ srcImage, srcSubresourceRange,
+ srcImage->info().layout,
+ srcImage->info().stages, 0,
+ srcLayout,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_SHADER_READ_BIT);
+
+ m_execAcquires.recordCommands(m_cmd);
+ }
+
+ // Create image views covering the requested subresourcs
+ DxvkImageViewCreateInfo dstViewInfo;
+ dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ dstViewInfo.format = format ? format : dstImage->info().format;
+ dstViewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ dstViewInfo.aspect = region.dstSubresource.aspectMask;
+ dstViewInfo.minLevel = region.dstSubresource.mipLevel;
+ dstViewInfo.numLevels = 1;
+ dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer;
+ dstViewInfo.numLayers = region.dstSubresource.layerCount;
+
+ if (region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
+ dstViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ DxvkImageViewCreateInfo srcViewInfo;
+ srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ srcViewInfo.format = format ? format : srcImage->info().format;
+ srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ srcViewInfo.aspect = region.srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_COLOR_BIT);
+ srcViewInfo.minLevel = region.srcSubresource.mipLevel;
+ srcViewInfo.numLevels = 1;
+ srcViewInfo.minLayer = region.srcSubresource.baseArrayLayer;
+ srcViewInfo.numLayers = region.srcSubresource.layerCount;
+
+ Rc<DxvkImageView> dstImageView = m_device->createImageView(dstImage, dstViewInfo);
+ Rc<DxvkImageView> srcImageView = m_device->createImageView(srcImage, srcViewInfo);
+ Rc<DxvkImageView> srcStencilView = nullptr;
+
+ if ((region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && stencilMode != VK_RESOLVE_MODE_NONE_KHR) {
+ srcViewInfo.aspect = VK_IMAGE_ASPECT_STENCIL_BIT;
+ srcStencilView = m_device->createImageView(srcImage, srcViewInfo);
+ }
+
+ // Create a framebuffer and pipeline for the resolve op
+ VkExtent3D passExtent = dstImageView->mipLevelExtent(0);
+
+ Rc<DxvkMetaResolveRenderPass> fb = new DxvkMetaResolveRenderPass(
+ m_device->vkd(), dstImageView, srcImageView, srcStencilView,
+ dstImage->isFullSubresource(region.dstSubresource, region.extent));
+
+ auto pipeInfo = m_common->metaResolve().getPipeline(
+ dstViewInfo.format, srcImage->info().sampleCount, depthMode, stencilMode);
+
+ VkDescriptorImageInfo descriptorImage;
+ descriptorImage.sampler = VK_NULL_HANDLE;
+ descriptorImage.imageView = srcImageView->handle();
+ descriptorImage.imageLayout = srcLayout;
+
+ VkWriteDescriptorSet descriptorWrite;
+ descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ descriptorWrite.pNext = nullptr;
+ descriptorWrite.dstBinding = 0;
+ descriptorWrite.dstArrayElement = 0;
+ descriptorWrite.descriptorCount = 1;
+ descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ descriptorWrite.pImageInfo = &descriptorImage;
+ descriptorWrite.pBufferInfo = nullptr;
+ descriptorWrite.pTexelBufferView = nullptr;
+
+ descriptorWrite.dstSet = allocateDescriptorSet(pipeInfo.dsetLayout);
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+
+ if (srcStencilView != nullptr) {
+ descriptorWrite.dstBinding = 1;
+ descriptorImage.imageView = srcStencilView->handle();
+ m_cmd->updateDescriptorSets(1, &descriptorWrite);
+ }
+
+ VkViewport viewport;
+ viewport.x = float(region.dstOffset.x);
+ viewport.y = float(region.dstOffset.y);
+ viewport.width = float(region.extent.width);
+ viewport.height = float(region.extent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { region.dstOffset.x, region.dstOffset.y };
+ scissor.extent = { region.extent.width, region.extent.height };
+
+ VkRenderPassBeginInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ info.pNext = nullptr;
+ info.renderPass = fb->renderPass();
+ info.framebuffer = fb->framebuffer();
+ info.renderArea.offset = { 0, 0 };
+ info.renderArea.extent = { passExtent.width, passExtent.height };
+ info.clearValueCount = 0;
+ info.pClearValues = nullptr;
+
+ // Perform the actual resolve operation
+ VkOffset2D srcOffset = {
+ region.srcOffset.x - region.dstOffset.x,
+ region.srcOffset.y - region.dstOffset.y };
+
+ m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
+ m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
+ m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr);
+ m_cmd->cmdSetViewport(0, 1, &viewport);
+ m_cmd->cmdSetScissor (0, 1, &scissor);
+ m_cmd->cmdPushConstants(pipeInfo.pipeLayout,
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, sizeof(srcOffset), &srcOffset);
+ m_cmd->cmdDraw(3, region.dstSubresource.layerCount, 0, 0);
+ m_cmd->cmdEndRenderPass();
+
+ if (srcImage->info().layout != srcLayout) {
+ m_execBarriers.accessImage(
+ srcImage, srcSubresourceRange, srcLayout,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
+ srcImage->info().layout,
+ srcImage->info().stages,
+ srcImage->info().access);
+ }
+
+ m_cmd->trackResource<DxvkAccess::Write>(dstImage);
+ m_cmd->trackResource<DxvkAccess::Read>(srcImage);
+ m_cmd->trackResource<DxvkAccess::None>(fb);
+ }
+
+
+ void DxvkContext::startRenderPass() {
+ if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
+ this->applyRenderTargetLoadLayouts();
+ this->flushClears(true);
+
+ m_flags.set(DxvkContextFlag::GpRenderPassBound);
+ m_flags.clr(DxvkContextFlag::GpRenderPassSuspended);
+
+ m_execBarriers.recordCommands(m_cmd);
+
+ this->renderPassBindFramebuffer(
+ m_state.om.framebuffer,
+ m_state.om.renderPassOps,
+ m_state.om.framebuffer->numAttachments(),
+ m_state.om.clearValues.data());
+
+ // Track the final layout of each render target
+ this->applyRenderTargetStoreLayouts();
+
+ // Don't discard image contents if we have
+ // to spill the current render pass
+ this->resetRenderPassOps(
+ m_state.om.renderTargets,
+ m_state.om.renderPassOps);
+
+ // Begin occlusion queries
+ m_queryManager.beginQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
+ m_queryManager.beginQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
+ }
+ }
+
+
+ void DxvkContext::spillRenderPass(bool suspend) {
+ if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) {
+ m_flags.clr(DxvkContextFlag::GpRenderPassBound);
+
+ this->pauseTransformFeedback();
+
+ m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_OCCLUSION);
+ m_queryManager.endQueries(m_cmd, VK_QUERY_TYPE_PIPELINE_STATISTICS);
+
+ this->renderPassUnbindFramebuffer();
+
+ if (suspend)
+ m_flags.set(DxvkContextFlag::GpRenderPassSuspended);
+ else
+ this->transitionRenderTargetLayouts(m_gfxBarriers, false);
+
+ m_gfxBarriers.recordCommands(m_cmd);
+
+ this->unbindGraphicsPipeline();
+ } else if (!suspend) {
+ // We may end a previously suspended render pass
+ if (m_flags.test(DxvkContextFlag::GpRenderPassSuspended)) {
+ m_flags.clr(DxvkContextFlag::GpRenderPassSuspended);
+ this->transitionRenderTargetLayouts(m_gfxBarriers, false);
+ m_gfxBarriers.recordCommands(m_cmd);
+ }
+
+ // Execute deferred clears if necessary
+ this->flushClears(false);
+ }
+ }
+
+
+ void DxvkContext::renderPassBindFramebuffer(
+ const Rc<DxvkFramebuffer>& framebuffer,
+ const DxvkRenderPassOps& ops,
+ uint32_t clearValueCount,
+ const VkClearValue* clearValues) {
+ const DxvkFramebufferSize fbSize = framebuffer->size();
+
+ VkRect2D renderArea;
+ renderArea.offset = VkOffset2D { 0, 0 };
+ renderArea.extent = VkExtent2D { fbSize.width, fbSize.height };
+
+ VkRenderPassBeginInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ info.pNext = nullptr;
+ info.renderPass = framebuffer->getRenderPassHandle(ops);
+ info.framebuffer = framebuffer->handle();
+ info.renderArea = renderArea;
+ info.clearValueCount = clearValueCount;
+ info.pClearValues = clearValues;
+
+ m_cmd->cmdBeginRenderPass(&info,
+ VK_SUBPASS_CONTENTS_INLINE);
+
+ m_cmd->trackResource<DxvkAccess::None>(framebuffer);
+
+ for (uint32_t i = 0; i < framebuffer->numAttachments(); i++) {
+ m_cmd->trackResource<DxvkAccess::None> (framebuffer->getAttachment(i).view);
+ m_cmd->trackResource<DxvkAccess::Write>(framebuffer->getAttachment(i).view->image());
+ }
+
+ m_cmd->addStatCtr(DxvkStatCounter::CmdRenderPassCount, 1);
+ }
+
+
+ void DxvkContext::renderPassUnbindFramebuffer() {
+ m_cmd->cmdEndRenderPass();
+ }
+
+
+ void DxvkContext::resetRenderPassOps(
+ const DxvkRenderTargets& renderTargets,
+ DxvkRenderPassOps& renderPassOps) {
+ VkAccessFlags access = 0;
+
+ if (renderTargets.depth.view != nullptr) {
+ renderPassOps.depthOps = DxvkDepthAttachmentOps {
+ VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD,
+ renderTargets.depth.layout, renderTargets.depth.layout };
+
+ access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+ if (renderTargets.depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
+ access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+ } else {
+ renderPassOps.depthOps = DxvkDepthAttachmentOps { };
+ }
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (renderTargets.color[i].view != nullptr) {
+ renderPassOps.colorOps[i] = DxvkColorAttachmentOps {
+ VK_ATTACHMENT_LOAD_OP_LOAD,
+ renderTargets.color[i].layout,
+ renderTargets.color[i].layout };
+
+ access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+ | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ } else {
+ renderPassOps.colorOps[i] = DxvkColorAttachmentOps { };
+ }
+ }
+
+ renderPassOps.barrier.srcStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+ renderPassOps.barrier.srcAccess = access;
+ renderPassOps.barrier.dstStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ renderPassOps.barrier.dstAccess = access;
+ }
+
+
+ void DxvkContext::startTransformFeedback() {
+ if (!m_flags.test(DxvkContextFlag::GpXfbActive)) {
+ m_flags.set(DxvkContextFlag::GpXfbActive);
+
+ VkBuffer ctrBuffers[MaxNumXfbBuffers];
+ VkDeviceSize ctrOffsets[MaxNumXfbBuffers];
+
+ for (uint32_t i = 0; i < MaxNumXfbBuffers; i++) {
+ auto physSlice = m_state.xfb.counters[i].getSliceHandle();
+
+ ctrBuffers[i] = physSlice.handle;
+ ctrOffsets[i] = physSlice.offset;
+
+ if (physSlice.handle != VK_NULL_HANDLE)
+ m_cmd->trackResource<DxvkAccess::Read>(m_state.xfb.counters[i].buffer());
+ }
+
+ m_cmd->cmdBeginTransformFeedback(
+ 0, MaxNumXfbBuffers, ctrBuffers, ctrOffsets);
+
+ m_queryManager.beginQueries(m_cmd,
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
+ }
+ }
+
+
+ void DxvkContext::pauseTransformFeedback() {
+ if (m_flags.test(DxvkContextFlag::GpXfbActive)) {
+ m_flags.clr(DxvkContextFlag::GpXfbActive);
+
+ VkBuffer ctrBuffers[MaxNumXfbBuffers];
+ VkDeviceSize ctrOffsets[MaxNumXfbBuffers];
+
+ for (uint32_t i = 0; i < MaxNumXfbBuffers; i++) {
+ auto physSlice = m_state.xfb.counters[i].getSliceHandle();
+
+ ctrBuffers[i] = physSlice.handle;
+ ctrOffsets[i] = physSlice.offset;
+
+ if (physSlice.handle != VK_NULL_HANDLE)
+ m_cmd->trackResource<DxvkAccess::Write>(m_state.xfb.counters[i].buffer());
+ }
+
+ m_queryManager.endQueries(m_cmd,
+ VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT);
+
+ m_cmd->cmdEndTransformFeedback(
+ 0, MaxNumXfbBuffers, ctrBuffers, ctrOffsets);
+ }
+ }
+
+
+ void DxvkContext::unbindComputePipeline() {
+ m_flags.set(
+ DxvkContextFlag::CpDirtyPipeline,
+ DxvkContextFlag::CpDirtyPipelineState,
+ DxvkContextFlag::CpDirtyResources);
+
+ m_cpActivePipeline = VK_NULL_HANDLE;
+ }
+
+
+ bool DxvkContext::updateComputePipeline() {
+ m_state.cp.pipeline = lookupComputePipeline(m_state.cp.shaders);
+
+ if (unlikely(m_state.cp.pipeline == nullptr))
+ return false;
+
+ if (m_state.cp.pipeline->layout()->pushConstRange().size)
+ m_flags.set(DxvkContextFlag::DirtyPushConstants);
+
+ m_flags.clr(DxvkContextFlag::CpDirtyPipeline);
+ return true;
+ }
+
+
+ bool DxvkContext::updateComputePipelineState() {
+ m_cpActivePipeline = m_state.cp.pipeline->getPipelineHandle(m_state.cp.state);
+
+ if (unlikely(!m_cpActivePipeline))
+ return false;
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ m_cpActivePipeline);
+
+ m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
+ return true;
+ }
+
+
+ void DxvkContext::unbindGraphicsPipeline() {
+ m_flags.set(
+ DxvkContextFlag::GpDirtyPipeline,
+ DxvkContextFlag::GpDirtyPipelineState,
+ DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::GpDirtyVertexBuffers,
+ DxvkContextFlag::GpDirtyIndexBuffer,
+ DxvkContextFlag::GpDirtyXfbBuffers,
+ DxvkContextFlag::GpDirtyBlendConstants,
+ DxvkContextFlag::GpDirtyStencilRef,
+ DxvkContextFlag::GpDirtyViewport,
+ DxvkContextFlag::GpDirtyDepthBias,
+ DxvkContextFlag::GpDirtyDepthBounds);
+
+ m_gpActivePipeline = VK_NULL_HANDLE;
+ }
+
+
+ bool DxvkContext::updateGraphicsPipeline() {
+ m_state.gp.pipeline = lookupGraphicsPipeline(m_state.gp.shaders);
+
+ if (unlikely(m_state.gp.pipeline == nullptr)) {
+ m_state.gp.flags = DxvkGraphicsPipelineFlags();
+ return false;
+ }
+
+ if (m_state.gp.flags != m_state.gp.pipeline->flags()) {
+ m_state.gp.flags = m_state.gp.pipeline->flags();
+
+ // Force-update vertex/index buffers for hazard checks
+ m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer,
+ DxvkContextFlag::GpDirtyVertexBuffers,
+ DxvkContextFlag::GpDirtyXfbBuffers,
+ DxvkContextFlag::DirtyDrawBuffer);
+
+ // This is necessary because we'll only do hazard
+ // tracking if the active pipeline has side effects
+ if (!m_barrierControl.test(DxvkBarrierControl::IgnoreGraphicsBarriers))
+ this->spillRenderPass(true);
+ }
+
+ if (m_state.gp.pipeline->layout()->pushConstRange().size)
+ m_flags.set(DxvkContextFlag::DirtyPushConstants);
+
+ m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
+ return true;
+ }
+
+
+ bool DxvkContext::updateGraphicsPipelineState() {
+ // Set up vertex buffer strides for active bindings
+ for (uint32_t i = 0; i < m_state.gp.state.il.bindingCount(); i++) {
+ const uint32_t binding = m_state.gp.state.ilBindings[i].binding();
+ m_state.gp.state.ilBindings[i].setStride(m_state.vi.vertexStrides[binding]);
+ }
+
+ // Check which dynamic states need to be active. States that
+ // are not dynamic will be invalidated in the command buffer.
+ m_flags.clr(DxvkContextFlag::GpDynamicBlendConstants,
+ DxvkContextFlag::GpDynamicDepthBias,
+ DxvkContextFlag::GpDynamicDepthBounds,
+ DxvkContextFlag::GpDynamicStencilRef);
+
+ m_flags.set(m_state.gp.state.useDynamicBlendConstants()
+ ? DxvkContextFlag::GpDynamicBlendConstants
+ : DxvkContextFlag::GpDirtyBlendConstants);
+
+ m_flags.set(m_state.gp.state.useDynamicDepthBias()
+ ? DxvkContextFlag::GpDynamicDepthBias
+ : DxvkContextFlag::GpDirtyDepthBias);
+
+ m_flags.set(m_state.gp.state.useDynamicDepthBounds()
+ ? DxvkContextFlag::GpDynamicDepthBounds
+ : DxvkContextFlag::GpDirtyDepthBounds);
+
+ m_flags.set(m_state.gp.state.useDynamicStencilRef()
+ ? DxvkContextFlag::GpDynamicStencilRef
+ : DxvkContextFlag::GpDirtyStencilRef);
+
+ // Retrieve and bind actual Vulkan pipeline handle
+ m_gpActivePipeline = m_state.gp.pipeline->getPipelineHandle(m_state.gp.state, m_state.om.framebuffer->getRenderPass());
+
+ if (unlikely(!m_gpActivePipeline))
+ return false;
+
+ m_cmd->cmdBindPipeline(
+ VK_PIPELINE_BIND_POINT_GRAPHICS,
+ m_gpActivePipeline);
+
+ m_flags.clr(DxvkContextFlag::GpDirtyPipelineState);
+ return true;
+ }
+
+
+ void DxvkContext::updateComputeShaderResources() {
+ if ((m_flags.test(DxvkContextFlag::CpDirtyResources))
+ || (m_state.cp.pipeline->layout()->hasStaticBufferBindings()))
+ this->updateShaderResources<VK_PIPELINE_BIND_POINT_COMPUTE>(m_state.cp.pipeline->layout());
+
+ this->updateShaderDescriptorSetBinding<VK_PIPELINE_BIND_POINT_COMPUTE>(
+ m_cpSet, m_state.cp.pipeline->layout());
+
+ m_flags.clr(DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::CpDirtyDescriptorBinding);
+ }
+
+
+ void DxvkContext::updateGraphicsShaderResources() {
+ if ((m_flags.test(DxvkContextFlag::GpDirtyResources))
+ || (m_state.gp.pipeline->layout()->hasStaticBufferBindings()))
+ this->updateShaderResources<VK_PIPELINE_BIND_POINT_GRAPHICS>(m_state.gp.pipeline->layout());
+
+ this->updateShaderDescriptorSetBinding<VK_PIPELINE_BIND_POINT_GRAPHICS>(
+ m_gpSet, m_state.gp.pipeline->layout());
+
+ m_flags.clr(DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::GpDirtyDescriptorBinding);
+ }
+
+
+ template<VkPipelineBindPoint BindPoint>
+ void DxvkContext::updateShaderResources(const DxvkPipelineLayout* layout) {
+ std::array<DxvkDescriptorInfo, MaxNumActiveBindings> descriptors;
+
+ // Assume that all bindings are active as a fast path
+ DxvkBindingMask bindMask;
+ bindMask.setFirst(layout->bindingCount());
+
+ for (uint32_t i = 0; i < layout->bindingCount(); i++) {
+ const auto& binding = layout->binding(i);
+ const auto& res = m_rc[binding.slot];
+
+ switch (binding.type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ if (res.sampler != nullptr) {
+ descriptors[i].image.sampler = res.sampler->handle();
+ descriptors[i].image.imageView = VK_NULL_HANDLE;
+ descriptors[i].image.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ if (m_rcTracked.set(binding.slot))
+ m_cmd->trackResource<DxvkAccess::None>(res.sampler);
+ } else {
+ descriptors[i].image = m_common->dummyResources().samplerDescriptor();
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ if (res.imageView != nullptr && res.imageView->handle(binding.view) != VK_NULL_HANDLE) {
+ descriptors[i].image.sampler = VK_NULL_HANDLE;
+ descriptors[i].image.imageView = res.imageView->handle(binding.view);
+ descriptors[i].image.imageLayout = res.imageView->imageInfo().layout;
+
+ if (m_rcTracked.set(binding.slot)) {
+ m_cmd->trackResource<DxvkAccess::None>(res.imageView);
+ m_cmd->trackResource<DxvkAccess::Read>(res.imageView->image());
+ }
+ } else {
+ bindMask.clr(i);
+ descriptors[i].image = m_common->dummyResources().imageViewDescriptor(binding.view, true);
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ if (res.imageView != nullptr && res.imageView->handle(binding.view) != VK_NULL_HANDLE) {
+ descriptors[i].image.sampler = VK_NULL_HANDLE;
+ descriptors[i].image.imageView = res.imageView->handle(binding.view);
+ descriptors[i].image.imageLayout = res.imageView->imageInfo().layout;
+
+ if (m_rcTracked.set(binding.slot)) {
+ m_cmd->trackResource<DxvkAccess::None>(res.imageView);
+ m_cmd->trackResource<DxvkAccess::Write>(res.imageView->image());
+ }
+ } else {
+ bindMask.clr(i);
+ descriptors[i].image = m_common->dummyResources().imageViewDescriptor(binding.view, false);
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ if (res.sampler != nullptr && res.imageView != nullptr
+ && res.imageView->handle(binding.view) != VK_NULL_HANDLE) {
+ descriptors[i].image.sampler = res.sampler->handle();
+ descriptors[i].image.imageView = res.imageView->handle(binding.view);
+ descriptors[i].image.imageLayout = res.imageView->imageInfo().layout;
+
+ if (m_rcTracked.set(binding.slot)) {
+ m_cmd->trackResource<DxvkAccess::None>(res.sampler);
+ m_cmd->trackResource<DxvkAccess::None>(res.imageView);
+ m_cmd->trackResource<DxvkAccess::Read>(res.imageView->image());
+ }
+ } else {
+ bindMask.clr(i);
+ descriptors[i].image = m_common->dummyResources().imageSamplerDescriptor(binding.view);
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ if (res.bufferView != nullptr) {
+ res.bufferView->updateView();
+ descriptors[i].texelBuffer = res.bufferView->handle();
+
+ if (m_rcTracked.set(binding.slot)) {
+ m_cmd->trackResource<DxvkAccess::None>(res.bufferView);
+ m_cmd->trackResource<DxvkAccess::Read>(res.bufferView->buffer());
+ }
+ } else {
+ bindMask.clr(i);
+ descriptors[i].texelBuffer = m_common->dummyResources().bufferViewDescriptor();
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ if (res.bufferView != nullptr) {
+ res.bufferView->updateView();
+ descriptors[i].texelBuffer = res.bufferView->handle();
+
+ if (m_rcTracked.set(binding.slot)) {
+ m_cmd->trackResource<DxvkAccess::None>(res.bufferView);
+ m_cmd->trackResource<DxvkAccess::Write>(res.bufferView->buffer());
+ }
+ } else {
+ bindMask.clr(i);
+ descriptors[i].texelBuffer = m_common->dummyResources().bufferViewDescriptor();
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ if (res.bufferSlice.defined()) {
+ descriptors[i] = res.bufferSlice.getDescriptor();
+
+ if (m_rcTracked.set(binding.slot))
+ m_cmd->trackResource<DxvkAccess::Read>(res.bufferSlice.buffer());
+ } else {
+ bindMask.clr(i);
+ descriptors[i].buffer = m_common->dummyResources().bufferDescriptor();
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ if (res.bufferSlice.defined()) {
+ descriptors[i] = res.bufferSlice.getDescriptor();
+
+ if (m_rcTracked.set(binding.slot))
+ m_cmd->trackResource<DxvkAccess::Write>(res.bufferSlice.buffer());
+ } else {
+ bindMask.clr(i);
+ descriptors[i].buffer = m_common->dummyResources().bufferDescriptor();
+ } break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ if (res.bufferSlice.defined()) {
+ descriptors[i] = res.bufferSlice.getDescriptor();
+ descriptors[i].buffer.offset = 0;
+
+ if (m_rcTracked.set(binding.slot))
+ m_cmd->trackResource<DxvkAccess::Read>(res.bufferSlice.buffer());
+ } else {
+ bindMask.clr(i);
+ descriptors[i].buffer = m_common->dummyResources().bufferDescriptor();
+ } break;
+
+ default:
+ Logger::err(str::format("DxvkContext: Unhandled descriptor type: ", binding.type));
+ }
+ }
+
+ // Allocate and update descriptor set
+ auto& set = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_gpSet : m_cpSet;
+
+ if (layout->bindingCount()) {
+ set = allocateDescriptorSet(layout->descriptorSetLayout());
+
+ m_cmd->updateDescriptorSetWithTemplate(set,
+ layout->descriptorTemplate(), descriptors.data());
+ } else {
+ set = VK_NULL_HANDLE;
+ }
+
+ // Select the active binding mask to update
+ auto& refMask = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
+ ? m_state.gp.state.bsBindingMask
+ : m_state.cp.state.bsBindingMask;
+
+ // If some resources are not bound, we may need to
+ // update spec constants and rebind the pipeline
+ if (refMask != bindMask) {
+ refMask = bindMask;
+
+ m_flags.set(BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
+ ? DxvkContextFlag::GpDirtyPipelineState
+ : DxvkContextFlag::CpDirtyPipelineState);
+ }
+ }
+
+
+ template<VkPipelineBindPoint BindPoint>
+ __attribute__((always_inline)) void DxvkContext::updateShaderDescriptorSetBinding(
+ VkDescriptorSet set,
+ const DxvkPipelineLayout* layout) {
+ if (set) {
+ std::array<uint32_t, MaxNumActiveBindings> offsets;
+
+ for (uint32_t i = 0; i < layout->dynamicBindingCount(); i++) {
+ const auto& binding = layout->dynamicBinding(i);
+ const auto& res = m_rc[binding.slot];
+
+ offsets[i] = res.bufferSlice.defined()
+ ? res.bufferSlice.getDynamicOffset()
+ : 0;
+ }
+
+ m_cmd->cmdBindDescriptorSet(BindPoint,
+ layout->pipelineLayout(), set,
+ layout->dynamicBindingCount(),
+ offsets.data());
+ }
+ }
+
+
+ void DxvkContext::updateFramebuffer() {
+ if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer);
+
+ this->spillRenderPass(true);
+
+ auto fb = m_device->createFramebuffer(m_state.om.renderTargets);
+ this->updateRenderTargetLayouts(fb, m_state.om.framebuffer);
+
+ m_state.gp.state.ms.setSampleCount(fb->getSampleCount());
+ m_state.om.framebuffer = fb;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ const Rc<DxvkImageView>& attachment = fb->getColorTarget(i).view;
+
+ VkComponentMapping mapping = attachment != nullptr
+ ? util::invertComponentMapping(attachment->info().swizzle)
+ : VkComponentMapping();
+
+ m_state.gp.state.omSwizzle[i] = DxvkOmAttachmentSwizzle(mapping);
+ }
+
+ m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
+ }
+ }
+
+
+ void DxvkContext::applyRenderTargetLoadLayouts() {
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
+ m_state.om.renderPassOps.colorOps[i].loadLayout = m_rtLayouts.color[i];
+
+ m_state.om.renderPassOps.depthOps.loadLayout = m_rtLayouts.depth;
+ }
+
+
+ void DxvkContext::applyRenderTargetStoreLayouts() {
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
+ m_rtLayouts.color[i] = m_state.om.renderPassOps.colorOps[i].storeLayout;
+
+ m_rtLayouts.depth = m_state.om.renderPassOps.depthOps.storeLayout;
+ }
+
+
+ void DxvkContext::transitionRenderTargetLayouts(
+ DxvkBarrierSet& barriers,
+ bool sharedOnly) {
+ if (m_state.om.framebuffer == nullptr)
+ return;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ const DxvkAttachment& color = m_state.om.framebuffer->getColorTarget(i);
+
+ if (color.view != nullptr && (!sharedOnly || color.view->imageInfo().shared)) {
+ this->transitionColorAttachment(barriers, color, m_rtLayouts.color[i]);
+ m_rtLayouts.color[i] = color.view->imageInfo().layout;
+ }
+ }
+
+ const DxvkAttachment& depth = m_state.om.framebuffer->getDepthTarget();
+
+ if (depth.view != nullptr && (!sharedOnly || depth.view->imageInfo().shared)) {
+ this->transitionDepthAttachment(barriers, depth, m_rtLayouts.depth);
+ m_rtLayouts.depth = depth.view->imageInfo().layout;
+ }
+ }
+
+
+ void DxvkContext::transitionColorAttachment(
+ DxvkBarrierSet& barriers,
+ const DxvkAttachment& attachment,
+ VkImageLayout oldLayout) {
+ if (oldLayout != attachment.view->imageInfo().layout) {
+ barriers.accessImage(
+ attachment.view->image(),
+ attachment.view->imageSubresources(), oldLayout,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ attachment.view->imageInfo().layout,
+ attachment.view->imageInfo().stages,
+ attachment.view->imageInfo().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(attachment.view->image());
+ }
+ }
+
+
+ void DxvkContext::transitionDepthAttachment(
+ DxvkBarrierSet& barriers,
+ const DxvkAttachment& attachment,
+ VkImageLayout oldLayout) {
+ if (oldLayout != attachment.view->imageInfo().layout) {
+ barriers.accessImage(
+ attachment.view->image(),
+ attachment.view->imageSubresources(), oldLayout,
+ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
+ VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+ oldLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT : 0,
+ attachment.view->imageInfo().layout,
+ attachment.view->imageInfo().stages,
+ attachment.view->imageInfo().access);
+
+ m_cmd->trackResource<DxvkAccess::Write>(attachment.view->image());
+ }
+ }
+
+
+ void DxvkContext::updateRenderTargetLayouts(
+ const Rc<DxvkFramebuffer>& newFb,
+ const Rc<DxvkFramebuffer>& oldFb) {
+ DxvkRenderTargetLayouts layouts = { };
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (newFb->getColorTarget(i).view != nullptr)
+ layouts.color[i] = newFb->getColorTarget(i).view->imageInfo().layout;
+ }
+
+ if (newFb->getDepthTarget().view != nullptr)
+ layouts.depth = newFb->getDepthTarget().view->imageInfo().layout;
+
+ if (oldFb != nullptr) {
+ // Check whether any of the previous attachments have been moved
+ // around or been rebound with a different view. This may help
+ // reduce the number of image layout transitions between passes.
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ const DxvkAttachment& oldAttachment = oldFb->getColorTarget(i);
+
+ if (oldAttachment.view != nullptr) {
+ bool found = false;
+
+ for (uint32_t j = 0; j < MaxNumRenderTargets && !found; j++) {
+ const DxvkAttachment& newAttachment = newFb->getColorTarget(j);
+
+ found = newAttachment.view == oldAttachment.view || (newAttachment.view != nullptr
+ && newAttachment.view->image() == oldAttachment.view->image()
+ && newAttachment.view->subresources() == oldAttachment.view->subresources());
+
+ if (found)
+ layouts.color[j] = m_rtLayouts.color[i];
+ }
+
+ if (!found && m_flags.test(DxvkContextFlag::GpRenderPassSuspended))
+ this->transitionColorAttachment(m_execBarriers, oldAttachment, m_rtLayouts.color[i]);
+ }
+ }
+
+ const DxvkAttachment& oldAttachment = oldFb->getDepthTarget();
+
+ if (oldAttachment.view != nullptr) {
+ const DxvkAttachment& newAttachment = newFb->getDepthTarget();
+
+ bool found = newAttachment.view == oldAttachment.view || (newAttachment.view != nullptr
+ && newAttachment.view->image() == oldAttachment.view->image()
+ && newAttachment.view->subresources() == oldAttachment.view->subresources());
+
+ if (found)
+ layouts.depth = m_rtLayouts.depth;
+ else if (m_flags.test(DxvkContextFlag::GpRenderPassSuspended))
+ this->transitionDepthAttachment(m_execBarriers, oldAttachment, m_rtLayouts.depth);
+ }
+ }
+
+ m_rtLayouts = layouts;
+ }
+
+
+ void DxvkContext::prepareImage(
+ DxvkBarrierSet& barriers,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ bool flushClears) {
+ // Images that can't be used as attachments are always in their
+ // default layout, so we don't have to do anything in this case
+ if (!(image->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)))
+ return;
+
+ // Flush clears if there are any since they may affect the image
+ if (!m_deferredClears.empty() && flushClears)
+ this->spillRenderPass(false);
+
+ // All images are in their default layout for suspended passes
+ if (!m_flags.test(DxvkContextFlag::GpRenderPassSuspended))
+ return;
+
+ // 3D images require special care because they only have one
+ // layer, but views may address individual 2D slices as layers
+ bool is3D = image->info().type == VK_IMAGE_TYPE_3D;
+
+ // Transition any attachment with overlapping subresources
+ if (image->info().usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ const DxvkAttachment& attachment = m_state.om.framebuffer->getColorTarget(i);
+
+ if (attachment.view != nullptr && attachment.view->image() == image
+ && (is3D || vk::checkSubresourceRangeOverlap(attachment.view->subresources(), subresources))) {
+ this->transitionColorAttachment(barriers, attachment, m_rtLayouts.color[i]);
+ m_rtLayouts.color[i] = image->info().layout;
+ }
+ }
+ } else {
+ const DxvkAttachment& attachment = m_state.om.framebuffer->getDepthTarget();
+
+ if (attachment.view != nullptr && attachment.view->image() == image
+ && (is3D || vk::checkSubresourceRangeOverlap(attachment.view->subresources(), subresources))) {
+ this->transitionDepthAttachment(barriers, attachment, m_rtLayouts.depth);
+ m_rtLayouts.depth = image->info().layout;
+ }
+ }
+ }
+
+
+ bool DxvkContext::updateIndexBufferBinding() {
+ if (unlikely(!m_state.vi.indexBuffer.defined()))
+ return false;
+
+ m_flags.clr(DxvkContextFlag::GpDirtyIndexBuffer);
+ auto bufferInfo = m_state.vi.indexBuffer.getDescriptor();
+
+ m_cmd->cmdBindIndexBuffer(
+ bufferInfo.buffer.buffer,
+ bufferInfo.buffer.offset,
+ m_state.vi.indexType);
+
+ if (m_vbTracked.set(MaxNumVertexBindings))
+ m_cmd->trackResource<DxvkAccess::Read>(m_state.vi.indexBuffer.buffer());
+
+ return true;
+ }
+
+
+ void DxvkContext::updateVertexBufferBindings() {
+ m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
+
+ if (unlikely(!m_state.gp.state.il.bindingCount()))
+ return;
+
+ std::array<VkBuffer, MaxNumVertexBindings> buffers;
+ std::array<VkDeviceSize, MaxNumVertexBindings> offsets;
+ std::array<VkDeviceSize, MaxNumVertexBindings> lengths;
+
+ // Set buffer handles and offsets for active bindings
+ for (uint32_t i = 0; i < m_state.gp.state.il.bindingCount(); i++) {
+ uint32_t binding = m_state.gp.state.ilBindings[i].binding();
+
+ if (likely(m_state.vi.vertexBuffers[binding].defined())) {
+ auto vbo = m_state.vi.vertexBuffers[binding].getDescriptor();
+
+ buffers[i] = vbo.buffer.buffer;
+ offsets[i] = vbo.buffer.offset;
+ lengths[i] = vbo.buffer.range;
+
+ if (m_vbTracked.set(binding))
+ m_cmd->trackResource<DxvkAccess::Read>(m_state.vi.vertexBuffers[binding].buffer());
+ } else if (m_features.test(DxvkContextFeature::NullDescriptors)) {
+ buffers[i] = VK_NULL_HANDLE;
+ offsets[i] = 0;
+ lengths[i] = 0;
+ } else {
+ buffers[i] = m_common->dummyResources().bufferHandle();
+ offsets[i] = 0;
+ lengths[i] = 0;
+ }
+ }
+
+ // Vertex bindigs get remapped when compiling the
+ // pipeline, so this actually does the right thing
+ if (m_features.test(DxvkContextFeature::ExtendedDynamicState)) {
+ m_cmd->cmdBindVertexBuffers2(0, m_state.gp.state.il.bindingCount(),
+ buffers.data(), offsets.data(), lengths.data(), nullptr);
+ } else {
+ m_cmd->cmdBindVertexBuffers(0, m_state.gp.state.il.bindingCount(),
+ buffers.data(), offsets.data());
+ }
+ }
+
+
+ void DxvkContext::updateTransformFeedbackBuffers() {
+ auto gsOptions = m_state.gp.shaders.gs->shaderOptions();
+
+ VkBuffer xfbBuffers[MaxNumXfbBuffers];
+ VkDeviceSize xfbOffsets[MaxNumXfbBuffers];
+ VkDeviceSize xfbLengths[MaxNumXfbBuffers];
+
+ for (size_t i = 0; i < MaxNumXfbBuffers; i++) {
+ auto physSlice = m_state.xfb.buffers[i].getSliceHandle();
+
+ xfbBuffers[i] = physSlice.handle;
+ xfbOffsets[i] = physSlice.offset;
+ xfbLengths[i] = physSlice.length;
+
+ if (physSlice.handle == VK_NULL_HANDLE)
+ xfbBuffers[i] = m_common->dummyResources().bufferHandle();
+
+ if (physSlice.handle != VK_NULL_HANDLE) {
+ const Rc<DxvkBuffer>& buffer = m_state.xfb.buffers[i].buffer();
+ buffer->setXfbVertexStride(gsOptions.xfbStrides[i]);
+
+ m_cmd->trackResource<DxvkAccess::Write>(buffer);
+ }
+ }
+
+ m_cmd->cmdBindTransformFeedbackBuffers(
+ 0, MaxNumXfbBuffers,
+ xfbBuffers, xfbOffsets, xfbLengths);
+ }
+
+
+ void DxvkContext::updateTransformFeedbackState() {
+ if (m_flags.test(DxvkContextFlag::GpDirtyXfbBuffers)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyXfbBuffers);
+
+ this->pauseTransformFeedback();
+ this->updateTransformFeedbackBuffers();
+ }
+
+ this->startTransformFeedback();
+ }
+
+
+ void DxvkContext::updateDynamicState() {
+ if (!m_gpActivePipeline)
+ return;
+
+ if (m_flags.test(DxvkContextFlag::GpDirtyViewport)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyViewport);
+
+ uint32_t viewportCount = m_state.gp.state.rs.viewportCount();
+ m_cmd->cmdSetViewport(0, viewportCount, m_state.vp.viewports.data());
+ m_cmd->cmdSetScissor (0, viewportCount, m_state.vp.scissorRects.data());
+ }
+
+ if (m_flags.all(DxvkContextFlag::GpDirtyBlendConstants,
+ DxvkContextFlag::GpDynamicBlendConstants)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyBlendConstants);
+ m_cmd->cmdSetBlendConstants(&m_state.dyn.blendConstants.r);
+ }
+
+ if (m_flags.all(DxvkContextFlag::GpDirtyStencilRef,
+ DxvkContextFlag::GpDynamicStencilRef)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyStencilRef);
+
+ m_cmd->cmdSetStencilReference(
+ VK_STENCIL_FRONT_AND_BACK,
+ m_state.dyn.stencilReference);
+ }
+
+ if (m_flags.all(DxvkContextFlag::GpDirtyDepthBias,
+ DxvkContextFlag::GpDynamicDepthBias)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyDepthBias);
+
+ m_cmd->cmdSetDepthBias(
+ m_state.dyn.depthBias.depthBiasConstant,
+ m_state.dyn.depthBias.depthBiasClamp,
+ m_state.dyn.depthBias.depthBiasSlope);
+ }
+
+ if (m_flags.all(DxvkContextFlag::GpDirtyDepthBounds,
+ DxvkContextFlag::GpDynamicDepthBounds)) {
+ m_flags.clr(DxvkContextFlag::GpDirtyDepthBounds);
+
+ m_cmd->cmdSetDepthBounds(
+ m_state.dyn.depthBounds.minDepthBounds,
+ m_state.dyn.depthBounds.maxDepthBounds);
+ }
+ }
+
+
+ template<VkPipelineBindPoint BindPoint>
+ void DxvkContext::updatePushConstants() {
+ m_flags.clr(DxvkContextFlag::DirtyPushConstants);
+
+ auto layout = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
+ ? m_state.gp.pipeline->layout()
+ : m_state.cp.pipeline->layout();
+
+ if (!layout)
+ return;
+
+ VkPushConstantRange pushConstRange = layout->pushConstRange();
+ if (!pushConstRange.size)
+ return;
+
+ m_cmd->cmdPushConstants(
+ layout->pipelineLayout(),
+ pushConstRange.stageFlags,
+ pushConstRange.offset,
+ pushConstRange.size,
+ &m_state.pc.data[pushConstRange.offset]);
+ }
+
+
+ bool DxvkContext::commitComputeState() {
+ this->spillRenderPass(false);
+
+ if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) {
+ if (unlikely(!this->updateComputePipeline()))
+ return false;
+ }
+
+ if (m_flags.any(
+ DxvkContextFlag::CpDirtyResources,
+ DxvkContextFlag::CpDirtyDescriptorBinding))
+ this->updateComputeShaderResources();
+
+ if (m_flags.test(DxvkContextFlag::CpDirtyPipelineState)) {
+ if (unlikely(!this->updateComputePipelineState()))
+ return false;
+ }
+
+ if (m_flags.test(DxvkContextFlag::DirtyPushConstants))
+ this->updatePushConstants<VK_PIPELINE_BIND_POINT_COMPUTE>();
+
+ return true;
+ }
+
+
+ template<bool Indexed, bool Indirect>
+ bool DxvkContext::commitGraphicsState() {
+ if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) {
+ if (unlikely(!this->updateGraphicsPipeline()))
+ return false;
+ }
+
+ if (m_state.gp.flags.any(DxvkGraphicsPipelineFlag::HasStorageDescriptors,
+ DxvkGraphicsPipelineFlag::HasTransformFeedback)) {
+ this->commitGraphicsBarriers<Indexed, Indirect, false>();
+ this->commitGraphicsBarriers<Indexed, Indirect, true>();
+ }
+
+ if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer))
+ this->updateFramebuffer();
+
+ if (!m_flags.test(DxvkContextFlag::GpRenderPassBound))
+ this->startRenderPass();
+
+ if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer) && Indexed) {
+ if (unlikely(!this->updateIndexBufferBinding()))
+ return false;
+ }
+
+ if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers))
+ this->updateVertexBufferBindings();
+
+ if (m_flags.any(
+ DxvkContextFlag::GpDirtyResources,
+ DxvkContextFlag::GpDirtyDescriptorBinding))
+ this->updateGraphicsShaderResources();
+
+ if (m_flags.test(DxvkContextFlag::GpDirtyPipelineState)) {
+ if (unlikely(!this->updateGraphicsPipelineState()))
+ return false;
+ }
+
+ if (m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasTransformFeedback))
+ this->updateTransformFeedbackState();
+
+ if (m_flags.any(
+ DxvkContextFlag::GpDirtyViewport,
+ DxvkContextFlag::GpDirtyBlendConstants,
+ DxvkContextFlag::GpDirtyStencilRef,
+ DxvkContextFlag::GpDirtyDepthBias,
+ DxvkContextFlag::GpDirtyDepthBounds))
+ this->updateDynamicState();
+
+ if (m_flags.test(DxvkContextFlag::DirtyPushConstants))
+ this->updatePushConstants<VK_PIPELINE_BIND_POINT_GRAPHICS>();
+
+ if (m_flags.test(DxvkContextFlag::DirtyDrawBuffer) && Indirect)
+ this->trackDrawBuffer();
+
+ return true;
+ }
+
+
+ void DxvkContext::commitComputeInitBarriers() {
+ auto layout = m_state.cp.pipeline->layout();
+
+ bool requiresBarrier = false;
+
+ for (uint32_t i = 0; i < layout->bindingCount() && !requiresBarrier; i++) {
+ if (m_state.cp.state.bsBindingMask.test(i)) {
+ const DxvkDescriptorSlot binding = layout->binding(i);
+ const DxvkShaderResourceSlot& slot = m_rc[binding.slot];
+
+ DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(binding.access);
+ DxvkAccessFlags srcAccess = 0;
+
+ switch (binding.type) {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ srcAccess = m_execBarriers.getBufferAccess(
+ slot.bufferSlice.getSliceHandle());
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ srcAccess = m_execBarriers.getBufferAccess(
+ slot.bufferView->getSliceHandle());
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ srcAccess = m_execBarriers.getImageAccess(
+ slot.imageView->image(),
+ slot.imageView->imageSubresources());
+ break;
+
+ default:
+ /* nothing to do */;
+ }
+
+ if (srcAccess == 0)
+ continue;
+
+ // Skip write-after-write barriers if explicitly requested
+ VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+
+ if ((m_barrierControl.test(DxvkBarrierControl::IgnoreWriteAfterWrite))
+ && (!(m_execBarriers.getSrcStages() & ~stageMask))
+ && ((srcAccess | dstAccess) == DxvkAccess::Write))
+ continue;
+
+ requiresBarrier = (srcAccess | dstAccess).test(DxvkAccess::Write);
+ }
+ }
+
+ if (requiresBarrier)
+ m_execBarriers.recordCommands(m_cmd);
+ }
+
+
+ void DxvkContext::commitComputePostBarriers() {
+ auto layout = m_state.cp.pipeline->layout();
+
+ for (uint32_t i = 0; i < layout->bindingCount(); i++) {
+ if (m_state.cp.state.bsBindingMask.test(i)) {
+ const DxvkDescriptorSlot binding = layout->binding(i);
+ const DxvkShaderResourceSlot& slot = m_rc[binding.slot];
+
+ VkPipelineStageFlags stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ VkAccessFlags access = binding.access;
+
+ switch (binding.type) {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ m_execBarriers.accessBuffer(
+ slot.bufferSlice.getSliceHandle(),
+ stages, access,
+ slot.bufferSlice.bufferInfo().stages,
+ slot.bufferSlice.bufferInfo().access);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ m_execBarriers.accessBuffer(
+ slot.bufferView->getSliceHandle(),
+ stages, access,
+ slot.bufferView->bufferInfo().stages,
+ slot.bufferView->bufferInfo().access);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ m_execBarriers.accessImage(
+ slot.imageView->image(),
+ slot.imageView->imageSubresources(),
+ slot.imageView->imageInfo().layout,
+ stages, access,
+ slot.imageView->imageInfo().layout,
+ slot.imageView->imageInfo().stages,
+ slot.imageView->imageInfo().access);
+ break;
+
+ default:
+ /* nothing to do */;
+ }
+ }
+ }
+ }
+
+
+ template<bool Indexed, bool Indirect, bool DoEmit>
+ void DxvkContext::commitGraphicsBarriers() {
+ if (m_barrierControl.test(DxvkBarrierControl::IgnoreGraphicsBarriers))
+ return;
+
+ auto layout = m_state.gp.pipeline->layout();
+
+ constexpr auto storageBufferAccess = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT;
+ constexpr auto storageImageAccess = VK_ACCESS_SHADER_WRITE_BIT;
+
+ bool requiresBarrier = false;
+
+ // Check the draw buffer for indirect draw calls
+ if (m_flags.test(DxvkContextFlag::DirtyDrawBuffer) && Indirect) {
+ std::array<DxvkBufferSlice*, 2> slices = {{
+ &m_state.id.argBuffer,
+ &m_state.id.cntBuffer,
+ }};
+
+ for (uint32_t i = 0; i < slices.size() && !requiresBarrier; i++) {
+ if ((slices[i]->defined())
+ && (slices[i]->bufferInfo().access & storageBufferAccess)) {
+ requiresBarrier = this->checkGfxBufferBarrier<DoEmit>(*slices[i],
+ VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
+ VK_ACCESS_INDIRECT_COMMAND_READ_BIT).test(DxvkAccess::Write);
+ }
+ }
+ }
+
+ // Read-only stage, so we only have to check this if
+ // the bindngs have actually changed between draws
+ if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer) && !requiresBarrier && Indexed) {
+ const auto& indexBufferSlice = m_state.vi.indexBuffer;
+
+ if ((indexBufferSlice.defined())
+ && (indexBufferSlice.bufferInfo().access & storageBufferAccess)) {
+ requiresBarrier = this->checkGfxBufferBarrier<DoEmit>(indexBufferSlice,
+ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
+ VK_ACCESS_INDEX_READ_BIT).test(DxvkAccess::Write);
+ }
+ }
+
+ // Same here, also ignore unused vertex bindings
+ if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
+ uint32_t bindingCount = m_state.gp.state.il.bindingCount();
+
+ for (uint32_t i = 0; i < bindingCount && !requiresBarrier; i++) {
+ uint32_t binding = m_state.gp.state.ilBindings[i].binding();
+ const auto& vertexBufferSlice = m_state.vi.vertexBuffers[binding];
+
+ if ((vertexBufferSlice.defined())
+ && (vertexBufferSlice.bufferInfo().access & storageBufferAccess)) {
+ requiresBarrier = this->checkGfxBufferBarrier<DoEmit>(vertexBufferSlice,
+ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
+ VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).test(DxvkAccess::Write);
+ }
+ }
+ }
+
+ // Transform feedback buffer writes won't overlap, so we
+ // also only need to check those when they are rebound
+ if (m_flags.test(DxvkContextFlag::GpDirtyXfbBuffers)
+ && m_state.gp.flags.test(DxvkGraphicsPipelineFlag::HasTransformFeedback)) {
+ for (uint32_t i = 0; i < MaxNumXfbBuffers && !requiresBarrier; i++) {
+ const auto& xfbBufferSlice = m_state.xfb.buffers[i];
+ const auto& xfbCounterSlice = m_state.xfb.counters[i];
+
+ if (xfbBufferSlice.defined()) {
+ requiresBarrier = this->checkGfxBufferBarrier<DoEmit>(xfbBufferSlice,
+ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
+ VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT) != 0;
+
+ if (xfbCounterSlice.defined()) {
+ requiresBarrier |= this->checkGfxBufferBarrier<DoEmit>(xfbCounterSlice,
+ VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
+ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT |
+ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT) != 0;
+ }
+ }
+ }
+ }
+
+ // Check shader resources on every draw to handle WAW hazards
+ for (uint32_t i = 0; i < layout->bindingCount() && !requiresBarrier; i++) {
+ const DxvkDescriptorSlot binding = layout->binding(i);
+ const DxvkShaderResourceSlot& slot = m_rc[binding.slot];
+
+ DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(binding.access);
+ DxvkAccessFlags srcAccess = 0;
+
+ switch (binding.type) {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ if ((slot.bufferSlice.defined())
+ && (slot.bufferSlice.bufferInfo().access & storageBufferAccess)) {
+ srcAccess = this->checkGfxBufferBarrier<DoEmit>(slot.bufferSlice,
+ binding.stages, binding.access);
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ if ((slot.bufferView != nullptr)
+ && (slot.bufferView->bufferInfo().access & storageBufferAccess)) {
+ srcAccess = this->checkGfxBufferBarrier<DoEmit>(slot.bufferView->slice(),
+ binding.stages, binding.access);
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ if ((slot.imageView != nullptr)
+ && (slot.imageView->imageInfo().access & storageImageAccess)) {
+ srcAccess = this->checkGfxImageBarrier<DoEmit>(slot.imageView,
+ binding.stages, binding.access);
+ }
+ break;
+
+ default:
+ /* nothing to do */;
+ }
+
+ if (srcAccess == 0)
+ continue;
+
+ // Skip write-after-write barriers if explicitly requested
+ if ((m_barrierControl.test(DxvkBarrierControl::IgnoreWriteAfterWrite))
+ && ((srcAccess | dstAccess) == DxvkAccess::Write))
+ continue;
+
+ requiresBarrier = (srcAccess | dstAccess).test(DxvkAccess::Write);
+ }
+
+ // External subpass dependencies serve as full memory
+ // and execution barriers, so we can use this to allow
+ // inter-stage synchronization.
+ if (requiresBarrier)
+ this->spillRenderPass(true);
+ }
+
+
+ template<bool DoEmit>
+ DxvkAccessFlags DxvkContext::checkGfxBufferBarrier(
+ const DxvkBufferSlice& slice,
+ VkPipelineStageFlags stages,
+ VkAccessFlags access) {
+ if constexpr (DoEmit) {
+ m_gfxBarriers.accessBuffer(
+ slice.getSliceHandle(),
+ stages, access,
+ slice.bufferInfo().stages,
+ slice.bufferInfo().access);
+ return DxvkAccessFlags();
+ } else {
+ return m_gfxBarriers.getBufferAccess(slice.getSliceHandle());
+ }
+ }
+
+
+ template<bool DoEmit>
+ DxvkAccessFlags DxvkContext::checkGfxImageBarrier(
+ const Rc<DxvkImageView>& imageView,
+ VkPipelineStageFlags stages,
+ VkAccessFlags access) {
+ if constexpr (DoEmit) {
+ m_gfxBarriers.accessImage(
+ imageView->image(),
+ imageView->imageSubresources(),
+ imageView->imageInfo().layout,
+ stages, access,
+ imageView->imageInfo().layout,
+ imageView->imageInfo().stages,
+ imageView->imageInfo().access);
+ return DxvkAccessFlags();
+ } else {
+ return m_gfxBarriers.getImageAccess(
+ imageView->image(),
+ imageView->imageSubresources());
+ }
+ }
+
+
+ void DxvkContext::emitMemoryBarrier(
+ VkDependencyFlags flags,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ VkMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.srcAccessMask = srcAccess;
+ barrier.dstAccessMask = dstAccess;
+
+ m_cmd->cmdPipelineBarrier(
+ DxvkCmdBuffer::ExecBuffer, srcStages, dstStages,
+ flags, 1, &barrier, 0, nullptr, 0, nullptr);
+ }
+
+
+ void DxvkContext::initializeImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess) {
+ if (m_execBarriers.isImageDirty(image, subresources, DxvkAccess::Write))
+ m_execBarriers.recordCommands(m_cmd);
+
+ VkPipelineStageFlags srcStages = 0;
+
+ if (image->isInUse())
+ srcStages = dstStages;
+
+ m_execAcquires.accessImage(image, subresources,
+ VK_IMAGE_LAYOUT_UNDEFINED, srcStages, 0,
+ dstLayout, dstStages, dstAccess);
+ }
+
+
+ VkDescriptorSet DxvkContext::allocateDescriptorSet(
+ VkDescriptorSetLayout layout) {
+ if (m_descPool == nullptr)
+ m_descPool = m_device->createDescriptorPool();
+
+ VkDescriptorSet set = m_descPool->alloc(layout);
+
+ if (set == VK_NULL_HANDLE) {
+ m_cmd->trackDescriptorPool(std::move(m_descPool));
+
+ m_descPool = m_device->createDescriptorPool();
+ set = m_descPool->alloc(layout);
+ }
+
+ return set;
+ }
+
+
+ void DxvkContext::trackDrawBuffer() {
+ if (m_flags.test(DxvkContextFlag::DirtyDrawBuffer)) {
+ m_flags.clr(DxvkContextFlag::DirtyDrawBuffer);
+
+ if (m_state.id.argBuffer.defined())
+ m_cmd->trackResource<DxvkAccess::Read>(m_state.id.argBuffer.buffer());
+
+ if (m_state.id.cntBuffer.defined())
+ m_cmd->trackResource<DxvkAccess::Read>(m_state.id.cntBuffer.buffer());
+ }
+ }
+
+
+ DxvkGraphicsPipeline* DxvkContext::lookupGraphicsPipeline(
+ const DxvkGraphicsPipelineShaders& shaders) {
+ auto idx = shaders.hash() % m_gpLookupCache.size();
+
+ if (unlikely(!m_gpLookupCache[idx] || !shaders.eq(m_gpLookupCache[idx]->shaders())))
+ m_gpLookupCache[idx] = m_common->pipelineManager().createGraphicsPipeline(shaders);
+
+ return m_gpLookupCache[idx];
+ }
+
+
+ DxvkComputePipeline* DxvkContext::lookupComputePipeline(
+ const DxvkComputePipelineShaders& shaders) {
+ auto idx = shaders.hash() % m_cpLookupCache.size();
+
+ if (unlikely(!m_cpLookupCache[idx] || !shaders.eq(m_cpLookupCache[idx]->shaders())))
+ m_cpLookupCache[idx] = m_common->pipelineManager().createComputePipeline(shaders);
+
+ return m_cpLookupCache[idx];
+ }
+
+
+ Rc<DxvkBuffer> DxvkContext::createZeroBuffer(
+ VkDeviceSize size) {
+ if (m_zeroBuffer != nullptr && m_zeroBuffer->info().size >= size)
+ return m_zeroBuffer;
+
+ DxvkBufferCreateInfo bufInfo;
+ bufInfo.size = align<VkDeviceSize>(size, 1 << 20);
+ bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ bufInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_TRANSFER_READ_BIT;
+
+ m_zeroBuffer = m_device->createBuffer(bufInfo,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ clearBuffer(m_zeroBuffer, 0, bufInfo.size, 0);
+ m_execBarriers.recordCommands(m_cmd);
+ return m_zeroBuffer;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.h
new file mode 100644
index 00000000..46c90375
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context.h
@@ -0,0 +1,1358 @@
+#pragma once
+
+#include "dxvk_barrier.h"
+#include "dxvk_bind_mask.h"
+#include "dxvk_cmdlist.h"
+#include "dxvk_context_state.h"
+#include "dxvk_data.h"
+#include "dxvk_objects.h"
+#include "dxvk_resource.h"
+#include "dxvk_util.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXVk context
+ *
+ * Tracks pipeline state and records command lists.
+ * This is where the actual rendering commands are
+ * recorded.
+ */
+ class DxvkContext : public RcObject {
+
+ public:
+
+ DxvkContext(const Rc<DxvkDevice>& device);
+ ~DxvkContext();
+
+ /**
+ * \brief Begins command buffer recording
+ *
+ * Begins recording a command list. This does
+ * not alter any context state other than the
+ * active command list.
+ * \param [in] cmdList Target command list
+ */
+ void beginRecording(
+ const Rc<DxvkCommandList>& cmdList);
+
+ /**
+ * \brief Ends command buffer recording
+ *
+ * Finishes recording the active command list.
+ * The command list can then be submitted to
+ * the device.
+ *
+ * This will not change any context state
+ * other than the active command list.
+ * \returns Active command list
+ */
+ Rc<DxvkCommandList> endRecording();
+
+ /**
+ * \brief Flushes command buffer
+ *
+ * Transparently submits the current command
+ * buffer and allocates a new one.
+ */
+ void flushCommandList();
+
+ /**
+ * \brief Begins generating query data
+ * \param [in] query The query to end
+ */
+ void beginQuery(
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Ends generating query data
+ * \param [in] query The query to end
+ */
+ void endQuery(
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Sets render targets
+ *
+ * Creates a framebuffer on the fly if necessary
+ * and binds it using \c bindFramebuffer.
+ * \param [in] targets Render targets to bind
+ */
+ void bindRenderTargets(
+ const DxvkRenderTargets& targets);
+
+ /**
+ * \brief Binds indirect argument buffer
+ *
+ * Sets the buffers that are going to be used
+ * for indirect draw and dispatch operations.
+ * \param [in] argBuffer New argument buffer
+ * \param [in] cntBuffer New count buffer
+ */
+ void bindDrawBuffers(
+ const DxvkBufferSlice& argBuffer,
+ const DxvkBufferSlice& cntBuffer);
+
+ /**
+ * \brief Binds index buffer
+ *
+ * The index buffer will be used when
+ * issuing \c drawIndexed commands.
+ * \param [in] buffer New index buffer
+ * \param [in] indexType Index type
+ */
+ void bindIndexBuffer(
+ const DxvkBufferSlice& buffer,
+ VkIndexType indexType);
+
+ /**
+ * \brief Binds buffer as a shader resource
+ *
+ * Can be used for uniform and storage buffers.
+ * \param [in] slot Resource binding slot
+ * \param [in] buffer Buffer to bind
+ */
+ void bindResourceBuffer(
+ uint32_t slot,
+ const DxvkBufferSlice& buffer);
+
+ /**
+ * \brief Binds image or buffer view
+ *
+ * Can be used for sampled images with a dedicated
+ * sampler and for storage images, as well as for
+ * uniform texel buffers and storage texel buffers.
+ * \param [in] slot Resource binding slot
+ * \param [in] imageView Image view to bind
+ * \param [in] bufferView Buffer view to bind
+ */
+ void bindResourceView(
+ uint32_t slot,
+ const Rc<DxvkImageView>& imageView,
+ const Rc<DxvkBufferView>& bufferView);
+
+ /**
+ * \brief Binds image sampler
+ *
+ * Binds a sampler that can be used together with
+ * an image in order to read from a texture.
+ * \param [in] slot Resource binding slot
+ * \param [in] sampler Sampler view to bind
+ */
+ void bindResourceSampler(
+ uint32_t slot,
+ const Rc<DxvkSampler>& sampler);
+
+ /**
+ * \brief Binds a shader to a given state
+ *
+ * \param [in] stage Target shader stage
+ * \param [in] shader The shader to bind
+ */
+ void bindShader(
+ VkShaderStageFlagBits stage,
+ const Rc<DxvkShader>& shader);
+
+ /**
+ * \brief Binds vertex buffer
+ *
+ * \param [in] binding Vertex buffer binding
+ * \param [in] buffer New vertex buffer
+ * \param [in] stride Stride between vertices
+ */
+ void bindVertexBuffer(
+ uint32_t binding,
+ const DxvkBufferSlice& buffer,
+ uint32_t stride);
+
+ /**
+ * \brief Binds transform feedback buffer
+ *
+ * \param [in] binding Xfb buffer binding
+ * \param [in] buffer The buffer to bind
+ * \param [in] counter Xfb counter buffer
+ */
+ void bindXfbBuffer(
+ uint32_t binding,
+ const DxvkBufferSlice& buffer,
+ const DxvkBufferSlice& counter);
+
+ /**
+ * \brief Blits an image
+ *
+ * \param [in] dstImage Destination image
+ * \param [in] dstMapping Destination swizzle
+ * \param [in] srcImage Source image
+ * \param [in] srcMapping Source swizzle
+ * \param [in] region Blit region
+ * \param [in] filter Texture filter
+ */
+ void blitImage(
+ const Rc<DxvkImage>& dstImage,
+ const VkComponentMapping& dstMapping,
+ const Rc<DxvkImage>& srcImage,
+ const VkComponentMapping& srcMapping,
+ const VkImageBlit& region,
+ VkFilter filter);
+
+ /**
+ * \brief Changes image layout
+ *
+ * Permanently changes the layout for a given
+ * image. Immediately performs the transition.
+ * \param [in] image The image to transition
+ * \param [in] layout New image layout
+ */
+ void changeImageLayout(
+ const Rc<DxvkImage>& image,
+ VkImageLayout layout);
+
+ /**
+ * \brief Clears a buffer with a fixed value
+ *
+ * Note that both \c offset and \c length must
+ * be multiples of four, and that \c value is
+ * consumed as a four-byte word.
+ * \param [in] buffer The buffer to clear
+ * \param [in] offset Offset of the range to clear
+ * \param [in] length Bumber of bytes to clear
+ * \param [in] value Clear value
+ */
+ void clearBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ uint32_t value);
+
+ /**
+ * \brief Clears a buffer view
+ *
+ * Unlike \c clearBuffer, this method can be used
+ * to clear a buffer view with format conversion.
+ * \param [in] bufferView The buffer view
+ * \param [in] offset Offset of the region to clear
+ * \param [in] length Extent of the region to clear
+ * \param [in] value The clear value
+ */
+ void clearBufferView(
+ const Rc<DxvkBufferView>& bufferView,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ VkClearColorValue value);
+
+ /**
+ * \brief Clears subresources of a color image
+ *
+ * \param [in] image The image to clear
+ * \param [in] value Clear value
+ * \param [in] subresources Subresources to clear
+ */
+ void clearColorImage(
+ const Rc<DxvkImage>& image,
+ const VkClearColorValue& value,
+ const VkImageSubresourceRange& subresources);
+
+ /**
+ * \brief Clears subresources of a depth-stencil image
+ *
+ * \param [in] image The image to clear
+ * \param [in] value Clear value
+ * \param [in] subresources Subresources to clear
+ */
+ void clearDepthStencilImage(
+ const Rc<DxvkImage>& image,
+ const VkClearDepthStencilValue& value,
+ const VkImageSubresourceRange& subresources);
+
+ /**
+ * \brief Clears a compressed image to black
+ *
+ * \param [in] image The image to clear
+ * \param [in] subresources Subresources to clear
+ */
+ void clearCompressedColorImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources);
+
+ /**
+ * \brief Clears an active render target
+ *
+ * \param [in] imageView Render target view to clear
+ * \param [in] clearAspects Image aspects to clear
+ * \param [in] clearValue The clear value
+ */
+ void clearRenderTarget(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue);
+
+ /**
+ * \brief Clears an image view
+ *
+ * Can be used to clear sub-regions of storage images
+ * that are not going to be used as render targets.
+ * Implicit format conversion will be applied.
+ * \param [in] imageView The image view
+ * \param [in] offset Offset of the rect to clear
+ * \param [in] extent Extent of the rect to clear
+ * \param [in] aspect Aspect mask to clear
+ * \param [in] value The clear value
+ */
+ void clearImageView(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkImageAspectFlags aspect,
+ VkClearValue value);
+
+ /**
+ * \brief Copies data from one buffer to another
+ *
+ * \param [in] dstBuffer Destination buffer
+ * \param [in] dstOffset Destination data offset
+ * \param [in] srcBuffer Source buffer
+ * \param [in] srcOffset Source data offset
+ * \param [in] numBytes Number of bytes to copy
+ */
+ void copyBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcOffset,
+ VkDeviceSize numBytes);
+
+ /**
+ * \brief Copies overlapping buffer region
+ *
+ * Can be used to copy potentially overlapping
+ * buffer regions within the same buffer. If
+ * the source and destination regions do not
+ * overlap, it will behave as \ref copyBuffer.
+ * \param [in] dstBuffer The buffer
+ * \param [in] dstOffset Offset of target region
+ * \param [in] srcOffset Offset of source region
+ * \param [in] numBytes Number of bytes to copy
+ */
+ void copyBufferRegion(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize srcOffset,
+ VkDeviceSize numBytes);
+
+ /**
+ * \brief Copies data from a buffer to an image
+ *
+ * Source data must be packed, except for the row alignment.
+ * \param [in] dstImage Destination image
+ * \param [in] dstSubresource Destination subresource
+ * \param [in] dstOffset Destination area offset
+ * \param [in] dstExtent Destination area size
+ * \param [in] srcBuffer Source buffer
+ * \param [in] srcOffset Source offset, in bytes
+ * \param [in] rowAlignment Row alignment, in bytes
+ * \param [in] sliceAlignment Slice alignment, in bytes
+ */
+ void copyBufferToImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkExtent3D dstExtent,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcOffset,
+ VkDeviceSize rowAlignment,
+ VkDeviceSize sliceAlignment);
+
+ /**
+ * \brief Copies data from one image to another
+ *
+ * \param [in] dstImage Destination image
+ * \param [in] dstSubresource Destination subresource
+ * \param [in] dstOffset Destination area offset
+ * \param [in] srcImage Source image
+ * \param [in] srcSubresource Source subresource
+ * \param [in] srcOffset Source area offset
+ * \param [in] extent Size of the area to copy
+ */
+ void copyImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent);
+
+ /**
+ * \brief Copies overlapping image region
+ *
+ * \param [in] dstImage The image
+ * \param [in] dstSubresource The image subresource
+ * \param [in] dstOffset Destination region offset
+ * \param [in] srcOffset Source region offset
+ * \param [in] extent Size of the copy region
+ */
+ void copyImageRegion(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkOffset3D srcOffset,
+ VkExtent3D extent);
+
+ /**
+ * \brief Copies data from an image into a buffer
+ *
+ * \param [in] dstBuffer Destination buffer
+ * \param [in] dstOffset Destination offset, in bytes
+ * \param [in] dstExtent Destination data extent
+ * \param [in] rowAlignment Row alignment, in bytes
+ * \param [in] sliceAlignment Slice alignment, in bytes
+ * \param [in] srcImage Source image
+ * \param [in] srcSubresource Source subresource
+ * \param [in] srcOffset Source area offset
+ * \param [in] srcExtent Source area size
+ */
+ void copyImageToBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstOffset,
+ VkDeviceSize rowAlignment,
+ VkDeviceSize sliceAlignment,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D srcExtent);
+
+ /**
+ * \brief Packs depth-stencil image data to a buffer
+ *
+ * Packs data from both the depth and stencil aspects
+ * of an image into a buffer. The supported formats are:
+ * - \c VK_FORMAT_D24_UNORM_S8_UINT: 0xssdddddd
+ * - \c VK_FORMAT_D32_SFLOAT_S8_UINT: 0xdddddddd 0x000000ss
+ * \param [in] dstBuffer Destination buffer
+ * \param [in] dstBufferOffset Destination offset, in bytes
+ * \param [in] dstOffset Destination image offset
+ * \param [in] dstSize Destination image size
+ * \param [in] srcImage Source image
+ * \param [in] srcSubresource Source subresource
+ * \param [in] srcOffset Source area offset
+ * \param [in] srcExtent Source area size
+ * \param [in] format Packed data format
+ */
+ void copyDepthStencilImageToPackedBuffer(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstBufferOffset,
+ VkOffset2D dstOffset,
+ VkExtent2D dstExtent,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset2D srcOffset,
+ VkExtent2D srcExtent,
+ VkFormat format);
+
+ /**
+ * \brief Copies image data stored in a linear buffer to another
+ *
+ * The source and destination regions may overlap, in which case
+ * a temporary copy of the source buffer will be created.
+ * \param [in] dstBuffer Destination buffer
+ * \param [in] dstBufferOffset Destination subresource offset
+ * \param [in] dstOffset Destination image offset
+ * \param [in] dstSize Total size of the destination image
+ * \param [in] srcBuffer Source buffer
+ * \param [in] srcBufferOffset Source subresource offset
+ * \param [in] srcOffset Source image offset
+ * \param [in] srcSize Total size of the source image
+ * \param [in] extent Number of pixels to copy
+ * \param [in] elementSize Pixel size, in bytes
+ */
+ void copyPackedBufferImage(
+ const Rc<DxvkBuffer>& dstBuffer,
+ VkDeviceSize dstBufferOffset,
+ VkOffset3D dstOffset,
+ VkExtent3D dstSize,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcBufferOffset,
+ VkOffset3D srcOffset,
+ VkExtent3D srcSize,
+ VkExtent3D extent,
+ VkDeviceSize elementSize);
+
+ /**
+ * \brief Unpacks buffer data to a depth-stencil image
+ *
+ * Writes the packed depth-stencil data to an image.
+ * See \ref copyDepthStencilImageToPackedBuffer for
+ * which formats are supported and how they are packed.
+ * \param [in] dstImage Destination image
+ * \param [in] dstSubresource Destination subresource
+ * \param [in] dstOffset Image area offset
+ * \param [in] dstExtent Image area size
+ * \param [in] srcBuffer Packed data buffer
+ * \param [in] srcBufferOffset Buffer offset of source image
+ * \param [in] srcOffset Offset into the source image
+ * \param [in] srcExtent Total size of the source image
+ * \param [in] format Packed data format
+ */
+ void copyPackedBufferToDepthStencilImage(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset2D dstOffset,
+ VkExtent2D dstExtent,
+ const Rc<DxvkBuffer>& srcBuffer,
+ VkDeviceSize srcBufferOffset,
+ VkOffset2D srcOffset,
+ VkExtent2D srcExtent,
+ VkFormat format);
+
+ /**
+ * \brief Discards a buffer
+ *
+ * Renames the buffer in case it is currently
+ * used by the GPU in order to avoid having to
+ * insert barriers before future commands using
+ * the buffer.
+ * \param [in] buffer The buffer to discard
+ */
+ void discardBuffer(
+ const Rc<DxvkBuffer>& buffer);
+
+ /**
+ * \brief Discards contents of an image view
+ *
+ * Discards the current contents of the image
+ * and performs a fast layout transition. This
+ * may improve performance in some cases.
+ * \param [in] imageView View to discard
+ * \param [in] discardAspects Image aspects to discard
+ */
+ void discardImageView(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags discardAspects);
+
+ /**
+ * \brief Starts compute jobs
+ *
+ * \param [in] x Number of threads in X direction
+ * \param [in] y Number of threads in Y direction
+ * \param [in] z Number of threads in Z direction
+ */
+ void dispatch(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z);
+
+ /**
+ * \brief Indirect dispatch call
+ *
+ * Takes arguments from a buffer. The buffer must contain
+ * a structure of the type \c VkDispatchIndirectCommand.
+ * \param [in] offset Draw buffer offset
+ */
+ void dispatchIndirect(
+ VkDeviceSize offset);
+
+ /**
+ * \brief Draws primitive without using an index buffer
+ *
+ * \param [in] vertexCount Number of vertices to draw
+ * \param [in] instanceCount Number of instances to render
+ * \param [in] firstVertex First vertex in vertex buffer
+ * \param [in] firstInstance First instance ID
+ */
+ void draw(
+ uint32_t vertexCount,
+ uint32_t instanceCount,
+ uint32_t firstVertex,
+ uint32_t firstInstance);
+
+ /**
+ * \brief Indirect draw call
+ *
+ * Takes arguments from a buffer. The structure stored
+ * in the buffer must be of type \c VkDrawIndirectCommand.
+ * \param [in] offset Draw buffer offset
+ * \param [in] count Number of draws
+ * \param [in] stride Stride between dispatch calls
+ */
+ void drawIndirect(
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride);
+
+ /**
+ * \brief Indirect draw call
+ *
+ * Takes arguments from a buffer. The structure stored
+ * in the buffer must be of type \c VkDrawIndirectCommand.
+ * \param [in] offset Draw buffer offset
+ * \param [in] countOffset Draw count offset
+ * \param [in] maxCount Maximum number of draws
+ * \param [in] stride Stride between dispatch calls
+ */
+ void drawIndirectCount(
+ VkDeviceSize offset,
+ VkDeviceSize countOffset,
+ uint32_t maxCount,
+ uint32_t stride);
+
+ /**
+ * \brief Draws primitives using an index buffer
+ *
+ * \param [in] indexCount Number of indices to draw
+ * \param [in] instanceCount Number of instances to render
+ * \param [in] firstIndex First index within the index buffer
+ * \param [in] vertexOffset Vertex ID that corresponds to index 0
+ * \param [in] firstInstance First instance ID
+ */
+ void drawIndexed(
+ uint32_t indexCount,
+ uint32_t instanceCount,
+ uint32_t firstIndex,
+ uint32_t vertexOffset,
+ uint32_t firstInstance);
+
+ /**
+ * \brief Indirect indexed draw call
+ *
+ * Takes arguments from a buffer. The structure type for
+ * the draw buffer is \c VkDrawIndexedIndirectCommand.
+ * \param [in] offset Draw buffer offset
+ * \param [in] count Number of draws
+ * \param [in] stride Stride between dispatch calls
+ */
+ void drawIndexedIndirect(
+ VkDeviceSize offset,
+ uint32_t count,
+ uint32_t stride);
+
+ /**
+ * \brief Indirect indexed draw call
+ *
+ * Takes arguments from a buffer. The structure type for
+ * the draw buffer is \c VkDrawIndexedIndirectCommand.
+ * \param [in] offset Draw buffer offset
+ * \param [in] countOffset Draw count offset
+ * \param [in] maxCount Maximum number of draws
+ * \param [in] stride Stride between dispatch calls
+ */
+ void drawIndexedIndirectCount(
+ VkDeviceSize offset,
+ VkDeviceSize countOffset,
+ uint32_t maxCount,
+ uint32_t stride);
+
+ /**
+ * \brief Transform feddback draw call
+
+ * \param [in] counterBuffer Xfb counter buffer
+ * \param [in] counterDivisor Vertex stride
+ * \param [in] counterBias Counter bias
+ */
+ void drawIndirectXfb(
+ const DxvkBufferSlice& counterBuffer,
+ uint32_t counterDivisor,
+ uint32_t counterBias);
+
+ /**
+ * \brief Emits barrier for render target readback
+ *
+ * Use between draw calls if the fragment shader
+ * reads one of the currently bound render targets.
+ */
+ void emitRenderTargetReadbackBarrier();
+
+ /**
+ * \brief Generates mip maps
+ *
+ * Uses blitting to generate lower mip levels from
+ * the top-most mip level passed to this method.
+ * \param [in] imageView The image to generate mips for
+ * \param [in] filter The filter to use for generation
+ */
+ void generateMipmaps(
+ const Rc<DxvkImageView>& imageView,
+ VkFilter filter);
+
+ /**
+ * \brief Initializes or invalidates an image
+ *
+ * Sets up the image layout for future operations
+ * while discarding any previous contents.
+ * \param [in] image The image to initialize
+ * \param [in] subresources Image subresources
+ * \param [in] initialLayout Initial image layout
+ */
+ void initImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout initialLayout);
+
+ /**
+ * \brief Invalidates a buffer's contents
+ *
+ * Discards a buffer's contents by replacing the
+ * backing resource. This allows the host to access
+ * the buffer while the GPU is still accessing the
+ * original backing resource.
+ *
+ * \warning If the buffer is used by another context,
+ * invalidating it will result in undefined behaviour.
+ * \param [in] buffer The buffer to invalidate
+ * \param [in] slice New buffer slice handle
+ */
+ void invalidateBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferSliceHandle& slice);
+
+ /**
+ * \brief Updates push constants
+ *
+ * Updates the given push constant range.
+ * \param [in] offset Byte offset of data to update
+ * \param [in] size Number of bytes to update
+ * \param [in] data Pointer to raw data
+ */
+ void pushConstants(
+ uint32_t offset,
+ uint32_t size,
+ const void* data);
+
+ /**
+ * \brief Resolves a multisampled image resource
+ *
+ * Resolves a multisampled image into a non-multisampled
+ * image. The subresources of both images must have the
+ * same size and compatible formats.
+ * A format can be specified for the resolve operation.
+ * If it is \c VK_FORMAT_UNDEFINED, the resolve operation
+ * will use the source image format.
+ * \param [in] dstImage Destination image
+ * \param [in] srcImage Source image
+ * \param [in] region Region to resolve
+ * \param [in] format Format for the resolve operation
+ */
+ void resolveImage(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkFormat format);
+
+ /**
+ * \brief Resolves a multisampled depth-stencil resource
+ *
+ * \param [in] dstImage Destination image
+ * \param [in] srcImage Source image
+ * \param [in] region Region to resolve
+ * \param [in] depthMode Resolve mode for depth aspect
+ * \param [in] stencilMode Resolve mode for stencil aspect
+ */
+ void resolveDepthStencilImage(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode);
+
+ /**
+ * \brief Transforms image subresource layouts
+ *
+ * \param [in] dstImage Image to transform
+ * \param [in] dstSubresources Subresources
+ * \param [in] srcLayout Current layout
+ * \param [in] dstLayout Desired layout
+ */
+ void transformImage(
+ const Rc<DxvkImage>& dstImage,
+ const VkImageSubresourceRange& dstSubresources,
+ VkImageLayout srcLayout,
+ VkImageLayout dstLayout);
+
+ /**
+ * \brief Updates a buffer
+ *
+ * Copies data from the host into a buffer.
+ * \param [in] buffer Destination buffer
+ * \param [in] offset Offset of sub range to update
+ * \param [in] size Length of sub range to update
+ * \param [in] data Data to upload
+ */
+ void updateBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ VkDeviceSize offset,
+ VkDeviceSize size,
+ const void* data);
+
+ /**
+ * \brief Updates an image
+ *
+ * Copies data from the host into an image.
+ * \param [in] image Destination image
+ * \param [in] subsresources Image subresources to update
+ * \param [in] imageOffset Offset of the image area to update
+ * \param [in] imageExtent Size of the image area to update
+ * \param [in] data Source data
+ * \param [in] pitchPerRow Row pitch of the source data
+ * \param [in] pitchPerLayer Layer pitch of the source data
+ */
+ void updateImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer);
+
+ /**
+ * \brief Updates an depth-stencil image
+ *
+ * \param [in] image Destination image
+ * \param [in] subsresources Image subresources to update
+ * \param [in] imageOffset Offset of the image area to update
+ * \param [in] imageExtent Size of the image area to update
+ * \param [in] data Source data
+ * \param [in] pitchPerRow Row pitch of the source data
+ * \param [in] pitchPerLayer Layer pitch of the source data
+ * \param [in] format Packed depth-stencil format
+ */
+ void updateDepthStencilImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ VkOffset2D imageOffset,
+ VkExtent2D imageExtent,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer,
+ VkFormat format);
+
+ /**
+ * \brief Uses transfer queue to initialize buffer
+ *
+ * Only safe to use if the buffer is not in use by the GPU.
+ * \param [in] buffer The buffer to initialize
+ * \param [in] data The data to copy to the buffer
+ */
+ void uploadBuffer(
+ const Rc<DxvkBuffer>& buffer,
+ const void* data);
+
+ /**
+ * \brief Uses transfer queue to initialize image
+ *
+ * Only safe to use if the image is not in use by the GPU.
+ * \param [in] image The image to initialize
+ * \param [in] subresources Subresources to initialize
+ * \param [in] data Source data
+ * \param [in] pitchPerRow Row pitch of the source data
+ * \param [in] pitchPerLayer Layer pitch of the source data
+ */
+ void uploadImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& subresources,
+ const void* data,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer);
+
+ /**
+ * \brief Sets viewports
+ *
+ * \param [in] viewportCount Number of viewports
+ * \param [in] viewports The viewports
+ * \param [in] scissorRects Schissor rectangles
+ */
+ void setViewports(
+ uint32_t viewportCount,
+ const VkViewport* viewports,
+ const VkRect2D* scissorRects);
+
+ /**
+ * \brief Sets blend constants
+ *
+ * Blend constants are a set of four floating
+ * point numbers that may be used as an input
+ * for blending operations.
+ * \param [in] blendConstants Blend constants
+ */
+ void setBlendConstants(
+ DxvkBlendConstants blendConstants);
+
+ /**
+ * \brief Sets depth bias
+ *
+ * Depth bias has to be enabled explicitly in
+ * the rasterizer state to have any effect.
+ * \param [in] depthBias Depth bias values
+ */
+ void setDepthBias(
+ DxvkDepthBias depthBias);
+
+ /**
+ * \brief Sets depth bounds
+ *
+ * Enables or disables the depth bounds test,
+ * and updates the values if necessary.
+ * \param [in] depthBounds Depth bounds
+ */
+ void setDepthBounds(
+ DxvkDepthBounds depthBounds);
+
+ /**
+ * \brief Sets stencil reference
+ *
+ * Sets the reference value for stencil compare operations.
+ * \param [in] reference Reference value
+ */
+ void setStencilReference(
+ uint32_t reference);
+
+ /**
+ * \brief Sets input assembly state
+ * \param [in] ia New state object
+ */
+ void setInputAssemblyState(
+ const DxvkInputAssemblyState& ia);
+
+ /**
+ * \brief Sets input layout
+ *
+ * \param [in] attributeCount Number of vertex attributes
+ * \param [in] attributes The vertex attributes
+ * \param [in] bindingCount Number of buffer bindings
+ * \param [in] bindings Vertex buffer bindigs
+ */
+ void setInputLayout(
+ uint32_t attributeCount,
+ const DxvkVertexAttribute* attributes,
+ uint32_t bindingCount,
+ const DxvkVertexBinding* bindings);
+
+ /**
+ * \brief Sets rasterizer state
+ * \param [in] rs New state object
+ */
+ void setRasterizerState(
+ const DxvkRasterizerState& rs);
+
+ /**
+ * \brief Sets multisample state
+ * \param [in] ms New state object
+ */
+ void setMultisampleState(
+ const DxvkMultisampleState& ms);
+
+ /**
+ * \brief Sets depth stencil state
+ * \param [in] ds New state object
+ */
+ void setDepthStencilState(
+ const DxvkDepthStencilState& ds);
+
+ /**
+ * \brief Sets logic op state
+ * \param [in] lo New state object
+ */
+ void setLogicOpState(
+ const DxvkLogicOpState& lo);
+
+ /**
+ * \brief Sets blend mode for an attachment
+ *
+ * \param [in] attachment The attachment index
+ * \param [in] blendMode The blend mode
+ */
+ void setBlendMode(
+ uint32_t attachment,
+ const DxvkBlendMode& blendMode);
+
+ /**
+ * \brief Sets specialization constants
+ *
+ * Replaces current specialization constants with
+ * the given list of constant entries. The specId
+ * in the shader can be computed with \c getSpecId.
+ * \param [in] pipeline Graphics or Compute pipeline
+ * \param [in] index Constant index
+ * \param [in] value Constant value
+ */
+ void setSpecConstant(
+ VkPipelineBindPoint pipeline,
+ uint32_t index,
+ uint32_t value);
+
+ /**
+ * \brief Sets barrier control flags
+ *
+ * Barrier control flags can be used to control
+ * implicit synchronization of compute shaders.
+ * \param [in] control New barrier control flags
+ */
+ void setBarrierControl(
+ DxvkBarrierControlFlags control);
+
+ /**
+ * \brief Launches a Cuda kernel
+ *
+ * Since the kernel is launched with an opaque set of
+ * kernel-specific parameters which may reference
+ * resources bindlessly, such resources must be listed by
+ * the caller in the 'buffers' and 'images' parameters so
+ * that their access may be tracked appropriately.
+ * \param [in] nvxLaunchInfo Kernel launch parameter struct
+ * \param [in] buffers List of {buffer,read,write} used by kernel
+ * \param [in] images List of {image,read,write} used by kernel
+ */
+ void launchCuKernelNVX(
+ const VkCuLaunchInfoNVX& nvxLaunchInfo,
+ const std::vector<std::pair<Rc<DxvkBuffer>, DxvkAccessFlags>>& buffers,
+ const std::vector<std::pair<Rc<DxvkImage>, DxvkAccessFlags>>& images);
+
+ /**
+ * \brief Signals a GPU event
+ * \param [in] event The event
+ */
+ void signalGpuEvent(
+ const Rc<DxvkGpuEvent>& event);
+
+ /**
+ * \brief Writes to a timestamp query
+ * \param [in] query The timestamp query
+ */
+ void writeTimestamp(
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Queues a signal
+ *
+ * The signal will be notified after all
+ * previously submitted commands have
+ * finished execution on the GPU.
+ * \param [in] signal The signal
+ * \param [in] value Signal value
+ */
+ void signal(
+ const Rc<sync::Signal>& signal,
+ uint64_t value);
+
+ /**
+ * \brief Trims staging buffers
+ *
+ * Releases staging buffer resources. Calling
+ * this may be useful if data updates on a
+ * given context are rare.
+ */
+ void trimStagingBuffers();
+
+ /**
+ * \brief Begins a debug label region
+ * \param [in] label The debug label
+ *
+ * Marks the start of a debug label region. Used by debugging/profiling
+ * tools to mark different workloads within a frame.
+ */
+ void beginDebugLabel(VkDebugUtilsLabelEXT *label);
+
+ /**
+ * \brief Ends a debug label region
+ *
+ * Marks the close of a debug label region. Used by debugging/profiling
+ * tools to mark different workloads within a frame.
+ */
+ void endDebugLabel();
+
+ /**
+ * \brief Inserts a debug label
+ * \param [in] label The debug label
+ *
+ * Inserts an instantaneous debug label. Used by debugging/profiling
+ * tools to mark different workloads within a frame.
+ */
+ void insertDebugLabel(VkDebugUtilsLabelEXT *label);
+ private:
+
+ Rc<DxvkDevice> m_device;
+ DxvkObjects* m_common;
+
+ Rc<DxvkCommandList> m_cmd;
+ Rc<DxvkDescriptorPool> m_descPool;
+ Rc<DxvkBuffer> m_zeroBuffer;
+
+ DxvkContextFlags m_flags;
+ DxvkContextState m_state;
+ DxvkContextFeatures m_features;
+
+ DxvkBarrierSet m_sdmaAcquires;
+ DxvkBarrierSet m_sdmaBarriers;
+ DxvkBarrierSet m_initBarriers;
+ DxvkBarrierSet m_execAcquires;
+ DxvkBarrierSet m_execBarriers;
+ DxvkBarrierSet m_gfxBarriers;
+ DxvkBarrierControlFlags m_barrierControl;
+
+ DxvkGpuQueryManager m_queryManager;
+ DxvkStagingDataAlloc m_staging;
+
+ DxvkRenderTargetLayouts m_rtLayouts = { };
+
+ VkPipeline m_gpActivePipeline = VK_NULL_HANDLE;
+ VkPipeline m_cpActivePipeline = VK_NULL_HANDLE;
+
+ VkDescriptorSet m_gpSet = VK_NULL_HANDLE;
+ VkDescriptorSet m_cpSet = VK_NULL_HANDLE;
+
+ DxvkBindingSet<MaxNumVertexBindings + 1> m_vbTracked;
+ DxvkBindingSet<MaxNumResourceSlots> m_rcTracked;
+
+ std::vector<DxvkDeferredClear> m_deferredClears;
+
+ std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
+ std::array<DxvkGraphicsPipeline*, 4096> m_gpLookupCache = { };
+ std::array<DxvkComputePipeline*, 256> m_cpLookupCache = { };
+
+ void blitImageFb(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ const VkComponentMapping& mapping,
+ VkFilter filter);
+
+ void blitImageHw(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ VkFilter filter);
+
+ template<bool ToImage>
+ void copyImageBufferData(
+ DxvkCmdBuffer cmd,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& imageSubresource,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ VkImageLayout imageLayout,
+ const DxvkBufferSliceHandle& bufferSlice,
+ VkDeviceSize bufferRowAlignment,
+ VkDeviceSize bufferSliceAlignment);
+
+ void copyImageHostData(
+ DxvkCmdBuffer cmd,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceLayers& imageSubresource,
+ VkOffset3D imageOffset,
+ VkExtent3D imageExtent,
+ const void* hostData,
+ VkDeviceSize rowPitch,
+ VkDeviceSize slicePitch);
+
+ void clearImageViewFb(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkImageAspectFlags aspect,
+ VkClearValue value);
+
+ void clearImageViewCs(
+ const Rc<DxvkImageView>& imageView,
+ VkOffset3D offset,
+ VkExtent3D extent,
+ VkClearValue value);
+
+ void copyImageHw(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent);
+
+ void copyImageFb(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource,
+ VkOffset3D srcOffset,
+ VkExtent3D extent);
+
+ bool copyImageClear(
+ const Rc<DxvkImage>& dstImage,
+ VkImageSubresourceLayers dstSubresource,
+ VkOffset3D dstOffset,
+ VkExtent3D dstExtent,
+ const Rc<DxvkImage>& srcImage,
+ VkImageSubresourceLayers srcSubresource);
+
+ void resolveImageHw(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region);
+
+ void resolveImageDs(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode);
+
+ void resolveImageFb(
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageResolve& region,
+ VkFormat format,
+ VkResolveModeFlagBitsKHR depthMode,
+ VkResolveModeFlagBitsKHR stencilMode);
+
+ void performClear(
+ const Rc<DxvkImageView>& imageView,
+ int32_t attachmentIndex,
+ VkImageAspectFlags discardAspects,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue);
+
+ void deferClear(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags clearAspects,
+ VkClearValue clearValue);
+
+ void deferDiscard(
+ const Rc<DxvkImageView>& imageView,
+ VkImageAspectFlags discardAspects);
+
+ void flushClears(
+ bool useRenderPass);
+
+ void flushSharedImages();
+
+ void startRenderPass();
+ void spillRenderPass(bool suspend);
+
+ void renderPassBindFramebuffer(
+ const Rc<DxvkFramebuffer>& framebuffer,
+ const DxvkRenderPassOps& ops,
+ uint32_t clearValueCount,
+ const VkClearValue* clearValues);
+
+ void renderPassUnbindFramebuffer();
+
+ void resetRenderPassOps(
+ const DxvkRenderTargets& renderTargets,
+ DxvkRenderPassOps& renderPassOps);
+
+ void startTransformFeedback();
+ void pauseTransformFeedback();
+
+ void unbindComputePipeline();
+ bool updateComputePipeline();
+ bool updateComputePipelineState();
+
+ void unbindGraphicsPipeline();
+ bool updateGraphicsPipeline();
+ bool updateGraphicsPipelineState();
+
+ void updateComputeShaderResources();
+ void updateGraphicsShaderResources();
+
+ template<VkPipelineBindPoint BindPoint>
+ void updateShaderResources(
+ const DxvkPipelineLayout* layout);
+
+ template<VkPipelineBindPoint BindPoint>
+ void updateShaderDescriptorSetBinding(
+ VkDescriptorSet set,
+ const DxvkPipelineLayout* layout);
+
+ void updateFramebuffer();
+
+ void applyRenderTargetLoadLayouts();
+
+ void applyRenderTargetStoreLayouts();
+
+ void transitionRenderTargetLayouts(
+ DxvkBarrierSet& barriers,
+ bool sharedOnly);
+
+ void transitionColorAttachment(
+ DxvkBarrierSet& barriers,
+ const DxvkAttachment& attachment,
+ VkImageLayout oldLayout);
+
+ void transitionDepthAttachment(
+ DxvkBarrierSet& barriers,
+ const DxvkAttachment& attachment,
+ VkImageLayout oldLayout);
+
+ void updateRenderTargetLayouts(
+ const Rc<DxvkFramebuffer>& newFb,
+ const Rc<DxvkFramebuffer>& oldFb);
+
+ void prepareImage(
+ DxvkBarrierSet& barriers,
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ bool flushClears = true);
+
+ bool updateIndexBufferBinding();
+ void updateVertexBufferBindings();
+
+ void updateTransformFeedbackBuffers();
+ void updateTransformFeedbackState();
+
+ void updateDynamicState();
+
+ template<VkPipelineBindPoint BindPoint>
+ void updatePushConstants();
+
+ bool commitComputeState();
+
+ template<bool Indexed, bool Indirect>
+ bool commitGraphicsState();
+
+ void commitComputeInitBarriers();
+ void commitComputePostBarriers();
+
+ template<bool Indexed, bool Indirect, bool DoEmit>
+ void commitGraphicsBarriers();
+
+ template<bool DoEmit>
+ DxvkAccessFlags checkGfxBufferBarrier(
+ const DxvkBufferSlice& slice,
+ VkPipelineStageFlags stages,
+ VkAccessFlags access);
+
+ template<bool DoEmit>
+ DxvkAccessFlags checkGfxImageBarrier(
+ const Rc<DxvkImageView>& imageView,
+ VkPipelineStageFlags stages,
+ VkAccessFlags access);
+
+ void emitMemoryBarrier(
+ VkDependencyFlags flags,
+ VkPipelineStageFlags srcStages,
+ VkAccessFlags srcAccess,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ void initializeImage(
+ const Rc<DxvkImage>& image,
+ const VkImageSubresourceRange& subresources,
+ VkImageLayout dstLayout,
+ VkPipelineStageFlags dstStages,
+ VkAccessFlags dstAccess);
+
+ VkDescriptorSet allocateDescriptorSet(
+ VkDescriptorSetLayout layout);
+
+ void trackDrawBuffer();
+
+ DxvkGraphicsPipeline* lookupGraphicsPipeline(
+ const DxvkGraphicsPipelineShaders& shaders);
+
+ DxvkComputePipeline* lookupComputePipeline(
+ const DxvkComputePipelineShaders& shaders);
+
+ Rc<DxvkBuffer> createZeroBuffer(
+ VkDeviceSize size);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context_state.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context_state.h
new file mode 100644
index 00000000..beafdaa0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_context_state.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#include "dxvk_buffer.h"
+#include "dxvk_compute.h"
+#include "dxvk_constant_state.h"
+#include "dxvk_framebuffer.h"
+#include "dxvk_graphics.h"
+#include "dxvk_image.h"
+#include "dxvk_limits.h"
+#include "dxvk_pipelayout.h"
+#include "dxvk_sampler.h"
+#include "dxvk_shader.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Graphics pipeline state flags
+ *
+ * Stores some information on which state
+ * of the graphics and compute pipelines
+ * has changed and/or needs to be updated.
+ */
+ enum class DxvkContextFlag : uint32_t {
+ GpRenderPassBound, ///< Render pass is currently bound
+ GpRenderPassSuspended, ///< Render pass is currently suspended
+ GpXfbActive, ///< Transform feedback is enabled
+ GpDirtyFramebuffer, ///< Framebuffer binding is out of date
+ GpDirtyPipeline, ///< Graphics pipeline binding is out of date
+ GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled
+ GpDirtyResources, ///< Graphics pipeline resource bindings are out of date
+ GpDirtyDescriptorBinding, ///< Graphics descriptor set needs to be rebound
+ GpDirtyVertexBuffers, ///< Vertex buffer bindings are out of date
+ GpDirtyIndexBuffer, ///< Index buffer binding are out of date
+ GpDirtyXfbBuffers, ///< Transform feedback buffer bindings are out of date
+ GpDirtyBlendConstants, ///< Blend constants have changed
+ GpDirtyDepthBias, ///< Depth bias has changed
+ GpDirtyDepthBounds, ///< Depth bounds have changed
+ GpDirtyStencilRef, ///< Stencil reference has changed
+ GpDirtyViewport, ///< Viewport state has changed
+ GpDynamicBlendConstants, ///< Blend constants are dynamic
+ GpDynamicDepthBias, ///< Depth bias is dynamic
+ GpDynamicDepthBounds, ///< Depth bounds are dynamic
+ GpDynamicStencilRef, ///< Stencil reference is dynamic
+
+ CpDirtyPipeline, ///< Compute pipeline binding are out of date
+ CpDirtyPipelineState, ///< Compute pipeline needs to be recompiled
+ CpDirtyResources, ///< Compute pipeline resource bindings are out of date
+ CpDirtyDescriptorBinding, ///< Compute descriptor set needs to be rebound
+
+ DirtyDrawBuffer, ///< Indirect argument buffer is dirty
+ DirtyPushConstants, ///< Push constant data has changed
+ };
+
+ using DxvkContextFlags = Flags<DxvkContextFlag>;
+
+
+ /**
+ * \brief Context feature bits
+ */
+ enum class DxvkContextFeature {
+ NullDescriptors,
+ ExtendedDynamicState,
+ };
+
+ using DxvkContextFeatures = Flags<DxvkContextFeature>;
+
+
+ /**
+ * \brief Barrier control flags
+ *
+ * These flags specify what (not) to
+ * synchronize implicitly.
+ */
+ enum class DxvkBarrierControl : uint32_t {
+ IgnoreWriteAfterWrite = 1,
+ IgnoreGraphicsBarriers = 2,
+ };
+
+ using DxvkBarrierControlFlags = Flags<DxvkBarrierControl>;
+
+
+ struct DxvkIndirectDrawState {
+ DxvkBufferSlice argBuffer;
+ DxvkBufferSlice cntBuffer;
+ };
+
+
+ struct DxvkVertexInputState {
+ DxvkBufferSlice indexBuffer;
+ VkIndexType indexType = VK_INDEX_TYPE_UINT32;
+
+ std::array<DxvkBufferSlice, DxvkLimits::MaxNumVertexBindings> vertexBuffers = { };
+ std::array<uint32_t, DxvkLimits::MaxNumVertexBindings> vertexStrides = { };
+ };
+
+
+ struct DxvkViewportState {
+ std::array<VkViewport, DxvkLimits::MaxNumViewports> viewports = { };
+ std::array<VkRect2D, DxvkLimits::MaxNumViewports> scissorRects = { };
+ };
+
+
+ struct DxvkOutputMergerState {
+ std::array<VkClearValue, MaxNumRenderTargets + 1> clearValues = { };
+
+ DxvkRenderTargets renderTargets;
+ DxvkRenderPassOps renderPassOps;
+ Rc<DxvkFramebuffer> framebuffer = nullptr;
+ };
+
+
+ struct DxvkPushConstantState {
+ char data[MaxPushConstantSize];
+ };
+
+
+ struct DxvkXfbState {
+ std::array<DxvkBufferSlice, MaxNumXfbBuffers> buffers;
+ std::array<DxvkBufferSlice, MaxNumXfbBuffers> counters;
+ };
+
+
+ struct DxvkGraphicsPipelineState {
+ DxvkGraphicsPipelineShaders shaders;
+ DxvkGraphicsPipelineStateInfo state;
+ DxvkGraphicsPipelineFlags flags;
+ DxvkGraphicsPipeline* pipeline = nullptr;
+ };
+
+
+ struct DxvkComputePipelineState {
+ DxvkComputePipelineShaders shaders;
+ DxvkComputePipelineStateInfo state;
+ DxvkComputePipeline* pipeline = nullptr;
+ };
+
+
+ struct DxvkDynamicState {
+ DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };
+ DxvkDepthBias depthBias = { 0.0f, 0.0f, 0.0f };
+ DxvkDepthBounds depthBounds = { false, 0.0f, 1.0f };
+ uint32_t stencilReference = 0;
+ };
+
+
+ struct DxvkDeferredClear {
+ Rc<DxvkImageView> imageView;
+ VkImageAspectFlags discardAspects;
+ VkImageAspectFlags clearAspects;
+ VkClearValue clearValue;
+ };
+
+
+ /**
+ * \brief Pipeline state
+ *
+ * Stores all bound shaders, resources,
+ * and constant pipeline state objects.
+ */
+ struct DxvkContextState {
+ DxvkIndirectDrawState id;
+ DxvkVertexInputState vi;
+ DxvkViewportState vp;
+ DxvkOutputMergerState om;
+ DxvkPushConstantState pc;
+ DxvkXfbState xfb;
+ DxvkDynamicState dyn;
+
+ DxvkGraphicsPipelineState gp;
+ DxvkComputePipelineState cp;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.cpp
new file mode 100644
index 00000000..290c3eba
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.cpp
@@ -0,0 +1,170 @@
+#include "dxvk_cs.h"
+
+namespace dxvk {
+
+ DxvkCsChunk::DxvkCsChunk() {
+
+ }
+
+
+ DxvkCsChunk::~DxvkCsChunk() {
+ this->reset();
+ }
+
+
+ void DxvkCsChunk::init(DxvkCsChunkFlags flags) {
+ m_flags = flags;
+ }
+
+
+ void DxvkCsChunk::executeAll(DxvkContext* ctx) {
+ auto cmd = m_head;
+
+ if (m_flags.test(DxvkCsChunkFlag::SingleUse)) {
+ m_commandOffset = 0;
+
+ while (cmd != nullptr) {
+ auto next = cmd->next();
+ cmd->exec(ctx);
+ cmd->~DxvkCsCmd();
+ cmd = next;
+ }
+
+ m_head = nullptr;
+ m_tail = nullptr;
+ } else {
+ while (cmd != nullptr) {
+ cmd->exec(ctx);
+ cmd = cmd->next();
+ }
+ }
+ }
+
+
+ void DxvkCsChunk::reset() {
+ auto cmd = m_head;
+
+ while (cmd != nullptr) {
+ auto next = cmd->next();
+ cmd->~DxvkCsCmd();
+ cmd = next;
+ }
+
+ m_head = nullptr;
+ m_tail = nullptr;
+
+ m_commandOffset = 0;
+ }
+
+
+ DxvkCsChunkPool::DxvkCsChunkPool() {
+
+ }
+
+
+ DxvkCsChunkPool::~DxvkCsChunkPool() {
+ for (DxvkCsChunk* chunk : m_chunks)
+ delete chunk;
+ }
+
+
+ DxvkCsChunk* DxvkCsChunkPool::allocChunk(DxvkCsChunkFlags flags) {
+ DxvkCsChunk* chunk = nullptr;
+
+ { std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ if (m_chunks.size() != 0) {
+ chunk = m_chunks.back();
+ m_chunks.pop_back();
+ }
+ }
+
+ if (!chunk)
+ chunk = new DxvkCsChunk();
+
+ chunk->init(flags);
+ return chunk;
+ }
+
+
+ void DxvkCsChunkPool::freeChunk(DxvkCsChunk* chunk) {
+ chunk->reset();
+
+ std::lock_guard<sync::Spinlock> lock(m_mutex);
+ m_chunks.push_back(chunk);
+ }
+
+
+ DxvkCsThread::DxvkCsThread(const Rc<DxvkContext>& context)
+ : m_context(context), m_thread([this] { threadFunc(); }) {
+
+ }
+
+
+ DxvkCsThread::~DxvkCsThread() {
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_stopped.store(true);
+ }
+
+ m_condOnAdd.notify_one();
+ m_thread.join();
+ }
+
+
+ void DxvkCsThread::dispatchChunk(DxvkCsChunkRef&& chunk) {
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_chunksQueued.push(std::move(chunk));
+ m_chunksPending += 1;
+ }
+
+ m_condOnAdd.notify_one();
+ }
+
+
+ void DxvkCsThread::synchronize() {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ m_condOnSync.wait(lock, [this] {
+ return !m_chunksPending.load();
+ });
+ }
+
+
+ void DxvkCsThread::threadFunc() {
+ env::setThreadName("dxvk-cs");
+
+ DxvkCsChunkRef chunk;
+
+ try {
+ while (!m_stopped.load()) {
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+ if (chunk) {
+ if (--m_chunksPending == 0)
+ m_condOnSync.notify_one();
+
+ chunk = DxvkCsChunkRef();
+ }
+
+ if (m_chunksQueued.size() == 0) {
+ m_condOnAdd.wait(lock, [this] {
+ return (m_chunksQueued.size() != 0)
+ || (m_stopped.load());
+ });
+ }
+
+ if (m_chunksQueued.size() != 0) {
+ chunk = std::move(m_chunksQueued.front());
+ m_chunksQueued.pop();
+ }
+ }
+
+ if (chunk)
+ chunk->executeAll(m_context.ptr());
+ }
+ } catch (const DxvkError& e) {
+ Logger::err("Exception on CS thread!");
+ Logger::err(e.message());
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.h
new file mode 100644
index 00000000..ca34fa23
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_cs.h
@@ -0,0 +1,433 @@
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+
+#include "../util/thread.h"
+#include "dxvk_context.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Command stream operation
+ *
+ * An abstract representation of an operation
+ * that can be recorded into a command list.
+ */
+ class DxvkCsCmd {
+
+ public:
+
+ virtual ~DxvkCsCmd() { }
+
+ /**
+ * \brief Retrieves next command in a command chain
+ *
+ * This can be used to quickly iterate
+ * over commands within a chunk.
+ * \returns Pointer the next command
+ */
+ DxvkCsCmd* next() const {
+ return m_next;
+ }
+
+ /**
+ * \brief Sets next command in a command chain
+ * \param [in] next Next command
+ */
+ void setNext(DxvkCsCmd* next) {
+ m_next = next;
+ }
+
+ /**
+ * \brief Executes embedded commands
+ * \param [in] ctx The target context
+ */
+ virtual void exec(DxvkContext* ctx) const = 0;
+
+ private:
+
+ DxvkCsCmd* m_next = nullptr;
+
+ };
+
+
+ /**
+ * \brief Typed command
+ *
+ * Stores a function object which is
+ * used to execute an embedded command.
+ */
+ template<typename T>
+ class alignas(16) DxvkCsTypedCmd : public DxvkCsCmd {
+
+ public:
+
+ DxvkCsTypedCmd(T&& cmd)
+ : m_command(std::move(cmd)) { }
+
+ DxvkCsTypedCmd (DxvkCsTypedCmd&&) = delete;
+ DxvkCsTypedCmd& operator = (DxvkCsTypedCmd&&) = delete;
+
+ void exec(DxvkContext* ctx) const {
+ m_command(ctx);
+ }
+
+ private:
+
+ T m_command;
+
+ };
+
+
+ /**
+ * \brief Typed command with metadata
+ *
+ * Stores a function object and an arbitrary
+ * data structure which can be modified after
+ * submitting the command to a cs chunk.
+ */
+ template<typename T, typename M>
+ class alignas(16) DxvkCsDataCmd : public DxvkCsCmd {
+
+ public:
+
+ template<typename... Args>
+ DxvkCsDataCmd(T&& cmd, Args&&... args)
+ : m_command (std::move(cmd)),
+ m_data (std::forward<Args>(args)...) { }
+
+ DxvkCsDataCmd (DxvkCsDataCmd&&) = delete;
+ DxvkCsDataCmd& operator = (DxvkCsDataCmd&&) = delete;
+
+ void exec(DxvkContext* ctx) const {
+ m_command(ctx, &m_data);
+ }
+
+ M* data() {
+ return &m_data;
+ }
+
+ private:
+
+ T m_command;
+ M m_data;
+
+ };
+
+
+ /**
+ * \brief Submission flags
+ */
+ enum class DxvkCsChunkFlag : uint32_t {
+ /// Indicates that the submitted chunk will
+ /// no longer be needed after one submission.
+ SingleUse,
+ };
+
+ using DxvkCsChunkFlags = Flags<DxvkCsChunkFlag>;
+
+
+ /**
+ * \brief Command chunk
+ *
+ * Stores a list of commands.
+ */
+ class DxvkCsChunk : public RcObject {
+ constexpr static size_t MaxBlockSize = 16384;
+ public:
+
+ DxvkCsChunk();
+ ~DxvkCsChunk();
+
+ /**
+ * \brief Checks whether the chunk is empty
+ * \returns \c true if the chunk is empty
+ */
+ bool empty() const {
+ return m_commandOffset == 0;
+ }
+
+ /**
+ * \brief Tries to add a command to the chunk
+ *
+ * If the given command can be added to the chunk, it
+ * will be consumed. Otherwise, a new chunk must be
+ * created which is large enough to hold the command.
+ * \param [in] command The command to add
+ * \returns \c true on success, \c false if
+ * a new chunk needs to be allocated
+ */
+ template<typename T>
+ bool push(T& command) {
+ using FuncType = DxvkCsTypedCmd<T>;
+
+ if (unlikely(m_commandOffset > MaxBlockSize - sizeof(FuncType)))
+ return false;
+
+ DxvkCsCmd* tail = m_tail;
+
+ m_tail = new (m_data + m_commandOffset)
+ FuncType(std::move(command));
+
+ if (likely(tail != nullptr))
+ tail->setNext(m_tail);
+ else
+ m_head = m_tail;
+
+ m_commandOffset += sizeof(FuncType);
+ return true;
+ }
+
+ /**
+ * \brief Adds a command with data to the chunk
+ *
+ * \param [in] command The command to add
+ * \param [in] args Constructor args for the data object
+ * \returns Pointer to the data object, or \c nullptr
+ */
+ template<typename M, typename T, typename... Args>
+ M* pushCmd(T& command, Args&&... args) {
+ using FuncType = DxvkCsDataCmd<T, M>;
+
+ if (unlikely(m_commandOffset > MaxBlockSize - sizeof(FuncType)))
+ return nullptr;
+
+ FuncType* func = new (m_data + m_commandOffset)
+ FuncType(std::move(command), std::forward<Args>(args)...);
+
+ if (likely(m_tail != nullptr))
+ m_tail->setNext(func);
+ else
+ m_head = func;
+ m_tail = func;
+
+ m_commandOffset += sizeof(FuncType);
+ return func->data();
+ }
+
+ /**
+ * \brief Initializes chunk for recording
+ * \param [in] flags Chunk flags
+ */
+ void init(DxvkCsChunkFlags flags);
+
+ /**
+ * \brief Executes all commands
+ *
+ * This will also reset the chunk
+ * so that it can be reused.
+ * \param [in] ctx The context
+ */
+ void executeAll(DxvkContext* ctx);
+
+ /**
+ * \brief Resets chunk
+ *
+ * Destroys all recorded commands and
+ * marks the chunk itself as empty, so
+ * that it can be reused later.
+ */
+ void reset();
+
+ private:
+
+ size_t m_commandOffset = 0;
+
+ DxvkCsCmd* m_head = nullptr;
+ DxvkCsCmd* m_tail = nullptr;
+
+ DxvkCsChunkFlags m_flags;
+
+ alignas(64)
+ char m_data[MaxBlockSize];
+
+ };
+
+
+ /**
+ * \brief Chunk pool
+ *
+ * Implements a pool of CS chunks which can be
+ * recycled. The goal is to reduce the number
+ * of dynamic memory allocations.
+ */
+ class DxvkCsChunkPool {
+
+ public:
+
+ DxvkCsChunkPool();
+ ~DxvkCsChunkPool();
+
+ DxvkCsChunkPool (const DxvkCsChunkPool&) = delete;
+ DxvkCsChunkPool& operator = (const DxvkCsChunkPool&) = delete;
+
+ /**
+ * \brief Allocates a chunk
+ *
+ * Takes an existing chunk from the pool,
+ * or creates a new one if necessary.
+ * \param [in] flags Chunk flags
+ * \returns Allocated chunk object
+ */
+ DxvkCsChunk* allocChunk(DxvkCsChunkFlags flags);
+
+ /**
+ * \brief Releases a chunk
+ *
+ * Resets the chunk and adds it to the pool.
+ * \param [in] chunk Chunk to release
+ */
+ void freeChunk(DxvkCsChunk* chunk);
+
+ private:
+
+ sync::Spinlock m_mutex;
+ std::vector<DxvkCsChunk*> m_chunks;
+
+ };
+
+
+ /**
+ * \brief Chunk reference
+ *
+ * Implements basic reference counting for
+ * CS chunks and returns them to the pool
+ * as soon as they are no longer needed.
+ */
+ class DxvkCsChunkRef {
+
+ public:
+
+ DxvkCsChunkRef() { }
+ DxvkCsChunkRef(
+ DxvkCsChunk* chunk,
+ DxvkCsChunkPool* pool)
+ : m_chunk (chunk),
+ m_pool (pool) {
+ this->incRef();
+ }
+
+ DxvkCsChunkRef(const DxvkCsChunkRef& other)
+ : m_chunk (other.m_chunk),
+ m_pool (other.m_pool) {
+ this->incRef();
+ }
+
+ DxvkCsChunkRef(DxvkCsChunkRef&& other)
+ : m_chunk (other.m_chunk),
+ m_pool (other.m_pool) {
+ other.m_chunk = nullptr;
+ other.m_pool = nullptr;
+ }
+
+ DxvkCsChunkRef& operator = (const DxvkCsChunkRef& other) {
+ other.incRef();
+ this->decRef();
+ this->m_chunk = other.m_chunk;
+ this->m_pool = other.m_pool;
+ return *this;
+ }
+
+ DxvkCsChunkRef& operator = (DxvkCsChunkRef&& other) {
+ this->decRef();
+ this->m_chunk = other.m_chunk;
+ this->m_pool = other.m_pool;
+ other.m_chunk = nullptr;
+ other.m_pool = nullptr;
+ return *this;
+ }
+
+ ~DxvkCsChunkRef() {
+ this->decRef();
+ }
+
+ DxvkCsChunk* operator -> () const {
+ return m_chunk;
+ }
+
+ operator bool () const {
+ return m_chunk != nullptr;
+ }
+
+ private:
+
+ DxvkCsChunk* m_chunk = nullptr;
+ DxvkCsChunkPool* m_pool = nullptr;
+
+ void incRef() const {
+ if (m_chunk != nullptr)
+ m_chunk->incRef();
+ }
+
+ void decRef() const {
+ if (m_chunk != nullptr && m_chunk->decRef() == 0)
+ m_pool->freeChunk(m_chunk);
+ }
+
+ };
+
+
+ /**
+ * \brief Command stream thread
+ *
+ * Spawns a thread that will execute
+ * commands on a DXVK context.
+ */
+ class DxvkCsThread {
+
+ public:
+
+ DxvkCsThread(const Rc<DxvkContext>& context);
+ ~DxvkCsThread();
+
+ /**
+ * \brief Dispatches an entire chunk
+ *
+ * Can be used to efficiently play back large
+ * command lists recorded on another thread.
+ * \param [in] chunk The chunk to dispatch
+ */
+ void dispatchChunk(DxvkCsChunkRef&& chunk);
+
+ /**
+ * \brief Synchronizes with the thread
+ *
+ * This waits for all chunks in the dispatch
+ * queue to be processed by the thread. Note
+ * that this does \e not implicitly call
+ * \ref flush.
+ */
+ void synchronize();
+
+ /**
+ * \brief Checks whether the worker thread is busy
+ *
+ * Note that this information is only reliable if
+ * only the calling thread dispatches jobs to the
+ * worker queue and if the result is \c false.
+ * \returns \c true if there is still work to do
+ */
+ bool isBusy() const {
+ return m_chunksPending.load() != 0;
+ }
+
+ private:
+
+ const Rc<DxvkContext> m_context;
+
+ std::atomic<bool> m_stopped = { false };
+ dxvk::mutex m_mutex;
+ dxvk::condition_variable m_condOnAdd;
+ dxvk::condition_variable m_condOnSync;
+ std::queue<DxvkCsChunkRef> m_chunksQueued;
+ std::atomic<uint32_t> m_chunksPending = { 0u };
+ dxvk::thread m_thread;
+
+ void threadFunc();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.cpp
new file mode 100644
index 00000000..bece0efd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.cpp
@@ -0,0 +1,26 @@
+#include <cstring>
+
+#include "dxvk_data.h"
+
+namespace dxvk {
+
+ DxvkDataBuffer:: DxvkDataBuffer() { }
+ DxvkDataBuffer::DxvkDataBuffer(size_t size)
+ : m_data(new char[size]), m_size(size) { }
+
+
+ DxvkDataBuffer::~DxvkDataBuffer() {
+ delete[] m_data;
+ }
+
+
+ DxvkDataSlice DxvkDataBuffer::alloc(size_t n) {
+ const size_t offset = m_offset;
+
+ if (offset + n <= m_size) {
+ m_offset += align(n, CACHE_LINE_SIZE);
+ return DxvkDataSlice(this, offset, n);
+ } return DxvkDataSlice();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.h
new file mode 100644
index 00000000..2a5ee924
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_data.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ class DxvkDataSlice;
+
+ /**
+ * \brief Data buffer
+ *
+ * Provides a fixed-size buffer with a linear memory
+ * allocator for arbitrary data. Can be used to copy
+ * data to or from resources. Note that allocations
+ * will be aligned to a cache line boundary.
+ */
+ class DxvkDataBuffer : public RcObject {
+ friend class DxvkDataSlice;
+ public:
+
+ DxvkDataBuffer();
+ DxvkDataBuffer(size_t size);
+ ~DxvkDataBuffer();
+
+ /**
+ * \brief Allocates a slice
+ *
+ * If the desired slice length is larger than the
+ * number of bytes left in the buffer, this will
+ * fail and the returned slice points to \c nullptr.
+ * \param [in] n Number of bytes to allocate
+ * \returns The slice, or an empty slice on failure
+ */
+ DxvkDataSlice alloc(size_t n);
+
+ private:
+
+ char* m_data = nullptr;
+ size_t m_size = 0;
+ size_t m_offset = 0;
+
+ };
+
+
+ /**
+ * \brief Data buffer slice
+ *
+ * A slice of a \ref DxvkDataBuffer which stores
+ * a strong reference to the backing buffer object.
+ */
+ class DxvkDataSlice {
+
+ public:
+
+ DxvkDataSlice() { }
+ DxvkDataSlice(
+ const Rc<DxvkDataBuffer>& buffer,
+ size_t offset,
+ size_t length)
+ : m_buffer(buffer),
+ m_offset(offset),
+ m_length(length) { }
+
+ void* ptr() const {
+ return m_buffer != nullptr
+ ? m_buffer->m_data + m_offset
+ : nullptr;
+ }
+
+ size_t offset() const { return m_offset; }
+ size_t length() const { return m_length; }
+
+ private:
+
+ Rc<DxvkDataBuffer> m_buffer;
+ size_t m_offset = 0;
+ size_t m_length = 0;
+
+ };
+
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.cpp
new file mode 100644
index 00000000..cdd2ae67
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.cpp
@@ -0,0 +1,88 @@
+#include "dxvk_descriptor.h"
+#include "dxvk_device.h"
+
+namespace dxvk {
+
+ DxvkDescriptorPool::DxvkDescriptorPool(const Rc<vk::DeviceFn>& vkd)
+ : m_vkd(vkd) {
+ constexpr uint32_t MaxSets = 2048;
+
+ std::array<VkDescriptorPoolSize, 9> pools = {{
+ { VK_DESCRIPTOR_TYPE_SAMPLER, MaxSets * 2 },
+ { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MaxSets * 3 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, MaxSets / 8 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, MaxSets * 3 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, MaxSets / 8 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, MaxSets * 3 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, MaxSets / 8 },
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, MaxSets * 3 },
+ { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MaxSets * 2 } }};
+
+ VkDescriptorPoolCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.maxSets = MaxSets;
+ info.poolSizeCount = pools.size();
+ info.pPoolSizes = pools.data();
+
+ if (m_vkd->vkCreateDescriptorPool(m_vkd->device(), &info, nullptr, &m_pool) != VK_SUCCESS)
+ throw DxvkError("DxvkDescriptorPool: Failed to create descriptor pool");
+ }
+
+
+ DxvkDescriptorPool::~DxvkDescriptorPool() {
+ m_vkd->vkDestroyDescriptorPool(
+ m_vkd->device(), m_pool, nullptr);
+ }
+
+
+ VkDescriptorSet DxvkDescriptorPool::alloc(VkDescriptorSetLayout layout) {
+ VkDescriptorSetAllocateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ info.pNext = nullptr;
+ info.descriptorPool = m_pool;
+ info.descriptorSetCount = 1;
+ info.pSetLayouts = &layout;
+
+ VkDescriptorSet set = VK_NULL_HANDLE;
+ if (m_vkd->vkAllocateDescriptorSets(m_vkd->device(), &info, &set) != VK_SUCCESS)
+ return VK_NULL_HANDLE;
+ return set;
+ }
+
+
+ void DxvkDescriptorPool::reset() {
+ m_vkd->vkResetDescriptorPool(
+ m_vkd->device(), m_pool, 0);
+ }
+
+
+
+
+ DxvkDescriptorPoolTracker::DxvkDescriptorPoolTracker(DxvkDevice* device)
+ : m_device(device) {
+
+ }
+
+
+ DxvkDescriptorPoolTracker::~DxvkDescriptorPoolTracker() {
+
+ }
+
+
+ void DxvkDescriptorPoolTracker::trackDescriptorPool(Rc<DxvkDescriptorPool> pool) {
+ m_pools.push_back(std::move(pool));
+ }
+
+
+ void DxvkDescriptorPoolTracker::reset() {
+ for (const auto& pool : m_pools) {
+ pool->reset();
+ m_device->recycleDescriptorPool(pool);
+ }
+
+ m_pools.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.h
new file mode 100644
index 00000000..243e6b0a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_descriptor.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Descriptor info
+ *
+ * Stores information that is required to
+ * update a single resource descriptor.
+ */
+ union DxvkDescriptorInfo {
+ VkDescriptorImageInfo image;
+ VkDescriptorBufferInfo buffer;
+ VkBufferView texelBuffer;
+ };
+
+
+ /**
+ * \brief Descriptor pool
+ *
+ * Wrapper around a Vulkan descriptor pool that
+ * descriptor sets can be allocated from.
+ */
+ class DxvkDescriptorPool : public RcObject {
+
+ public:
+
+ DxvkDescriptorPool(
+ const Rc<vk::DeviceFn>& vkd);
+ ~DxvkDescriptorPool();
+
+ /**
+ * \brief Allocates a descriptor set
+ *
+ * \param [in] layout Descriptor set layout
+ * \returns The descriptor set
+ */
+ VkDescriptorSet alloc(
+ VkDescriptorSetLayout layout);
+
+ /**
+ * \brief Resets descriptor set allocator
+ *
+ * Destroys all descriptor sets and
+ * resets the Vulkan descriptor pools.
+ */
+ void reset();
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ VkDescriptorPool m_pool;
+
+ };
+
+
+ /**
+ * \brief Descriptor pool tracker
+ *
+ * Tracks descriptor pools that are either full
+ * or no longer needed by the DXVK context. The
+ * command list will reset and recycle all pools
+ * once it has completed execution on the GPU.
+ */
+ class DxvkDescriptorPoolTracker {
+
+ public:
+
+ DxvkDescriptorPoolTracker(DxvkDevice* device);
+ ~DxvkDescriptorPoolTracker();
+
+ /**
+ * \brief Adds a descriptor pool to track
+ * \param [in] pool The descriptor pool
+ */
+ void trackDescriptorPool(Rc<DxvkDescriptorPool> pool);
+
+ /**
+ * \brief Resets event tracker
+ *
+ * Resets all tracked descriptor pools
+ * and returns them to the device.
+ */
+ void reset();
+
+ private:
+
+ DxvkDevice* m_device;
+
+ std::vector<Rc<DxvkDescriptorPool>> m_pools;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.cpp
new file mode 100644
index 00000000..8dad4e97
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.cpp
@@ -0,0 +1,291 @@
+#include "dxvk_device.h"
+#include "dxvk_instance.h"
+
+namespace dxvk {
+
+ DxvkDevice::DxvkDevice(
+ const Rc<DxvkInstance>& instance,
+ const Rc<DxvkAdapter>& adapter,
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDeviceExtensions& extensions,
+ const DxvkDeviceFeatures& features)
+ : m_options (instance->options()),
+ m_instance (instance),
+ m_adapter (adapter),
+ m_vkd (vkd),
+ m_extensions (extensions),
+ m_features (features),
+ m_properties (adapter->devicePropertiesExt()),
+ m_perfHints (getPerfHints()),
+ m_objects (this),
+ m_submissionQueue (this) {
+ auto queueFamilies = m_adapter->findQueueFamilies();
+ m_queues.graphics = getQueue(queueFamilies.graphics, 0);
+ m_queues.transfer = getQueue(queueFamilies.transfer, 0);
+ }
+
+
+ DxvkDevice::~DxvkDevice() {
+ // Wait for all pending Vulkan commands to be
+ // executed before we destroy any resources.
+ this->waitForIdle();
+
+ // Stop workers explicitly in order to prevent
+ // access to structures that are being destroyed.
+ m_objects.pipelineManager().stopWorkerThreads();
+ }
+
+
+ bool DxvkDevice::isUnifiedMemoryArchitecture() const {
+ return m_adapter->isUnifiedMemoryArchitecture();
+ }
+
+
+ VkPipelineStageFlags DxvkDevice::getShaderPipelineStages() const {
+ VkPipelineStageFlags result = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+
+ if (m_features.core.features.geometryShader)
+ result |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
+
+ if (m_features.core.features.tessellationShader) {
+ result |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
+ | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
+ }
+
+ return result;
+ }
+
+
+ DxvkDeviceOptions DxvkDevice::options() const {
+ DxvkDeviceOptions options;
+ options.maxNumDynamicUniformBuffers = m_properties.core.properties.limits.maxDescriptorSetUniformBuffersDynamic;
+ options.maxNumDynamicStorageBuffers = m_properties.core.properties.limits.maxDescriptorSetStorageBuffersDynamic;
+ return options;
+ }
+
+
+ Rc<DxvkCommandList> DxvkDevice::createCommandList() {
+ Rc<DxvkCommandList> cmdList = m_recycledCommandLists.retrieveObject();
+
+ if (cmdList == nullptr)
+ cmdList = new DxvkCommandList(this);
+
+ return cmdList;
+ }
+
+
+ Rc<DxvkDescriptorPool> DxvkDevice::createDescriptorPool() {
+ Rc<DxvkDescriptorPool> pool = m_recycledDescriptorPools.retrieveObject();
+
+ if (pool == nullptr)
+ pool = new DxvkDescriptorPool(m_vkd);
+
+ return pool;
+ }
+
+
+ Rc<DxvkContext> DxvkDevice::createContext() {
+ return new DxvkContext(this);
+ }
+
+
+ Rc<DxvkGpuEvent> DxvkDevice::createGpuEvent() {
+ return new DxvkGpuEvent(m_vkd);
+ }
+
+
+ Rc<DxvkGpuQuery> DxvkDevice::createGpuQuery(
+ VkQueryType type,
+ VkQueryControlFlags flags,
+ uint32_t index) {
+ return new DxvkGpuQuery(m_vkd, type, flags, index);
+ }
+
+
+ Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
+ const DxvkRenderTargets& renderTargets) {
+ const DxvkFramebufferSize defaultSize = {
+ m_properties.core.properties.limits.maxFramebufferWidth,
+ m_properties.core.properties.limits.maxFramebufferHeight,
+ m_properties.core.properties.limits.maxFramebufferLayers };
+
+ auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets);
+ auto renderPassObject = m_objects.renderPassPool().getRenderPass(renderPassFormat);
+
+ return new DxvkFramebuffer(m_vkd,
+ renderPassObject, renderTargets, defaultSize);
+ }
+
+
+ Rc<DxvkBuffer> DxvkDevice::createBuffer(
+ const DxvkBufferCreateInfo& createInfo,
+ VkMemoryPropertyFlags memoryType) {
+ return new DxvkBuffer(this, createInfo, m_objects.memoryManager(), memoryType);
+ }
+
+
+ Rc<DxvkBufferView> DxvkDevice::createBufferView(
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferViewCreateInfo& createInfo) {
+ return new DxvkBufferView(m_vkd, buffer, createInfo);
+ }
+
+
+ Rc<DxvkImage> DxvkDevice::createImage(
+ const DxvkImageCreateInfo& createInfo,
+ VkMemoryPropertyFlags memoryType) {
+ return new DxvkImage(m_vkd, createInfo, m_objects.memoryManager(), memoryType);
+ }
+
+
+ Rc<DxvkImage> DxvkDevice::createImageFromVkImage(
+ const DxvkImageCreateInfo& createInfo,
+ VkImage image) {
+ return new DxvkImage(m_vkd, createInfo, image);
+ }
+
+ Rc<DxvkImageView> DxvkDevice::createImageView(
+ const Rc<DxvkImage>& image,
+ const DxvkImageViewCreateInfo& createInfo) {
+ return new DxvkImageView(m_vkd, image, createInfo);
+ }
+
+
+ Rc<DxvkSampler> DxvkDevice::createSampler(
+ const DxvkSamplerCreateInfo& createInfo) {
+ return new DxvkSampler(this, createInfo);
+ }
+
+
+ Rc<DxvkShader> DxvkDevice::createShader(
+ VkShaderStageFlagBits stage,
+ uint32_t slotCount,
+ const DxvkResourceSlot* slotInfos,
+ const DxvkInterfaceSlots& iface,
+ const SpirvCodeBuffer& code) {
+ return new DxvkShader(stage,
+ slotCount, slotInfos, iface, code,
+ DxvkShaderOptions(),
+ DxvkShaderConstData());
+ }
+
+
+ DxvkStatCounters DxvkDevice::getStatCounters() {
+ DxvkPipelineCount pipe = m_objects.pipelineManager().getPipelineCount();
+
+ DxvkStatCounters result;
+ result.setCtr(DxvkStatCounter::PipeCountGraphics, pipe.numGraphicsPipelines);
+ result.setCtr(DxvkStatCounter::PipeCountCompute, pipe.numComputePipelines);
+ result.setCtr(DxvkStatCounter::PipeCompilerBusy, m_objects.pipelineManager().isCompilingShaders());
+ result.setCtr(DxvkStatCounter::GpuIdleTicks, m_submissionQueue.gpuIdleTicks());
+
+ std::lock_guard<sync::Spinlock> lock(m_statLock);
+ result.merge(m_statCounters);
+ return result;
+ }
+
+
+ DxvkMemoryStats DxvkDevice::getMemoryStats(uint32_t heap) {
+ return m_objects.memoryManager().getMemoryStats(heap);
+ }
+
+
+ uint32_t DxvkDevice::getCurrentFrameId() const {
+ return m_statCounters.getCtr(DxvkStatCounter::QueuePresentCount);
+ }
+
+
+ void DxvkDevice::initResources() {
+ m_objects.dummyResources().clearResources(this);
+ }
+
+
+ void DxvkDevice::registerShader(const Rc<DxvkShader>& shader) {
+ m_objects.pipelineManager().registerShader(shader);
+ }
+
+
+ void DxvkDevice::presentImage(
+ const Rc<vk::Presenter>& presenter,
+ DxvkSubmitStatus* status) {
+ status->result = VK_NOT_READY;
+
+ DxvkPresentInfo presentInfo;
+ presentInfo.presenter = presenter;
+ m_submissionQueue.present(presentInfo, status);
+
+ std::lock_guard<sync::Spinlock> statLock(m_statLock);
+ m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1);
+ }
+
+
+ void DxvkDevice::submitCommandList(
+ const Rc<DxvkCommandList>& commandList,
+ VkSemaphore waitSync,
+ VkSemaphore wakeSync) {
+ DxvkSubmitInfo submitInfo;
+ submitInfo.cmdList = commandList;
+ submitInfo.waitSync = waitSync;
+ submitInfo.wakeSync = wakeSync;
+ m_submissionQueue.submit(submitInfo);
+
+ std::lock_guard<sync::Spinlock> statLock(m_statLock);
+ m_statCounters.merge(commandList->statCounters());
+ m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, 1);
+ }
+
+
+ VkResult DxvkDevice::waitForSubmission(DxvkSubmitStatus* status) {
+ VkResult result = status->result.load();
+
+ if (result == VK_NOT_READY) {
+ m_submissionQueue.synchronizeSubmission(status);
+ result = status->result.load();
+ }
+
+ return result;
+ }
+
+
+ void DxvkDevice::waitForIdle() {
+ this->lockSubmission();
+ if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS)
+ Logger::err("DxvkDevice: waitForIdle: Operation failed");
+ this->unlockSubmission();
+ }
+
+
+ DxvkDevicePerfHints DxvkDevice::getPerfHints() {
+ DxvkDevicePerfHints hints;
+ hints.preferFbDepthStencilCopy = m_extensions.extShaderStencilExport
+ && (m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_MESA_RADV_KHR, 0, 0)
+ || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
+ || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
+ hints.preferFbResolve = m_extensions.amdShaderFragmentMask
+ && (m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
+ || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
+ return hints;
+ }
+
+
+ void DxvkDevice::recycleCommandList(const Rc<DxvkCommandList>& cmdList) {
+ m_recycledCommandLists.returnObject(cmdList);
+ }
+
+
+ void DxvkDevice::recycleDescriptorPool(const Rc<DxvkDescriptorPool>& pool) {
+ m_recycledDescriptorPools.returnObject(pool);
+ }
+
+
+ DxvkDeviceQueue DxvkDevice::getQueue(
+ uint32_t family,
+ uint32_t index) const {
+ VkQueue queue = VK_NULL_HANDLE;
+ m_vkd->vkGetDeviceQueue(m_vkd->device(), family, index, &queue);
+ return DxvkDeviceQueue { queue, family, index };
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.h
new file mode 100644
index 00000000..246cef1c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device.h
@@ -0,0 +1,512 @@
+#pragma once
+
+#include "dxvk_adapter.h"
+#include "dxvk_buffer.h"
+#include "dxvk_compute.h"
+#include "dxvk_constant_state.h"
+#include "dxvk_context.h"
+#include "dxvk_extensions.h"
+#include "dxvk_framebuffer.h"
+#include "dxvk_image.h"
+#include "dxvk_instance.h"
+#include "dxvk_memory.h"
+#include "dxvk_meta_clear.h"
+#include "dxvk_objects.h"
+#include "dxvk_options.h"
+#include "dxvk_pipecache.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_queue.h"
+#include "dxvk_recycler.h"
+#include "dxvk_renderpass.h"
+#include "dxvk_sampler.h"
+#include "dxvk_shader.h"
+#include "dxvk_stats.h"
+#include "dxvk_unbound.h"
+
+#include "../vulkan/vulkan_presenter.h"
+
+namespace dxvk {
+
+ class DxvkInstance;
+
+ /**
+ * \brief Device options
+ */
+ struct DxvkDeviceOptions {
+ uint32_t maxNumDynamicUniformBuffers = 0;
+ uint32_t maxNumDynamicStorageBuffers = 0;
+ };
+
+ /**
+ * \brief Device performance hints
+ */
+ struct DxvkDevicePerfHints {
+ VkBool32 preferFbDepthStencilCopy : 1;
+ VkBool32 preferFbResolve : 1;
+ };
+
+ /**
+ * \brief Device queue
+ *
+ * Stores a Vulkan queue and the
+ * queue family that it belongs to.
+ */
+ struct DxvkDeviceQueue {
+ VkQueue queueHandle = VK_NULL_HANDLE;
+ uint32_t queueFamily = 0;
+ uint32_t queueIndex = 0;
+ };
+
+ /**
+ * \brief Device queue infos
+ */
+ struct DxvkDeviceQueueSet {
+ DxvkDeviceQueue graphics;
+ DxvkDeviceQueue transfer;
+ };
+
+ /**
+ * \brief DXVK device
+ *
+ * Device object. This is responsible for resource creation,
+ * memory allocation, command submission and state tracking.
+ * Rendering commands are recorded into command lists using
+ * contexts. Multiple contexts can be created for a device.
+ */
+ class DxvkDevice : public RcObject {
+ friend class DxvkContext;
+ friend class DxvkSubmissionQueue;
+ friend class DxvkDescriptorPoolTracker;
+ public:
+
+ DxvkDevice(
+ const Rc<DxvkInstance>& instance,
+ const Rc<DxvkAdapter>& adapter,
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDeviceExtensions& extensions,
+ const DxvkDeviceFeatures& features);
+
+ ~DxvkDevice();
+
+ /**
+ * \brief Vulkan device functions
+ * \returns Vulkan device functions
+ */
+ Rc<vk::DeviceFn> vkd() const {
+ return m_vkd;
+ }
+
+ /**
+ * \brief Logical device handle
+ * \returns The device handle
+ */
+ VkDevice handle() const {
+ return m_vkd->device();
+ }
+
+ /**
+ * \brief Device options
+ * \returns Device options
+ */
+ const DxvkOptions& config() const {
+ return m_options;
+ }
+
+ /**
+ * \brief Queue handles
+ *
+ * Handles and queue family indices
+ * of all known device queues.
+ * \returns Device queue infos
+ */
+ const DxvkDeviceQueueSet& queues() const {
+ return m_queues;
+ }
+
+ /**
+ * \brief Tests whether a dedicated transfer queue is available
+ * \returns \c true if an SDMA queue is supported by the device
+ */
+ bool hasDedicatedTransferQueue() const {
+ return m_queues.transfer.queueHandle
+ != m_queues.graphics.queueHandle;
+ }
+
+ /**
+ * \brief The instance
+ *
+ * The DXVK instance that created this device.
+ * \returns Instance
+ */
+ Rc<DxvkInstance> instance() const {
+ return m_instance;
+ }
+
+ /**
+ * \brief The adapter
+ *
+ * The physical device that the
+ * device has been created for.
+ * \returns Adapter
+ */
+ Rc<DxvkAdapter> adapter() const {
+ return m_adapter;
+ }
+
+ /**
+ * \brief Enabled device extensions
+ * \returns Enabled device extensions
+ */
+ const DxvkDeviceExtensions& extensions() const {
+ return m_extensions;
+ }
+
+ /**
+ * \brief Enabled device features
+ * \returns Enabled features
+ */
+ const DxvkDeviceFeatures& features() const {
+ return m_features;
+ }
+
+ /**
+ * \brief Device properties
+ * \returns Device properties
+ */
+ const DxvkDeviceInfo& properties() const {
+ return m_properties;
+ }
+
+ /**
+ * \brief Get device status
+ *
+ * This may report device loss in
+ * case a submission failed.
+ * \returns Device status
+ */
+ VkResult getDeviceStatus() const {
+ return m_submissionQueue.getLastError();
+ }
+
+ /**
+ * \brief Checks whether this is a UMA system
+ *
+ * Basically tests whether all heaps are device-local.
+ * Can be used for various optimizations in client APIs.
+ * \returns \c true if the system has unified memory.
+ */
+ bool isUnifiedMemoryArchitecture() const;
+
+ /**
+ * \brief Queries supported shader stages
+ * \returns Supported shader pipeline stages
+ */
+ VkPipelineStageFlags getShaderPipelineStages() const;
+
+ /**
+ * \brief Retrieves device options
+ * \returns Device options
+ */
+ DxvkDeviceOptions options() const;
+
+ /**
+ * \brief Retrieves performance hints
+ * \returns Device-specific perf hints
+ */
+ DxvkDevicePerfHints perfHints() const {
+ return m_perfHints;
+ }
+
+ /**
+ * \brief Creates a command list
+ * \returns The command list
+ */
+ Rc<DxvkCommandList> createCommandList();
+
+ /**
+ * \brief Creates a descriptor pool
+ *
+ * Returns a previously recycled pool, or creates
+ * a new one if necessary. The context should take
+ * ownership of the returned pool.
+ * \returns Descriptor pool
+ */
+ Rc<DxvkDescriptorPool> createDescriptorPool();
+
+ /**
+ * \brief Creates a context
+ *
+ * Creates a context object that can
+ * be used to record command buffers.
+ * \returns The context object
+ */
+ Rc<DxvkContext> createContext();
+
+ /**
+ * \brief Creates a GPU event
+ * \returns New GPU event
+ */
+ Rc<DxvkGpuEvent> createGpuEvent();
+
+ /**
+ * \brief Creates a query
+ *
+ * \param [in] type Query type
+ * \param [in] flags Query flags
+ * \param [in] index Query index
+ * \returns New query
+ */
+ Rc<DxvkGpuQuery> createGpuQuery(
+ VkQueryType type,
+ VkQueryControlFlags flags,
+ uint32_t index);
+
+ /**
+ * \brief Creates framebuffer for a set of render targets
+ *
+ * Automatically deduces framebuffer dimensions
+ * from the supplied render target views.
+ * \param [in] renderTargets Render targets
+ * \returns The framebuffer object
+ */
+ Rc<DxvkFramebuffer> createFramebuffer(
+ const DxvkRenderTargets& renderTargets);
+
+ /**
+ * \brief Creates a buffer object
+ *
+ * \param [in] createInfo Buffer create info
+ * \param [in] memoryType Memory type flags
+ * \returns The buffer object
+ */
+ Rc<DxvkBuffer> createBuffer(
+ const DxvkBufferCreateInfo& createInfo,
+ VkMemoryPropertyFlags memoryType);
+
+ /**
+ * \brief Creates a buffer view
+ *
+ * \param [in] buffer The buffer to view
+ * \param [in] createInfo Buffer view properties
+ * \returns The buffer view object
+ */
+ Rc<DxvkBufferView> createBufferView(
+ const Rc<DxvkBuffer>& buffer,
+ const DxvkBufferViewCreateInfo& createInfo);
+
+ /**
+ * \brief Creates an image object
+ *
+ * \param [in] createInfo Image create info
+ * \param [in] memoryType Memory type flags
+ * \returns The image object
+ */
+ Rc<DxvkImage> createImage(
+ const DxvkImageCreateInfo& createInfo,
+ VkMemoryPropertyFlags memoryType);
+
+ /**
+ * \brief Creates an image object for an existing VkImage
+ *
+ * \param [in] createInfo Image create info
+ * \param [in] image Vulkan image to wrap
+ * \returns The image object
+ */
+ Rc<DxvkImage> createImageFromVkImage(
+ const DxvkImageCreateInfo& createInfo,
+ VkImage image);
+
+ /**
+ * \brief Creates an image view
+ *
+ * \param [in] image The image to create a view for
+ * \param [in] createInfo Image view create info
+ * \returns The image view
+ */
+ Rc<DxvkImageView> createImageView(
+ const Rc<DxvkImage>& image,
+ const DxvkImageViewCreateInfo& createInfo);
+
+ /**
+ * \brief Creates a sampler object
+ *
+ * \param [in] createInfo Sampler parameters
+ * \returns Newly created sampler object
+ */
+ Rc<DxvkSampler> createSampler(
+ const DxvkSamplerCreateInfo& createInfo);
+
+ /**
+ * \brief Creates a shader module
+ *
+ * \param [in] stage Shader stage
+ * \param [in] slotCount Resource slot count
+ * \param [in] slotInfos Resource slot descriptions
+ * \param [in] iface Inter-stage interface slots
+ * \param [in] code Shader code
+ * \returns New shader module
+ */
+ Rc<DxvkShader> createShader(
+ VkShaderStageFlagBits stage,
+ uint32_t slotCount,
+ const DxvkResourceSlot* slotInfos,
+ const DxvkInterfaceSlots& iface,
+ const SpirvCodeBuffer& code);
+
+ /**
+ * \brief Retrieves stat counters
+ *
+ * Can be used by the HUD to display some
+ * internal information, such as memory
+ * usage, draw calls, etc.
+ */
+ DxvkStatCounters getStatCounters();
+
+ /**
+ * \brief Retrieves memors statistics
+ *
+ * \param [in] heap Memory heap index
+ * \returns Memory stats for this heap
+ */
+ DxvkMemoryStats getMemoryStats(uint32_t heap);
+
+ /**
+ * \brief Retreves current frame ID
+ * \returns Current frame ID
+ */
+ uint32_t getCurrentFrameId() const;
+
+ /**
+ * \brief Initializes dummy resources
+ *
+ * Should be called after creating the device in
+ * case the device initialization was successful
+ * and the device is usable.
+ */
+ void initResources();
+
+ /**
+ * \brief Registers a shader
+ * \param [in] shader Newly compiled shader
+ */
+ void registerShader(
+ const Rc<DxvkShader>& shader);
+
+ /**
+ * \brief Presents a swap chain image
+ *
+ * Invokes the presenter's \c presentImage method on
+ * the submission thread. The status of this operation
+ * can be retrieved with \ref waitForSubmission.
+ * \param [in] presenter The presenter
+ * \param [out] status Present status
+ */
+ void presentImage(
+ const Rc<vk::Presenter>& presenter,
+ DxvkSubmitStatus* status);
+
+ /**
+ * \brief Submits a command list
+ *
+ * Submits the given command list to the device using
+ * the given set of optional synchronization primitives.
+ * \param [in] commandList The command list to submit
+ * \param [in] waitSync (Optional) Semaphore to wait on
+ * \param [in] wakeSync (Optional) Semaphore to notify
+ */
+ void submitCommandList(
+ const Rc<DxvkCommandList>& commandList,
+ VkSemaphore waitSync,
+ VkSemaphore wakeSync);
+
+ /**
+ * \brief Locks submission queue
+ *
+ * Since Vulkan queues are only meant to be accessed
+ * from one thread at a time, external libraries need
+ * to lock the queue before submitting command buffers.
+ */
+ void lockSubmission() {
+ m_submissionQueue.synchronize();
+ m_submissionQueue.lockDeviceQueue();
+ }
+
+ /**
+ * \brief Unlocks submission queue
+ *
+ * Releases the Vulkan queues again so that DXVK
+ * itself can use them for submissions again.
+ */
+ void unlockSubmission() {
+ m_submissionQueue.unlockDeviceQueue();
+ }
+
+ /**
+ * \brief Number of pending submissions
+ *
+ * A return value of 0 indicates
+ * that the GPU is currently idle.
+ * \returns Pending submission count
+ */
+ uint32_t pendingSubmissions() const {
+ return m_submissionQueue.pendingSubmissions();
+ }
+
+ /**
+ * \brief Waits for a given submission
+ *
+ * \param [in,out] status Submission status
+ * \returns Result of the submission
+ */
+ VkResult waitForSubmission(DxvkSubmitStatus* status);
+
+ /**
+ * \brief Waits until the device becomes idle
+ *
+ * Waits for the GPU to complete the execution of all
+ * previously submitted command buffers. This may be
+ * used to ensure that resources that were previously
+ * used by the GPU can be safely destroyed.
+ */
+ void waitForIdle();
+
+ private:
+
+ DxvkOptions m_options;
+
+ Rc<DxvkInstance> m_instance;
+ Rc<DxvkAdapter> m_adapter;
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkDeviceExtensions m_extensions;
+
+ DxvkDeviceFeatures m_features;
+ DxvkDeviceInfo m_properties;
+
+ DxvkDevicePerfHints m_perfHints;
+ DxvkObjects m_objects;
+
+ sync::Spinlock m_statLock;
+ DxvkStatCounters m_statCounters;
+
+ DxvkDeviceQueueSet m_queues;
+
+ DxvkRecycler<DxvkCommandList, 16> m_recycledCommandLists;
+ DxvkRecycler<DxvkDescriptorPool, 16> m_recycledDescriptorPools;
+
+ DxvkSubmissionQueue m_submissionQueue;
+
+ DxvkDevicePerfHints getPerfHints();
+
+ void recycleCommandList(
+ const Rc<DxvkCommandList>& cmdList);
+
+ void recycleDescriptorPool(
+ const Rc<DxvkDescriptorPool>& pool);
+
+ DxvkDeviceQueue getQueue(
+ uint32_t family,
+ uint32_t index) const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.cpp
new file mode 100644
index 00000000..02d8329e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.cpp
@@ -0,0 +1,40 @@
+#include "dxvk_device_filter.h"
+
+namespace dxvk {
+
+ DxvkDeviceFilter::DxvkDeviceFilter(DxvkDeviceFilterFlags flags)
+ : m_flags(flags) {
+ m_matchDeviceName = env::getEnvVar("DXVK_FILTER_DEVICE_NAME");
+
+ if (m_matchDeviceName.size() != 0)
+ m_flags.set(DxvkDeviceFilterFlag::MatchDeviceName);
+ }
+
+
+ DxvkDeviceFilter::~DxvkDeviceFilter() {
+
+ }
+
+
+ bool DxvkDeviceFilter::testAdapter(const VkPhysicalDeviceProperties& properties) const {
+ if (properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ Logger::warn(str::format("Skipping Vulkan 1.0 adapter: ", properties.deviceName));
+ return false;
+ }
+
+ if (m_flags.test(DxvkDeviceFilterFlag::MatchDeviceName)) {
+ if (std::string(properties.deviceName).find(m_matchDeviceName) == std::string::npos)
+ return false;
+ }
+
+ if (m_flags.test(DxvkDeviceFilterFlag::SkipCpuDevices)) {
+ if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
+ Logger::warn(str::format("Skipping CPU adapter: ", properties.deviceName));
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.h
new file mode 100644
index 00000000..7b411e6a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_filter.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "dxvk_adapter.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Device filter flags
+ *
+ * The device filter flags specify which device
+ * properties are considered when testing adapters.
+ * If no flags are set, all devices pass the test.
+ */
+ enum class DxvkDeviceFilterFlag {
+ MatchDeviceName = 0,
+ SkipCpuDevices = 1,
+ };
+
+ using DxvkDeviceFilterFlags = Flags<DxvkDeviceFilterFlag>;
+
+
+ /**
+ * \brief DXVK device filter
+ *
+ * Used to select specific Vulkan devices to use
+ * with DXVK. This may be useful for games which
+ * do not offer an option to select the correct
+ * device.
+ */
+ class DxvkDeviceFilter {
+
+ public:
+
+ DxvkDeviceFilter(DxvkDeviceFilterFlags flags);
+ ~DxvkDeviceFilter();
+
+ /**
+ * \brief Tests an adapter
+ *
+ * \param [in] properties Adapter properties
+ * \returns \c true if the test passes
+ */
+ bool testAdapter(
+ const VkPhysicalDeviceProperties& properties) const;
+
+ private:
+
+ DxvkDeviceFilterFlags m_flags;
+
+ std::string m_matchDeviceName;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_info.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_info.h
new file mode 100644
index 00000000..d832bec1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_device_info.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Device info
+ *
+ * Stores core properties and a bunch of extension-specific
+ * properties, if the respective extensions are available.
+ * Structures for unsupported extensions will be undefined,
+ * so before using them, check whether they are supported.
+ */
+ struct DxvkDeviceInfo {
+ VkPhysicalDeviceProperties2 core;
+ VkPhysicalDeviceIDProperties coreDeviceId;
+ VkPhysicalDeviceSubgroupProperties coreSubgroup;
+ VkPhysicalDeviceConservativeRasterizationPropertiesEXT extConservativeRasterization;
+ VkPhysicalDeviceCustomBorderColorPropertiesEXT extCustomBorderColor;
+ VkPhysicalDeviceRobustness2PropertiesEXT extRobustness2;
+ VkPhysicalDeviceTransformFeedbackPropertiesEXT extTransformFeedback;
+ VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT extVertexAttributeDivisor;
+ VkPhysicalDeviceDepthStencilResolvePropertiesKHR khrDepthStencilResolve;
+ VkPhysicalDeviceDriverPropertiesKHR khrDeviceDriverProperties;
+ VkPhysicalDeviceFloatControlsPropertiesKHR khrShaderFloatControls;
+ };
+
+
+ /**
+ * \brief Device features
+ *
+ * Stores core features and extension-specific features.
+ * If the respective extensions are not available, the
+ * extended features will be marked as unsupported.
+ */
+ struct DxvkDeviceFeatures {
+ VkPhysicalDeviceFeatures2 core;
+ VkPhysicalDeviceShaderDrawParametersFeatures shaderDrawParameters;
+ VkPhysicalDevice4444FormatsFeaturesEXT ext4444Formats;
+ VkPhysicalDeviceCustomBorderColorFeaturesEXT extCustomBorderColor;
+ VkPhysicalDeviceDepthClipEnableFeaturesEXT extDepthClipEnable;
+ VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extExtendedDynamicState;
+ VkPhysicalDeviceHostQueryResetFeaturesEXT extHostQueryReset;
+ VkPhysicalDeviceMemoryPriorityFeaturesEXT extMemoryPriority;
+ VkPhysicalDeviceRobustness2FeaturesEXT extRobustness2;
+ VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT extShaderDemoteToHelperInvocation;
+ VkPhysicalDeviceTransformFeedbackFeaturesEXT extTransformFeedback;
+ VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT extVertexAttributeDivisor;
+ VkPhysicalDeviceBufferDeviceAddressFeaturesKHR khrBufferDeviceAddress;
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extension_provider.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extension_provider.h
new file mode 100644
index 00000000..090d56d3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extension_provider.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "dxvk_include.h"
+#include "dxvk_extensions.h"
+
+#include <vector>
+#include <string>
+
+namespace dxvk {
+
+ class DxvkInstance;
+ class DxvkExtensionProvider;
+
+ /**
+ * \brief Extension provider base
+ *
+ * Abstract interface for extension
+ * providers
+ */
+ class DxvkExtensionProvider {
+
+ public:
+
+ /**
+ * \brief Extension provider name
+ * \returns The extension provider's name
+ */
+ virtual std::string_view getName() = 0;
+
+ /**
+ * \brief Query instance extensions
+ * \returns Instance extensions
+ */
+ virtual DxvkNameSet getInstanceExtensions() = 0;
+
+ /**
+ * \brief Query device extensions
+ *
+ * Retrieves the extensions required for a specific
+ * physical device. The adapter index should remain
+ * the same across multiple Vulkan instances.
+ * \param [in] adapterId Adapter index
+ */
+ virtual DxvkNameSet getDeviceExtensions(
+ uint32_t adapterId) = 0;
+
+ /**
+ * \brief Initializes instance extension set
+ *
+ * Should be called before creating
+ * the first Vulkan instance.
+ */
+ virtual void initInstanceExtensions() = 0;
+
+ /**
+ * \brief Initializes device extension sets
+ *
+ * Should be called after setting
+ * up the Vulkan physical devices.
+ * \param [in] instance DXVK instance
+ */
+ virtual void initDeviceExtensions(
+ const DxvkInstance* instance) = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.cpp
new file mode 100644
index 00000000..6cb4c325
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.cpp
@@ -0,0 +1,132 @@
+#include "dxvk_extensions.h"
+
+namespace dxvk {
+
+ DxvkNameSet::DxvkNameSet() { }
+ DxvkNameSet::~DxvkNameSet() { }
+
+
+ void DxvkNameSet::add(const char* pName) {
+ m_names.insert({ pName, 1u });
+ }
+
+
+ void DxvkNameSet::merge(const DxvkNameSet& names) {
+ for (const auto& pair : names.m_names)
+ m_names.insert(pair);
+ }
+
+
+ uint32_t DxvkNameSet::supports(const char* pName) const {
+ auto entry = m_names.find(pName);
+
+ if (entry == m_names.end())
+ return 0;
+
+ return entry->second != 0
+ ? entry->second
+ : 1;
+ }
+
+
+ bool DxvkNameSet::enableExtensions(
+ uint32_t numExtensions,
+ DxvkExt** ppExtensions,
+ DxvkNameSet& nameSet) const {
+ bool allRequiredEnabled = true;
+
+ for (uint32_t i = 0; i < numExtensions; i++) {
+ DxvkExt* ext = ppExtensions[i];
+
+ if (ext->mode() == DxvkExtMode::Disabled)
+ continue;
+
+ uint32_t revision = supports(ext->name());
+
+ if (revision) {
+ if (ext->mode() != DxvkExtMode::Passive)
+ nameSet.add(ext->name());
+
+ ext->enable(revision);
+ } else if (ext->mode() == DxvkExtMode::Required) {
+ Logger::info(str::format("Required Vulkan extension ", ext->name(), " not supported"));
+ allRequiredEnabled = false;
+ continue;
+ }
+ }
+
+ return allRequiredEnabled;
+ }
+
+
+ void DxvkNameSet::disableExtension(
+ DxvkExt& ext) {
+ m_names.erase(ext.name());
+ ext.disable();
+ }
+
+
+ DxvkNameList DxvkNameSet::toNameList() const {
+ DxvkNameList nameList;
+ for (const auto& pair : m_names)
+ nameList.add(pair.first.c_str());
+ return nameList;
+ }
+
+
+ DxvkNameSet DxvkNameSet::enumInstanceLayers(const Rc<vk::LibraryFn>& vkl) {
+ uint32_t entryCount = 0;
+ if (vkl->vkEnumerateInstanceLayerProperties(
+ &entryCount, nullptr) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ std::vector<VkLayerProperties> entries(entryCount);
+ if (vkl->vkEnumerateInstanceLayerProperties(
+ &entryCount, entries.data()) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ DxvkNameSet set;
+ for (uint32_t i = 0; i < entryCount; i++)
+ set.m_names.insert({ entries[i].layerName, entries[i].specVersion });
+ return set;
+ }
+
+
+ DxvkNameSet DxvkNameSet::enumInstanceExtensions(const Rc<vk::LibraryFn>& vkl) {
+ uint32_t entryCount = 0;
+ if (vkl->vkEnumerateInstanceExtensionProperties(
+ nullptr, &entryCount, nullptr) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ std::vector<VkExtensionProperties> entries(entryCount);
+ if (vkl->vkEnumerateInstanceExtensionProperties(
+ nullptr, &entryCount, entries.data()) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ DxvkNameSet set;
+ for (uint32_t i = 0; i < entryCount; i++)
+ set.m_names.insert({ entries[i].extensionName, entries[i].specVersion });
+ return set;
+ }
+
+
+ DxvkNameSet DxvkNameSet::enumDeviceExtensions(
+ const Rc<vk::InstanceFn>& vki,
+ VkPhysicalDevice device) {
+ uint32_t entryCount = 0;
+ if (vki->vkEnumerateDeviceExtensionProperties(
+ device, nullptr, &entryCount, nullptr) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ std::vector<VkExtensionProperties> entries(entryCount);
+ if (vki->vkEnumerateDeviceExtensionProperties(
+ device, nullptr, &entryCount, entries.data()) != VK_SUCCESS)
+ return DxvkNameSet();
+
+ DxvkNameSet set;
+ for (uint32_t i = 0; i < entryCount; i++)
+ set.m_names.insert({ entries[i].extensionName, entries[i].specVersion });
+ return set;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.h
new file mode 100644
index 00000000..33c72a42
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_extensions.h
@@ -0,0 +1,321 @@
+#pragma once
+
+#include <algorithm>
+#include <map>
+#include <vector>
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Vulkan extension mode
+ *
+ * Defines whether an extension is
+ * optional, required, or disabled.
+ */
+ enum class DxvkExtMode {
+ Disabled,
+ Optional,
+ Required,
+ Passive,
+ };
+
+
+ /**
+ * \brief Vulkan extension info
+ *
+ * Stores information for a single extension.
+ * The renderer can use this information to
+ * find out which extensions are enabled.
+ */
+ class DxvkExt {
+
+ public:
+
+ DxvkExt(
+ const char* pName,
+ DxvkExtMode mode)
+ : m_name(pName), m_mode(mode) { }
+
+ /**
+ * \brief Extension name
+ * \returns Extension name
+ */
+ const char* name() const {
+ return m_name;
+ }
+
+ /**
+ * \brief Extension mode
+ * \returns Extension mode
+ */
+ DxvkExtMode mode() const {
+ return m_mode;
+ }
+
+ /**
+ * \brief Checks whether the extension is enabled
+ *
+ * If an extension is enabled, the features
+ * provided by the extension can be used.
+ * \returns \c true if the extension is enabled
+ */
+ operator bool () const {
+ return m_revision != 0;
+ }
+
+ /**
+ * \brief Supported revision
+ * \returns Supported revision
+ */
+ uint32_t revision() const {
+ return m_revision;
+ }
+
+ /**
+ * \brief Changes extension mode
+ *
+ * In some cases, it may be useful to change the
+ * default mode dynamically after initialization.
+ */
+ void setMode(DxvkExtMode mode) {
+ m_mode = mode;
+ }
+
+ /**
+ * \brief Enables the extension
+ */
+ void enable(uint32_t revision) {
+ m_revision = revision;
+ }
+
+ /**
+ * \brief Disables the extension
+ */
+ void disable() {
+ m_revision = 0;
+ }
+
+ private:
+
+ const char* m_name = nullptr;
+ DxvkExtMode m_mode = DxvkExtMode::Disabled;
+ uint32_t m_revision = 0;
+
+ };
+
+
+ /**
+ * \brief Vulkan name list
+ *
+ * A simple \c vector wrapper that can
+ * be used to build a list of layer and
+ * extension names.
+ */
+ class DxvkNameList {
+
+ public:
+
+ /**
+ * \brief Adds a name
+ * \param [in] pName The name
+ */
+ void add(const char* pName) {
+ m_names.push_back(pName);
+ }
+
+ /**
+ * \brief Number of names
+ * \returns Name count
+ */
+ uint32_t count() const {
+ return m_names.size();
+ }
+
+ /**
+ * \brief Name list
+ * \returns Name list
+ */
+ const char* const* names() const {
+ return m_names.data();
+ }
+
+ /**
+ * \brief Retrieves a single name
+ *
+ * \param [in] index Name index
+ * \returns The given name
+ */
+ const char* name(uint32_t index) const {
+ return m_names.at(index);
+ }
+
+ private:
+
+ std::vector<const char*> m_names;
+
+ };
+
+
+ /**
+ * \brief Vulkan extension set
+ *
+ * Stores a set of extensions or layers
+ * supported by the Vulkan implementation.
+ */
+ class DxvkNameSet {
+
+ public:
+
+ DxvkNameSet();
+ ~DxvkNameSet();
+
+ /**
+ * \brief Adds a name to the set
+ * \param [in] pName Extension name
+ */
+ void add(
+ const char* pName);
+
+ /**
+ * \brief Merges two name sets
+ *
+ * Adds all names from the given name set to
+ * this name set, avoiding duplicate entries.
+ * \param [in] names Name set to merge
+ */
+ void merge(
+ const DxvkNameSet& names);
+
+ /**
+ * \brief Checks whether an extension is supported
+ *
+ * \param [in] pName Extension name
+ * \returns Supported revision, or zero
+ */
+ uint32_t supports(
+ const char* pName) const;
+
+ /**
+ * \brief Enables requested extensions
+ *
+ * Walks over a set of extensions and enables all
+ * extensions that are supported and not disabled.
+ * This also checks whether all required extensions
+ * could be enabled, and returns \c false otherwise.
+ * \param [in] numExtensions Number of extensions
+ * \param [in] ppExtensions List of extensions
+ * \param [out] nameSet Extension name set
+ * \returns \c true on success
+ */
+ bool enableExtensions(
+ uint32_t numExtensions,
+ DxvkExt** ppExtensions,
+ DxvkNameSet& nameSet) const;
+
+ /**
+ * \brief Disables given extension
+ *
+ * Removes the given extension from the set
+ * and sets its revision to 0 (i.e. disabled).
+ * \param [in,out] ext Extension to disable
+ */
+ void disableExtension(
+ DxvkExt& ext);
+
+ /**
+ * \brief Creates name list from name set
+ *
+ * Adds all names contained in the name set
+ * to a name list, which can then be passed
+ * to Vulkan functions.
+ * \returns Name list
+ */
+ DxvkNameList toNameList() const;
+
+ /**
+ * \brief Enumerates instance layers
+ *
+ * \param [in] vkl Vulkan library functions
+ * \returns Set of available instance layers
+ */
+ static DxvkNameSet enumInstanceLayers(
+ const Rc<vk::LibraryFn>& vkl);
+
+ /**
+ * \brief Enumerates instance extensions
+ *
+ * \param [in] vkl Vulkan library functions
+ * \returns Set of available instance extensions
+ */
+ static DxvkNameSet enumInstanceExtensions(
+ const Rc<vk::LibraryFn>& vkl);
+
+ /**
+ * \brief Enumerates device extensions
+ *
+ * \param [in] vki Vulkan instance functions
+ * \param [in] device The device to query
+ * \returns Set of available device extensions
+ */
+ static DxvkNameSet enumDeviceExtensions(
+ const Rc<vk::InstanceFn>& vki,
+ VkPhysicalDevice device);
+
+ private:
+
+ std::map<std::string, uint32_t> m_names;
+
+ };
+
+ /**
+ * \brief Device extensions
+ *
+ * Lists all Vulkan extensions that are potentially
+ * used by DXVK if supported by the implementation.
+ */
+ struct DxvkDeviceExtensions {
+ DxvkExt amdMemoryOverallocationBehaviour = { VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt amdShaderFragmentMask = { VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt ext4444Formats = { VK_EXT_4444_FORMATS_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extConservativeRasterization = { VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extCustomBorderColor = { VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extDepthClipEnable = { VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extExtendedDynamicState = { VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extFullScreenExclusive = { VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extHostQueryReset = { VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extMemoryBudget = { VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, DxvkExtMode::Passive };
+ DxvkExt extMemoryPriority = { VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extRobustness2 = { VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extShaderDemoteToHelperInvocation = { VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extShaderStencilExport = { VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extShaderViewportIndexLayer = { VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extTransformFeedback = { VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt extVertexAttributeDivisor = { VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrBufferDeviceAddress = { VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, DxvkExtMode::Disabled };
+ DxvkExt khrCreateRenderPass2 = { VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrDepthStencilResolve = { VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrDrawIndirectCount = { VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrDriverProperties = { VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrImageFormatList = { VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, DxvkExtMode::Required };
+ DxvkExt khrSamplerMirrorClampToEdge = { VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrShaderFloatControls = { VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
+ DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
+ DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
+ };
+
+ /**
+ * \brief Instance extensions
+ *
+ * Lists all Vulkan extensions that are potentially
+ * used by DXVK if supported by the implementation.
+ */
+ struct DxvkInstanceExtensions {
+ DxvkExt extDebugUtils = { VK_EXT_DEBUG_UTILS_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrGetSurfaceCapabilities2 = { VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, DxvkExtMode::Optional };
+ DxvkExt khrSurface = { VK_KHR_SURFACE_EXTENSION_NAME, DxvkExtMode::Required };
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.cpp
new file mode 100644
index 00000000..acda79c8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.cpp
@@ -0,0 +1,586 @@
+#include "dxvk_format.h"
+
+namespace dxvk {
+
+ const std::array<DxvkFormatInfo, 152> g_formatInfos = {{
+ // VK_FORMAT_UNDEFINED
+ { },
+
+ // VK_FORMAT_R4G4_UNORM_PACK8
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R4G4B4A4_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B4G4R4A4_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R5G6B5_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B5G6R5_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R5G5B5A1_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B5G5R5A1_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A1R5G5B5_UNORM_PACK16
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8_UNORM
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8_SNORM
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8_USCALED
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8_SSCALED
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8_UINT
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R8_SINT
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R8_SRGB
+ { 1, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_R8G8_UNORM
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8_SNORM
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8_USCALED
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8_SSCALED
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8_UINT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R8G8_SINT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R8G8_SRGB
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_R8G8B8_UNORM
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8_SNORM
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8_USCALED
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8_SSCALED
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8_UINT
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R8G8B8_SINT
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R8G8B8_SRGB
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_B8G8R8_UNORM
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8_SNORM
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8_USCALED
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8_SSCALED
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8_UINT
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_B8G8R8_SINT
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_B8G8R8_SRGB
+ { 3, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_R8G8B8A8_UNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8A8_SNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8A8_USCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8A8_SSCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R8G8B8A8_UINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R8G8B8A8_SINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R8G8B8A8_SRGB
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_B8G8R8A8_UNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8A8_SNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8A8_USCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8A8_SSCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B8G8R8A8_UINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_B8G8R8A8_SINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_B8G8R8A8_SRGB
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_A8B8G8R8_UNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A8B8G8R8_SNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A8B8G8R8_USCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A8B8G8R8_SSCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A8B8G8R8_UINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_A8B8G8R8_SINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_A8B8G8R8_SRGB_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::ColorSpaceSrgb },
+
+ // VK_FORMAT_A2R10G10B10_UNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2R10G10B10_SNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2R10G10B10_USCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2R10G10B10_SSCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2R10G10B10_UINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_A2R10G10B10_SINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_A2B10G10R10_UNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2B10G10R10_SNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2B10G10R10_USCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2B10G10R10_SSCALED_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A2B10G10R10_UINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_A2B10G10R10_SINT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R16_UNORM
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16_SNORM
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16_USCALED
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16_SSCALED
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16_UINT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R16_SINT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R16_SFLOAT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16_UNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16_SNORM
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16_USCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16_SSCALED
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16_UINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R16G16_SINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R16G16_SFLOAT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16_UNORM
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16_SNORM
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16_USCALED
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16_SSCALED
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16_UINT
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R16G16B16_SINT
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R16G16B16_SFLOAT
+ { 6, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16A16_UNORM
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16A16_SNORM
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16A16_USCALED
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16A16_SSCALED
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R16G16B16A16_UINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R16G16B16A16_SINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R16G16B16A16_SFLOAT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R32_UINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R32_SINT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R32_SFLOAT
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R32G32_UINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R32G32_SINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R32G32_SFLOAT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R32G32B32_UINT
+ { 12, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R32G32B32_SINT
+ { 12, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R32G32B32_SFLOAT
+ { 12, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R32G32B32A32_UINT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R32G32B32A32_SINT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R32G32B32A32_SFLOAT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R64_UINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R64_SINT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R64_SFLOAT
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R64G64_UINT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R64G64_SINT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R64G64_SFLOAT
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R64G64B64_UINT
+ { 24, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R64G64B64_SINT
+ { 24, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R64G64B64_SFLOAT
+ { 24, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_R64G64B64A64_UINT
+ { 32, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledUInt },
+
+ // VK_FORMAT_R64G64B64A64_SINT
+ { 32, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::SampledSInt },
+
+ // VK_FORMAT_R64G64B64A64_SFLOAT
+ { 32, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_B10G11R11_UFLOAT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_D16_UNORM
+ { 2, VK_IMAGE_ASPECT_DEPTH_BIT },
+
+ // VK_FORMAT_X8_D24_UNORM_PACK32
+ { 4, VK_IMAGE_ASPECT_DEPTH_BIT },
+
+ // VK_FORMAT_D32_SFLOAT
+ { 4, VK_IMAGE_ASPECT_DEPTH_BIT },
+
+ // VK_FORMAT_S8_UINT
+ { 1, VK_IMAGE_ASPECT_STENCIL_BIT },
+
+ // VK_FORMAT_D16_UNORM_S8_UINT
+ { 4, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+
+ // VK_FORMAT_D24_UNORM_S8_UINT
+ { 4, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+
+ // VK_FORMAT_D32_SFLOAT_S8_UINT
+ { 8, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+
+ // VK_FORMAT_BC1_RGB_UNORM_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC1_RGB_SRGB_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlags(
+ DxvkFormatFlag::BlockCompressed,
+ DxvkFormatFlag::ColorSpaceSrgb),
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC1_RGBA_UNORM_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC1_RGBA_SRGB_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlags(
+ DxvkFormatFlag::BlockCompressed,
+ DxvkFormatFlag::ColorSpaceSrgb),
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC2_UNORM_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC2_SRGB_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlags(
+ DxvkFormatFlag::BlockCompressed,
+ DxvkFormatFlag::ColorSpaceSrgb),
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC3_UNORM_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC3_SRGB_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlags(
+ DxvkFormatFlag::BlockCompressed,
+ DxvkFormatFlag::ColorSpaceSrgb),
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC4_UNORM_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC4_SNORM_BLOCK
+ { 8, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC5_UNORM_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC5_SNORM_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC6H_UFLOAT_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC6H_SFLOAT_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC7_UNORM_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_BC7_SRGB_BLOCK
+ { 16, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlags(
+ DxvkFormatFlag::BlockCompressed,
+ DxvkFormatFlag::ColorSpaceSrgb),
+ VkExtent3D { 4, 4, 1 } },
+
+ // VK_FORMAT_G8B8G8R8_422_UNORM_KHR
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 2, 1, 1 } },
+
+ // VK_FORMAT_B8G8R8G8_422_UNORM_KHR
+ { 4, VK_IMAGE_ASPECT_COLOR_BIT,
+ DxvkFormatFlag::BlockCompressed,
+ VkExtent3D { 2, 1, 1 } },
+
+ // VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT
+ { 2, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ // VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
+ { 6, VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT,
+ DxvkFormatFlag::MultiPlane, VkExtent3D { 1, 1, 1 },
+ { DxvkPlaneFormatInfo { 1, { 1, 1 } },
+ DxvkPlaneFormatInfo { 2, { 2, 2 } } } },
+ }};
+
+
+ const std::array<std::pair<VkFormat, VkFormat>, 4> g_formatGroups = {{
+ { VK_FORMAT_UNDEFINED, VK_FORMAT_BC7_SRGB_BLOCK },
+ { VK_FORMAT_G8B8G8R8_422_UNORM_KHR, VK_FORMAT_B8G8R8G8_422_UNORM_KHR },
+ { VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT, VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT },
+ { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM },
+ }};
+
+
+ const DxvkFormatInfo* imageFormatInfo(VkFormat format) {
+ uint32_t indexOffset = 0;
+
+ for (const auto& group : g_formatGroups) {
+ if (format >= group.first && format <= group.second) {
+ uint32_t index = uint32_t(format) - uint32_t(group.first);
+ return &g_formatInfos[indexOffset + index];
+ } else {
+ indexOffset += uint32_t(group.second)
+ - uint32_t(group.first) + 1;
+ }
+ }
+
+ return nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.h
new file mode 100644
index 00000000..21e6a678
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_format.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ enum class DxvkFormatFlag {
+ BlockCompressed = 0, ///< Image format is block compressed
+ SampledUInt = 1, ///< Sampled type is an unsigned integer type
+ SampledSInt = 2, ///< Sampled type is a signed integer type
+ ColorSpaceSrgb = 3, ///< Non-linear SRGB color format
+ MultiPlane = 4, ///< Multi-plane format
+ };
+
+ using DxvkFormatFlags = Flags<DxvkFormatFlag>;
+
+ /**
+ * \brief Planar format info
+ */
+ struct DxvkPlaneFormatInfo {
+ /// Byte size of a pixel in the current plane
+ VkDeviceSize elementSize = 0;
+ /// Number of image pixels covered by a
+ /// single pixel in the current plane
+ VkExtent2D blockSize = { 1, 1 };
+ };
+
+ /**
+ * \brief Format info structure
+ *
+ * Provides some useful information
+ * about a Vulkan image format.
+ */
+ struct DxvkFormatInfo {
+ /// Size of an element in this format. For compressed
+ /// formats, this is the size of a block, in bytes.
+ VkDeviceSize elementSize = 0;
+
+ /// Available image aspect flags
+ VkImageAspectFlags aspectMask = 0;
+
+ /// Some other format info flags
+ DxvkFormatFlags flags = 0;
+
+ /// Size, in pixels, of a compressed block. For
+ /// non-block formats, all these values are 1.
+ VkExtent3D blockSize = { 1, 1, 1 };
+
+ /// Plane info for multi-planar formats
+ std::array<DxvkPlaneFormatInfo, 3> planes;
+ };
+
+
+
+ const DxvkFormatInfo* imageFormatInfo(VkFormat format);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.cpp
new file mode 100644
index 00000000..2184f3f6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.cpp
@@ -0,0 +1,141 @@
+#include "dxvk_framebuffer.h"
+
+namespace dxvk {
+
+ DxvkFramebuffer::DxvkFramebuffer(
+ const Rc<vk::DeviceFn>& vkd,
+ DxvkRenderPass* renderPass,
+ const DxvkRenderTargets& renderTargets,
+ const DxvkFramebufferSize& defaultSize)
+ : m_vkd (vkd),
+ m_renderPass (renderPass),
+ m_renderTargets (renderTargets),
+ m_renderSize (computeRenderSize(defaultSize)) {
+ std::array<VkImageView, MaxNumRenderTargets + 1> views;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (m_renderTargets.color[i].view != nullptr) {
+ views[m_attachmentCount] = m_renderTargets.color[i].view->handle();
+ m_attachments[m_attachmentCount] = i;
+ m_attachmentCount += 1;
+ }
+ }
+
+ if (m_renderTargets.depth.view != nullptr) {
+ views[m_attachmentCount] = m_renderTargets.depth.view->handle();
+ m_attachments[m_attachmentCount] = -1;
+ m_attachmentCount += 1;
+ }
+
+ VkFramebufferCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.renderPass = m_renderPass->getDefaultHandle();
+ info.attachmentCount = m_attachmentCount;
+ info.pAttachments = views.data();
+ info.width = m_renderSize.width;
+ info.height = m_renderSize.height;
+ info.layers = m_renderSize.layers;
+
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_handle) != VK_SUCCESS)
+ Logger::err("DxvkFramebuffer: Failed to create framebuffer object");
+ }
+
+
+ DxvkFramebuffer::~DxvkFramebuffer() {
+ m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_handle, nullptr);
+ }
+
+
+ int32_t DxvkFramebuffer::findAttachment(const Rc<DxvkImageView>& view) const {
+ for (uint32_t i = 0; i < m_attachmentCount; i++) {
+ if (getAttachment(i).view->matchesView(view))
+ return int32_t(i);
+ }
+
+ return -1;
+ }
+
+
+ bool DxvkFramebuffer::hasTargets(const DxvkRenderTargets& renderTargets) {
+ bool eq = m_renderTargets.depth.view == renderTargets.depth.view
+ && m_renderTargets.depth.layout == renderTargets.depth.layout;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
+ eq &= m_renderTargets.color[i].view == renderTargets.color[i].view
+ && m_renderTargets.color[i].layout == renderTargets.color[i].layout;
+ }
+
+ return eq;
+ }
+
+
+ bool DxvkFramebuffer::isFullSize(const Rc<DxvkImageView>& view) const {
+ return m_renderSize.width == view->mipLevelExtent(0).width
+ && m_renderSize.height == view->mipLevelExtent(0).height
+ && m_renderSize.layers == view->info().numLayers;
+ }
+
+
+ bool DxvkFramebuffer::isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const {
+ VkImageAspectFlags writableAspects = vk::getWritableAspectsForLayout(getAttachment(attachmentIndex).layout);
+ return (writableAspects & aspects) == aspects;
+ }
+
+
+ DxvkRenderPassFormat DxvkFramebuffer::getRenderPassFormat(const DxvkRenderTargets& renderTargets) {
+ DxvkRenderPassFormat format;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (renderTargets.color[i].view != nullptr) {
+ format.sampleCount = renderTargets.color[i].view->imageInfo().sampleCount;
+ format.color[i].format = renderTargets.color[i].view->info().format;
+ format.color[i].layout = renderTargets.color[i].layout;
+ }
+ }
+
+ if (renderTargets.depth.view != nullptr) {
+ format.sampleCount = renderTargets.depth.view->imageInfo().sampleCount;
+ format.depth.format = renderTargets.depth.view->info().format;
+ format.depth.layout = renderTargets.depth.layout;
+ }
+
+ return format;
+ }
+
+
+ DxvkFramebufferSize DxvkFramebuffer::computeRenderSize(
+ const DxvkFramebufferSize& defaultSize) const {
+ // Some games bind render targets of a different size and
+ // expect it to work, so we'll compute the minimum size
+ DxvkFramebufferSize minSize = defaultSize;
+
+ if (m_renderTargets.depth.view != nullptr) {
+ DxvkFramebufferSize depthSize = this->computeRenderTargetSize(m_renderTargets.depth.view);
+ minSize.width = std::min(minSize.width, depthSize.width);
+ minSize.height = std::min(minSize.height, depthSize.height);
+ minSize.layers = std::min(minSize.layers, depthSize.layers);
+ }
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (m_renderTargets.color[i].view != nullptr) {
+ DxvkFramebufferSize colorSize = this->computeRenderTargetSize(m_renderTargets.color[i].view);
+ minSize.width = std::min(minSize.width, colorSize.width);
+ minSize.height = std::min(minSize.height, colorSize.height);
+ minSize.layers = std::min(minSize.layers, colorSize.layers);
+ }
+ }
+
+ return minSize;
+ }
+
+
+ DxvkFramebufferSize DxvkFramebuffer::computeRenderTargetSize(
+ const Rc<DxvkImageView>& renderTarget) const {
+ auto extent = renderTarget->mipLevelExtent(0);
+ auto layers = renderTarget->info().numLayers;
+ return DxvkFramebufferSize { extent.width, extent.height, layers };
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.h
new file mode 100644
index 00000000..070efee4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_framebuffer.h
@@ -0,0 +1,252 @@
+#pragma once
+
+#include "dxvk_image.h"
+#include "dxvk_renderpass.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Framebuffer size
+ *
+ * Stores the width, height and number of layers
+ * of a framebuffer. This can be used in case a
+ * framebuffer does not have any attachments.
+ */
+ struct DxvkFramebufferSize {
+ uint32_t width;
+ uint32_t height;
+ uint32_t layers;
+ };
+
+
+ /**
+ * \brief Framebuffer attachment
+ *
+ * Stores an attachment, as well as the image layout
+ * that will be used for rendering to the attachment.
+ */
+ struct DxvkAttachment {
+ Rc<DxvkImageView> view = nullptr;
+ VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
+ };
+
+
+ /**
+ * \brief Render targets
+ *
+ * Stores all depth-stencil and color
+ * attachments attached to a framebuffer.
+ */
+ struct DxvkRenderTargets {
+ DxvkAttachment depth;
+ DxvkAttachment color[MaxNumRenderTargets];
+ };
+
+
+ /**
+ * \brief Render target layouts
+ */
+ struct DxvkRenderTargetLayouts {
+ VkImageLayout color[MaxNumRenderTargets];
+ VkImageLayout depth;
+ };
+
+
+ /**
+ * \brief Framebuffer
+ *
+ * A framebuffer either stores a set of image views
+ * that will be used as render targets, or in case
+ * no render targets are attached, fixed dimensions.
+ */
+ class DxvkFramebuffer : public DxvkResource {
+
+ public:
+
+ DxvkFramebuffer(
+ const Rc<vk::DeviceFn>& vkd,
+ DxvkRenderPass* renderPass,
+ const DxvkRenderTargets& renderTargets,
+ const DxvkFramebufferSize& defaultSize);
+
+ ~DxvkFramebuffer();
+
+ /**
+ * \brief Framebuffer handle
+ * \returns Framebuffer handle
+ */
+ VkFramebuffer handle() const {
+ return m_handle;
+ }
+
+ /**
+ * \brief Framebuffer size
+ * \returns Framebuffer size
+ */
+ DxvkFramebufferSize size() const {
+ return m_renderSize;
+ }
+
+ /**
+ * \brief Framebuffer sample count
+ *
+ * Returns the sample count of the color
+ * and depth-stencil attachments, or 0 if
+ * there are no attachments.
+ * \returns Sample count
+ */
+ VkSampleCountFlags getSampleCount() const {
+ return m_attachmentCount != 0
+ ? m_renderPass->getSampleCount()
+ : 0;
+ }
+
+ /**
+ * \brief Retrieves default render pass handle
+ *
+ * Retrieves the render pass handle that was used
+ * to create the Vulkan framebuffer object with,
+ * and that should be used to create pipelines.
+ * \returns The default render pass handle
+ */
+ VkRenderPass getDefaultRenderPassHandle() const {
+ return m_renderPass->getDefaultHandle();
+ }
+
+ /**
+ * \brief Retrieves render pass handle
+ *
+ * Retrieves a render pass handle that can
+ * be used to begin a render pass instance.
+ * \param [in] ops Render pass ops
+ * \returns The render pass handle
+ */
+ VkRenderPass getRenderPassHandle(const DxvkRenderPassOps& ops) const {
+ return m_renderPass->getHandle(ops);
+ }
+
+ /**
+ * \brief Retrieves render pass
+ * \returns Render pass reference
+ */
+ DxvkRenderPass* getRenderPass() const {
+ return m_renderPass;
+ }
+
+ /**
+ * \brief Depth-stencil target
+ * \returns Depth-stencil target
+ */
+ const DxvkAttachment& getDepthTarget() const {
+ return m_renderTargets.depth;
+ }
+
+ /**
+ * \brief Color target
+ *
+ * \param [in] id Target Index
+ * \returns The color target
+ */
+ const DxvkAttachment& getColorTarget(uint32_t id) const {
+ return m_renderTargets.color[id];
+ }
+
+ /**
+ * \brief Number of framebuffer attachment
+ * \returns Total attachment count
+ */
+ uint32_t numAttachments() const {
+ return m_attachmentCount;
+ }
+
+ /**
+ * \brief Queries color attachment index of a given attachment
+ * \returns The index, or -1 if the given attachment is the depth attachment
+ */
+ const int32_t getColorAttachmentIndex(uint32_t id) const {
+ return m_attachments[id];
+ }
+
+ /**
+ * \brief Retrieves attachment by index
+ *
+ * \param [in] id Framebuffer attachment ID
+ * \returns The framebuffer attachment
+ */
+ const DxvkAttachment& getAttachment(uint32_t id) const {
+ int32_t idx = getColorAttachmentIndex(id);
+ return idx < 0 ? m_renderTargets.depth : m_renderTargets.color[idx];
+ }
+
+ /**
+ * \brief Finds attachment index by view
+ *
+ * Color attachments start at 0
+ * \param [in] view Image view
+ * \returns Attachment index
+ */
+ int32_t findAttachment(const Rc<DxvkImageView>& view) const;
+
+ /**
+ * \brief Checks whether the framebuffer's targets match
+ *
+ * \param [in] renderTargets Render targets to check
+ * \returns \c true if the render targets are the same
+ * as the ones used for this framebuffer object.
+ */
+ bool hasTargets(const DxvkRenderTargets& renderTargets);
+
+ /**
+ * \brief Checks whether view and framebuffer sizes match
+ *
+ * Tests whether the size of the framebuffer is the same
+ * as the size of one of its views. This may be \c false
+ * when mixing attachments with mismatched dimensions.
+ * \param [in] view Image view to test
+ * \returns \c true if \c view has the same size as
+ * the framebuffer.
+ */
+ bool isFullSize(const Rc<DxvkImageView>& view) const;
+
+ /**
+ * \brief Checks whether an attachment is writable
+ *
+ * Needed for certain clear optimizations.
+ * \param [in] attachmentIndex Attachment to check
+ * \param [in] aspects Aspect mask to check
+ * \returns \c true if all aspects can be written for the given attachment
+ */
+ bool isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const;
+
+ /**
+ * \brief Generatess render pass format
+ *
+ * This render pass format can be used to
+ * look up a compatible render pass.
+ * \param [in] renderTargets Render targets
+ * \returns The render pass format
+ */
+ static DxvkRenderPassFormat getRenderPassFormat(
+ const DxvkRenderTargets& renderTargets);
+
+ private:
+
+ const Rc<vk::DeviceFn> m_vkd;
+ DxvkRenderPass* m_renderPass;
+ const DxvkRenderTargets m_renderTargets;
+ const DxvkFramebufferSize m_renderSize;
+
+ uint32_t m_attachmentCount = 0;
+ std::array<int32_t, MaxNumRenderTargets + 1> m_attachments;
+
+ VkFramebuffer m_handle = VK_NULL_HANDLE;
+
+ DxvkFramebufferSize computeRenderSize(
+ const DxvkFramebufferSize& defaultSize) const;
+
+ DxvkFramebufferSize computeRenderTargetSize(
+ const Rc<DxvkImageView>& renderTarget) const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.cpp
new file mode 100644
index 00000000..55a5004c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.cpp
@@ -0,0 +1,104 @@
+#include "dxvk_gpu_event.h"
+#include "dxvk_device.h"
+
+namespace dxvk {
+
+ DxvkGpuEvent::DxvkGpuEvent(const Rc<vk::DeviceFn>& vkd)
+ : m_vkd(vkd) { }
+
+
+ DxvkGpuEvent::~DxvkGpuEvent() {
+ if (m_handle.pool && m_handle.event)
+ m_handle.pool->freeEvent(m_handle.event);
+ }
+
+
+ DxvkGpuEventStatus DxvkGpuEvent::test() const {
+ if (!m_handle.event)
+ return DxvkGpuEventStatus::Invalid;
+
+ VkResult status = m_vkd->vkGetEventStatus(
+ m_vkd->device(), m_handle.event);
+
+ switch (status) {
+ case VK_EVENT_SET: return DxvkGpuEventStatus::Signaled;
+ case VK_EVENT_RESET: return DxvkGpuEventStatus::Pending;
+ default: return DxvkGpuEventStatus::Invalid;
+ }
+ }
+
+
+ DxvkGpuEventHandle DxvkGpuEvent::reset(DxvkGpuEventHandle handle) {
+ m_vkd->vkResetEvent(m_vkd->device(), handle.event);
+ return std::exchange(m_handle, handle);
+ }
+
+
+
+
+ DxvkGpuEventPool::DxvkGpuEventPool(const DxvkDevice* device)
+ : m_vkd(device->vkd()) { }
+
+
+ DxvkGpuEventPool::~DxvkGpuEventPool() {
+ for (VkEvent ev : m_events)
+ m_vkd->vkDestroyEvent(m_vkd->device(), ev, nullptr);
+ }
+
+
+ DxvkGpuEventHandle DxvkGpuEventPool::allocEvent() {
+ VkEvent event = VK_NULL_HANDLE;
+
+ { std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ if (m_events.size() > 0) {
+ event = m_events.back();
+ m_events.pop_back();
+ }
+ }
+
+ if (!event) {
+ VkEventCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+
+ VkResult status = m_vkd->vkCreateEvent(
+ m_vkd->device(), &info, nullptr, &event);
+
+ if (status != VK_SUCCESS) {
+ Logger::err("DXVK: Failed to create GPU event");
+ return DxvkGpuEventHandle();
+ }
+ }
+
+ return { this, event };
+ }
+
+
+ void DxvkGpuEventPool::freeEvent(VkEvent event) {
+ std::lock_guard<sync::Spinlock> lock(m_mutex);
+ m_events.push_back(event);
+ }
+
+
+
+
+ DxvkGpuEventTracker::DxvkGpuEventTracker() { }
+ DxvkGpuEventTracker::~DxvkGpuEventTracker() { }
+
+
+ void DxvkGpuEventTracker::trackEvent(DxvkGpuEventHandle handle) {
+ if (handle.pool && handle.event)
+ m_handles.push_back(handle);
+ }
+
+
+ void DxvkGpuEventTracker::reset() {
+ for (const auto& h : m_handles)
+ h.pool->freeEvent(h.event);
+
+ m_handles.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.h
new file mode 100644
index 00000000..143ceacf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_event.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+ class DxvkGpuEventPool;
+
+ /**
+ * \brief Event status
+ *
+ * Reports whether the event is in
+ * a signaled or unsignaled state.
+ */
+ enum class DxvkGpuEventStatus : uint32_t {
+ Invalid = 0,
+ Pending = 1,
+ Signaled = 2,
+ };
+
+
+ /**
+ * \brief Event handle
+ *
+ * Stores the event handle itself as well
+ * as a pointer to the pool that the event
+ * was allocated from.
+ */
+ struct DxvkGpuEventHandle {
+ DxvkGpuEventPool* pool = nullptr;
+ VkEvent event = VK_NULL_HANDLE;
+ };
+
+
+ /**
+ * \brief GPU event
+ *
+ * An event managed by the GPU which allows
+ * the application to check whether a specific
+ * command has completed execution.
+ */
+ class DxvkGpuEvent : public DxvkResource {
+
+ public:
+
+ DxvkGpuEvent(const Rc<vk::DeviceFn>& vkd);
+ ~DxvkGpuEvent();
+
+ /**
+ * \brief Retrieves event status
+ *
+ * Only valid after the event has been
+ * recorded intro a command buffer.
+ * \returns Event status
+ */
+ DxvkGpuEventStatus test() const;
+
+ /**
+ * \brief Resets event
+ *
+ * Assigns a new Vulkan event to this event
+ * object and replaces the old one. The old
+ * event should be freed as soon as the GPU
+ * stops using it.
+ * \param [in] handle New GPU event handle
+ * \returns Old GPU event handle
+ */
+ DxvkGpuEventHandle reset(DxvkGpuEventHandle handle);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkGpuEventHandle m_handle;
+
+ };
+
+
+ /**
+ * \brief Event pool
+ *
+ * Thread-safe event allocator that provides
+ * a way to create and recycle Vulkan events.
+ */
+ class DxvkGpuEventPool {
+
+ public:
+
+ DxvkGpuEventPool(const DxvkDevice* device);
+ ~DxvkGpuEventPool();
+
+ /**
+ * \brief Allocates an event
+ *
+ * Either returns a recycled event, or
+ * creates a new one if necessary. The
+ * state of the event is undefined.
+ * \returns An event handle
+ */
+ DxvkGpuEventHandle allocEvent();
+
+ /**
+ * \brief Recycles an event
+ *
+ * \param [in] handle Event to free
+ */
+ void freeEvent(VkEvent event);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ sync::Spinlock m_mutex;
+ std::vector<VkEvent> m_events;
+
+ };
+
+
+ /**
+ * \brief GPU event tracker
+ *
+ * Stores events currently accessed by the
+ * GPU, and returns them to the event pool
+ * once they are no longer in use.
+ */
+ class DxvkGpuEventTracker {
+
+ public:
+
+ DxvkGpuEventTracker();
+ ~DxvkGpuEventTracker();
+
+ /**
+ * \brief Tracks an event
+ * \param [in] handle Event to track
+ */
+ void trackEvent(DxvkGpuEventHandle handle);
+
+ /**
+ * \brief Resets event tracker
+ *
+ * Releases all tracked events back
+ * to the respective event pool
+ */
+ void reset();
+
+ private:
+
+ std::vector<DxvkGpuEventHandle> m_handles;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.cpp
new file mode 100644
index 00000000..c42ed75f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.cpp
@@ -0,0 +1,456 @@
+#include <algorithm>
+
+#include "dxvk_cmdlist.h"
+#include "dxvk_device.h"
+#include "dxvk_gpu_query.h"
+
+namespace dxvk {
+
+ DxvkGpuQuery::DxvkGpuQuery(
+ const Rc<vk::DeviceFn>& vkd,
+ VkQueryType type,
+ VkQueryControlFlags flags,
+ uint32_t index)
+ : m_vkd(vkd), m_type(type), m_flags(flags),
+ m_index(index), m_ended(false) {
+
+ }
+
+
+ DxvkGpuQuery::~DxvkGpuQuery() {
+ if (m_handle.queryPool)
+ m_handle.allocator->freeQuery(m_handle);
+
+ for (DxvkGpuQueryHandle handle : m_handles)
+ handle.allocator->freeQuery(handle);
+ }
+
+
+ bool DxvkGpuQuery::isIndexed() const {
+ return m_type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
+ }
+
+
+ DxvkGpuQueryStatus DxvkGpuQuery::getData(DxvkQueryData& queryData) const {
+ queryData = DxvkQueryData();
+
+ if (!m_ended)
+ return DxvkGpuQueryStatus::Invalid;
+
+ // Empty begin/end pair
+ if (!m_handle.queryPool)
+ return DxvkGpuQueryStatus::Available;
+
+ // Get query data from all associated handles
+ DxvkGpuQueryStatus status = getDataForHandle(queryData, m_handle);
+
+ for (size_t i = 0; i < m_handles.size()
+ && status == DxvkGpuQueryStatus::Available; i++)
+ status = getDataForHandle(queryData, m_handles[i]);
+
+ // Treat non-precise occlusion queries as available
+ // if we already know the result will be non-zero
+ if ((status == DxvkGpuQueryStatus::Pending)
+ && (m_type == VK_QUERY_TYPE_OCCLUSION)
+ && !(m_flags & VK_QUERY_CONTROL_PRECISE_BIT)
+ && (queryData.occlusion.samplesPassed))
+ status = DxvkGpuQueryStatus::Available;
+
+ return status;
+ }
+
+
+ void DxvkGpuQuery::begin(const Rc<DxvkCommandList>& cmd) {
+ m_ended = false;
+
+ cmd->trackGpuQuery(m_handle);
+ m_handle = DxvkGpuQueryHandle();
+
+ for (const auto& handle : m_handles)
+ cmd->trackGpuQuery(handle);
+ m_handles.clear();
+ }
+
+
+ void DxvkGpuQuery::end() {
+ m_ended = true;
+ }
+
+
+ void DxvkGpuQuery::addQueryHandle(const DxvkGpuQueryHandle& handle) {
+ if (m_handle.queryPool)
+ m_handles.push_back(m_handle);
+
+ m_handle = handle;
+ }
+
+
+ DxvkGpuQueryStatus DxvkGpuQuery::getDataForHandle(
+ DxvkQueryData& queryData,
+ const DxvkGpuQueryHandle& handle) const {
+ DxvkQueryData tmpData;
+
+ // Wait for the query to be reset first
+ VkResult result;
+
+ if (handle.resetEvent) {
+ result = m_vkd->vkGetEventStatus(
+ m_vkd->device(), handle.resetEvent);
+
+ if (result == VK_EVENT_RESET)
+ return DxvkGpuQueryStatus::Pending;
+ else if (result != VK_EVENT_SET)
+ return DxvkGpuQueryStatus::Failed;
+ }
+
+ // Try to copy query data to temporary structure
+ result = m_vkd->vkGetQueryPoolResults(m_vkd->device(),
+ handle.queryPool, handle.queryId, 1,
+ sizeof(DxvkQueryData), &tmpData,
+ sizeof(DxvkQueryData), VK_QUERY_RESULT_64_BIT);
+
+ if (result == VK_NOT_READY)
+ return DxvkGpuQueryStatus::Pending;
+ else if (result != VK_SUCCESS)
+ return DxvkGpuQueryStatus::Failed;
+
+ // Add numbers to the destination structure
+ switch (m_type) {
+ case VK_QUERY_TYPE_OCCLUSION:
+ queryData.occlusion.samplesPassed += tmpData.occlusion.samplesPassed;
+ break;
+
+ case VK_QUERY_TYPE_TIMESTAMP:
+ queryData.timestamp.time = tmpData.timestamp.time;
+ break;
+
+ case VK_QUERY_TYPE_PIPELINE_STATISTICS:
+ queryData.statistic.iaVertices += tmpData.statistic.iaVertices;
+ queryData.statistic.iaPrimitives += tmpData.statistic.iaPrimitives;
+ queryData.statistic.vsInvocations += tmpData.statistic.vsInvocations;
+ queryData.statistic.gsInvocations += tmpData.statistic.gsInvocations;
+ queryData.statistic.gsPrimitives += tmpData.statistic.gsPrimitives;
+ queryData.statistic.clipInvocations += tmpData.statistic.clipInvocations;
+ queryData.statistic.clipPrimitives += tmpData.statistic.clipPrimitives;
+ queryData.statistic.fsInvocations += tmpData.statistic.fsInvocations;
+ queryData.statistic.tcsPatches += tmpData.statistic.tcsPatches;
+ queryData.statistic.tesInvocations += tmpData.statistic.tesInvocations;
+ queryData.statistic.csInvocations += tmpData.statistic.csInvocations;
+ break;
+
+ case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
+ queryData.xfbStream.primitivesWritten += tmpData.xfbStream.primitivesWritten;
+ queryData.xfbStream.primitivesNeeded += tmpData.xfbStream.primitivesNeeded;
+ break;
+
+ default:
+ Logger::err(str::format("DXVK: Unhandled query type: ", m_type));
+ return DxvkGpuQueryStatus::Invalid;
+ }
+
+ return DxvkGpuQueryStatus::Available;
+ }
+
+
+
+
+ DxvkGpuQueryAllocator::DxvkGpuQueryAllocator(
+ DxvkDevice* device,
+ VkQueryType queryType,
+ uint32_t queryPoolSize)
+ : m_device (device),
+ m_vkd (device->vkd()),
+ m_queryType (queryType),
+ m_queryPoolSize (queryPoolSize) {
+
+ }
+
+
+ DxvkGpuQueryAllocator::~DxvkGpuQueryAllocator() {
+ for (DxvkGpuQueryHandle handle : m_handles) {
+ m_vkd->vkDestroyEvent(m_vkd->device(),
+ handle.resetEvent, nullptr);
+ }
+
+ for (VkQueryPool pool : m_pools) {
+ m_vkd->vkDestroyQueryPool(
+ m_vkd->device(), pool, nullptr);
+ }
+ }
+
+
+ DxvkGpuQueryHandle DxvkGpuQueryAllocator::allocQuery() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_handles.size() == 0)
+ this->createQueryPool();
+
+ if (m_handles.size() == 0)
+ return DxvkGpuQueryHandle();
+
+ DxvkGpuQueryHandle result = m_handles.back();
+ m_handles.pop_back();
+ return result;
+ }
+
+
+ void DxvkGpuQueryAllocator::freeQuery(DxvkGpuQueryHandle handle) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ m_handles.push_back(handle);
+ }
+
+
+ void DxvkGpuQueryAllocator::createQueryPool() {
+ VkQueryPoolCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.queryType = m_queryType;
+ info.queryCount = m_queryPoolSize;
+ info.pipelineStatistics = 0;
+
+ if (m_queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
+ info.pipelineStatistics
+ = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
+ | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
+ }
+
+ VkQueryPool queryPool = VK_NULL_HANDLE;
+
+ if (m_vkd->vkCreateQueryPool(m_vkd->device(), &info, nullptr, &queryPool)) {
+ Logger::err(str::format("DXVK: Failed to create query pool (", m_queryType, "; ", m_queryPoolSize, ")"));
+ return;
+ }
+
+ m_pools.push_back(queryPool);
+
+ VkEventCreateInfo eventInfo;
+ eventInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+ eventInfo.pNext = nullptr;
+ eventInfo.flags = 0;
+
+ for (uint32_t i = 0; i < m_queryPoolSize; i++) {
+ VkEvent event = VK_NULL_HANDLE;
+
+ if (!m_device->features().extHostQueryReset.hostQueryReset
+ && m_vkd->vkCreateEvent(m_vkd->device(), &eventInfo, nullptr, &event) != VK_SUCCESS) {
+ Logger::err("DXVK: Failed to create query reset event");
+ return;
+ }
+
+ m_handles.push_back({ this, event, queryPool, i });
+ }
+ }
+
+
+
+
+ DxvkGpuQueryPool::DxvkGpuQueryPool(DxvkDevice* device)
+ : m_occlusion(device, VK_QUERY_TYPE_OCCLUSION, 16384),
+ m_statistic(device, VK_QUERY_TYPE_PIPELINE_STATISTICS, 1024),
+ m_timestamp(device, VK_QUERY_TYPE_TIMESTAMP, 1024),
+ m_xfbStream(device, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 1024) {
+
+ }
+
+
+ DxvkGpuQueryPool::~DxvkGpuQueryPool() {
+
+ }
+
+
+ DxvkGpuQueryHandle DxvkGpuQueryPool::allocQuery(VkQueryType type) {
+ switch (type) {
+ case VK_QUERY_TYPE_OCCLUSION:
+ return m_occlusion.allocQuery();
+ case VK_QUERY_TYPE_PIPELINE_STATISTICS:
+ return m_statistic.allocQuery();
+ case VK_QUERY_TYPE_TIMESTAMP:
+ return m_timestamp.allocQuery();
+ case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
+ return m_xfbStream.allocQuery();
+ default:
+ Logger::err(str::format("DXVK: Unhandled query type: ", type));
+ return DxvkGpuQueryHandle();
+ }
+ }
+
+
+
+
+ DxvkGpuQueryManager::DxvkGpuQueryManager(DxvkGpuQueryPool& pool)
+ : m_pool(&pool), m_activeTypes(0) {
+
+ }
+
+
+ DxvkGpuQueryManager::~DxvkGpuQueryManager() {
+
+ }
+
+
+ void DxvkGpuQueryManager::enableQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query) {
+ query->begin(cmd);
+
+ m_activeQueries.push_back(query);
+
+ if (m_activeTypes & getQueryTypeBit(query->type()))
+ beginSingleQuery(cmd, query);
+ }
+
+
+ void DxvkGpuQueryManager::disableQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query) {
+ auto iter = std::find(
+ m_activeQueries.begin(),
+ m_activeQueries.end(),
+ query);
+
+ if (iter != m_activeQueries.end()) {
+ if (m_activeTypes & getQueryTypeBit((*iter)->type()))
+ endSingleQuery(cmd, query);
+ m_activeQueries.erase(iter);
+
+ query->end();
+ }
+ }
+
+
+ void DxvkGpuQueryManager::writeTimestamp(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query) {
+ DxvkGpuQueryHandle handle = m_pool->allocQuery(query->type());
+
+ query->begin(cmd);
+ query->addQueryHandle(handle);
+ query->end();
+
+ cmd->cmdResetQuery(
+ handle.queryPool,
+ handle.queryId,
+ handle.resetEvent);
+
+ cmd->cmdWriteTimestamp(
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ handle.queryPool,
+ handle.queryId);
+
+ cmd->trackResource<DxvkAccess::None>(query);
+ }
+
+
+ void DxvkGpuQueryManager::beginQueries(
+ const Rc<DxvkCommandList>& cmd,
+ VkQueryType type) {
+ m_activeTypes |= getQueryTypeBit(type);
+
+ for (size_t i = 0; i < m_activeQueries.size(); i++) {
+ if (m_activeQueries[i]->type() == type)
+ beginSingleQuery(cmd, m_activeQueries[i]);
+ }
+ }
+
+
+ void DxvkGpuQueryManager::endQueries(
+ const Rc<DxvkCommandList>& cmd,
+ VkQueryType type) {
+ m_activeTypes &= ~getQueryTypeBit(type);
+
+ for (size_t i = 0; i < m_activeQueries.size(); i++) {
+ if (m_activeQueries[i]->type() == type)
+ endSingleQuery(cmd, m_activeQueries[i]);
+ }
+ }
+
+
+ void DxvkGpuQueryManager::beginSingleQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query) {
+ DxvkGpuQueryHandle handle = m_pool->allocQuery(query->type());
+
+ cmd->cmdResetQuery(
+ handle.queryPool,
+ handle.queryId,
+ handle.resetEvent);
+
+ if (query->isIndexed()) {
+ cmd->cmdBeginQueryIndexed(
+ handle.queryPool,
+ handle.queryId,
+ query->flags(),
+ query->index());
+ } else {
+ cmd->cmdBeginQuery(
+ handle.queryPool,
+ handle.queryId,
+ query->flags());
+ }
+
+ query->addQueryHandle(handle);
+ }
+
+
+ void DxvkGpuQueryManager::endSingleQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query) {
+ DxvkGpuQueryHandle handle = query->handle();
+
+ if (query->isIndexed()) {
+ cmd->cmdEndQueryIndexed(
+ handle.queryPool,
+ handle.queryId,
+ query->index());
+ } else {
+ cmd->cmdEndQuery(
+ handle.queryPool,
+ handle.queryId);
+ }
+
+ cmd->trackResource<DxvkAccess::None>(query);
+ }
+
+
+ uint32_t DxvkGpuQueryManager::getQueryTypeBit(
+ VkQueryType type) {
+ switch (type) {
+ case VK_QUERY_TYPE_OCCLUSION: return 0x01;
+ case VK_QUERY_TYPE_PIPELINE_STATISTICS: return 0x02;
+ case VK_QUERY_TYPE_TIMESTAMP: return 0x04;
+ case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT: return 0x08;
+ default: return 0;
+ }
+ }
+
+
+
+
+ DxvkGpuQueryTracker::DxvkGpuQueryTracker() { }
+ DxvkGpuQueryTracker::~DxvkGpuQueryTracker() { }
+
+
+ void DxvkGpuQueryTracker::trackQuery(DxvkGpuQueryHandle handle) {
+ if (handle.queryPool)
+ m_handles.push_back(handle);
+ }
+
+
+ void DxvkGpuQueryTracker::reset() {
+ for (DxvkGpuQueryHandle handle : m_handles)
+ handle.allocator->freeQuery(handle);
+
+ m_handles.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.h
new file mode 100644
index 00000000..e410f9ee
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_gpu_query.h
@@ -0,0 +1,449 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ class DxvkCommandList;
+
+ class DxvkGpuQueryPool;
+ class DxvkGpuQueryAllocator;
+
+ /**
+ * \brief Query status
+ *
+ * Reports whether a query is in
+ * signaled or unsignaled state.
+ */
+ enum class DxvkGpuQueryStatus : uint32_t {
+ Invalid = 0,
+ Pending = 1,
+ Available = 2,
+ Failed = 3,
+ };
+
+
+ /**
+ * \brief Occlusion query data
+ *
+ * Stores the number of samples
+ * that passes fragment tests.
+ */
+ struct DxvkQueryOcclusionData {
+ uint64_t samplesPassed;
+ };
+
+ /**
+ * \brief Timestamp data
+ *
+ * Stores a GPU time stamp.
+ */
+ struct DxvkQueryTimestampData {
+ uint64_t time;
+ };
+
+ /**
+ * \brief Pipeline statistics
+ *
+ * Stores the counters for
+ * pipeline statistics queries.
+ */
+ struct DxvkQueryStatisticData {
+ uint64_t iaVertices;
+ uint64_t iaPrimitives;
+ uint64_t vsInvocations;
+ uint64_t gsInvocations;
+ uint64_t gsPrimitives;
+ uint64_t clipInvocations;
+ uint64_t clipPrimitives;
+ uint64_t fsInvocations;
+ uint64_t tcsPatches;
+ uint64_t tesInvocations;
+ uint64_t csInvocations;
+ };
+
+ /**
+ * \brief Transform feedback stream query
+ *
+ * Stores the number of primitives written to the
+ * buffer, as well as the number of primitives
+ * generated. The latter can be used to check for
+ * overflow.
+ */
+ struct DxvkQueryXfbStreamData {
+ uint64_t primitivesWritten;
+ uint64_t primitivesNeeded;
+ };
+
+ /**
+ * \brief Query data
+ *
+ * A union that stores query data. Select an
+ * appropriate member based on the query type.
+ */
+ union DxvkQueryData {
+ DxvkQueryOcclusionData occlusion;
+ DxvkQueryTimestampData timestamp;
+ DxvkQueryStatisticData statistic;
+ DxvkQueryXfbStreamData xfbStream;
+ };
+
+
+ /**
+ * \brief Query handle
+ *
+ * Stores the query allocator, as well as
+ * the actual pool and query index. Since
+ * query pools have to be reset on the GPU,
+ * this also comes with a reset event.
+ */
+ struct DxvkGpuQueryHandle {
+ DxvkGpuQueryAllocator* allocator = nullptr;
+ VkEvent resetEvent = VK_NULL_HANDLE;
+ VkQueryPool queryPool = VK_NULL_HANDLE;
+ uint32_t queryId = 0;
+ };
+
+
+ /**
+ * \brief Query object
+ *
+ * Manages Vulkan queries that are sub-allocated
+ * from larger query pools
+ */
+ class DxvkGpuQuery : public DxvkResource {
+
+ public:
+
+ DxvkGpuQuery(
+ const Rc<vk::DeviceFn>& vkd,
+ VkQueryType type,
+ VkQueryControlFlags flags,
+ uint32_t index);
+
+ ~DxvkGpuQuery();
+
+ /**
+ * \brief Query type
+ * \returns Query type
+ */
+ VkQueryType type() const {
+ return m_type;
+ }
+
+ /**
+ * \brief Query control flags
+ * \returns Query control flags
+ */
+ VkQueryControlFlags flags() const {
+ return m_flags;
+ }
+
+ /**
+ * \brief Retrieves current handle
+ *
+ * Note that the query handle will change
+ * when calling \ref addQueryHandle.
+ * \returns Current query handle
+ */
+ DxvkGpuQueryHandle handle() const {
+ return m_handle;
+ }
+
+ /**
+ * \brief Query index
+ *
+ * Only valid for indexed query types.
+ * For non-zero values, indexed query
+ * functions must be used.
+ * \returns Query index
+ */
+ uint32_t index() const {
+ return m_index;
+ }
+
+ /**
+ * \brief Checks whether query is indexed
+ * \returns \c true for indexed query types
+ */
+ bool isIndexed() const;
+
+ /**
+ * \brief Retrieves query data
+ *
+ * If all query data is available, this will
+ * return \c DxvkGpuQueryStatus::Signaled, and
+ * the destination structure will be filled
+ * with the data retrieved from all associated
+ * query handles.
+ * \param [out] queryData Query data
+ * \returns Current query status
+ */
+ DxvkGpuQueryStatus getData(
+ DxvkQueryData& queryData) const;
+
+ /**
+ * \brief Begins query
+ *
+ * Moves all current query handles to the given
+ * command list and sets the query into active
+ * state. No data can be retrieved while the
+ * query is active.
+ * \param [in] cmd Command list
+ */
+ void begin(
+ const Rc<DxvkCommandList>& cmd);
+
+ /**
+ * \brief Ends query
+ *
+ * Sets query into pending state. Calling
+ * \c getData is legal after calling this.
+ */
+ void end();
+
+ /**
+ * \brief Adds a query handle to the query
+ *
+ * The given query handle shall be used when
+ * retrieving query data. A query can have
+ * multiple handles attached.
+ * \param [in] handle The query handle
+ */
+ void addQueryHandle(
+ const DxvkGpuQueryHandle& handle);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkQueryType m_type;
+ VkQueryControlFlags m_flags;
+ uint32_t m_index;
+ bool m_ended;
+
+ DxvkGpuQueryHandle m_handle;
+
+ std::vector<DxvkGpuQueryHandle> m_handles;
+
+ DxvkGpuQueryStatus getDataForHandle(
+ DxvkQueryData& queryData,
+ const DxvkGpuQueryHandle& handle) const;
+
+ };
+
+
+ /**
+ * \brief Query allocator
+ *
+ * Creates query pools and allocates
+ * queries for a single query type.
+ */
+ class DxvkGpuQueryAllocator {
+
+ public:
+
+ DxvkGpuQueryAllocator(
+ DxvkDevice* device,
+ VkQueryType queryType,
+ uint32_t queryPoolSize);
+
+ ~DxvkGpuQueryAllocator();
+
+ /**
+ * \brief Allocates a query
+ *
+ * If possible, this returns a free query
+ * from an existing query pool. Otherwise,
+ * a new query pool will be created.
+ * \returns Query handle
+ */
+ DxvkGpuQueryHandle allocQuery();
+
+ /**
+ * \brief Recycles a query
+ *
+ * Returns a query back to the allocator
+ * so that it can be reused. The query
+ * must not be in pending state.
+ * \param [in] handle Query to reset
+ */
+ void freeQuery(DxvkGpuQueryHandle handle);
+
+ private:
+
+ DxvkDevice* m_device;
+ Rc<vk::DeviceFn> m_vkd;
+ VkQueryType m_queryType;
+ uint32_t m_queryPoolSize;
+
+ dxvk::mutex m_mutex;
+ std::vector<DxvkGpuQueryHandle> m_handles;
+ std::vector<VkQueryPool> m_pools;
+
+ void createQueryPool();
+
+ };
+
+
+ /**
+ * \brief Query pool
+ *
+ * Small wrapper class that manages query
+ * allocators for all supported query types,
+ */
+ class DxvkGpuQueryPool {
+
+ public:
+
+ DxvkGpuQueryPool(DxvkDevice* device);
+
+ ~DxvkGpuQueryPool();
+
+ /**
+ * \brief Allocates a single query
+ *
+ * \param [in] type Query type
+ * \returns Handle to the allocated query
+ */
+ DxvkGpuQueryHandle allocQuery(VkQueryType type);
+
+ private:
+
+ DxvkGpuQueryAllocator m_occlusion;
+ DxvkGpuQueryAllocator m_statistic;
+ DxvkGpuQueryAllocator m_timestamp;
+ DxvkGpuQueryAllocator m_xfbStream;
+
+ };
+
+
+ /**
+ * \brief Query manager
+ *
+ * Keeps track of enabled and disabled queries
+ * and assigns Vulkan queries to them as needed.
+ */
+ class DxvkGpuQueryManager {
+
+ public:
+
+ DxvkGpuQueryManager(DxvkGpuQueryPool& pool);
+
+ ~DxvkGpuQueryManager();
+
+ /**
+ * \brief Enables a query
+ *
+ * This will also immediately begin the
+ * query in case the query type is active.
+ * \param [in] cmd Command list
+ * \param [in] query Query to allocate
+ */
+ void enableQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Disables a query
+ *
+ * This will also immediately end the
+ * query in case the query type is active.
+ * \param [in] cmd Command list
+ * \param [in] query Query to allocate
+ */
+ void disableQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Signals a time stamp query
+ *
+ * Timestamp queries are not scoped.
+ * \param [in] cmd Command list
+ * \param [in] query Query to allocate
+ */
+ void writeTimestamp(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query);
+
+ /**
+ * \brief Begins queries of a given type
+ *
+ * Makes a query type \e active. Begins
+ * all enabled queries of this type.
+ * \param [in] cmd Command list
+ * \param [in] type Query type
+ */
+ void beginQueries(
+ const Rc<DxvkCommandList>& cmd,
+ VkQueryType type);
+
+ /**
+ * \brief Ends queries of a given type
+ *
+ * Makes a query type \e inactive. Ends
+ * all enabled queries of this type.
+ * \param [in] cmd Command list
+ * \param [in] type Query type
+ */
+ void endQueries(
+ const Rc<DxvkCommandList>& cmd,
+ VkQueryType type);
+
+ private:
+
+ DxvkGpuQueryPool* m_pool;
+ uint32_t m_activeTypes;
+ std::vector<Rc<DxvkGpuQuery>> m_activeQueries;
+
+ void beginSingleQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query);
+
+ void endSingleQuery(
+ const Rc<DxvkCommandList>& cmd,
+ const Rc<DxvkGpuQuery>& query);
+
+ static uint32_t getQueryTypeBit(
+ VkQueryType type);
+
+ };
+
+
+ /**
+ * \brief Query tracker
+ *
+ * Returns queries to their allocators after
+ * the command buffer has finished executing.
+ */
+ class DxvkGpuQueryTracker {
+
+ public:
+
+ DxvkGpuQueryTracker();
+ ~DxvkGpuQueryTracker();
+
+ /**
+ * \param Tracks a query
+ * \param [in] handle Query handle
+ */
+ void trackQuery(DxvkGpuQueryHandle handle);
+
+ /**
+ * \brief Recycles all tracked handles
+ *
+ * Releases all tracked query handles
+ * to their respective query allocator.
+ */
+ void reset();
+
+ private:
+
+ std::vector<DxvkGpuQueryHandle> m_handles;
+
+ };
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.cpp
new file mode 100644
index 00000000..96bdb050
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.cpp
@@ -0,0 +1,561 @@
+#include "../util/util_time.h"
+
+#include "dxvk_device.h"
+#include "dxvk_graphics.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_spec_const.h"
+#include "dxvk_state_cache.h"
+
+namespace dxvk {
+
+ DxvkGraphicsPipeline::DxvkGraphicsPipeline(
+ DxvkPipelineManager* pipeMgr,
+ DxvkGraphicsPipelineShaders shaders)
+ : m_vkd(pipeMgr->m_device->vkd()), m_pipeMgr(pipeMgr),
+ m_shaders(std::move(shaders)) {
+ if (m_shaders.vs != nullptr) m_shaders.vs ->defineResourceSlots(m_slotMapping);
+ if (m_shaders.tcs != nullptr) m_shaders.tcs->defineResourceSlots(m_slotMapping);
+ if (m_shaders.tes != nullptr) m_shaders.tes->defineResourceSlots(m_slotMapping);
+ if (m_shaders.gs != nullptr) m_shaders.gs ->defineResourceSlots(m_slotMapping);
+ if (m_shaders.fs != nullptr) m_shaders.fs ->defineResourceSlots(m_slotMapping);
+
+ m_slotMapping.makeDescriptorsDynamic(
+ pipeMgr->m_device->options().maxNumDynamicUniformBuffers,
+ pipeMgr->m_device->options().maxNumDynamicStorageBuffers);
+
+ m_layout = new DxvkPipelineLayout(m_vkd,
+ m_slotMapping, VK_PIPELINE_BIND_POINT_GRAPHICS);
+
+ m_vsIn = m_shaders.vs != nullptr ? m_shaders.vs->interfaceSlots().inputSlots : 0;
+ m_fsOut = m_shaders.fs != nullptr ? m_shaders.fs->interfaceSlots().outputSlots : 0;
+
+ if (m_shaders.gs != nullptr && m_shaders.gs->flags().test(DxvkShaderFlag::HasTransformFeedback))
+ m_flags.set(DxvkGraphicsPipelineFlag::HasTransformFeedback);
+
+ if (m_layout->getStorageDescriptorStages())
+ m_flags.set(DxvkGraphicsPipelineFlag::HasStorageDescriptors);
+
+ m_common.msSampleShadingEnable = m_shaders.fs != nullptr && m_shaders.fs->flags().test(DxvkShaderFlag::HasSampleRateShading);
+ m_common.msSampleShadingFactor = 1.0f;
+ }
+
+
+ DxvkGraphicsPipeline::~DxvkGraphicsPipeline() {
+ for (const auto& instance : m_pipelines)
+ this->destroyPipeline(instance.pipeline());
+ }
+
+
+ Rc<DxvkShader> DxvkGraphicsPipeline::getShader(
+ VkShaderStageFlagBits stage) const {
+ switch (stage) {
+ case VK_SHADER_STAGE_VERTEX_BIT: return m_shaders.vs;
+ case VK_SHADER_STAGE_GEOMETRY_BIT: return m_shaders.gs;
+ case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return m_shaders.tcs;
+ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return m_shaders.tes;
+ case VK_SHADER_STAGE_FRAGMENT_BIT: return m_shaders.fs;
+ default:
+ return nullptr;
+ }
+ }
+
+
+ VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) {
+ DxvkGraphicsPipelineInstance* instance = nullptr;
+
+ { std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ instance = this->findInstance(state, renderPass);
+
+ if (instance)
+ return instance->pipeline();
+
+ instance = this->createInstance(state, renderPass);
+ }
+
+ if (!instance)
+ return VK_NULL_HANDLE;
+
+ this->writePipelineStateToCache(state, renderPass->format());
+ return instance->pipeline();
+ }
+
+
+ void DxvkGraphicsPipeline::compilePipeline(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) {
+ std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ if (!this->findInstance(state, renderPass))
+ this->createInstance(state, renderPass);
+ }
+
+
+ DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::createInstance(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) {
+ // If the pipeline state vector is invalid, don't try
+ // to create a new pipeline, it won't work anyway.
+ if (!this->validatePipelineState(state))
+ return nullptr;
+
+ VkPipeline newPipelineHandle = this->createPipeline(state, renderPass);
+
+ m_pipeMgr->m_numGraphicsPipelines += 1;
+ return &m_pipelines.emplace_back(state, renderPass, newPipelineHandle);
+ }
+
+
+ DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) {
+ for (auto& instance : m_pipelines) {
+ if (instance.isCompatible(state, renderPass))
+ return &instance;
+ }
+
+ return nullptr;
+ }
+
+
+ VkPipeline DxvkGraphicsPipeline::createPipeline(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) const {
+ if (Logger::logLevel() <= LogLevel::Debug) {
+ Logger::debug("Compiling graphics pipeline...");
+ this->logPipelineState(LogLevel::Debug, state);
+ }
+
+ // Render pass format and image layouts
+ DxvkRenderPassFormat passFormat = renderPass->format();
+
+ // Set up dynamic states as needed
+ std::array<VkDynamicState, 6> dynamicStates;
+ uint32_t dynamicStateCount = 0;
+
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
+
+ if (state.useDynamicDepthBias())
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS;
+
+ if (state.useDynamicDepthBounds())
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BOUNDS;
+
+ if (state.useDynamicBlendConstants())
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
+
+ if (state.useDynamicStencilRef())
+ dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
+
+ // Figure out the actual sample count to use
+ VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
+
+ if (state.ms.sampleCount())
+ sampleCount = VkSampleCountFlagBits(state.ms.sampleCount());
+ else if (state.rs.sampleCount())
+ sampleCount = VkSampleCountFlagBits(state.rs.sampleCount());
+
+ // Set up some specialization constants
+ DxvkSpecConstants specData;
+ specData.set(uint32_t(DxvkSpecConstantId::RasterizerSampleCount), sampleCount, VK_SAMPLE_COUNT_1_BIT);
+
+ for (uint32_t i = 0; i < m_layout->bindingCount(); i++)
+ specData.set(i, state.bsBindingMask.test(i), true);
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if ((m_fsOut & (1 << i)) != 0) {
+ specData.set(uint32_t(DxvkSpecConstantId::ColorComponentMappings) + i,
+ state.omSwizzle[i].rIndex() << 0 | state.omSwizzle[i].gIndex() << 4 |
+ state.omSwizzle[i].bIndex() << 8 | state.omSwizzle[i].aIndex() << 12, 0x3210u);
+ }
+ }
+
+ for (uint32_t i = 0; i < MaxNumSpecConstants; i++)
+ specData.set(getSpecId(i), state.sc.specConstants[i], 0u);
+
+ VkSpecializationInfo specInfo = specData.getSpecInfo();
+
+ auto vsm = createShaderModule(m_shaders.vs, state);
+ auto tcsm = createShaderModule(m_shaders.tcs, state);
+ auto tesm = createShaderModule(m_shaders.tes, state);
+ auto gsm = createShaderModule(m_shaders.gs, state);
+ auto fsm = createShaderModule(m_shaders.fs, state);
+
+ std::vector<VkPipelineShaderStageCreateInfo> stages;
+ if (vsm) stages.push_back(vsm.stageInfo(&specInfo));
+ if (tcsm) stages.push_back(tcsm.stageInfo(&specInfo));
+ if (tesm) stages.push_back(tesm.stageInfo(&specInfo));
+ if (gsm) stages.push_back(gsm.stageInfo(&specInfo));
+ if (fsm) stages.push_back(fsm.stageInfo(&specInfo));
+
+ // Fix up color write masks using the component mappings
+ std::array<VkPipelineColorBlendAttachmentState, MaxNumRenderTargets> omBlendAttachments;
+
+ const VkColorComponentFlags fullMask
+ = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ omBlendAttachments[i] = state.omBlend[i].state();
+
+ if (omBlendAttachments[i].colorWriteMask != fullMask) {
+ omBlendAttachments[i].colorWriteMask = util::remapComponentMask(
+ state.omBlend[i].colorWriteMask(), state.omSwizzle[i].mapping());
+ }
+
+ if ((m_fsOut & (1 << i)) == 0)
+ omBlendAttachments[i].colorWriteMask = 0;
+ }
+
+ // Generate per-instance attribute divisors
+ std::array<VkVertexInputBindingDivisorDescriptionEXT, MaxNumVertexBindings> viDivisorDesc;
+ uint32_t viDivisorCount = 0;
+
+ for (uint32_t i = 0; i < state.il.bindingCount(); i++) {
+ if (state.ilBindings[i].inputRate() == VK_VERTEX_INPUT_RATE_INSTANCE
+ && state.ilBindings[i].divisor() != 1) {
+ const uint32_t id = viDivisorCount++;
+
+ viDivisorDesc[id].binding = i; /* see below */
+ viDivisorDesc[id].divisor = state.ilBindings[i].divisor();
+ }
+ }
+
+ int32_t rasterizedStream = m_shaders.gs != nullptr
+ ? m_shaders.gs->shaderOptions().rasterizedStream
+ : 0;
+
+ // Compact vertex bindings so that we can more easily update vertex buffers
+ std::array<VkVertexInputAttributeDescription, MaxNumVertexAttributes> viAttribs;
+ std::array<VkVertexInputBindingDescription, MaxNumVertexBindings> viBindings;
+ std::array<uint32_t, MaxNumVertexBindings> viBindingMap = { };
+
+ for (uint32_t i = 0; i < state.il.bindingCount(); i++) {
+ viBindings[i] = state.ilBindings[i].description();
+ viBindings[i].binding = i;
+ viBindingMap[state.ilBindings[i].binding()] = i;
+ }
+
+ for (uint32_t i = 0; i < state.il.attributeCount(); i++) {
+ viAttribs[i] = state.ilAttributes[i].description();
+ viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding()];
+ }
+
+ VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo;
+ viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
+ viDivisorInfo.pNext = nullptr;
+ viDivisorInfo.vertexBindingDivisorCount = viDivisorCount;
+ viDivisorInfo.pVertexBindingDivisors = viDivisorDesc.data();
+
+ VkPipelineVertexInputStateCreateInfo viInfo;
+ viInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ viInfo.pNext = &viDivisorInfo;
+ viInfo.flags = 0;
+ viInfo.vertexBindingDescriptionCount = state.il.bindingCount();
+ viInfo.pVertexBindingDescriptions = viBindings.data();
+ viInfo.vertexAttributeDescriptionCount = state.il.attributeCount();
+ viInfo.pVertexAttributeDescriptions = viAttribs.data();
+
+ if (viDivisorCount == 0)
+ viInfo.pNext = viDivisorInfo.pNext;
+
+ // TODO remove this once the extension is widely supported
+ if (!m_pipeMgr->m_device->features().extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor)
+ viInfo.pNext = viDivisorInfo.pNext;
+
+ VkPipelineInputAssemblyStateCreateInfo iaInfo;
+ iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaInfo.pNext = nullptr;
+ iaInfo.flags = 0;
+ iaInfo.topology = state.ia.primitiveTopology();
+ iaInfo.primitiveRestartEnable = state.ia.primitiveRestart();
+
+ VkPipelineTessellationStateCreateInfo tsInfo;
+ tsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+ tsInfo.pNext = nullptr;
+ tsInfo.flags = 0;
+ tsInfo.patchControlPoints = state.ia.patchVertexCount();
+
+ VkPipelineViewportStateCreateInfo vpInfo;
+ vpInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vpInfo.pNext = nullptr;
+ vpInfo.flags = 0;
+ vpInfo.viewportCount = state.rs.viewportCount();
+ vpInfo.pViewports = nullptr;
+ vpInfo.scissorCount = state.rs.viewportCount();
+ vpInfo.pScissors = nullptr;
+
+ VkPipelineRasterizationConservativeStateCreateInfoEXT conservativeInfo;
+ conservativeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT;
+ conservativeInfo.pNext = nullptr;
+ conservativeInfo.flags = 0;
+ conservativeInfo.conservativeRasterizationMode = state.rs.conservativeMode();
+ conservativeInfo.extraPrimitiveOverestimationSize = 0.0f;
+
+ VkPipelineRasterizationStateStreamCreateInfoEXT xfbStreamInfo;
+ xfbStreamInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT;
+ xfbStreamInfo.pNext = nullptr;
+ xfbStreamInfo.flags = 0;
+ xfbStreamInfo.rasterizationStream = uint32_t(rasterizedStream);
+
+ VkPipelineRasterizationDepthClipStateCreateInfoEXT rsDepthClipInfo;
+ rsDepthClipInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT;
+ rsDepthClipInfo.pNext = nullptr;
+ rsDepthClipInfo.flags = 0;
+ rsDepthClipInfo.depthClipEnable = state.rs.depthClipEnable();
+
+ VkPipelineRasterizationStateCreateInfo rsInfo;
+ rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsInfo.pNext = nullptr;
+ rsInfo.flags = 0;
+ rsInfo.depthClampEnable = VK_TRUE;
+ rsInfo.rasterizerDiscardEnable = rasterizedStream < 0;
+ rsInfo.polygonMode = state.rs.polygonMode();
+ rsInfo.cullMode = state.rs.cullMode();
+ rsInfo.frontFace = state.rs.frontFace();
+ rsInfo.depthBiasEnable = state.rs.depthBiasEnable();
+ rsInfo.depthBiasConstantFactor= 0.0f;
+ rsInfo.depthBiasClamp = 0.0f;
+ rsInfo.depthBiasSlopeFactor = 0.0f;
+ rsInfo.lineWidth = 1.0f;
+
+ if (rasterizedStream > 0)
+ xfbStreamInfo.pNext = std::exchange(rsInfo.pNext, &xfbStreamInfo);
+
+ if (conservativeInfo.conservativeRasterizationMode != VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT)
+ conservativeInfo.pNext = std::exchange(rsInfo.pNext, &conservativeInfo);
+
+ if (m_pipeMgr->m_device->features().extDepthClipEnable.depthClipEnable)
+ rsDepthClipInfo.pNext = std::exchange(rsInfo.pNext, &rsDepthClipInfo);
+ else
+ rsInfo.depthClampEnable = !state.rs.depthClipEnable();
+
+ uint32_t sampleMask = state.ms.sampleMask();
+
+ VkPipelineMultisampleStateCreateInfo msInfo;
+ msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msInfo.pNext = nullptr;
+ msInfo.flags = 0;
+ msInfo.rasterizationSamples = sampleCount;
+ msInfo.sampleShadingEnable = m_common.msSampleShadingEnable;
+ msInfo.minSampleShading = m_common.msSampleShadingFactor;
+ msInfo.pSampleMask = &sampleMask;
+ msInfo.alphaToCoverageEnable = state.ms.enableAlphaToCoverage();
+ msInfo.alphaToOneEnable = VK_FALSE;
+
+ VkPipelineDepthStencilStateCreateInfo dsInfo;
+ dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ dsInfo.pNext = nullptr;
+ dsInfo.flags = 0;
+ dsInfo.depthTestEnable = state.ds.enableDepthTest();
+ dsInfo.depthWriteEnable = state.ds.enableDepthWrite() && !util::isDepthReadOnlyLayout(passFormat.depth.layout);
+ dsInfo.depthCompareOp = state.ds.depthCompareOp();
+ dsInfo.depthBoundsTestEnable = state.ds.enableDepthBoundsTest();
+ dsInfo.stencilTestEnable = state.ds.enableStencilTest();
+ dsInfo.front = state.dsFront.state();
+ dsInfo.back = state.dsBack.state();
+ dsInfo.minDepthBounds = 0.0f;
+ dsInfo.maxDepthBounds = 1.0f;
+
+ VkPipelineColorBlendStateCreateInfo cbInfo;
+ cbInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cbInfo.pNext = nullptr;
+ cbInfo.flags = 0;
+ cbInfo.logicOpEnable = state.om.enableLogicOp();
+ cbInfo.logicOp = state.om.logicOp();
+ cbInfo.attachmentCount = DxvkLimits::MaxNumRenderTargets;
+ cbInfo.pAttachments = omBlendAttachments.data();
+
+ for (uint32_t i = 0; i < 4; i++)
+ cbInfo.blendConstants[i] = 0.0f;
+
+ VkPipelineDynamicStateCreateInfo dyInfo;
+ dyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dyInfo.pNext = nullptr;
+ dyInfo.flags = 0;
+ dyInfo.dynamicStateCount = dynamicStateCount;
+ dyInfo.pDynamicStates = dynamicStates.data();
+
+ VkGraphicsPipelineCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.stageCount = stages.size();
+ info.pStages = stages.data();
+ info.pVertexInputState = &viInfo;
+ info.pInputAssemblyState = &iaInfo;
+ info.pTessellationState = &tsInfo;
+ info.pViewportState = &vpInfo;
+ info.pRasterizationState = &rsInfo;
+ info.pMultisampleState = &msInfo;
+ info.pDepthStencilState = &dsInfo;
+ info.pColorBlendState = &cbInfo;
+ info.pDynamicState = &dyInfo;
+ info.layout = m_layout->pipelineLayout();
+ info.renderPass = renderPass->getDefaultHandle();
+ info.subpass = 0;
+ info.basePipelineHandle = VK_NULL_HANDLE;
+ info.basePipelineIndex = -1;
+
+ if (tsInfo.patchControlPoints == 0)
+ info.pTessellationState = nullptr;
+
+ // Time pipeline compilation for debugging purposes
+ dxvk::high_resolution_clock::time_point t0, t1;
+
+ if (Logger::logLevel() <= LogLevel::Debug)
+ t0 = dxvk::high_resolution_clock::now();
+
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(),
+ m_pipeMgr->m_cache->handle(), 1, &info, nullptr, &pipeline) != VK_SUCCESS) {
+ Logger::err("DxvkGraphicsPipeline: Failed to compile pipeline");
+ this->logPipelineState(LogLevel::Error, state);
+ return VK_NULL_HANDLE;
+ }
+
+ if (Logger::logLevel() <= LogLevel::Debug) {
+ t1 = dxvk::high_resolution_clock::now();
+ auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
+ Logger::debug(str::format("DxvkGraphicsPipeline: Finished in ", td.count(), " ms"));
+ }
+
+ return pipeline;
+ }
+
+
+ void DxvkGraphicsPipeline::destroyPipeline(VkPipeline pipeline) const {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), pipeline, nullptr);
+ }
+
+
+ DxvkShaderModule DxvkGraphicsPipeline::createShaderModule(
+ const Rc<DxvkShader>& shader,
+ const DxvkGraphicsPipelineStateInfo& state) const {
+ if (shader == nullptr)
+ return DxvkShaderModule();
+
+ DxvkShaderModuleCreateInfo info;
+
+ // Fix up fragment shader outputs for dual-source blending
+ if (shader->stage() == VK_SHADER_STAGE_FRAGMENT_BIT) {
+ info.fsDualSrcBlend = state.omBlend[0].blendEnable() && (
+ util::isDualSourceBlendFactor(state.omBlend[0].srcColorBlendFactor()) ||
+ util::isDualSourceBlendFactor(state.omBlend[0].dstColorBlendFactor()) ||
+ util::isDualSourceBlendFactor(state.omBlend[0].srcAlphaBlendFactor()) ||
+ util::isDualSourceBlendFactor(state.omBlend[0].dstAlphaBlendFactor()));
+ }
+
+ // Deal with undefined shader inputs
+ uint32_t consumedInputs = shader->interfaceSlots().inputSlots;
+ uint32_t providedInputs = 0;
+
+ if (shader->stage() == VK_SHADER_STAGE_VERTEX_BIT) {
+ for (uint32_t i = 0; i < state.il.attributeCount(); i++)
+ providedInputs |= 1u << state.ilAttributes[i].location();
+ } else if (shader->stage() != VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
+ auto prevStage = getPrevStageShader(shader->stage());
+ providedInputs = prevStage->interfaceSlots().outputSlots;
+ } else {
+ // Technically not correct, but this
+ // would need a lot of extra care
+ providedInputs = consumedInputs;
+ }
+
+ info.undefinedInputs = (providedInputs & consumedInputs) ^ consumedInputs;
+ return shader->createShaderModule(m_vkd, m_slotMapping, info);
+ }
+
+
+ Rc<DxvkShader> DxvkGraphicsPipeline::getPrevStageShader(VkShaderStageFlagBits stage) const {
+ if (stage == VK_SHADER_STAGE_VERTEX_BIT)
+ return nullptr;
+
+ if (stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+ return m_shaders.tcs;
+
+ Rc<DxvkShader> result = m_shaders.vs;
+
+ if (stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+ return result;
+
+ if (m_shaders.tes != nullptr)
+ result = m_shaders.tes;
+
+ if (stage == VK_SHADER_STAGE_GEOMETRY_BIT)
+ return result;
+
+ if (m_shaders.gs != nullptr)
+ result = m_shaders.gs;
+
+ return result;
+ }
+
+
+ bool DxvkGraphicsPipeline::validatePipelineState(
+ const DxvkGraphicsPipelineStateInfo& state) const {
+ // Tessellation shaders and patches must be used together
+ bool hasPatches = state.ia.primitiveTopology() == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+
+ bool hasTcs = m_shaders.tcs != nullptr;
+ bool hasTes = m_shaders.tes != nullptr;
+
+ if (hasPatches != hasTcs || hasPatches != hasTes)
+ return false;
+
+ // Filter out undefined primitive topologies
+ if (state.ia.primitiveTopology() == VK_PRIMITIVE_TOPOLOGY_MAX_ENUM)
+ return false;
+
+ // Prevent unintended out-of-bounds access to the IL arrays
+ if (state.il.attributeCount() > DxvkLimits::MaxNumVertexAttributes
+ || state.il.bindingCount() > DxvkLimits::MaxNumVertexBindings)
+ return false;
+
+ // No errors
+ return true;
+ }
+
+
+ void DxvkGraphicsPipeline::writePipelineStateToCache(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPassFormat& format) const {
+ if (m_pipeMgr->m_stateCache == nullptr)
+ return;
+
+ DxvkStateCacheKey key;
+ if (m_shaders.vs != nullptr) key.vs = m_shaders.vs->getShaderKey();
+ if (m_shaders.tcs != nullptr) key.tcs = m_shaders.tcs->getShaderKey();
+ if (m_shaders.tes != nullptr) key.tes = m_shaders.tes->getShaderKey();
+ if (m_shaders.gs != nullptr) key.gs = m_shaders.gs->getShaderKey();
+ if (m_shaders.fs != nullptr) key.fs = m_shaders.fs->getShaderKey();
+
+ m_pipeMgr->m_stateCache->addGraphicsPipeline(key, state, format);
+ }
+
+
+ void DxvkGraphicsPipeline::logPipelineState(
+ LogLevel level,
+ const DxvkGraphicsPipelineStateInfo& state) const {
+ if (m_shaders.vs != nullptr) Logger::log(level, str::format(" vs : ", m_shaders.vs ->debugName()));
+ if (m_shaders.tcs != nullptr) Logger::log(level, str::format(" tcs : ", m_shaders.tcs->debugName()));
+ if (m_shaders.tes != nullptr) Logger::log(level, str::format(" tes : ", m_shaders.tes->debugName()));
+ if (m_shaders.gs != nullptr) Logger::log(level, str::format(" gs : ", m_shaders.gs ->debugName()));
+ if (m_shaders.fs != nullptr) Logger::log(level, str::format(" fs : ", m_shaders.fs ->debugName()));
+
+ for (uint32_t i = 0; i < state.il.attributeCount(); i++) {
+ const auto& attr = state.ilAttributes[i];
+ Logger::log(level, str::format(" attr ", i, " : location ", attr.location(), ", binding ", attr.binding(), ", format ", attr.format(), ", offset ", attr.offset()));
+ }
+ for (uint32_t i = 0; i < state.il.bindingCount(); i++) {
+ const auto& bind = state.ilBindings[i];
+ Logger::log(level, str::format(" binding ", i, " : binding ", bind.binding(), ", stride ", bind.stride(), ", rate ", bind.inputRate(), ", divisor ", bind.divisor()));
+ }
+
+ // TODO log more pipeline state
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.h
new file mode 100644
index 00000000..4194599d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics.h
@@ -0,0 +1,261 @@
+#pragma once
+
+#include <mutex>
+
+#include "dxvk_bind_mask.h"
+#include "dxvk_constant_state.h"
+#include "dxvk_graphics_state.h"
+#include "dxvk_pipecache.h"
+#include "dxvk_pipelayout.h"
+#include "dxvk_renderpass.h"
+#include "dxvk_resource.h"
+#include "dxvk_shader.h"
+#include "dxvk_stats.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+ class DxvkPipelineManager;
+
+ /**
+ * \brief Flags that describe pipeline properties
+ */
+ enum class DxvkGraphicsPipelineFlag {
+ HasTransformFeedback,
+ HasStorageDescriptors,
+ };
+
+ using DxvkGraphicsPipelineFlags = Flags<DxvkGraphicsPipelineFlag>;
+
+
+ /**
+ * \brief Shaders used in graphics pipelines
+ */
+ struct DxvkGraphicsPipelineShaders {
+ Rc<DxvkShader> vs;
+ Rc<DxvkShader> tcs;
+ Rc<DxvkShader> tes;
+ Rc<DxvkShader> gs;
+ Rc<DxvkShader> fs;
+
+ bool eq(const DxvkGraphicsPipelineShaders& other) const {
+ return vs == other.vs && tcs == other.tcs
+ && tes == other.tes && gs == other.gs
+ && fs == other.fs;
+ }
+
+ size_t hash() const {
+ DxvkHashState state;
+ state.add(DxvkShader::getHash(vs));
+ state.add(DxvkShader::getHash(tcs));
+ state.add(DxvkShader::getHash(tes));
+ state.add(DxvkShader::getHash(gs));
+ state.add(DxvkShader::getHash(fs));
+ return state;
+ }
+ };
+
+
+ /**
+ * \brief Common graphics pipeline state
+ *
+ * Non-dynamic pipeline state that cannot
+ * be changed dynamically.
+ */
+ struct DxvkGraphicsCommonPipelineStateInfo {
+ bool msSampleShadingEnable;
+ float msSampleShadingFactor;
+ };
+
+
+ /**
+ * \brief Graphics pipeline instance
+ *
+ * Stores a state vector and the
+ * corresponding pipeline handle.
+ */
+ class DxvkGraphicsPipelineInstance {
+
+ public:
+
+ DxvkGraphicsPipelineInstance()
+ : m_stateVector (),
+ m_renderPass (VK_NULL_HANDLE),
+ m_pipeline (VK_NULL_HANDLE) { }
+
+ DxvkGraphicsPipelineInstance(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* rp,
+ VkPipeline pipe)
+ : m_stateVector (state),
+ m_renderPass (rp),
+ m_pipeline (pipe) { }
+
+ /**
+ * \brief Checks for matching pipeline state
+ *
+ * \param [in] stateVector Graphics pipeline state
+ * \param [in] renderPass Render pass handle
+ * \returns \c true if the specialization is compatible
+ */
+ bool isCompatible(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* rp) {
+ return m_renderPass == rp
+ && m_stateVector == state;
+ }
+
+ /**
+ * \brief Retrieves pipeline
+ * \returns The pipeline handle
+ */
+ VkPipeline pipeline() const {
+ return m_pipeline;
+ }
+
+ private:
+
+ DxvkGraphicsPipelineStateInfo m_stateVector;
+ const DxvkRenderPass* m_renderPass;
+ VkPipeline m_pipeline;
+
+ };
+
+
+ /**
+ * \brief Graphics pipeline
+ *
+ * Stores the pipeline layout as well as methods to
+ * recompile the graphics pipeline against a given
+ * pipeline state vector.
+ */
+ class DxvkGraphicsPipeline {
+
+ public:
+
+ DxvkGraphicsPipeline(
+ DxvkPipelineManager* pipeMgr,
+ DxvkGraphicsPipelineShaders shaders);
+
+ ~DxvkGraphicsPipeline();
+
+ /**
+ * \brief Shaders used by the pipeline
+ * \returns Shaders used by the pipeline
+ */
+ const DxvkGraphicsPipelineShaders& shaders() const {
+ return m_shaders;
+ }
+
+ /**
+ * \brief Returns graphics pipeline flags
+ * \returns Graphics pipeline property flags
+ */
+ DxvkGraphicsPipelineFlags flags() const {
+ return m_flags;
+ }
+
+ /**
+ * \brief Pipeline layout
+ *
+ * Stores the pipeline layout and the descriptor set
+ * layout, as well as information on the resource
+ * slots used by the pipeline.
+ * \returns Pipeline layout
+ */
+ DxvkPipelineLayout* layout() const {
+ return m_layout.ptr();
+ }
+
+ /**
+ * \brief Queries shader for a given stage
+ *
+ * In case no shader is specified for the
+ * given stage, \c nullptr will be returned.
+ * \param [in] stage The shader stage
+ * \returns Shader of the given stage
+ */
+ Rc<DxvkShader> getShader(
+ VkShaderStageFlagBits stage) const;
+
+ /**
+ * \brief Pipeline handle
+ *
+ * Retrieves a pipeline handle for the given pipeline
+ * state. If necessary, a new pipeline will be created.
+ * \param [in] state Pipeline state vector
+ * \param [in] renderPass The render pass
+ * \returns Pipeline handle
+ */
+ VkPipeline getPipelineHandle(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass);
+
+ /**
+ * \brief Compiles a pipeline
+ *
+ * Asynchronously compiles the given pipeline
+ * and stores the result for future use.
+ * \param [in] state Pipeline state vector
+ * \param [in] renderPass The render pass
+ */
+ void compilePipeline(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkPipelineManager* m_pipeMgr;
+
+ DxvkGraphicsPipelineShaders m_shaders;
+ DxvkDescriptorSlotMapping m_slotMapping;
+
+ Rc<DxvkPipelineLayout> m_layout;
+
+ uint32_t m_vsIn = 0;
+ uint32_t m_fsOut = 0;
+
+ DxvkGraphicsPipelineFlags m_flags;
+ DxvkGraphicsCommonPipelineStateInfo m_common;
+
+ // List of pipeline instances, shared between threads
+ alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex;
+ std::vector<DxvkGraphicsPipelineInstance> m_pipelines;
+
+ DxvkGraphicsPipelineInstance* createInstance(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass);
+
+ DxvkGraphicsPipelineInstance* findInstance(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass);
+
+ VkPipeline createPipeline(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPass* renderPass) const;
+
+ void destroyPipeline(
+ VkPipeline pipeline) const;
+
+ DxvkShaderModule createShaderModule(
+ const Rc<DxvkShader>& shader,
+ const DxvkGraphicsPipelineStateInfo& state) const;
+
+ Rc<DxvkShader> getPrevStageShader(
+ VkShaderStageFlagBits stage) const;
+
+ bool validatePipelineState(
+ const DxvkGraphicsPipelineStateInfo& state) const;
+
+ void writePipelineStateToCache(
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPassFormat& format) const;
+
+ void logPipelineState(
+ LogLevel level,
+ const DxvkGraphicsPipelineStateInfo& state) const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics_state.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics_state.h
new file mode 100644
index 00000000..b10f7835
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_graphics_state.h
@@ -0,0 +1,728 @@
+#pragma once
+
+#include "dxvk_limits.h"
+
+#include <cstring>
+
+namespace dxvk {
+
+ /**
+ * \brief Packed input assembly state
+ *
+ * Stores the primitive topology
+ * and primitive restart info.
+ */
+ class DxvkIaInfo {
+
+ public:
+
+ DxvkIaInfo() = default;
+
+ DxvkIaInfo(
+ VkPrimitiveTopology primitiveTopology,
+ VkBool32 primitiveRestart,
+ uint32_t patchVertexCount)
+ : m_primitiveTopology (uint16_t(primitiveTopology)),
+ m_primitiveRestart (uint16_t(primitiveRestart)),
+ m_patchVertexCount (uint16_t(patchVertexCount)),
+ m_reserved (0) { }
+
+ VkPrimitiveTopology primitiveTopology() const {
+ return m_primitiveTopology <= VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
+ ? VkPrimitiveTopology(m_primitiveTopology)
+ : VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
+ }
+
+ VkBool32 primitiveRestart() const {
+ return VkBool32(m_primitiveRestart);
+ }
+
+ uint32_t patchVertexCount() const {
+ return m_patchVertexCount;
+ }
+
+ private:
+
+ uint16_t m_primitiveTopology : 4;
+ uint16_t m_primitiveRestart : 1;
+ uint16_t m_patchVertexCount : 6;
+ uint16_t m_reserved : 5;
+
+ };
+
+
+ /**
+ * \brief Packed input layout metadata
+ *
+ * Stores the number of vertex attributes
+ * and bindings in one byte each.
+ */
+ class DxvkIlInfo {
+
+ public:
+
+ DxvkIlInfo() = default;
+
+ DxvkIlInfo(
+ uint32_t attributeCount,
+ uint32_t bindingCount)
+ : m_attributeCount(uint8_t(attributeCount)),
+ m_bindingCount (uint8_t(bindingCount)) { }
+
+ uint32_t attributeCount() const {
+ return m_attributeCount;
+ }
+
+ uint32_t bindingCount() const {
+ return m_bindingCount;
+ }
+
+ private:
+
+ uint8_t m_attributeCount;
+ uint8_t m_bindingCount;
+
+ };
+
+
+ /**
+ * \brief Packed vertex attribute
+ *
+ * Stores a vertex attribute description. Assumes
+ * that all vertex formats have numerical values
+ * of 127 or less (i.e. fit into 7 bits).
+ */
+ class DxvkIlAttribute {
+
+ public:
+
+ DxvkIlAttribute() = default;
+
+ DxvkIlAttribute(
+ uint32_t location,
+ uint32_t binding,
+ VkFormat format,
+ uint32_t offset)
+ : m_location(uint32_t(location)),
+ m_binding (uint32_t(binding)),
+ m_format (uint32_t(format)),
+ m_offset (uint32_t(offset)),
+ m_reserved(0) { }
+
+ uint32_t location() const {
+ return m_location;
+ }
+
+ uint32_t binding() const {
+ return m_binding;
+ }
+
+ VkFormat format() const {
+ return VkFormat(m_format);
+ }
+
+ uint32_t offset() const {
+ return m_offset;
+ }
+
+ VkVertexInputAttributeDescription description() const {
+ VkVertexInputAttributeDescription result;
+ result.location = m_location;
+ result.binding = m_binding;
+ result.format = VkFormat(m_format);
+ result.offset = m_offset;
+ return result;
+ }
+
+ private:
+
+ uint32_t m_location : 5;
+ uint32_t m_binding : 5;
+ uint32_t m_format : 7;
+ uint32_t m_offset : 11;
+ uint32_t m_reserved : 4;
+
+ };
+
+
+ /**
+ * \brief Packed vertex binding
+ *
+ * Stores a vertex binding description,
+ * including the 32-bit divisor.
+ */
+ class DxvkIlBinding {
+
+ public:
+
+ DxvkIlBinding() = default;
+
+ DxvkIlBinding(
+ uint32_t binding,
+ uint32_t stride,
+ VkVertexInputRate inputRate,
+ uint32_t divisor)
+ : m_binding (uint32_t(binding)),
+ m_stride (uint32_t(stride)),
+ m_inputRate (uint32_t(inputRate)),
+ m_divisor (uint32_t(divisor < (1u << 14) ? divisor : 0u)) { }
+
+ uint32_t binding() const {
+ return m_binding;
+ }
+
+ uint32_t stride() const {
+ return m_stride;
+ }
+
+ VkVertexInputRate inputRate() const {
+ return VkVertexInputRate(m_inputRate);
+ }
+
+ uint32_t divisor() const {
+ return m_divisor;
+ }
+
+ VkVertexInputBindingDescription description() const {
+ VkVertexInputBindingDescription result;
+ result.binding = m_binding;
+ result.stride = m_stride;
+ result.inputRate = VkVertexInputRate(m_inputRate);
+ return result;
+ }
+
+ void setStride(uint32_t stride) {
+ m_stride = stride;
+ }
+
+ private:
+
+ uint32_t m_binding : 5;
+ uint32_t m_stride : 12;
+ uint32_t m_inputRate : 1;
+ uint32_t m_divisor : 14;
+
+ };
+
+
+ /**
+ * \brief Packed rasterizer state
+ *
+ * Stores a bunch of flags and parameters
+ * related to rasterization in four bytes.
+ */
+ class DxvkRsInfo {
+
+ public:
+
+ DxvkRsInfo() = default;
+
+ DxvkRsInfo(
+ VkBool32 depthClipEnable,
+ VkBool32 depthBiasEnable,
+ VkPolygonMode polygonMode,
+ VkCullModeFlags cullMode,
+ VkFrontFace frontFace,
+ uint32_t viewportCount,
+ VkSampleCountFlags sampleCount,
+ VkConservativeRasterizationModeEXT conservativeMode)
+ : m_depthClipEnable (uint32_t(depthClipEnable)),
+ m_depthBiasEnable (uint32_t(depthBiasEnable)),
+ m_polygonMode (uint32_t(polygonMode)),
+ m_cullMode (uint32_t(cullMode)),
+ m_frontFace (uint32_t(frontFace)),
+ m_viewportCount (uint32_t(viewportCount)),
+ m_sampleCount (uint32_t(sampleCount)),
+ m_conservativeMode(uint32_t(conservativeMode)),
+ m_reserved (0) { }
+
+ VkBool32 depthClipEnable() const {
+ return VkBool32(m_depthClipEnable);
+ }
+
+ VkBool32 depthBiasEnable() const {
+ return VkBool32(m_depthBiasEnable);
+ }
+
+ VkPolygonMode polygonMode() const {
+ return VkPolygonMode(m_polygonMode);
+ }
+
+ VkCullModeFlags cullMode() const {
+ return VkCullModeFlags(m_cullMode);
+ }
+
+ VkFrontFace frontFace() const {
+ return VkFrontFace(m_frontFace);
+ }
+
+ uint32_t viewportCount() const {
+ return m_viewportCount;
+ }
+
+ VkSampleCountFlags sampleCount() const {
+ return VkSampleCountFlags(m_sampleCount);
+ }
+
+ VkConservativeRasterizationModeEXT conservativeMode() const {
+ return VkConservativeRasterizationModeEXT(m_conservativeMode);
+ }
+
+ void setViewportCount(uint32_t viewportCount) {
+ m_viewportCount = viewportCount;
+ }
+
+ private:
+
+ uint32_t m_depthClipEnable : 1;
+ uint32_t m_depthBiasEnable : 1;
+ uint32_t m_polygonMode : 2;
+ uint32_t m_cullMode : 2;
+ uint32_t m_frontFace : 1;
+ uint32_t m_viewportCount : 5;
+ uint32_t m_sampleCount : 5;
+ uint32_t m_conservativeMode : 2;
+ uint32_t m_reserved : 13;
+
+ };
+
+
+ /**
+ * \brief Packed multisample info
+ *
+ * Stores the sample mask, sample count override
+ * and alpha-to-coverage state in four bytes.
+ */
+ class DxvkMsInfo {
+
+ public:
+
+ DxvkMsInfo() = default;
+
+ DxvkMsInfo(
+ VkSampleCountFlags sampleCount,
+ uint32_t sampleMask,
+ VkBool32 enableAlphaToCoverage)
+ : m_sampleCount (uint16_t(sampleCount)),
+ m_enableAlphaToCoverage (uint16_t(enableAlphaToCoverage)),
+ m_reserved (0),
+ m_sampleMask (uint16_t(sampleMask)) { }
+
+ VkSampleCountFlags sampleCount() const {
+ return VkSampleCountFlags(m_sampleCount);
+ }
+
+ uint32_t sampleMask() const {
+ return m_sampleMask;
+ }
+
+ VkBool32 enableAlphaToCoverage() const {
+ return VkBool32(m_enableAlphaToCoverage);
+ }
+
+ void setSampleCount(VkSampleCountFlags sampleCount) {
+ m_sampleCount = uint16_t(sampleCount);
+ }
+
+ private:
+
+ uint16_t m_sampleCount : 5;
+ uint16_t m_enableAlphaToCoverage : 1;
+ uint16_t m_reserved : 10;
+ uint16_t m_sampleMask;
+
+ };
+
+
+ /**
+ * \brief Packed depth-stencil metadata
+ *
+ * Stores some flags and the depth-compare op in
+ * two bytes. Stencil ops are stored separately.
+ */
+ class DxvkDsInfo {
+
+ public:
+
+ DxvkDsInfo() = default;
+
+ DxvkDsInfo(
+ VkBool32 enableDepthTest,
+ VkBool32 enableDepthWrite,
+ VkBool32 enableDepthBoundsTest,
+ VkBool32 enableStencilTest,
+ VkCompareOp depthCompareOp)
+ : m_enableDepthTest (uint16_t(enableDepthTest)),
+ m_enableDepthWrite (uint16_t(enableDepthWrite)),
+ m_enableDepthBoundsTest (uint16_t(enableDepthBoundsTest)),
+ m_enableStencilTest (uint16_t(enableStencilTest)),
+ m_depthCompareOp (uint16_t(depthCompareOp)),
+ m_reserved (0) { }
+
+ VkBool32 enableDepthTest() const {
+ return VkBool32(m_enableDepthTest);
+ }
+
+ VkBool32 enableDepthWrite() const {
+ return VkBool32(m_enableDepthWrite);
+ }
+
+ VkBool32 enableDepthBoundsTest() const {
+ return VkBool32(m_enableDepthBoundsTest);
+ }
+
+ VkBool32 enableStencilTest() const {
+ return VkBool32(m_enableStencilTest);
+ }
+
+ VkCompareOp depthCompareOp() const {
+ return VkCompareOp(m_depthCompareOp);
+ }
+
+ void setEnableDepthBoundsTest(VkBool32 enableDepthBoundsTest) {
+ m_enableDepthBoundsTest = VkBool32(enableDepthBoundsTest);
+ }
+
+ private:
+
+ uint16_t m_enableDepthTest : 1;
+ uint16_t m_enableDepthWrite : 1;
+ uint16_t m_enableDepthBoundsTest : 1;
+ uint16_t m_enableStencilTest : 1;
+ uint16_t m_depthCompareOp : 3;
+ uint16_t m_reserved : 9;
+
+ };
+
+
+ /**
+ * \brief Packed stencil op
+ *
+ * Stores various stencil op parameters
+ * for one single face in four bytes.
+ */
+ class DxvkDsStencilOp {
+
+ public:
+
+ DxvkDsStencilOp() = default;
+
+ DxvkDsStencilOp(VkStencilOpState state)
+ : m_failOp (uint32_t(state.failOp)),
+ m_passOp (uint32_t(state.passOp)),
+ m_depthFailOp (uint32_t(state.depthFailOp)),
+ m_compareOp (uint32_t(state.compareOp)),
+ m_reserved (0),
+ m_compareMask (uint32_t(state.compareMask)),
+ m_writeMask (uint32_t(state.writeMask)) { }
+
+ VkStencilOpState state() const {
+ VkStencilOpState result;
+ result.failOp = VkStencilOp(m_failOp);
+ result.passOp = VkStencilOp(m_passOp);
+ result.depthFailOp = VkStencilOp(m_depthFailOp);
+ result.compareOp = VkCompareOp(m_compareOp);
+ result.compareMask = m_compareMask;
+ result.writeMask = m_writeMask;
+ result.reference = 0;
+ return result;
+ }
+
+ private:
+
+ uint32_t m_failOp : 3;
+ uint32_t m_passOp : 3;
+ uint32_t m_depthFailOp : 3;
+ uint32_t m_compareOp : 3;
+ uint32_t m_reserved : 4;
+ uint32_t m_compareMask : 8;
+ uint32_t m_writeMask : 8;
+
+ };
+
+
+ /**
+ * \brief Packed output merger metadata
+ *
+ * Stores the logic op state in two bytes.
+ * Blend modes are stored separately.
+ */
+ class DxvkOmInfo {
+
+ public:
+
+ DxvkOmInfo() = default;
+
+ DxvkOmInfo(
+ VkBool32 enableLogicOp,
+ VkLogicOp logicOp)
+ : m_enableLogicOp (uint16_t(enableLogicOp)),
+ m_logicOp (uint16_t(logicOp)),
+ m_reserved (0) { }
+
+ VkBool32 enableLogicOp() const {
+ return VkBool32(m_enableLogicOp);
+ }
+
+ VkLogicOp logicOp() const {
+ return VkLogicOp(m_logicOp);
+ }
+
+ private:
+
+ uint16_t m_enableLogicOp : 1;
+ uint16_t m_logicOp : 4;
+ uint16_t m_reserved : 11;
+
+ };
+
+
+ /**
+ * \brief Packed attachment blend mode
+ *
+ * Stores blendig parameters for a single
+ * color attachment in four bytes.
+ */
+ class DxvkOmAttachmentBlend {
+
+ public:
+
+ DxvkOmAttachmentBlend() = default;
+
+ DxvkOmAttachmentBlend(
+ VkBool32 blendEnable,
+ VkBlendFactor srcColorBlendFactor,
+ VkBlendFactor dstColorBlendFactor,
+ VkBlendOp colorBlendOp,
+ VkBlendFactor srcAlphaBlendFactor,
+ VkBlendFactor dstAlphaBlendFactor,
+ VkBlendOp alphaBlendOp,
+ VkColorComponentFlags colorWriteMask)
+ : m_blendEnable (uint32_t(blendEnable)),
+ m_srcColorBlendFactor (uint32_t(srcColorBlendFactor)),
+ m_dstColorBlendFactor (uint32_t(dstColorBlendFactor)),
+ m_colorBlendOp (uint32_t(colorBlendOp)),
+ m_srcAlphaBlendFactor (uint32_t(srcAlphaBlendFactor)),
+ m_dstAlphaBlendFactor (uint32_t(dstAlphaBlendFactor)),
+ m_alphaBlendOp (uint32_t(alphaBlendOp)),
+ m_colorWriteMask (uint32_t(colorWriteMask)),
+ m_reserved (0) { }
+
+ VkBool32 blendEnable() const {
+ return m_blendEnable;
+ }
+
+ VkBlendFactor srcColorBlendFactor() const {
+ return VkBlendFactor(m_srcColorBlendFactor);
+ }
+
+ VkBlendFactor dstColorBlendFactor() const {
+ return VkBlendFactor(m_dstColorBlendFactor);
+ }
+
+ VkBlendOp colorBlendOp() const {
+ return VkBlendOp(m_colorBlendOp);
+ }
+
+ VkBlendFactor srcAlphaBlendFactor() const {
+ return VkBlendFactor(m_srcAlphaBlendFactor);
+ }
+
+ VkBlendFactor dstAlphaBlendFactor() const {
+ return VkBlendFactor(m_dstAlphaBlendFactor);
+ }
+
+ VkBlendOp alphaBlendOp() const {
+ return VkBlendOp(m_alphaBlendOp);
+ }
+
+ VkColorComponentFlags colorWriteMask() const {
+ return VkColorComponentFlags(m_colorWriteMask);
+ }
+
+ VkPipelineColorBlendAttachmentState state() const {
+ VkPipelineColorBlendAttachmentState result;
+ result.blendEnable = VkBool32(m_blendEnable);
+ result.srcColorBlendFactor = VkBlendFactor(m_srcColorBlendFactor);
+ result.dstColorBlendFactor = VkBlendFactor(m_dstColorBlendFactor);
+ result.colorBlendOp = VkBlendOp(m_colorBlendOp);
+ result.srcAlphaBlendFactor = VkBlendFactor(m_srcAlphaBlendFactor);
+ result.dstAlphaBlendFactor = VkBlendFactor(m_dstAlphaBlendFactor);
+ result.alphaBlendOp = VkBlendOp(m_alphaBlendOp);
+ result.colorWriteMask = VkColorComponentFlags(m_colorWriteMask);
+ return result;
+ }
+
+ private:
+
+ uint32_t m_blendEnable : 1;
+ uint32_t m_srcColorBlendFactor : 5;
+ uint32_t m_dstColorBlendFactor : 5;
+ uint32_t m_colorBlendOp : 3;
+ uint32_t m_srcAlphaBlendFactor : 5;
+ uint32_t m_dstAlphaBlendFactor : 5;
+ uint32_t m_alphaBlendOp : 3;
+ uint32_t m_colorWriteMask : 4;
+ uint32_t m_reserved : 1;
+
+ };
+
+
+ /**
+ * \brief Packed attachment swizzle
+ *
+ * Stores the component mapping for one
+ * single color attachment in one byte.
+ */
+ class DxvkOmAttachmentSwizzle {
+
+ public:
+
+ DxvkOmAttachmentSwizzle() = default;
+
+ DxvkOmAttachmentSwizzle(VkComponentMapping mapping)
+ : m_r(util::getComponentIndex(mapping.r, 0)),
+ m_g(util::getComponentIndex(mapping.g, 1)),
+ m_b(util::getComponentIndex(mapping.b, 2)),
+ m_a(util::getComponentIndex(mapping.a, 3)) { }
+
+ uint32_t rIndex() const { return m_r; }
+ uint32_t gIndex() const { return m_g; }
+ uint32_t bIndex() const { return m_b; }
+ uint32_t aIndex() const { return m_a; }
+
+ VkComponentMapping mapping() const {
+ VkComponentMapping result;
+ result.r = decodeSwizzle(m_r);
+ result.g = decodeSwizzle(m_g);
+ result.b = decodeSwizzle(m_b);
+ result.a = decodeSwizzle(m_a);
+ return result;
+ }
+
+ private:
+
+ uint8_t m_r : 2;
+ uint8_t m_g : 2;
+ uint8_t m_b : 2;
+ uint8_t m_a : 2;
+
+ static VkComponentSwizzle decodeSwizzle(uint8_t swizzle) {
+ return VkComponentSwizzle(uint32_t(swizzle) + uint32_t(VK_COMPONENT_SWIZZLE_R));
+ }
+
+ };
+
+
+ /**
+ * \brief Specialization constant state
+ *
+ * Stores the raw 32-bit spec constant values.
+ */
+ struct DxvkScInfo {
+ uint32_t specConstants[DxvkLimits::MaxNumSpecConstants];
+ };
+
+
+ /**
+ * \brief Packed graphics pipeline state
+ *
+ * Stores a compressed representation of the full
+ * graphics pipeline state which is optimized for
+ * lookup performance.
+ */
+ struct alignas(32) DxvkGraphicsPipelineStateInfo {
+ DxvkGraphicsPipelineStateInfo() {
+ std::memset(this, 0, sizeof(*this));
+ }
+
+ DxvkGraphicsPipelineStateInfo(const DxvkGraphicsPipelineStateInfo& other) {
+ std::memcpy(this, &other, sizeof(*this));
+ }
+
+ DxvkGraphicsPipelineStateInfo& operator = (const DxvkGraphicsPipelineStateInfo& other) {
+ std::memcpy(this, &other, sizeof(*this));
+ return *this;
+ }
+
+ bool operator == (const DxvkGraphicsPipelineStateInfo& other) const {
+ return bit::bcmpeq(this, &other);
+ }
+
+ bool operator != (const DxvkGraphicsPipelineStateInfo& other) const {
+ return !bit::bcmpeq(this, &other);
+ }
+
+ bool useDynamicStencilRef() const {
+ return ds.enableStencilTest();
+ }
+
+ bool useDynamicDepthBias() const {
+ return rs.depthBiasEnable();
+ }
+
+ bool useDynamicDepthBounds() const {
+ return ds.enableDepthBoundsTest();
+ }
+
+ bool useDynamicBlendConstants() const {
+ bool result = false;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets && !result; i++) {
+ result |= omBlend[i].blendEnable()
+ && (util::isBlendConstantBlendFactor(omBlend[i].srcColorBlendFactor())
+ || util::isBlendConstantBlendFactor(omBlend[i].dstColorBlendFactor())
+ || util::isBlendConstantBlendFactor(omBlend[i].srcAlphaBlendFactor())
+ || util::isBlendConstantBlendFactor(omBlend[i].dstAlphaBlendFactor()));
+ }
+
+ return result;
+ }
+
+ DxvkBindingMask bsBindingMask;
+ DxvkIaInfo ia;
+ DxvkIlInfo il;
+ DxvkRsInfo rs;
+ DxvkMsInfo ms;
+ DxvkDsInfo ds;
+ DxvkOmInfo om;
+ DxvkScInfo sc;
+ DxvkDsStencilOp dsFront;
+ DxvkDsStencilOp dsBack;
+ DxvkOmAttachmentSwizzle omSwizzle [DxvkLimits::MaxNumRenderTargets];
+ DxvkOmAttachmentBlend omBlend [DxvkLimits::MaxNumRenderTargets];
+ DxvkIlAttribute ilAttributes [DxvkLimits::MaxNumVertexAttributes];
+ DxvkIlBinding ilBindings [DxvkLimits::MaxNumVertexBindings];
+ };
+
+
+ /**
+ * \brief Compute pipeline state info
+ */
+ struct alignas(32) DxvkComputePipelineStateInfo {
+ DxvkComputePipelineStateInfo() {
+ std::memset(this, 0, sizeof(*this));
+ }
+
+ DxvkComputePipelineStateInfo(const DxvkComputePipelineStateInfo& other) {
+ std::memcpy(this, &other, sizeof(*this));
+ }
+
+ DxvkComputePipelineStateInfo& operator = (const DxvkComputePipelineStateInfo& other) {
+ std::memcpy(this, &other, sizeof(*this));
+ return *this;
+ }
+
+ bool operator == (const DxvkComputePipelineStateInfo& other) const {
+ return bit::bcmpeq(this, &other);
+ }
+
+ bool operator != (const DxvkComputePipelineStateInfo& other) const {
+ return !bit::bcmpeq(this, &other);
+ }
+
+ DxvkBindingMask bsBindingMask;
+ DxvkScInfo sc;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_hash.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_hash.h
new file mode 100644
index 00000000..a0fe561d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_hash.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <cstddef>
+
+namespace dxvk {
+
+ struct DxvkEq {
+ template<typename T>
+ size_t operator () (const T& a, const T& b) const {
+ return a.eq(b);
+ }
+ };
+
+ struct DxvkHash {
+ template<typename T>
+ size_t operator () (const T& object) const {
+ return object.hash();
+ }
+ };
+
+ class DxvkHashState {
+
+ public:
+
+ void add(size_t hash) {
+ m_value ^= hash + 0x9e3779b9
+ + (m_value << 6)
+ + (m_value >> 2);
+ }
+
+ operator size_t () const {
+ return m_value;
+ }
+
+ private:
+
+ size_t m_value = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.cpp
new file mode 100644
index 00000000..f849a72d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.cpp
@@ -0,0 +1,244 @@
+#include "dxvk_image.h"
+
+namespace dxvk {
+
+ DxvkImage::DxvkImage(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkImageCreateInfo& createInfo,
+ DxvkMemoryAllocator& memAlloc,
+ VkMemoryPropertyFlags memFlags)
+ : m_vkd(vkd), m_info(createInfo), m_memFlags(memFlags) {
+
+ // Copy the compatible view formats to a persistent array
+ m_viewFormats.resize(createInfo.viewFormatCount);
+ for (uint32_t i = 0; i < createInfo.viewFormatCount; i++)
+ m_viewFormats[i] = createInfo.viewFormats[i];
+ m_info.viewFormats = m_viewFormats.data();
+
+ // If defined, we should provide a format list, which
+ // allows some drivers to enable image compression
+ VkImageFormatListCreateInfoKHR formatList;
+ formatList.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+ formatList.pNext = nullptr;
+ formatList.viewFormatCount = createInfo.viewFormatCount;
+ formatList.pViewFormats = createInfo.viewFormats;
+
+ VkImageCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ info.pNext = &formatList;
+ info.flags = createInfo.flags;
+ info.imageType = createInfo.type;
+ info.format = createInfo.format;
+ info.extent = createInfo.extent;
+ info.mipLevels = createInfo.mipLevels;
+ info.arrayLayers = createInfo.numLayers;
+ info.samples = createInfo.sampleCount;
+ info.tiling = createInfo.tiling;
+ info.usage = createInfo.usage;
+ info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ info.queueFamilyIndexCount = 0;
+ info.pQueueFamilyIndices = nullptr;
+ info.initialLayout = createInfo.initialLayout;
+
+ if (m_vkd->vkCreateImage(m_vkd->device(),
+ &info, nullptr, &m_image.image) != VK_SUCCESS) {
+ throw DxvkError(str::format(
+ "DxvkImage: Failed to create image:",
+ "\n Type: ", info.imageType,
+ "\n Format: ", info.format,
+ "\n Extent: ", "(", info.extent.width,
+ ",", info.extent.height,
+ ",", info.extent.depth, ")",
+ "\n Mip levels: ", info.mipLevels,
+ "\n Array layers: ", info.arrayLayers,
+ "\n Samples: ", info.samples,
+ "\n Usage: ", info.usage,
+ "\n Tiling: ", info.tiling));
+ }
+
+ // Get memory requirements for the image. We may enforce strict
+ // alignment on non-linear images in order not to violate the
+ // bufferImageGranularity limit, which may be greater than the
+ // required resource memory alignment on some GPUs.
+ VkMemoryDedicatedRequirements dedicatedRequirements;
+ dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+ dedicatedRequirements.pNext = VK_NULL_HANDLE;
+ dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE;
+ dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE;
+
+ VkMemoryRequirements2 memReq;
+ memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ memReq.pNext = &dedicatedRequirements;
+
+ VkImageMemoryRequirementsInfo2 memReqInfo;
+ memReqInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
+ memReqInfo.image = m_image.image;
+ memReqInfo.pNext = VK_NULL_HANDLE;
+
+ VkMemoryDedicatedAllocateInfo dedMemoryAllocInfo;
+ dedMemoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+ dedMemoryAllocInfo.pNext = VK_NULL_HANDLE;
+ dedMemoryAllocInfo.buffer = VK_NULL_HANDLE;
+ dedMemoryAllocInfo.image = m_image.image;
+
+ m_vkd->vkGetImageMemoryRequirements2(
+ m_vkd->device(), &memReqInfo, &memReq);
+
+ if (info.tiling != VK_IMAGE_TILING_LINEAR && !dedicatedRequirements.prefersDedicatedAllocation) {
+ memReq.memoryRequirements.size = align(memReq.memoryRequirements.size, memAlloc.bufferImageGranularity());
+ memReq.memoryRequirements.alignment = align(memReq.memoryRequirements.alignment , memAlloc.bufferImageGranularity());
+ }
+
+ // Use high memory priority for GPU-writable resources
+ bool isGpuWritable = (m_info.access & (
+ VK_ACCESS_SHADER_WRITE_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) != 0;
+
+ float priority = isGpuWritable ? 1.0f : 0.5f;
+
+ // Ask driver whether we should be using a dedicated allocation
+ m_image.memory = memAlloc.alloc(&memReq.memoryRequirements,
+ dedicatedRequirements, dedMemoryAllocInfo, memFlags, priority);
+
+ // Try to bind the allocated memory slice to the image
+ if (m_vkd->vkBindImageMemory(m_vkd->device(), m_image.image,
+ m_image.memory.memory(), m_image.memory.offset()) != VK_SUCCESS)
+ throw DxvkError("DxvkImage::DxvkImage: Failed to bind device memory");
+ }
+
+
+ DxvkImage::DxvkImage(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkImageCreateInfo& info,
+ VkImage image)
+ : m_vkd(vkd), m_info(info), m_image({ image }) {
+
+ m_viewFormats.resize(info.viewFormatCount);
+ for (uint32_t i = 0; i < info.viewFormatCount; i++)
+ m_viewFormats[i] = info.viewFormats[i];
+ m_info.viewFormats = m_viewFormats.data();
+ }
+
+
+ DxvkImage::~DxvkImage() {
+ // This is a bit of a hack to determine whether
+ // the image is implementation-handled or not
+ if (m_image.memory.memory() != VK_NULL_HANDLE)
+ m_vkd->vkDestroyImage(m_vkd->device(), m_image.image, nullptr);
+ }
+
+
+ DxvkImageView::DxvkImageView(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImage>& image,
+ const DxvkImageViewCreateInfo& info)
+ : m_vkd(vkd), m_image(image), m_info(info) {
+ for (uint32_t i = 0; i < ViewCount; i++)
+ m_views[i] = VK_NULL_HANDLE;
+
+ switch (m_info.type) {
+ case VK_IMAGE_VIEW_TYPE_1D:
+ case VK_IMAGE_VIEW_TYPE_1D_ARRAY: {
+ this->createView(VK_IMAGE_VIEW_TYPE_1D, 1);
+ this->createView(VK_IMAGE_VIEW_TYPE_1D_ARRAY, m_info.numLayers);
+ } break;
+
+ case VK_IMAGE_VIEW_TYPE_2D:
+ case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
+ this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
+ /* fall through */
+
+ case VK_IMAGE_VIEW_TYPE_CUBE:
+ case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: {
+ this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, m_info.numLayers);
+
+ if (m_image->info().flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
+ uint32_t cubeCount = m_info.numLayers / 6;
+
+ if (cubeCount > 0) {
+ this->createView(VK_IMAGE_VIEW_TYPE_CUBE, 6);
+ this->createView(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, 6 * cubeCount);
+ }
+ }
+ } break;
+
+ case VK_IMAGE_VIEW_TYPE_3D: {
+ this->createView(VK_IMAGE_VIEW_TYPE_3D, 1);
+
+ if (m_image->info().flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT && m_info.numLevels == 1) {
+ this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
+ this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, m_image->mipLevelExtent(m_info.minLevel).depth);
+ }
+ } break;
+
+ default:
+ throw DxvkError(str::format("DxvkImageView: Invalid view type: ", m_info.type));
+ }
+ }
+
+
+ DxvkImageView::~DxvkImageView() {
+ for (uint32_t i = 0; i < ViewCount; i++)
+ m_vkd->vkDestroyImageView(m_vkd->device(), m_views[i], nullptr);
+ }
+
+
+ void DxvkImageView::createView(VkImageViewType type, uint32_t numLayers) {
+ VkImageSubresourceRange subresourceRange;
+ subresourceRange.aspectMask = m_info.aspect;
+ subresourceRange.baseMipLevel = m_info.minLevel;
+ subresourceRange.levelCount = m_info.numLevels;
+ subresourceRange.baseArrayLayer = m_info.minLayer;
+ subresourceRange.layerCount = numLayers;
+
+ VkImageViewUsageCreateInfo viewUsage;
+ viewUsage.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
+ viewUsage.pNext = nullptr;
+ viewUsage.usage = m_info.usage;
+
+ VkImageViewCreateInfo viewInfo;
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.pNext = &viewUsage;
+ viewInfo.flags = 0;
+ viewInfo.image = m_image->handle();
+ viewInfo.viewType = type;
+ viewInfo.format = m_info.format;
+ viewInfo.components = m_info.swizzle;
+ viewInfo.subresourceRange = subresourceRange;
+
+ if (m_info.usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
+ viewInfo.components = {
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ }
+
+ if (m_vkd->vkCreateImageView(m_vkd->device(),
+ &viewInfo, nullptr, &m_views[type]) != VK_SUCCESS) {
+ throw DxvkError(str::format(
+ "DxvkImageView: Failed to create image view:"
+ "\n View type: ", viewInfo.viewType,
+ "\n View format: ", viewInfo.format,
+ "\n Subresources: ",
+ "\n Aspect mask: ", std::hex, viewInfo.subresourceRange.aspectMask,
+ "\n Mip levels: ", viewInfo.subresourceRange.baseMipLevel, " - ",
+ viewInfo.subresourceRange.levelCount,
+ "\n Array layers: ", viewInfo.subresourceRange.baseArrayLayer, " - ",
+ viewInfo.subresourceRange.layerCount,
+ "\n Image properties:",
+ "\n Type: ", m_image->info().type,
+ "\n Format: ", m_image->info().format,
+ "\n Extent: ", "(", m_image->info().extent.width,
+ ",", m_image->info().extent.height,
+ ",", m_image->info().extent.depth, ")",
+ "\n Mip levels: ", m_image->info().mipLevels,
+ "\n Array layers: ", m_image->info().numLayers,
+ "\n Samples: ", m_image->info().sampleCount,
+ "\n Usage: ", std::hex, m_image->info().usage,
+ "\n Tiling: ", m_image->info().tiling));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.h
new file mode 100644
index 00000000..b3b721e0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_image.h
@@ -0,0 +1,542 @@
+#pragma once
+
+#include "dxvk_descriptor.h"
+#include "dxvk_format.h"
+#include "dxvk_memory.h"
+#include "dxvk_resource.h"
+#include "dxvk_util.h"
+
+namespace dxvk {
+
+ class DxvkImageView;
+
+ /**
+ * \brief Image create info
+ *
+ * The properties of an image that are
+ * passed to \ref DxvkDevice::createImage
+ */
+ struct DxvkImageCreateInfo {
+ /// Image dimension
+ VkImageType type;
+
+ /// Pixel format
+ VkFormat format;
+
+ /// Flags
+ VkImageCreateFlags flags;
+
+ /// Sample count for MSAA
+ VkSampleCountFlagBits sampleCount;
+
+ /// Image size, in texels
+ VkExtent3D extent;
+
+ /// Number of image array layers
+ uint32_t numLayers;
+
+ /// Number of mip levels
+ uint32_t mipLevels;
+
+ /// Image usage flags
+ VkImageUsageFlags usage;
+
+ /// Pipeline stages that can access
+ /// the contents of the image
+ VkPipelineStageFlags stages;
+
+ /// Allowed access pattern
+ VkAccessFlags access;
+
+ /// Image tiling mode
+ VkImageTiling tiling;
+
+ /// Common image layout
+ VkImageLayout layout;
+
+ // Initial image layout
+ VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ // Image is used by multiple contexts so it needs
+ // to be in its default layout after each submission
+ VkBool32 shared = VK_FALSE;
+
+ // Image view formats that can
+ // be used with this image
+ uint32_t viewFormatCount = 0;
+ const VkFormat* viewFormats = nullptr;
+ };
+
+
+ /**
+ * \brief Image create info
+ *
+ * The properties of an image view that are
+ * passed to \ref DxvkDevice::createImageView
+ */
+ struct DxvkImageViewCreateInfo {
+ /// Image view dimension
+ VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D;
+
+ /// Pixel format
+ VkFormat format = VK_FORMAT_UNDEFINED;
+
+ /// Image view usage flags
+ VkImageUsageFlags usage = 0;
+
+ /// Subresources to use in the view
+ VkImageAspectFlags aspect = 0;
+
+ uint32_t minLevel = 0;
+ uint32_t numLevels = 0;
+ uint32_t minLayer = 0;
+ uint32_t numLayers = 0;
+
+ /// Component mapping. Defaults to identity.
+ VkComponentMapping swizzle = {
+ VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY,
+ };
+ };
+
+
+ /**
+ * \brief Stores an image and its memory slice.
+ */
+ struct DxvkPhysicalImage {
+ VkImage image = VK_NULL_HANDLE;
+ DxvkMemory memory;
+ };
+
+
+ /**
+ * \brief DXVK image
+ *
+ * An image resource consisting of various subresources.
+ * Can be accessed by the host if allocated on a suitable
+ * memory type and if created with the linear tiling option.
+ */
+ class DxvkImage : public DxvkResource {
+ friend class DxvkContext;
+ friend class DxvkImageView;
+ public:
+
+ DxvkImage(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkImageCreateInfo& createInfo,
+ DxvkMemoryAllocator& memAlloc,
+ VkMemoryPropertyFlags memFlags);
+
+ /**
+ * \brief Creates image object from existing image
+ *
+ * This can be used to create an image object for
+ * an implementation-managed image. Make sure to
+ * provide the correct image properties, since
+ * otherwise some image operations may fail.
+ */
+ DxvkImage(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkImageCreateInfo& info,
+ VkImage image);
+
+ /**
+ * \brief Destroys image
+ *
+ * If this is an implementation-managed image,
+ * this will not destroy the Vulkan image.
+ */
+ ~DxvkImage();
+
+ /**
+ * \brief Image handle
+ *
+ * Internal use only.
+ * \returns Image handle
+ */
+ VkImage handle() const {
+ return m_image.image;
+ }
+
+ /**
+ * \brief Image properties
+ *
+ * The image create info structure.
+ * \returns Image properties
+ */
+ const DxvkImageCreateInfo& info() const {
+ return m_info;
+ }
+
+ /**
+ * \brief Memory type flags
+ *
+ * Use this to determine whether a
+ * buffer is mapped to host memory.
+ * \returns Vulkan memory flags
+ */
+ VkMemoryPropertyFlags memFlags() const {
+ return m_memFlags;
+ }
+
+ /**
+ * \brief Map pointer
+ *
+ * If the image has been created on a host-visible
+ * memory type, its memory is mapped and can be
+ * accessed by the host.
+ * \param [in] offset Byte offset into mapped region
+ * \returns Pointer to mapped memory region
+ */
+ void* mapPtr(VkDeviceSize offset) const {
+ return m_image.memory.mapPtr(offset);
+ }
+
+ /**
+ * \brief Image format info
+ * \returns Image format info
+ */
+ const DxvkFormatInfo* formatInfo() const {
+ return imageFormatInfo(m_info.format);
+ }
+
+ /**
+ * \brief Size of a mipmap level
+ *
+ * \param [in] level Mip level
+ * \returns Size of that level
+ */
+ VkExtent3D mipLevelExtent(uint32_t level) const {
+ return util::computeMipLevelExtent(m_info.extent, level);
+ }
+
+ /**
+ * \brief Size of a mipmap level
+ *
+ * \param [in] level Mip level
+ * \returns Size of that level
+ */
+ VkExtent3D mipLevelExtent(uint32_t level, VkImageAspectFlags aspect) const {
+ return util::computeMipLevelExtent(m_info.extent, level, m_info.format, aspect);
+ }
+
+ /**
+ * \brief Queries memory layout of a subresource
+ *
+ * Can be used to retrieve the exact pointer to a
+ * subresource of a mapped image with linear tiling.
+ * \param [in] subresource The image subresource
+ * \returns Memory layout of that subresource
+ */
+ VkSubresourceLayout querySubresourceLayout(
+ const VkImageSubresource& subresource) const {
+ VkSubresourceLayout result;
+ m_vkd->vkGetImageSubresourceLayout(
+ m_vkd->device(), m_image.image,
+ &subresource, &result);
+ return result;
+ }
+
+ /**
+ * \brief Picks a compatible layout
+ *
+ * Under some circumstances, we have to return
+ * a different layout than the one requested.
+ * \param [in] layout The image layout
+ * \returns A compatible image layout
+ */
+ VkImageLayout pickLayout(VkImageLayout layout) const {
+ return m_info.layout == VK_IMAGE_LAYOUT_GENERAL
+ ? VK_IMAGE_LAYOUT_GENERAL : layout;
+ }
+
+ /**
+ * \brief Changes image layout
+ * \param [in] layout New layout
+ */
+ void setLayout(VkImageLayout layout) {
+ m_info.layout = layout;
+ }
+
+ /**
+ * \brief Checks whether a subresource is entirely covered
+ *
+ * This can be used to determine whether an image can or
+ * should be initialized with \c VK_IMAGE_LAYOUT_UNDEFINED.
+ * \param [in] subresource The image subresource
+ * \param [in] extent Image extent to check
+ */
+ bool isFullSubresource(
+ const VkImageSubresourceLayers& subresource,
+ VkExtent3D extent) const {
+ return subresource.aspectMask == this->formatInfo()->aspectMask
+ && extent == this->mipLevelExtent(subresource.mipLevel);
+ }
+
+ /**
+ * \brief Checks view format compatibility
+ *
+ * If this returns true, a view with the given
+ * format can be safely created for this image.
+ * \param [in] format The format to check
+ * \returns \c true if the format is vompatible
+ */
+ bool isViewCompatible(VkFormat format) const {
+ bool result = m_info.format == format;
+ for (uint32_t i = 0; i < m_viewFormats.size() && !result; i++)
+ result |= m_viewFormats[i] == format;
+ return result;
+ }
+
+ /**
+ * \brief Memory size
+ *
+ * \returns The memory size of the image
+ */
+ VkDeviceSize memSize() const {
+ return m_image.memory.length();
+ }
+
+ /**
+ * \brief Get full subresource range of the image
+ *
+ * \returns Resource range of the whole image
+ */
+ VkImageSubresourceRange getAvailableSubresources() const {
+ VkImageSubresourceRange result;
+ result.aspectMask = formatInfo()->aspectMask;
+ result.baseMipLevel = 0;
+ result.levelCount = info().mipLevels;
+ result.baseArrayLayer = 0;
+ result.layerCount = info().numLayers;
+ return result;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkImageCreateInfo m_info;
+ VkMemoryPropertyFlags m_memFlags;
+ DxvkPhysicalImage m_image;
+
+ small_vector<VkFormat, 4> m_viewFormats;
+
+ };
+
+
+ /**
+ * \brief DXVK image view
+ */
+ class DxvkImageView : public DxvkResource {
+ friend class DxvkImage;
+ constexpr static uint32_t ViewCount = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY + 1;
+ public:
+
+ DxvkImageView(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImage>& image,
+ const DxvkImageViewCreateInfo& info);
+
+ ~DxvkImageView();
+
+ /**
+ * \brief Image view handle for the default type
+ *
+ * The default view type is guaranteed to be
+ * supported by the image view, and should be
+ * preferred over picking a different type.
+ * \returns Image view handle
+ */
+ VkImageView handle() const {
+ return handle(m_info.type);
+ }
+
+ /**
+ * \brief Image view handle for a given view type
+ *
+ * If the view does not support the requested image
+ * view type, \c VK_NULL_HANDLE will be returned.
+ * \param [in] viewType The requested view type
+ * \returns The image view handle
+ */
+ VkImageView handle(VkImageViewType viewType) const {
+ if (unlikely(viewType == VK_IMAGE_VIEW_TYPE_MAX_ENUM))
+ viewType = m_info.type;
+ return m_views[viewType];
+ }
+
+ /**
+ * \brief Image view type
+ *
+ * Convenience method to query the view type
+ * in order to check for resource compatibility.
+ * \returns Image view type
+ */
+ VkImageViewType type() const {
+ return m_info.type;
+ }
+
+ /**
+ * \brief Image view properties
+ * \returns Image view properties
+ */
+ const DxvkImageViewCreateInfo& info() const {
+ return m_info;
+ }
+
+ /**
+ * \brief Image handle
+ * \returns Image handle
+ */
+ VkImage imageHandle() const {
+ return m_image->handle();
+ }
+
+ /**
+ * \brief Image properties
+ * \returns Image properties
+ */
+ const DxvkImageCreateInfo& imageInfo() const {
+ return m_image->info();
+ }
+
+ /**
+ * \brief Image object
+ * \returns Image object
+ */
+ const Rc<DxvkImage>& image() const {
+ return m_image;
+ }
+
+ /**
+ * \brief View format info
+ * \returns View format info
+ */
+ const DxvkFormatInfo* formatInfo() const {
+ return imageFormatInfo(m_info.format);
+ }
+
+ /**
+ * \brief Mip level size
+ *
+ * Computes the mip level size relative to
+ * the first mip level that the view includes.
+ * \param [in] level Mip level
+ * \returns Size of that level
+ */
+ VkExtent3D mipLevelExtent(uint32_t level) const {
+ return m_image->mipLevelExtent(level + m_info.minLevel, m_info.aspect);
+ }
+
+ /**
+ * \brief View subresource range
+ *
+ * Returns the subresource range from the image
+ * description. For 2D views of 3D images, this
+ * will return the viewed 3D slices.
+ * \returns View subresource range
+ */
+ VkImageSubresourceRange subresources() const {
+ VkImageSubresourceRange result;
+ result.aspectMask = m_info.aspect;
+ result.baseMipLevel = m_info.minLevel;
+ result.levelCount = m_info.numLevels;
+ result.baseArrayLayer = m_info.minLayer;
+ result.layerCount = m_info.numLayers;
+ return result;
+ }
+
+ /**
+ * \brief Actual image subresource range
+ *
+ * Handles 3D images correctly in that it only
+ * returns one single array layer. Use this for
+ * barriers.
+ * \returns Image subresource range
+ */
+ VkImageSubresourceRange imageSubresources() const {
+ VkImageSubresourceRange result;
+ result.aspectMask = m_info.aspect;
+ result.baseMipLevel = m_info.minLevel;
+ result.levelCount = m_info.numLevels;
+ if (likely(m_image->info().type != VK_IMAGE_TYPE_3D)) {
+ result.baseArrayLayer = m_info.minLayer;
+ result.layerCount = m_info.numLayers;
+ } else {
+ result.baseArrayLayer = 0;
+ result.layerCount = 1;
+ }
+ return result;
+ }
+
+ /**
+ * \brief Picks an image layout
+ * \see DxvkImage::pickLayout
+ */
+ VkImageLayout pickLayout(VkImageLayout layout) const {
+ return m_image->pickLayout(layout);
+ }
+
+ /**
+ * \brief Retrieves descriptor info
+ *
+ * \param [in] type Exact view type
+ * \param [in] layout Image layout
+ * \returns Image descriptor
+ */
+ DxvkDescriptorInfo getDescriptor(VkImageViewType type, VkImageLayout layout) const {
+ DxvkDescriptorInfo result;
+ result.image.sampler = VK_NULL_HANDLE;
+ result.image.imageView = handle(type);
+ result.image.imageLayout = layout;
+ return result;
+ }
+
+ /**
+ * \brief Checks whether this view matches another
+ *
+ * \param [in] view The other view to check
+ * \returns \c true if the two views have the same subresources
+ */
+ bool matchesView(const Rc<DxvkImageView>& view) const {
+ if (this == view.ptr())
+ return true;
+
+ return this->image() == view->image()
+ && this->subresources() == view->subresources()
+ && this->info().type == view->info().type
+ && this->info().format == view->info().format;
+ }
+
+ /**
+ * \brief Checks whether this view overlaps with another one
+ *
+ * Two views overlap if they were created for the same
+ * image and have at least one subresource in common.
+ * \param [in] view The other view to check
+ * \returns \c true if the two views overlap
+ */
+ bool checkSubresourceOverlap(const Rc<DxvkImageView>& view) const {
+ if (likely(m_image != view->m_image))
+ return false;
+
+ return vk::checkSubresourceRangeOverlap(
+ this->imageSubresources(),
+ view->imageSubresources());
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ Rc<DxvkImage> m_image;
+
+ DxvkImageViewCreateInfo m_info;
+ VkImageView m_views[ViewCount];
+
+ void createView(VkImageViewType type, uint32_t numLayers);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_include.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_include.h
new file mode 100644
index 00000000..3803afb5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_include.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/util_env.h"
+#include "../util/util_error.h"
+#include "../util/util_flags.h"
+#include "../util/util_likely.h"
+#include "../util/util_math.h"
+#include "../util/util_small_vector.h"
+#include "../util/util_string.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#include "../util/sha1/sha1_util.h"
+
+#include "../util/sync/sync_signal.h"
+#include "../util/sync/sync_spinlock.h"
+#include "../util/sync/sync_ticketlock.h"
+
+#include "../vulkan/vulkan_loader.h"
+#include "../vulkan/vulkan_names.h"
+#include "../vulkan/vulkan_util.h"
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.cpp
new file mode 100644
index 00000000..3d18a1cd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.cpp
@@ -0,0 +1,218 @@
+#include <version.h>
+
+#include "dxvk_instance.h"
+#include "dxvk_openvr.h"
+#include "dxvk_openxr.h"
+#include "dxvk_platform_exts.h"
+
+#include <algorithm>
+
+namespace dxvk {
+
+ DxvkInstance::DxvkInstance() {
+ Logger::info(str::format("Game: ", env::getExeName()));
+ Logger::info(str::format("DXVK: ", DXVK_VERSION));
+
+ m_config = Config::getUserConfig();
+ m_config.merge(Config::getAppConfig(env::getExePath()));
+ m_config.logOptions();
+
+ m_options = DxvkOptions(m_config);
+
+ m_extProviders.push_back(&DxvkPlatformExts::s_instance);
+
+#ifndef DXVK_NATIVE
+ if (m_options.enableOpenVR)
+ m_extProviders.push_back(&VrInstance::s_instance);
+
+ if (m_options.enableOpenXR)
+ m_extProviders.push_back(&DxvkXrProvider::s_instance);
+#endif
+
+ Logger::info("Built-in extension providers:");
+ for (const auto& provider : m_extProviders)
+ Logger::info(str::format(" ", provider->getName()));
+
+ for (const auto& provider : m_extProviders)
+ provider->initInstanceExtensions();
+
+ m_vkl = new vk::LibraryFn();
+ m_vki = new vk::InstanceFn(true, this->createInstance());
+
+ m_adapters = this->queryAdapters();
+
+ for (const auto& provider : m_extProviders)
+ provider->initDeviceExtensions(this);
+
+ for (uint32_t i = 0; i < m_adapters.size(); i++) {
+ for (const auto& provider : m_extProviders) {
+ m_adapters[i]->enableExtensions(
+ provider->getDeviceExtensions(i));
+ }
+ }
+ }
+
+
+ DxvkInstance::~DxvkInstance() {
+
+ }
+
+
+ Rc<DxvkAdapter> DxvkInstance::enumAdapters(uint32_t index) const {
+ return index < m_adapters.size()
+ ? m_adapters[index]
+ : nullptr;
+ }
+
+
+ Rc<DxvkAdapter> DxvkInstance::findAdapterByLuid(const void* luid) const {
+ for (const auto& adapter : m_adapters) {
+ const auto& props = adapter->devicePropertiesExt().coreDeviceId;
+
+ if (props.deviceLUIDValid && !std::memcmp(luid, props.deviceLUID, VK_LUID_SIZE))
+ return adapter;
+ }
+
+ return nullptr;
+ }
+
+
+ Rc<DxvkAdapter> DxvkInstance::findAdapterByDeviceId(uint16_t vendorId, uint16_t deviceId) const {
+ for (const auto& adapter : m_adapters) {
+ const auto& props = adapter->deviceProperties();
+
+ if (props.vendorID == vendorId
+ && props.deviceID == deviceId)
+ return adapter;
+ }
+
+ return nullptr;
+ }
+
+
+ VkInstance DxvkInstance::createInstance() {
+ DxvkInstanceExtensions insExtensions;
+
+ std::vector<DxvkExt*> insExtensionList = {{
+ &insExtensions.khrGetSurfaceCapabilities2,
+ &insExtensions.khrSurface,
+ }};
+
+ // Hide VK_EXT_debug_utils behind an environment variable. This extension
+ // adds additional overhead to winevulkan
+ if (env::getEnvVar("DXVK_PERF_EVENTS") == "1") {
+ insExtensionList.push_back(&insExtensions.extDebugUtils);
+ }
+
+ DxvkNameSet extensionsEnabled;
+ DxvkNameSet extensionsAvailable = DxvkNameSet::enumInstanceExtensions(m_vkl);
+
+ if (!extensionsAvailable.enableExtensions(
+ insExtensionList.size(),
+ insExtensionList.data(),
+ extensionsEnabled))
+ throw DxvkError("DxvkInstance: Failed to create instance");
+
+ m_extensions = insExtensions;
+
+ // Enable additional extensions if necessary
+ for (const auto& provider : m_extProviders)
+ extensionsEnabled.merge(provider->getInstanceExtensions());
+
+ DxvkNameList extensionNameList = extensionsEnabled.toNameList();
+
+ Logger::info("Enabled instance extensions:");
+ this->logNameList(extensionNameList);
+
+ std::string appName = env::getExeName();
+
+ VkApplicationInfo appInfo;
+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appInfo.pNext = nullptr;
+ appInfo.pApplicationName = appName.c_str();
+ appInfo.applicationVersion = 0;
+ appInfo.pEngineName = "DXVK";
+ appInfo.engineVersion = VK_MAKE_VERSION(1, 9, 2);
+ appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
+
+ VkInstanceCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.pApplicationInfo = &appInfo;
+ info.enabledLayerCount = 0;
+ info.ppEnabledLayerNames = nullptr;
+ info.enabledExtensionCount = extensionNameList.count();
+ info.ppEnabledExtensionNames = extensionNameList.names();
+
+ VkInstance result = VK_NULL_HANDLE;
+ VkResult status = m_vkl->vkCreateInstance(&info, nullptr, &result);
+
+ if (status != VK_SUCCESS)
+ throw DxvkError("DxvkInstance::createInstance: Failed to create Vulkan 1.1 instance");
+
+ return result;
+ }
+
+
+ std::vector<Rc<DxvkAdapter>> DxvkInstance::queryAdapters() {
+ uint32_t numAdapters = 0;
+ if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, nullptr) != VK_SUCCESS)
+ throw DxvkError("DxvkInstance::enumAdapters: Failed to enumerate adapters");
+
+ std::vector<VkPhysicalDevice> adapters(numAdapters);
+ if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, adapters.data()) != VK_SUCCESS)
+ throw DxvkError("DxvkInstance::enumAdapters: Failed to enumerate adapters");
+
+ std::vector<VkPhysicalDeviceProperties> deviceProperties(numAdapters);
+ DxvkDeviceFilterFlags filterFlags = 0;
+
+ for (uint32_t i = 0; i < numAdapters; i++) {
+ m_vki->vkGetPhysicalDeviceProperties(adapters[i], &deviceProperties[i]);
+
+ if (deviceProperties[i].deviceType != VK_PHYSICAL_DEVICE_TYPE_CPU)
+ filterFlags.set(DxvkDeviceFilterFlag::SkipCpuDevices);
+ }
+
+ DxvkDeviceFilter filter(filterFlags);
+ std::vector<Rc<DxvkAdapter>> result;
+
+ for (uint32_t i = 0; i < numAdapters; i++) {
+ if (filter.testAdapter(deviceProperties[i]))
+ result.push_back(new DxvkAdapter(m_vki, adapters[i]));
+ }
+
+ std::stable_sort(result.begin(), result.end(),
+ [] (const Rc<DxvkAdapter>& a, const Rc<DxvkAdapter>& b) -> bool {
+ static const std::array<VkPhysicalDeviceType, 3> deviceTypes = {{
+ VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
+ VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
+ VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU,
+ }};
+
+ uint32_t aRank = deviceTypes.size();
+ uint32_t bRank = deviceTypes.size();
+
+ for (uint32_t i = 0; i < std::min(aRank, bRank); i++) {
+ if (a->deviceProperties().deviceType == deviceTypes[i]) aRank = i;
+ if (b->deviceProperties().deviceType == deviceTypes[i]) bRank = i;
+ }
+
+ return aRank < bRank;
+ });
+
+ if (result.size() == 0) {
+ Logger::warn("DXVK: No adapters found. Please check your "
+ "device filter settings and Vulkan setup.");
+ }
+
+ return result;
+ }
+
+
+ void DxvkInstance::logNameList(const DxvkNameList& names) {
+ for (uint32_t i = 0; i < names.count(); i++)
+ Logger::info(str::format(" ", names.name(i)));
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.h
new file mode 100644
index 00000000..f945ed6d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_instance.h
@@ -0,0 +1,129 @@
+#pragma once
+
+#include "../util/config/config.h"
+
+#include "dxvk_adapter.h"
+#include "dxvk_device_filter.h"
+#include "dxvk_extension_provider.h"
+#include "dxvk_options.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXVK instance
+ *
+ * Manages a Vulkan instance and stores a list
+ * of adapters. This also provides methods for
+ * device creation.
+ */
+ class DxvkInstance : public RcObject {
+
+ public:
+
+ DxvkInstance();
+ ~DxvkInstance();
+
+ /**
+ * \brief Vulkan instance functions
+ * \returns Vulkan instance functions
+ */
+ Rc<vk::InstanceFn> vki() const {
+ return m_vki;
+ }
+
+ /**
+ * \brief Vulkan instance handle
+ * \returns The instance handle
+ */
+ VkInstance handle() {
+ return m_vki->instance();
+ }
+
+ /**
+ * \brief Number of adapters
+ *
+ * \returns The number of adapters
+ */
+ size_t adapterCount() {
+ return m_adapters.size();
+ }
+
+ /**
+ * \brief Retrieves an adapter
+ *
+ * Note that the adapter does not hold
+ * a hard reference to the instance.
+ * \param [in] index Adapter index
+ * \returns The adapter, or \c nullptr.
+ */
+ Rc<DxvkAdapter> enumAdapters(
+ uint32_t index) const;
+
+ /**
+ * \brief Finds adapter by LUID
+ *
+ * \param [in] luid Pointer to LUID
+ * \returns Matching adapter, if any
+ */
+ Rc<DxvkAdapter> findAdapterByLuid(
+ const void* luid) const;
+
+ /**
+ * \brief Finds adapter by device IDs
+ *
+ * \param [in] vendorId Vendor ID
+ * \param [in] deviceId Device ID
+ * \returns Matching adapter, if any
+ */
+ Rc<DxvkAdapter> findAdapterByDeviceId(
+ uint16_t vendorId,
+ uint16_t deviceId) const;
+
+ /**
+ * \brief Retrieves configuration options
+ *
+ * The configuration set contains user-defined
+ * options as well as app-specific options.
+ * \returns Configuration options
+ */
+ const Config& config() const {
+ return m_config;
+ }
+
+ /**
+ * \brief DXVK options
+ * \returns DXVK options
+ */
+ const DxvkOptions& options() const {
+ return m_options;
+ }
+
+ /**
+ * \brief Enabled instance extensions
+ * \returns Enabled instance extensions
+ */
+ const DxvkInstanceExtensions& extensions() const {
+ return m_extensions;
+ }
+
+ private:
+
+ Config m_config;
+ DxvkOptions m_options;
+
+ Rc<vk::LibraryFn> m_vkl;
+ Rc<vk::InstanceFn> m_vki;
+ DxvkInstanceExtensions m_extensions;
+
+ std::vector<DxvkExtensionProvider*> m_extProviders;
+ std::vector<Rc<DxvkAdapter>> m_adapters;
+
+ VkInstance createInstance();
+
+ std::vector<Rc<DxvkAdapter>> queryAdapters();
+
+ static void logNameList(const DxvkNameList& names);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.cpp
new file mode 100644
index 00000000..777cf020
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.cpp
@@ -0,0 +1,15 @@
+#include "dxvk_lifetime.h"
+
+namespace dxvk {
+
+ DxvkLifetimeTracker:: DxvkLifetimeTracker() { }
+ DxvkLifetimeTracker::~DxvkLifetimeTracker() { }
+
+
+ void DxvkLifetimeTracker::reset() {
+ for (const auto& resource : m_resources)
+ resource.first->release(resource.second);
+ m_resources.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.h
new file mode 100644
index 00000000..75f3c8df
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_lifetime.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ /**
+ * \brief DXVK lifetime tracker
+ *
+ * Maintains references to a set of resources. This is
+ * used to guarantee that resources are not destroyed
+ * or otherwise accessed in an unsafe manner until the
+ * device has finished using them.
+ */
+ class DxvkLifetimeTracker {
+
+ public:
+
+ DxvkLifetimeTracker();
+ ~DxvkLifetimeTracker();
+
+ /**
+ * \brief Adds a resource to track
+ * \param [in] rc The resource to track
+ */
+ template<DxvkAccess Access>
+ void trackResource(Rc<DxvkResource>&& rc) {
+ rc->acquire(Access);
+ m_resources.emplace_back(std::move(rc), Access);
+ }
+
+ /**
+ * \brief Resets the command list
+ *
+ * Called automatically by the device when
+ * the command list has completed execution.
+ */
+ void reset();
+
+ private:
+
+ std::vector<std::pair<Rc<DxvkResource>, DxvkAccess>> m_resources;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_limits.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_limits.h
new file mode 100644
index 00000000..eb2431e6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_limits.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ enum DxvkLimits : size_t {
+ MaxNumRenderTargets = 8,
+ MaxNumVertexAttributes = 32,
+ MaxNumVertexBindings = 32,
+ MaxNumXfbBuffers = 4,
+ MaxNumXfbStreams = 4,
+ MaxNumViewports = 16,
+ MaxNumResourceSlots = 1216,
+ MaxNumActiveBindings = 384,
+ MaxNumQueuedCommandBuffers = 18,
+ MaxNumQueryCountPerPool = 128,
+ MaxNumSpecConstants = 12,
+ MaxUniformBufferSize = 65536,
+ MaxVertexBindingStride = 2048,
+ MaxPushConstantSize = 128,
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.cpp
new file mode 100644
index 00000000..a47c6993
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.cpp
@@ -0,0 +1,5 @@
+#include "dxvk_main.h"
+
+namespace dxvk {
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.h
new file mode 100644
index 00000000..624613e2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_main.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "../util/log/log.h"
+
+
+namespace dxvk {
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.cpp
new file mode 100644
index 00000000..9a0656a8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.cpp
@@ -0,0 +1,448 @@
+#include "dxvk_device.h"
+#include "dxvk_memory.h"
+
+namespace dxvk {
+
+ DxvkMemory::DxvkMemory() { }
+ DxvkMemory::DxvkMemory(
+ DxvkMemoryAllocator* alloc,
+ DxvkMemoryChunk* chunk,
+ DxvkMemoryType* type,
+ VkDeviceMemory memory,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ void* mapPtr)
+ : m_alloc (alloc),
+ m_chunk (chunk),
+ m_type (type),
+ m_memory (memory),
+ m_offset (offset),
+ m_length (length),
+ m_mapPtr (mapPtr) { }
+
+
+ DxvkMemory::DxvkMemory(DxvkMemory&& other)
+ : m_alloc (std::exchange(other.m_alloc, nullptr)),
+ m_chunk (std::exchange(other.m_chunk, nullptr)),
+ m_type (std::exchange(other.m_type, nullptr)),
+ m_memory (std::exchange(other.m_memory, VkDeviceMemory(VK_NULL_HANDLE))),
+ m_offset (std::exchange(other.m_offset, 0)),
+ m_length (std::exchange(other.m_length, 0)),
+ m_mapPtr (std::exchange(other.m_mapPtr, nullptr)) { }
+
+
+ DxvkMemory& DxvkMemory::operator = (DxvkMemory&& other) {
+ this->free();
+ m_alloc = std::exchange(other.m_alloc, nullptr);
+ m_chunk = std::exchange(other.m_chunk, nullptr);
+ m_type = std::exchange(other.m_type, nullptr);
+ m_memory = std::exchange(other.m_memory, VkDeviceMemory(VK_NULL_HANDLE));
+ m_offset = std::exchange(other.m_offset, 0);
+ m_length = std::exchange(other.m_length, 0);
+ m_mapPtr = std::exchange(other.m_mapPtr, nullptr);
+ return *this;
+ }
+
+
+ DxvkMemory::~DxvkMemory() {
+ this->free();
+ }
+
+
+ void DxvkMemory::free() {
+ if (m_alloc != nullptr)
+ m_alloc->free(*this);
+ }
+
+
+ DxvkMemoryChunk::DxvkMemoryChunk(
+ DxvkMemoryAllocator* alloc,
+ DxvkMemoryType* type,
+ DxvkDeviceMemory memory)
+ : m_alloc(alloc), m_type(type), m_memory(memory) {
+ // Mark the entire chunk as free
+ m_freeList.push_back(FreeSlice { 0, memory.memSize });
+ }
+
+
+ DxvkMemoryChunk::~DxvkMemoryChunk() {
+ // This call is technically not thread-safe, but it
+ // doesn't need to be since we don't free chunks
+ m_alloc->freeDeviceMemory(m_type, m_memory);
+ }
+
+
+ DxvkMemory DxvkMemoryChunk::alloc(
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ VkDeviceSize align,
+ float priority) {
+ // Property flags must be compatible. This could
+ // be refined a bit in the future if necessary.
+ if (m_memory.memFlags != flags
+ || m_memory.priority != priority)
+ return DxvkMemory();
+
+ // If the chunk is full, return
+ if (m_freeList.size() == 0)
+ return DxvkMemory();
+
+ // Select the slice to allocate from in a worst-fit
+ // manner. This may help keep fragmentation low.
+ auto bestSlice = m_freeList.begin();
+
+ for (auto slice = m_freeList.begin(); slice != m_freeList.end(); slice++) {
+ if (slice->length == size) {
+ bestSlice = slice;
+ break;
+ } else if (slice->length > bestSlice->length) {
+ bestSlice = slice;
+ }
+ }
+
+ // We need to align the allocation to the requested alignment
+ const VkDeviceSize sliceStart = bestSlice->offset;
+ const VkDeviceSize sliceEnd = bestSlice->offset + bestSlice->length;
+
+ const VkDeviceSize allocStart = dxvk::align(sliceStart, align);
+ const VkDeviceSize allocEnd = dxvk::align(allocStart + size, align);
+
+ if (allocEnd > sliceEnd)
+ return DxvkMemory();
+
+ // We can use this slice, but we'll have to add
+ // the unused parts of it back to the free list.
+ m_freeList.erase(bestSlice);
+
+ if (allocStart != sliceStart)
+ m_freeList.push_back({ sliceStart, allocStart - sliceStart });
+
+ if (allocEnd != sliceEnd)
+ m_freeList.push_back({ allocEnd, sliceEnd - allocEnd });
+
+ // Create the memory object with the aligned slice
+ return DxvkMemory(m_alloc, this, m_type,
+ m_memory.memHandle, allocStart, allocEnd - allocStart,
+ reinterpret_cast<char*>(m_memory.memPointer) + allocStart);
+ }
+
+
+ void DxvkMemoryChunk::free(
+ VkDeviceSize offset,
+ VkDeviceSize length) {
+ // Remove adjacent entries from the free list and then add
+ // a new slice that covers all those entries. Without doing
+ // so, the slice could not be reused for larger allocations.
+ auto curr = m_freeList.begin();
+
+ while (curr != m_freeList.end()) {
+ if (curr->offset == offset + length) {
+ length += curr->length;
+ curr = m_freeList.erase(curr);
+ } else if (curr->offset + curr->length == offset) {
+ offset -= curr->length;
+ length += curr->length;
+ curr = m_freeList.erase(curr);
+ } else {
+ curr++;
+ }
+ }
+
+ m_freeList.push_back({ offset, length });
+ }
+
+
+ DxvkMemoryAllocator::DxvkMemoryAllocator(const DxvkDevice* device)
+ : m_vkd (device->vkd()),
+ m_device (device),
+ m_devProps (device->adapter()->deviceProperties()),
+ m_memProps (device->adapter()->memoryProperties()) {
+ for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
+ m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
+ m_memHeaps[i].stats = DxvkMemoryStats { 0, 0 };
+ m_memHeaps[i].budget = 0;
+
+ /* Target 80% of a heap on systems where we want
+ * to avoid oversubscribing memory heaps */
+ if ((m_memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
+ && (m_device->isUnifiedMemoryArchitecture()))
+ m_memHeaps[i].budget = (8 * m_memProps.memoryHeaps[i].size) / 10;
+ }
+
+ for (uint32_t i = 0; i < m_memProps.memoryTypeCount; i++) {
+ m_memTypes[i].heap = &m_memHeaps[m_memProps.memoryTypes[i].heapIndex];
+ m_memTypes[i].heapId = m_memProps.memoryTypes[i].heapIndex;
+ m_memTypes[i].memType = m_memProps.memoryTypes[i];
+ m_memTypes[i].memTypeId = i;
+ m_memTypes[i].chunkSize = pickChunkSize(i);
+ }
+
+ /* Work around an issue on Nvidia drivers where using the entire
+ * device_local | host_visible heap can cause crashes, presumably
+ * due to subsequent internal driver allocations failing */
+ bool nvidiaBug3114283Active = false;
+
+ // Fix is available in mainline drivers starting with the 465 driver series.
+ if (device->adapter()->matchesDriver(DxvkGpuVendor::Nvidia,
+ VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR,
+ 0,
+ VK_MAKE_VERSION(465, 0, 0))) {
+ nvidiaBug3114283Active = true;
+ }
+
+ applyTristate(nvidiaBug3114283Active, device->config().halveNvidiaHVVHeap);
+
+ if ((m_device->properties().core.properties.vendorID == uint16_t(DxvkGpuVendor::Nvidia))
+ && (nvidiaBug3114283Active)) {
+ for (uint32_t i = 0; i < m_memProps.memoryTypeCount; i++) {
+ constexpr VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+
+ if ((m_memTypes[i].memType.propertyFlags & flags) == flags)
+ m_memTypes[i].heap->budget = m_memTypes[i].heap->properties.size / 2;
+ }
+ }
+ }
+
+
+ DxvkMemoryAllocator::~DxvkMemoryAllocator() {
+
+ }
+
+
+ DxvkMemory DxvkMemoryAllocator::alloc(
+ const VkMemoryRequirements* req,
+ const VkMemoryDedicatedRequirements& dedAllocReq,
+ const VkMemoryDedicatedAllocateInfo& dedAllocInfo,
+ VkMemoryPropertyFlags flags,
+ float priority) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ // Try to allocate from a memory type which supports the given flags exactly
+ auto dedAllocPtr = dedAllocReq.prefersDedicatedAllocation ? &dedAllocInfo : nullptr;
+ DxvkMemory result = this->tryAlloc(req, dedAllocPtr, flags, priority);
+
+ // If the first attempt failed, try ignoring the dedicated allocation
+ if (!result && dedAllocPtr && !dedAllocReq.requiresDedicatedAllocation) {
+ result = this->tryAlloc(req, nullptr, flags, priority);
+ dedAllocPtr = nullptr;
+ }
+
+ // If that still didn't work, probe slower memory types as well
+ VkMemoryPropertyFlags optFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
+ | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ VkMemoryPropertyFlags remFlags = 0;
+
+ while (!result && (flags & optFlags)) {
+ remFlags |= optFlags & -optFlags;
+ optFlags &= ~remFlags;
+
+ result = this->tryAlloc(req, dedAllocPtr, flags & ~remFlags, priority);
+ }
+
+ if (!result) {
+ DxvkAdapterMemoryInfo memHeapInfo = m_device->adapter()->getMemoryHeapInfo();
+
+ Logger::err(str::format(
+ "DxvkMemoryAllocator: Memory allocation failed",
+ "\n Size: ", req->size,
+ "\n Alignment: ", req->alignment,
+ "\n Mem flags: ", "0x", std::hex, flags,
+ "\n Mem types: ", "0x", std::hex, req->memoryTypeBits));
+
+ for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
+ Logger::err(str::format("Heap ", i, ": ",
+ (m_memHeaps[i].stats.memoryAllocated >> 20), " MB allocated, ",
+ (m_memHeaps[i].stats.memoryUsed >> 20), " MB used, ",
+ m_device->extensions().extMemoryBudget
+ ? str::format(
+ (memHeapInfo.heaps[i].memoryAllocated >> 20), " MB allocated (driver), ",
+ (memHeapInfo.heaps[i].memoryBudget >> 20), " MB budget (driver), ",
+ (m_memHeaps[i].properties.size >> 20), " MB total")
+ : str::format(
+ (m_memHeaps[i].properties.size >> 20), " MB total")));
+ }
+
+ throw DxvkError("DxvkMemoryAllocator: Memory allocation failed");
+ }
+
+ return result;
+ }
+
+
+ DxvkMemory DxvkMemoryAllocator::tryAlloc(
+ const VkMemoryRequirements* req,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo,
+ VkMemoryPropertyFlags flags,
+ float priority) {
+ DxvkMemory result;
+
+ for (uint32_t i = 0; i < m_memProps.memoryTypeCount && !result; i++) {
+ const bool supported = (req->memoryTypeBits & (1u << i)) != 0;
+ const bool adequate = (m_memTypes[i].memType.propertyFlags & flags) == flags;
+
+ if (supported && adequate) {
+ result = this->tryAllocFromType(&m_memTypes[i],
+ flags, req->size, req->alignment, priority, dedAllocInfo);
+ }
+ }
+
+ return result;
+ }
+
+
+ DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
+ DxvkMemoryType* type,
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ VkDeviceSize align,
+ float priority,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo) {
+ // Prevent unnecessary external host memory fragmentation
+ bool isDeviceLocal = (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0;
+
+ if (!isDeviceLocal)
+ priority = 0.0f;
+
+ DxvkMemory memory;
+
+ if (size >= type->chunkSize || dedAllocInfo) {
+ DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(
+ type, flags, size, priority, dedAllocInfo);
+
+ if (devMem.memHandle != VK_NULL_HANDLE)
+ memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer);
+ } else {
+ for (uint32_t i = 0; i < type->chunks.size() && !memory; i++)
+ memory = type->chunks[i]->alloc(flags, size, align, priority);
+
+ if (!memory) {
+ DxvkDeviceMemory devMem;
+
+ for (uint32_t i = 0; i < 6 && (type->chunkSize >> i) >= size && !devMem.memHandle; i++)
+ devMem = tryAllocDeviceMemory(type, flags, type->chunkSize >> i, priority, nullptr);
+
+ if (devMem.memHandle) {
+ Rc<DxvkMemoryChunk> chunk = new DxvkMemoryChunk(this, type, devMem);
+ memory = chunk->alloc(flags, size, align, priority);
+
+ type->chunks.push_back(std::move(chunk));
+ }
+ }
+ }
+
+ if (memory)
+ type->heap->stats.memoryUsed += memory.m_length;
+
+ return memory;
+ }
+
+
+ DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
+ DxvkMemoryType* type,
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ float priority,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo) {
+ bool useMemoryPriority = (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+ && (m_device->features().extMemoryPriority.memoryPriority);
+
+ if (type->heap->budget && type->heap->stats.memoryAllocated + size > type->heap->budget)
+ return DxvkDeviceMemory();
+
+ DxvkDeviceMemory result;
+ result.memSize = size;
+ result.memFlags = flags;
+ result.priority = priority;
+
+ VkMemoryPriorityAllocateInfoEXT prio;
+ prio.sType = VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT;
+ prio.pNext = dedAllocInfo;
+ prio.priority = priority;
+
+ VkMemoryAllocateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ info.pNext = useMemoryPriority ? &prio : prio.pNext;
+ info.allocationSize = size;
+ info.memoryTypeIndex = type->memTypeId;
+
+ if (m_vkd->vkAllocateMemory(m_vkd->device(), &info, nullptr, &result.memHandle) != VK_SUCCESS)
+ return DxvkDeviceMemory();
+
+ if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ VkResult status = m_vkd->vkMapMemory(m_vkd->device(), result.memHandle, 0, VK_WHOLE_SIZE, 0, &result.memPointer);
+
+ if (status != VK_SUCCESS) {
+ Logger::err(str::format("DxvkMemoryAllocator: Mapping memory failed with ", status));
+ m_vkd->vkFreeMemory(m_vkd->device(), result.memHandle, nullptr);
+ return DxvkDeviceMemory();
+ }
+ }
+
+ type->heap->stats.memoryAllocated += size;
+ m_device->adapter()->notifyHeapMemoryAlloc(type->heapId, size);
+ return result;
+ }
+
+
+ void DxvkMemoryAllocator::free(
+ const DxvkMemory& memory) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ memory.m_type->heap->stats.memoryUsed -= memory.m_length;
+
+ if (memory.m_chunk != nullptr) {
+ this->freeChunkMemory(
+ memory.m_type,
+ memory.m_chunk,
+ memory.m_offset,
+ memory.m_length);
+ } else {
+ DxvkDeviceMemory devMem;
+ devMem.memHandle = memory.m_memory;
+ devMem.memPointer = nullptr;
+ devMem.memSize = memory.m_length;
+ this->freeDeviceMemory(memory.m_type, devMem);
+ }
+ }
+
+
+ void DxvkMemoryAllocator::freeChunkMemory(
+ DxvkMemoryType* type,
+ DxvkMemoryChunk* chunk,
+ VkDeviceSize offset,
+ VkDeviceSize length) {
+ chunk->free(offset, length);
+ }
+
+
+ void DxvkMemoryAllocator::freeDeviceMemory(
+ DxvkMemoryType* type,
+ DxvkDeviceMemory memory) {
+ m_vkd->vkFreeMemory(m_vkd->device(), memory.memHandle, nullptr);
+ type->heap->stats.memoryAllocated -= memory.memSize;
+ m_device->adapter()->notifyHeapMemoryFree(type->heapId, memory.memSize);
+ }
+
+
+ VkDeviceSize DxvkMemoryAllocator::pickChunkSize(uint32_t memTypeId) const {
+ VkMemoryType type = m_memProps.memoryTypes[memTypeId];
+ VkMemoryHeap heap = m_memProps.memoryHeaps[type.heapIndex];
+
+ // Default to a chunk size of 128 MiB
+ VkDeviceSize chunkSize = 128 << 20;
+
+ // Try to waste a bit less system memory in 32-bit
+ // applications due to address space constraints
+ if (env::is32BitHostPlatform()) {
+ if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ chunkSize = 32 << 20;
+ }
+
+ // Reduce the chunk size on small heaps so
+ // we can at least fit in 15 allocations
+ while (chunkSize * 15 > heap.size)
+ chunkSize >>= 1;
+
+ return chunkSize;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.h
new file mode 100644
index 00000000..cc9e20a9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_memory.h
@@ -0,0 +1,328 @@
+#pragma once
+
+#include "dxvk_adapter.h"
+
+namespace dxvk {
+
+ class DxvkMemoryAllocator;
+ class DxvkMemoryChunk;
+
+ /**
+ * \brief Memory stats
+ *
+ * Reports the amount of device memory
+ * allocated and used by the application.
+ */
+ struct DxvkMemoryStats {
+ VkDeviceSize memoryAllocated = 0;
+ VkDeviceSize memoryUsed = 0;
+ };
+
+
+ /**
+ * \brief Device memory object
+ *
+ * Stores a Vulkan memory object. If the object
+ * was allocated on host-visible memory, it will
+ * be persistently mapped.
+ */
+ struct DxvkDeviceMemory {
+ VkDeviceMemory memHandle = VK_NULL_HANDLE;
+ void* memPointer = nullptr;
+ VkDeviceSize memSize = 0;
+ VkMemoryPropertyFlags memFlags = 0;
+ float priority = 0.0f;
+ };
+
+
+ /**
+ * \brief Memory heap
+ *
+ * Corresponds to a Vulkan memory heap and stores
+ * its properties as well as allocation statistics.
+ */
+ struct DxvkMemoryHeap {
+ VkMemoryHeap properties;
+ DxvkMemoryStats stats;
+ VkDeviceSize budget;
+ };
+
+
+ /**
+ * \brief Memory type
+ *
+ * Corresponds to a Vulkan memory type and stores
+ * memory chunks used to sub-allocate memory on
+ * this memory type.
+ */
+ struct DxvkMemoryType {
+ DxvkMemoryHeap* heap;
+ uint32_t heapId;
+
+ VkMemoryType memType;
+ uint32_t memTypeId;
+
+ VkDeviceSize chunkSize;
+
+ std::vector<Rc<DxvkMemoryChunk>> chunks;
+ };
+
+
+ /**
+ * \brief Memory slice
+ *
+ * Represents a slice of memory that has
+ * been sub-allocated from a bigger chunk.
+ */
+ class DxvkMemory {
+ friend class DxvkMemoryAllocator;
+ public:
+
+ DxvkMemory();
+ DxvkMemory(
+ DxvkMemoryAllocator* alloc,
+ DxvkMemoryChunk* chunk,
+ DxvkMemoryType* type,
+ VkDeviceMemory memory,
+ VkDeviceSize offset,
+ VkDeviceSize length,
+ void* mapPtr);
+ DxvkMemory (DxvkMemory&& other);
+ DxvkMemory& operator = (DxvkMemory&& other);
+ ~DxvkMemory();
+
+ /**
+ * \brief Memory object
+ *
+ * This information is required when
+ * binding memory to Vulkan objects.
+ * \returns Memory object
+ */
+ VkDeviceMemory memory() const {
+ return m_memory;
+ }
+
+ /**
+ * \brief Offset into device memory
+ *
+ * This information is required when
+ * binding memory to Vulkan objects.
+ * \returns Offset into device memory
+ */
+ VkDeviceSize offset() const {
+ return m_offset;
+ }
+
+ /**
+ * \brief Pointer to mapped data
+ *
+ * \param [in] offset Byte offset
+ * \returns Pointer to mapped data
+ */
+ void* mapPtr(VkDeviceSize offset) const {
+ return reinterpret_cast<char*>(m_mapPtr) + offset;
+ }
+
+ /**
+ * \brief Returns length of memory allocated
+ *
+ * \returns Memory size
+ */
+ VkDeviceSize length() const {
+ return m_length;
+ }
+
+ /**
+ * \brief Checks whether the memory slice is defined
+ *
+ * \returns \c true if this slice points to actual device
+ * memory, and \c false if it is undefined.
+ */
+ operator bool () const {
+ return m_memory != VK_NULL_HANDLE;
+ }
+
+ private:
+
+ DxvkMemoryAllocator* m_alloc = nullptr;
+ DxvkMemoryChunk* m_chunk = nullptr;
+ DxvkMemoryType* m_type = nullptr;
+ VkDeviceMemory m_memory = VK_NULL_HANDLE;
+ VkDeviceSize m_offset = 0;
+ VkDeviceSize m_length = 0;
+ void* m_mapPtr = nullptr;
+
+ void free();
+
+ };
+
+
+ /**
+ * \brief Memory chunk
+ *
+ * A single chunk of memory that provides a
+ * sub-allocator. This is not thread-safe.
+ */
+ class DxvkMemoryChunk : public RcObject {
+
+ public:
+
+ DxvkMemoryChunk(
+ DxvkMemoryAllocator* alloc,
+ DxvkMemoryType* type,
+ DxvkDeviceMemory memory);
+
+ ~DxvkMemoryChunk();
+
+ /**
+ * \brief Allocates memory from the chunk
+ *
+ * On failure, this returns a slice with
+ * \c VK_NULL_HANDLE as the memory handle.
+ * \param [in] flags Requested memory flags
+ * \param [in] size Number of bytes to allocate
+ * \param [in] align Required alignment
+ * \param [in] priority Requested priority
+ * \returns The allocated memory slice
+ */
+ DxvkMemory alloc(
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ VkDeviceSize align,
+ float priority);
+
+ /**
+ * \brief Frees memory
+ *
+ * Returns a slice back to the chunk.
+ * Called automatically when a memory
+ * slice runs out of scope.
+ * \param [in] offset Slice offset
+ * \param [in] length Slice length
+ */
+ void free(
+ VkDeviceSize offset,
+ VkDeviceSize length);
+
+ private:
+
+ struct FreeSlice {
+ VkDeviceSize offset;
+ VkDeviceSize length;
+ };
+
+ DxvkMemoryAllocator* m_alloc;
+ DxvkMemoryType* m_type;
+ DxvkDeviceMemory m_memory;
+
+ std::vector<FreeSlice> m_freeList;
+
+ };
+
+
+ /**
+ * \brief Memory allocator
+ *
+ * Allocates device memory for Vulkan resources.
+ * Memory objects will be destroyed automatically.
+ */
+ class DxvkMemoryAllocator {
+ friend class DxvkMemory;
+ friend class DxvkMemoryChunk;
+ public:
+
+ DxvkMemoryAllocator(const DxvkDevice* device);
+ ~DxvkMemoryAllocator();
+
+ /**
+ * \brief Buffer-image granularity
+ *
+ * The granularity between linear and non-linear
+ * resources in adjacent memory locations. See
+ * section 11.6 of the Vulkan spec for details.
+ * \returns Buffer-image granularity
+ */
+ VkDeviceSize bufferImageGranularity() const {
+ return m_devProps.limits.bufferImageGranularity;
+ }
+
+ /**
+ * \brief Allocates device memory
+ *
+ * \param [in] req Memory requirements
+ * \param [in] dedAllocReq Dedicated allocation requirements
+ * \param [in] dedAllocInfo Dedicated allocation info
+ * \param [in] flags Memory type flags
+ * \param [in] priority Device-local memory priority
+ * \returns Allocated memory slice
+ */
+ DxvkMemory alloc(
+ const VkMemoryRequirements* req,
+ const VkMemoryDedicatedRequirements& dedAllocReq,
+ const VkMemoryDedicatedAllocateInfo& dedAllocInfo,
+ VkMemoryPropertyFlags flags,
+ float priority);
+
+ /**
+ * \brief Queries memory stats
+ *
+ * Returns the total amount of memory
+ * allocated and used for a given heap.
+ * \param [in] heap Heap index
+ * \returns Memory stats for this heap
+ */
+ DxvkMemoryStats getMemoryStats(uint32_t heap) const {
+ return m_memHeaps[heap].stats;
+ }
+
+ private:
+
+ const Rc<vk::DeviceFn> m_vkd;
+ const DxvkDevice* m_device;
+ const VkPhysicalDeviceProperties m_devProps;
+ const VkPhysicalDeviceMemoryProperties m_memProps;
+
+ dxvk::mutex m_mutex;
+ std::array<DxvkMemoryHeap, VK_MAX_MEMORY_HEAPS> m_memHeaps;
+ std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes;
+
+ DxvkMemory tryAlloc(
+ const VkMemoryRequirements* req,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo,
+ VkMemoryPropertyFlags flags,
+ float priority);
+
+ DxvkMemory tryAllocFromType(
+ DxvkMemoryType* type,
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ VkDeviceSize align,
+ float priority,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
+
+ DxvkDeviceMemory tryAllocDeviceMemory(
+ DxvkMemoryType* type,
+ VkMemoryPropertyFlags flags,
+ VkDeviceSize size,
+ float priority,
+ const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
+
+ void free(
+ const DxvkMemory& memory);
+
+ void freeChunkMemory(
+ DxvkMemoryType* type,
+ DxvkMemoryChunk* chunk,
+ VkDeviceSize offset,
+ VkDeviceSize length);
+
+ void freeDeviceMemory(
+ DxvkMemoryType* type,
+ DxvkDeviceMemory memory);
+
+ VkDeviceSize pickChunkSize(
+ uint32_t memTypeId) const;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.cpp
new file mode 100644
index 00000000..7956b2ed
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.cpp
@@ -0,0 +1,599 @@
+#include "dxvk_device.h"
+#include "dxvk_meta_blit.h"
+
+#include <dxvk_fullscreen_geom.h>
+#include <dxvk_fullscreen_vert.h>
+#include <dxvk_fullscreen_layer_vert.h>
+
+#include <dxvk_blit_frag_1d.h>
+#include <dxvk_blit_frag_2d.h>
+#include <dxvk_blit_frag_3d.h>
+
+namespace dxvk {
+
+ DxvkMetaBlitRenderPass::DxvkMetaBlitRenderPass(
+ const Rc<DxvkDevice>& device,
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ const VkComponentMapping& mapping)
+ : m_vkd (device->vkd()),
+ m_dstImage (dstImage),
+ m_srcImage (srcImage),
+ m_region (region),
+ m_dstView (createDstView()),
+ m_srcView (createSrcView(mapping)),
+ m_renderPass (createRenderPass()),
+ m_framebuffer (createFramebuffer()) {
+
+ }
+
+
+ DxvkMetaBlitRenderPass::~DxvkMetaBlitRenderPass() {
+ m_vkd->vkDestroyImageView(m_vkd->device(), m_dstView, nullptr);
+ m_vkd->vkDestroyImageView(m_vkd->device(), m_srcView, nullptr);
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), m_renderPass, nullptr);
+ m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr);
+ }
+
+
+ VkImageViewType DxvkMetaBlitRenderPass::viewType() const {
+ std::array<VkImageViewType, 3> viewTypes = {{
+ VK_IMAGE_VIEW_TYPE_1D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_3D,
+ }};
+
+ return viewTypes.at(uint32_t(m_srcImage->info().type));
+ }
+
+
+ uint32_t DxvkMetaBlitRenderPass::framebufferLayerIndex() const {
+ uint32_t result = m_region.dstSubresource.baseArrayLayer;
+
+ if (m_dstImage->info().type == VK_IMAGE_TYPE_3D)
+ result = std::min(m_region.dstOffsets[0].z, m_region.dstOffsets[1].z);
+
+ return result;
+ }
+
+
+ uint32_t DxvkMetaBlitRenderPass::framebufferLayerCount() const {
+ uint32_t result = m_region.dstSubresource.layerCount;
+
+ if (m_dstImage->info().type == VK_IMAGE_TYPE_3D) {
+ uint32_t minZ = std::min(m_region.dstOffsets[0].z, m_region.dstOffsets[1].z);
+ uint32_t maxZ = std::max(m_region.dstOffsets[0].z, m_region.dstOffsets[1].z);
+ result = maxZ - minZ;
+ }
+
+ return result;
+ }
+
+
+ DxvkMetaBlitPass DxvkMetaBlitRenderPass::pass() const {
+ DxvkMetaBlitPass result;
+ result.srcView = m_srcView;
+ result.dstView = m_dstView;
+ result.renderPass = m_renderPass;
+ result.framebuffer = m_framebuffer;
+ return result;
+ }
+
+
+ VkImageView DxvkMetaBlitRenderPass::createDstView() {
+ std::array<VkImageViewType, 3> viewTypes = {{
+ VK_IMAGE_VIEW_TYPE_1D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ }};
+
+ VkImageViewUsageCreateInfo usageInfo;
+ usageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
+ usageInfo.pNext = nullptr;
+ usageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ VkImageViewCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ info.pNext = &usageInfo;
+ info.flags = 0;
+ info.image = m_dstImage->handle();
+ info.viewType = viewTypes.at(uint32_t(m_dstImage->info().type));
+ info.format = m_dstImage->info().format;
+ info.components = VkComponentMapping();
+ info.subresourceRange = vk::makeSubresourceRange(m_region.dstSubresource);
+
+ if (m_dstImage->info().type) {
+ info.subresourceRange.baseArrayLayer = framebufferLayerIndex();
+ info.subresourceRange.layerCount = framebufferLayerCount();
+ }
+
+ VkImageView result;
+ if (m_vkd->vkCreateImageView(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitRenderPass: Failed to create image view");
+ return result;
+ }
+
+
+ VkImageView DxvkMetaBlitRenderPass::createSrcView(const VkComponentMapping& mapping) {
+ VkImageViewUsageCreateInfo usageInfo;
+ usageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
+ usageInfo.pNext = nullptr;
+ usageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+
+ VkImageViewCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ info.pNext = &usageInfo;
+ info.flags = 0;
+ info.image = m_srcImage->handle();
+ info.viewType = this->viewType();
+ info.format = m_srcImage->info().format;
+ info.components = mapping;
+ info.subresourceRange = vk::makeSubresourceRange(m_region.srcSubresource);
+
+ VkImageView result;
+ if (m_vkd->vkCreateImageView(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitRenderPass: Failed to create image view");
+ return result;
+ }
+
+
+ VkRenderPass DxvkMetaBlitRenderPass::createRenderPass() {
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = m_dstImage->info().format;
+ attachment.samples = m_dstImage->info().sampleCount;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachment.initialLayout = m_dstImage->info().layout;
+ attachment.finalLayout = m_dstImage->info().layout;
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &attachmentRef;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = nullptr;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = 0;
+ info.pDependencies = nullptr;
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitRenderPass: Failed to create render pass");
+ return result;
+ }
+
+
+ VkFramebuffer DxvkMetaBlitRenderPass::createFramebuffer() {
+ VkExtent3D extent = m_dstImage->mipLevelExtent(m_region.dstSubresource.mipLevel);
+
+ VkFramebufferCreateInfo fboInfo;
+ fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fboInfo.pNext = nullptr;
+ fboInfo.flags = 0;
+ fboInfo.renderPass = m_renderPass;
+ fboInfo.attachmentCount = 1;
+ fboInfo.pAttachments = &m_dstView;
+ fboInfo.width = extent.width;
+ fboInfo.height = extent.height;
+ fboInfo.layers = framebufferLayerCount();
+
+ VkFramebuffer result;
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitRenderPass: Failed to create target framebuffer");
+ return result;
+ }
+
+
+
+
+ DxvkMetaBlitObjects::DxvkMetaBlitObjects(const DxvkDevice* device)
+ : m_vkd (device->vkd()),
+ m_samplerCopy (createSampler(VK_FILTER_NEAREST)),
+ m_samplerBlit (createSampler(VK_FILTER_LINEAR)),
+ m_shaderFrag1D(createShaderModule(dxvk_blit_frag_1d)),
+ m_shaderFrag2D(createShaderModule(dxvk_blit_frag_2d)),
+ m_shaderFrag3D(createShaderModule(dxvk_blit_frag_3d)) {
+ if (device->extensions().extShaderViewportIndexLayer) {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_layer_vert);
+ } else {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_vert);
+ m_shaderGeom = createShaderModule(dxvk_fullscreen_geom);
+ }
+ }
+
+
+ DxvkMetaBlitObjects::~DxvkMetaBlitObjects() {
+ for (const auto& pair : m_renderPasses)
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second, nullptr);
+
+ for (const auto& pair : m_pipelines) {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr);
+ }
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag3D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag2D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag1D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr);
+
+ m_vkd->vkDestroySampler(m_vkd->device(), m_samplerBlit, nullptr);
+ m_vkd->vkDestroySampler(m_vkd->device(), m_samplerCopy, nullptr);
+ }
+
+
+ DxvkMetaBlitPipeline DxvkMetaBlitObjects::getPipeline(
+ VkImageViewType viewType,
+ VkFormat viewFormat,
+ VkSampleCountFlagBits samples) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ DxvkMetaBlitPipelineKey key;
+ key.viewType = viewType;
+ key.viewFormat = viewFormat;
+ key.samples = samples;
+
+ auto entry = m_pipelines.find(key);
+ if (entry != m_pipelines.end())
+ return entry->second;
+
+ DxvkMetaBlitPipeline pipeline = this->createPipeline(key);
+ m_pipelines.insert({ key, pipeline });
+ return pipeline;
+ }
+
+
+ VkSampler DxvkMetaBlitObjects::getSampler(VkFilter filter) {
+ return filter == VK_FILTER_NEAREST
+ ? m_samplerCopy
+ : m_samplerBlit;
+ }
+
+
+ VkRenderPass DxvkMetaBlitObjects::getRenderPass(
+ VkFormat viewFormat,
+ VkSampleCountFlagBits samples) {
+ DxvkMetaBlitRenderPassKey key;
+ key.viewFormat = viewFormat;
+ key.samples = samples;
+
+ auto entry = m_renderPasses.find(key);
+ if (entry != m_renderPasses.end())
+ return entry->second;
+
+ VkRenderPass renderPass = this->createRenderPass(viewFormat, samples);
+ m_renderPasses.insert({ key, renderPass });
+ return renderPass;
+ }
+
+
+ VkSampler DxvkMetaBlitObjects::createSampler(VkFilter filter) const {
+ VkSamplerCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.magFilter = filter;
+ info.minFilter = filter;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.mipLodBias = 0.0f;
+ info.anisotropyEnable = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.compareEnable = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_ALWAYS;
+ info.minLod = 0.0f;
+ info.maxLod = 0.0f;
+ info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ info.unnormalizedCoordinates = VK_FALSE;
+
+ VkSampler result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create sampler");
+ return result;
+ }
+
+
+ VkShaderModule DxvkMetaBlitObjects::createShaderModule(const SpirvCodeBuffer& code) const {
+ VkShaderModuleCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.codeSize = code.size();
+ info.pCode = code.data();
+
+ VkShaderModule result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create shader module");
+ return result;
+ }
+
+
+ DxvkMetaBlitPipeline DxvkMetaBlitObjects::createPipeline(
+ const DxvkMetaBlitPipelineKey& key) {
+ DxvkMetaBlitPipeline pipe;
+ pipe.dsetLayout = this->createDescriptorSetLayout(key.viewType);
+ pipe.pipeLayout = this->createPipelineLayout(pipe.dsetLayout);
+ pipe.pipeHandle = this->createPipeline(key.viewType, pipe.pipeLayout,
+ this->getRenderPass(key.viewFormat, key.samples), key.samples);
+ return pipe;
+ }
+
+
+ VkRenderPass DxvkMetaBlitObjects::createRenderPass(
+ VkFormat format,
+ VkSampleCountFlagBits samples) const {
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = format;
+ attachment.samples = samples;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &attachmentRef;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = nullptr;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = 0;
+ info.pDependencies = nullptr;
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create render pass");
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaBlitObjects::createDescriptorSetLayout(
+ VkImageViewType viewType) const {
+ VkDescriptorSetLayoutBinding binding;
+ binding.binding = 0;
+ binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ binding.descriptorCount = 1;
+ binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ binding.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.bindingCount = 1;
+ info.pBindings = &binding;
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create descriptor set layout");
+ return result;
+ }
+
+
+ VkPipelineLayout DxvkMetaBlitObjects::createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout) const {
+ VkPushConstantRange pushRange;
+ pushRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ pushRange.offset = 0;
+ pushRange.size = sizeof(DxvkMetaBlitPushConstants);
+
+ VkPipelineLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.setLayoutCount = 1;
+ info.pSetLayouts = &descriptorSetLayout;
+ info.pushConstantRangeCount = 1;
+ info.pPushConstantRanges = &pushRange;
+
+ VkPipelineLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create pipeline layout");
+ return result;
+ }
+
+
+ VkPipeline DxvkMetaBlitObjects::createPipeline(
+ VkImageViewType imageViewType,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass,
+ VkSampleCountFlagBits samples) const {
+ std::array<VkPipelineShaderStageCreateInfo, 3> stages;
+ uint32_t stageCount = 0;
+
+ VkPipelineShaderStageCreateInfo& vsStage = stages[stageCount++];
+ vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vsStage.pNext = nullptr;
+ vsStage.flags = 0;
+ vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vsStage.module = m_shaderVert;
+ vsStage.pName = "main";
+ vsStage.pSpecializationInfo = nullptr;
+
+ if (m_shaderGeom) {
+ VkPipelineShaderStageCreateInfo& gsStage = stages[stageCount++];
+ gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ gsStage.pNext = nullptr;
+ gsStage.flags = 0;
+ gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
+ gsStage.module = m_shaderGeom;
+ gsStage.pName = "main";
+ gsStage.pSpecializationInfo = nullptr;
+ }
+
+ VkPipelineShaderStageCreateInfo& psStage = stages[stageCount++];
+ psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ psStage.pNext = nullptr;
+ psStage.flags = 0;
+ psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ psStage.module = VK_NULL_HANDLE;
+ psStage.pName = "main";
+ psStage.pSpecializationInfo = nullptr;
+
+ switch (imageViewType) {
+ case VK_IMAGE_VIEW_TYPE_1D_ARRAY: psStage.module = m_shaderFrag1D; break;
+ case VK_IMAGE_VIEW_TYPE_2D_ARRAY: psStage.module = m_shaderFrag2D; break;
+ case VK_IMAGE_VIEW_TYPE_3D: psStage.module = m_shaderFrag3D; break;
+ default: throw DxvkError("DxvkMetaBlitObjects: Invalid view type");
+ }
+
+ std::array<VkDynamicState, 2> dynStates = {{
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ }};
+
+ VkPipelineDynamicStateCreateInfo dynState;
+ dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynState.pNext = nullptr;
+ dynState.flags = 0;
+ dynState.dynamicStateCount = dynStates.size();
+ dynState.pDynamicStates = dynStates.data();
+
+ VkPipelineVertexInputStateCreateInfo viState;
+ viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ viState.pNext = nullptr;
+ viState.flags = 0;
+ viState.vertexBindingDescriptionCount = 0;
+ viState.pVertexBindingDescriptions = nullptr;
+ viState.vertexAttributeDescriptionCount = 0;
+ viState.pVertexAttributeDescriptions = nullptr;
+
+ VkPipelineInputAssemblyStateCreateInfo iaState;
+ iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaState.pNext = nullptr;
+ iaState.flags = 0;
+ iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ iaState.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineViewportStateCreateInfo vpState;
+ vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vpState.pNext = nullptr;
+ vpState.flags = 0;
+ vpState.viewportCount = 1;
+ vpState.pViewports = nullptr;
+ vpState.scissorCount = 1;
+ vpState.pScissors = nullptr;
+
+ VkPipelineRasterizationStateCreateInfo rsState;
+ rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsState.pNext = nullptr;
+ rsState.flags = 0;
+ rsState.depthClampEnable = VK_TRUE;
+ rsState.rasterizerDiscardEnable = VK_FALSE;
+ rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ rsState.cullMode = VK_CULL_MODE_NONE;
+ rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rsState.depthBiasEnable = VK_FALSE;
+ rsState.depthBiasConstantFactor = 0.0f;
+ rsState.depthBiasClamp = 0.0f;
+ rsState.depthBiasSlopeFactor = 0.0f;
+ rsState.lineWidth = 1.0f;
+
+ uint32_t msMask = 0xFFFFFFFF;
+ VkPipelineMultisampleStateCreateInfo msState;
+ msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msState.pNext = nullptr;
+ msState.flags = 0;
+ msState.rasterizationSamples = samples;
+ msState.sampleShadingEnable = VK_FALSE;
+ msState.minSampleShading = 1.0f;
+ msState.pSampleMask = &msMask;
+ msState.alphaToCoverageEnable = VK_FALSE;
+ msState.alphaToOneEnable = VK_FALSE;
+
+ VkPipelineColorBlendAttachmentState cbAttachment;
+ cbAttachment.blendEnable = VK_FALSE;
+ cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.colorBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.colorWriteMask =
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineColorBlendStateCreateInfo cbState;
+ cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cbState.pNext = nullptr;
+ cbState.flags = 0;
+ cbState.logicOpEnable = VK_FALSE;
+ cbState.logicOp = VK_LOGIC_OP_NO_OP;
+ cbState.attachmentCount = 1;
+ cbState.pAttachments = &cbAttachment;
+
+ for (uint32_t i = 0; i < 4; i++)
+ cbState.blendConstants[i] = 0.0f;
+
+ VkGraphicsPipelineCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.stageCount = stageCount;
+ info.pStages = stages.data();
+ info.pVertexInputState = &viState;
+ info.pInputAssemblyState = &iaState;
+ info.pTessellationState = nullptr;
+ info.pViewportState = &vpState;
+ info.pRasterizationState = &rsState;
+ info.pMultisampleState = &msState;
+ info.pColorBlendState = &cbState;
+ info.pDepthStencilState = nullptr;
+ info.pDynamicState = &dynState;
+ info.layout = pipelineLayout;
+ info.renderPass = renderPass;
+ info.subpass = 0;
+ info.basePipelineHandle = VK_NULL_HANDLE;
+ info.basePipelineIndex = -1;
+
+ VkPipeline result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaBlitObjects: Failed to create graphics pipeline");
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.h
new file mode 100644
index 00000000..28f8616c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_blit.h
@@ -0,0 +1,245 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "../spirv/spirv_code_buffer.h"
+
+#include "dxvk_hash.h"
+#include "dxvk_image.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Texture coordinates
+ */
+ struct DxvkMetaBlitOffset {
+ float x, y, z;
+ };
+
+ /**
+ * \brief Push constant data
+ */
+ struct DxvkMetaBlitPushConstants {
+ DxvkMetaBlitOffset srcCoord0;
+ uint32_t pad1;
+ DxvkMetaBlitOffset srcCoord1;
+ uint32_t layerCount;
+ };
+
+ /**
+ * \brief Blit pipeline key
+ *
+ * We have to create pipelines for each
+ * combination of source image view type
+ * and image format.
+ */
+ struct DxvkMetaBlitPipelineKey {
+ VkImageViewType viewType;
+ VkFormat viewFormat;
+ VkSampleCountFlagBits samples;
+
+ bool eq(const DxvkMetaBlitPipelineKey& other) const {
+ return this->viewType == other.viewType
+ && this->viewFormat == other.viewFormat
+ && this->samples == other.samples;
+ }
+
+ size_t hash() const {
+ DxvkHashState result;
+ result.add(uint32_t(this->viewType));
+ result.add(uint32_t(this->viewFormat));
+ result.add(uint32_t(this->samples));
+ return result;
+ }
+ };
+
+ /**
+ * \brief Blit render pass key
+ */
+ struct DxvkMetaBlitRenderPassKey {
+ VkFormat viewFormat;
+ VkSampleCountFlagBits samples;
+
+ bool eq(const DxvkMetaBlitRenderPassKey& other) const {
+ return this->viewFormat == other.viewFormat
+ && this->samples == other.samples;
+ }
+
+ size_t hash() const {
+ DxvkHashState result;
+ result.add(uint32_t(this->viewFormat));
+ result.add(uint32_t(this->samples));
+ return result;
+ }
+ };
+
+ /**
+ * \brief Blit pipeline
+ *
+ * Stores the objects for a single pipeline
+ * that is used for blitting.
+ */
+ struct DxvkMetaBlitPipeline {
+ VkDescriptorSetLayout dsetLayout;
+ VkPipelineLayout pipeLayout;
+ VkPipeline pipeHandle;
+ };
+
+
+ /**
+ * \brief Blit framebuffer
+ *
+ * Stores the image views and framebuffer
+ * handle used to generate one mip level.
+ */
+ struct DxvkMetaBlitPass {
+ VkImageView srcView;
+ VkImageView dstView;
+ VkRenderPass renderPass;
+ VkFramebuffer framebuffer;
+ };
+
+
+ /**
+ * \brief Blit render pass
+ *
+ * Stores image view, render pass and framebuffer
+ * objects for a blit operation, as well as some
+ * metadata.
+ */
+ class DxvkMetaBlitRenderPass : public DxvkResource {
+
+ public:
+
+ DxvkMetaBlitRenderPass(
+ const Rc<DxvkDevice>& device,
+ const Rc<DxvkImage>& dstImage,
+ const Rc<DxvkImage>& srcImage,
+ const VkImageBlit& region,
+ const VkComponentMapping& mapping);
+
+ ~DxvkMetaBlitRenderPass();
+
+ VkImageViewType viewType() const;
+
+ uint32_t framebufferLayerIndex() const;
+ uint32_t framebufferLayerCount() const;
+
+ DxvkMetaBlitPass pass() const;
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ Rc<DxvkImage> m_dstImage;
+ Rc<DxvkImage> m_srcImage;
+
+ VkImageBlit m_region;
+ VkImageView m_dstView;
+ VkImageView m_srcView;
+ VkRenderPass m_renderPass;
+ VkFramebuffer m_framebuffer;
+
+ VkImageView createDstView();
+ VkImageView createSrcView(const VkComponentMapping& mapping);
+
+ VkRenderPass createRenderPass();
+ VkFramebuffer createFramebuffer();
+
+ };
+
+
+ /**
+ * \brief Blitter objects
+ *
+ * Stores render pass objects and pipelines used
+ * to generate mip maps. Due to Vulkan API design
+ * decisions, we have to create one render pass
+ * and pipeline object per image format used.
+ */
+ class DxvkMetaBlitObjects {
+
+ public:
+
+ DxvkMetaBlitObjects(const DxvkDevice* device);
+ ~DxvkMetaBlitObjects();
+
+ /**
+ * \brief Creates a blit pipeline
+ *
+ * \param [in] viewType Source image view type
+ * \param [in] viewFormat Image view format
+ * \param [in] samples Target sample count
+ * \returns The blit pipeline
+ */
+ DxvkMetaBlitPipeline getPipeline(
+ VkImageViewType viewType,
+ VkFormat viewFormat,
+ VkSampleCountFlagBits samples);
+
+ /**
+ * \brief Retrieves sampler with a given filter
+ *
+ * \param [in] filter The desired filter
+ * \returns Sampler object with the given filter
+ */
+ VkSampler getSampler(
+ VkFilter filter);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkSampler m_samplerCopy;
+ VkSampler m_samplerBlit;
+
+ VkShaderModule m_shaderVert = VK_NULL_HANDLE;
+ VkShaderModule m_shaderGeom = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFrag1D = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFrag2D = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFrag3D = VK_NULL_HANDLE;
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkMetaBlitRenderPassKey,
+ VkRenderPass,
+ DxvkHash, DxvkEq> m_renderPasses;
+
+ std::unordered_map<
+ DxvkMetaBlitPipelineKey,
+ DxvkMetaBlitPipeline,
+ DxvkHash, DxvkEq> m_pipelines;
+
+ VkRenderPass getRenderPass(
+ VkFormat viewFormat,
+ VkSampleCountFlagBits samples);
+
+ VkSampler createSampler(
+ VkFilter filter) const;
+
+ VkShaderModule createShaderModule(
+ const SpirvCodeBuffer& code) const;
+
+ DxvkMetaBlitPipeline createPipeline(
+ const DxvkMetaBlitPipelineKey& key);
+
+ VkRenderPass createRenderPass(
+ VkFormat format,
+ VkSampleCountFlagBits samples) const;
+
+ VkDescriptorSetLayout createDescriptorSetLayout(
+ VkImageViewType viewType) const;
+
+ VkPipelineLayout createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout) const;
+
+ VkPipeline createPipeline(
+ VkImageViewType imageViewType,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass,
+ VkSampleCountFlagBits samples) const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.cpp
new file mode 100644
index 00000000..d5b3381d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.cpp
@@ -0,0 +1,210 @@
+#include "dxvk_meta_clear.h"
+#include "dxvk_device.h"
+
+#include <dxvk_clear_buffer_f.h>
+#include <dxvk_clear_buffer_u.h>
+#include <dxvk_clear_image1d_f.h>
+#include <dxvk_clear_image1d_u.h>
+#include <dxvk_clear_image1darr_f.h>
+#include <dxvk_clear_image1darr_u.h>
+#include <dxvk_clear_image2d_f.h>
+#include <dxvk_clear_image2d_u.h>
+#include <dxvk_clear_image2darr_f.h>
+#include <dxvk_clear_image2darr_u.h>
+#include <dxvk_clear_image3d_f.h>
+#include <dxvk_clear_image3d_u.h>
+
+namespace dxvk {
+
+ DxvkMetaClearObjects::DxvkMetaClearObjects(const DxvkDevice* device)
+ : m_vkd(device->vkd()) {
+ // Create descriptor set layouts
+ m_clearBufDsetLayout = createDescriptorSetLayout(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
+ m_clearImgDsetLayout = createDescriptorSetLayout(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
+
+ // Create pipeline layouts using those descriptor set layouts
+ m_clearBufPipeLayout = createPipelineLayout(m_clearBufDsetLayout);
+ m_clearImgPipeLayout = createPipelineLayout(m_clearImgDsetLayout);
+
+ // Create the actual compute pipelines
+ m_clearPipesF32.clearBuf = createPipeline(dxvk_clear_buffer_f, m_clearBufPipeLayout);
+ m_clearPipesU32.clearBuf = createPipeline(dxvk_clear_buffer_u, m_clearBufPipeLayout);
+
+ m_clearPipesF32.clearImg1D = createPipeline(dxvk_clear_image1d_f, m_clearImgPipeLayout);
+ m_clearPipesU32.clearImg1D = createPipeline(dxvk_clear_image1d_u, m_clearImgPipeLayout);
+ m_clearPipesF32.clearImg2D = createPipeline(dxvk_clear_image2d_f, m_clearImgPipeLayout);
+ m_clearPipesU32.clearImg2D = createPipeline(dxvk_clear_image2d_u, m_clearImgPipeLayout);
+ m_clearPipesF32.clearImg3D = createPipeline(dxvk_clear_image3d_f, m_clearImgPipeLayout);
+ m_clearPipesU32.clearImg3D = createPipeline(dxvk_clear_image3d_u, m_clearImgPipeLayout);
+
+ m_clearPipesF32.clearImg1DArray = createPipeline(dxvk_clear_image1darr_f, m_clearImgPipeLayout);
+ m_clearPipesU32.clearImg1DArray = createPipeline(dxvk_clear_image1darr_u, m_clearImgPipeLayout);
+ m_clearPipesF32.clearImg2DArray = createPipeline(dxvk_clear_image2darr_f, m_clearImgPipeLayout);
+ m_clearPipesU32.clearImg2DArray = createPipeline(dxvk_clear_image2darr_u, m_clearImgPipeLayout);
+ }
+
+
+ DxvkMetaClearObjects::~DxvkMetaClearObjects() {
+ // Destroy pipelines
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearBuf, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearBuf, nullptr);
+
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearImg1D, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearImg1D, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearImg2D, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearImg2D, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearImg3D, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearImg3D, nullptr);
+
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearImg1DArray, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearImg1DArray, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesF32.clearImg2DArray, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_clearPipesU32.clearImg2DArray, nullptr);
+
+ // Destroy pipeline layouts
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_clearBufPipeLayout, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_clearImgPipeLayout, nullptr);
+
+ // Destroy descriptor set layouts
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_clearBufDsetLayout, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_clearImgDsetLayout, nullptr);
+ }
+
+
+ DxvkMetaClearPipeline DxvkMetaClearObjects::getClearBufferPipeline(
+ DxvkFormatFlags formatFlags) const {
+ DxvkMetaClearPipeline result;
+ result.dsetLayout = m_clearBufDsetLayout;
+ result.pipeLayout = m_clearBufPipeLayout;
+ result.pipeline = m_clearPipesF32.clearBuf;
+
+ if (formatFlags.any(DxvkFormatFlag::SampledUInt, DxvkFormatFlag::SampledSInt))
+ result.pipeline = m_clearPipesU32.clearBuf;
+
+ result.workgroupSize = VkExtent3D { 128, 1, 1 };
+ return result;
+ }
+
+
+ DxvkMetaClearPipeline DxvkMetaClearObjects::getClearImagePipeline(
+ VkImageViewType viewType,
+ DxvkFormatFlags formatFlags) const {
+ const DxvkMetaClearPipelines& pipes = formatFlags.any(
+ DxvkFormatFlag::SampledUInt, DxvkFormatFlag::SampledSInt)
+ ? m_clearPipesU32 : m_clearPipesF32;
+
+ DxvkMetaClearPipeline result;
+ result.dsetLayout = m_clearImgDsetLayout;
+ result.pipeLayout = m_clearImgPipeLayout;
+
+ auto pipeInfo = [&pipes, viewType] () -> std::pair<VkPipeline, VkExtent3D> {
+ switch (viewType) {
+ case VK_IMAGE_VIEW_TYPE_1D: return { pipes.clearImg1D, VkExtent3D { 64, 1, 1 } };
+ case VK_IMAGE_VIEW_TYPE_2D: return { pipes.clearImg2D, VkExtent3D { 8, 8, 1 } };
+ case VK_IMAGE_VIEW_TYPE_3D: return { pipes.clearImg3D, VkExtent3D { 4, 4, 4 } };
+ case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return { pipes.clearImg1DArray, VkExtent3D { 64, 1, 1 } };
+ case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return { pipes.clearImg2DArray, VkExtent3D { 8, 8, 1 } };
+ default: return { VkPipeline(VK_NULL_HANDLE), VkExtent3D { 0, 0, 0, } };
+ }
+ }();
+
+ result.pipeline = pipeInfo.first;
+ result.workgroupSize = pipeInfo.second;
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaClearObjects::createDescriptorSetLayout(
+ VkDescriptorType descriptorType) {
+ VkDescriptorSetLayoutBinding bindInfo;
+ bindInfo.binding = 0;
+ bindInfo.descriptorType = descriptorType;
+ bindInfo.descriptorCount = 1;
+ bindInfo.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ bindInfo.pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo dsetInfo;
+ dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsetInfo.pNext = nullptr;
+ dsetInfo.flags = 0;
+ dsetInfo.bindingCount = 1;
+ dsetInfo.pBindings = &bindInfo;
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(),
+ &dsetInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("Dxvk: Failed to create meta clear descriptor set layout");
+ return result;
+ }
+
+
+ VkPipelineLayout DxvkMetaClearObjects::createPipelineLayout(
+ VkDescriptorSetLayout dsetLayout) {
+ VkPushConstantRange pushInfo;
+ pushInfo.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ pushInfo.offset = 0;
+ pushInfo.size = sizeof(DxvkMetaClearArgs);
+
+ VkPipelineLayoutCreateInfo pipeInfo;
+ pipeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipeInfo.pNext = nullptr;
+ pipeInfo.flags = 0;
+ pipeInfo.setLayoutCount = 1;
+ pipeInfo.pSetLayouts = &dsetLayout;
+ pipeInfo.pushConstantRangeCount = 1;
+ pipeInfo.pPushConstantRanges = &pushInfo;
+
+ VkPipelineLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(),
+ &pipeInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("Dxvk: Failed to create meta clear pipeline layout");
+ return result;
+ }
+
+
+ VkPipeline DxvkMetaClearObjects::createPipeline(
+ const SpirvCodeBuffer& spirvCode,
+ VkPipelineLayout pipeLayout) {
+ VkShaderModuleCreateInfo shaderInfo;
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.pNext = nullptr;
+ shaderInfo.flags = 0;
+ shaderInfo.codeSize = spirvCode.size();
+ shaderInfo.pCode = spirvCode.data();
+
+ VkShaderModule shaderModule = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(),
+ &shaderInfo, nullptr, &shaderModule) != VK_SUCCESS)
+ throw DxvkError("Dxvk: Failed to create meta clear shader module");
+
+ VkPipelineShaderStageCreateInfo stageInfo;
+ stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo.pNext = nullptr;
+ stageInfo.flags = 0;
+ stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ stageInfo.module = shaderModule;
+ stageInfo.pName = "main";
+ stageInfo.pSpecializationInfo = nullptr;
+
+ VkComputePipelineCreateInfo pipeInfo;
+ pipeInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ pipeInfo.pNext = nullptr;
+ pipeInfo.flags = 0;
+ pipeInfo.stage = stageInfo;
+ pipeInfo.layout = pipeLayout;
+ pipeInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipeInfo.basePipelineIndex = -1;
+
+ VkPipeline result = VK_NULL_HANDLE;
+
+ const VkResult status = m_vkd->vkCreateComputePipelines(
+ m_vkd->device(), VK_NULL_HANDLE, 1, &pipeInfo, nullptr, &result);
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), shaderModule, nullptr);
+
+ if (status != VK_SUCCESS)
+ throw DxvkError("Dxvk: Failed to create meta clear compute pipeline");
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.h
new file mode 100644
index 00000000..eaf12ade
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_clear.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include "dxvk_format.h"
+#include "dxvk_include.h"
+
+#include "../spirv/spirv_code_buffer.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Clear args
+ *
+ * The data structure that can be passed
+ * to the clear shaders as push constants.
+ */
+ struct DxvkMetaClearArgs {
+ VkClearColorValue clearValue;
+ VkOffset3D offset; uint32_t pad1;
+ VkExtent3D extent; uint32_t pad2;
+ };
+
+
+ /**
+ * \brief Pipeline-related objects
+ *
+ * Use this to bind the pipeline
+ * and allocate a descriptor set.
+ */
+ struct DxvkMetaClearPipeline {
+ VkDescriptorSetLayout dsetLayout;
+ VkPipelineLayout pipeLayout;
+ VkPipeline pipeline;
+ VkExtent3D workgroupSize;
+ };
+
+
+ /**
+ * \brief Clear shaders and related objects
+ *
+ * Creates the shaders, pipeline layouts, and
+ * compute pipelines that are going to be used
+ * for clear operations.
+ */
+ class DxvkMetaClearObjects {
+
+ public:
+
+ DxvkMetaClearObjects(const DxvkDevice* device);
+ ~DxvkMetaClearObjects();
+
+ /**
+ * \brief Retrieves objects to use for buffers
+ *
+ * Returns the pipeline, pipeline layout and descriptor
+ * set layout which are required to perform a meta clear
+ * operation on a buffer resource with the given format.
+ * \param [in] viewType The image virw type
+ */
+ DxvkMetaClearPipeline getClearBufferPipeline(
+ DxvkFormatFlags formatFlags) const;
+
+ /**
+ * \brief Retrieves objects for a given image view type
+ *
+ * Returns the pipeline, pipeline layout and descriptor
+ * set layout which are required to perform a meta clear
+ * operation on a resource with the given view type.
+ * \param [in] viewType The image virw type
+ * \returns The pipeline-related objects to use
+ */
+ DxvkMetaClearPipeline getClearImagePipeline(
+ VkImageViewType viewType,
+ DxvkFormatFlags formatFlags) const;
+
+ private:
+
+ struct DxvkMetaClearPipelines {
+ VkPipeline clearBuf = VK_NULL_HANDLE;
+ VkPipeline clearImg1D = VK_NULL_HANDLE;
+ VkPipeline clearImg2D = VK_NULL_HANDLE;
+ VkPipeline clearImg3D = VK_NULL_HANDLE;
+ VkPipeline clearImg1DArray = VK_NULL_HANDLE;
+ VkPipeline clearImg2DArray = VK_NULL_HANDLE;
+ };
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkDescriptorSetLayout m_clearBufDsetLayout = VK_NULL_HANDLE;
+ VkDescriptorSetLayout m_clearImgDsetLayout = VK_NULL_HANDLE;
+
+ VkPipelineLayout m_clearBufPipeLayout = VK_NULL_HANDLE;
+ VkPipelineLayout m_clearImgPipeLayout = VK_NULL_HANDLE;
+
+ DxvkMetaClearPipelines m_clearPipesF32;
+ DxvkMetaClearPipelines m_clearPipesU32;
+
+ VkDescriptorSetLayout createDescriptorSetLayout(
+ VkDescriptorType descriptorType);
+
+ VkPipelineLayout createPipelineLayout(
+ VkDescriptorSetLayout dsetLayout);
+
+ VkPipeline createPipeline(
+ const SpirvCodeBuffer& spirvCode,
+ VkPipelineLayout pipeLayout);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.cpp
new file mode 100644
index 00000000..ed79bb4a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.cpp
@@ -0,0 +1,695 @@
+#include "dxvk_device.h"
+#include "dxvk_meta_copy.h"
+
+#include <dxvk_fullscreen_geom.h>
+#include <dxvk_fullscreen_vert.h>
+#include <dxvk_fullscreen_layer_vert.h>
+
+#include <dxvk_copy_buffer_image.h>
+#include <dxvk_copy_color_1d.h>
+#include <dxvk_copy_color_2d.h>
+#include <dxvk_copy_color_ms.h>
+#include <dxvk_copy_depth_1d.h>
+#include <dxvk_copy_depth_2d.h>
+#include <dxvk_copy_depth_ms.h>
+#include <dxvk_copy_depth_stencil_1d.h>
+#include <dxvk_copy_depth_stencil_2d.h>
+#include <dxvk_copy_depth_stencil_ms.h>
+
+namespace dxvk {
+
+ DxvkMetaCopyRenderPass::DxvkMetaCopyRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ const Rc<DxvkImageView>& srcStencilView,
+ bool discardDst)
+ : m_vkd (vkd),
+ m_dstImageView (dstImageView),
+ m_srcImageView (srcImageView),
+ m_srcStencilView(srcStencilView),
+ m_renderPass (createRenderPass(discardDst)),
+ m_framebuffer (createFramebuffer()) {
+
+ }
+
+
+ DxvkMetaCopyRenderPass::~DxvkMetaCopyRenderPass() {
+ m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr);
+ m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr);
+ }
+
+
+ VkRenderPass DxvkMetaCopyRenderPass::createRenderPass(bool discard) const {
+ auto aspect = m_dstImageView->info().aspect;
+
+ VkPipelineStageFlags cpyStages = 0;
+ VkAccessFlags cpyAccess = 0;
+
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = m_dstImageView->info().format;
+ attachment.samples = m_dstImageView->imageInfo().sampleCount;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.initialLayout = m_dstImageView->imageInfo().layout;
+ attachment.finalLayout = m_dstImageView->imageInfo().layout;
+
+ if (discard) {
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT)
+ ? m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
+ : m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 0;
+ subpass.pColorAttachments = nullptr;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = nullptr;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &attachmentRef;
+
+ cpyStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ if (!discard)
+ cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ } else {
+ subpass.pDepthStencilAttachment = &attachmentRef;
+
+ cpyStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+
+ if (!discard)
+ cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+ }
+
+ // We have to be somewhat conservative here since we cannot assume
+ // that the backend blocks stages that are only used for meta ops
+ VkPipelineStageFlags extStages = m_dstImageView->imageInfo().stages | m_srcImageView->imageInfo().stages;
+ VkAccessFlags extAccess = m_dstImageView->imageInfo().access;
+
+ std::array<VkSubpassDependency, 2> dependencies = {{
+ { VK_SUBPASS_EXTERNAL, 0, extStages, cpyStages, 0, cpyAccess, 0 },
+ { 0, VK_SUBPASS_EXTERNAL, cpyStages, extStages, cpyAccess, extAccess, 0 },
+ }};
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = dependencies.size();
+ info.pDependencies = dependencies.data();
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyRenderPass: Failed to create render pass");
+ return result;
+ }
+
+
+ VkFramebuffer DxvkMetaCopyRenderPass::createFramebuffer() const {
+ VkImageView dstViewHandle = m_dstImageView->handle();
+ VkImageSubresourceRange dstSubresources = m_dstImageView->subresources();
+ VkExtent3D dstExtent = m_dstImageView->mipLevelExtent(0);
+
+ VkFramebufferCreateInfo fboInfo;
+ fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fboInfo.pNext = nullptr;
+ fboInfo.flags = 0;
+ fboInfo.renderPass = m_renderPass;
+ fboInfo.attachmentCount = 1;
+ fboInfo.pAttachments = &dstViewHandle;
+ fboInfo.width = dstExtent.width;
+ fboInfo.height = dstExtent.height;
+ fboInfo.layers = dstSubresources.layerCount;
+
+ VkFramebuffer result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyRenderPass: Failed to create target framebuffer");
+ return result;
+ }
+
+
+ DxvkMetaCopyObjects::DxvkMetaCopyObjects(const DxvkDevice* device)
+ : m_vkd (device->vkd()),
+ m_sampler (createSampler()),
+ m_color {
+ createShaderModule(dxvk_copy_color_1d),
+ createShaderModule(dxvk_copy_color_2d),
+ createShaderModule(dxvk_copy_color_ms) },
+ m_depth {
+ createShaderModule(dxvk_copy_depth_1d),
+ createShaderModule(dxvk_copy_depth_2d),
+ createShaderModule(dxvk_copy_depth_ms) } {
+ if (device->extensions().extShaderViewportIndexLayer) {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_layer_vert);
+ } else {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_vert);
+ m_shaderGeom = createShaderModule(dxvk_fullscreen_geom);
+ }
+
+ if (device->extensions().extShaderStencilExport) {
+ m_depthStencil = {
+ createShaderModule(dxvk_copy_depth_stencil_1d),
+ createShaderModule(dxvk_copy_depth_stencil_2d),
+ createShaderModule(dxvk_copy_depth_stencil_ms) };
+ }
+ }
+
+
+ DxvkMetaCopyObjects::~DxvkMetaCopyObjects() {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_copyBufferImagePipeline.pipeHandle, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_copyBufferImagePipeline.pipeLayout, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_copyBufferImagePipeline.dsetLayout, nullptr);
+
+ for (const auto& pair : m_pipelines) {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr);
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second.renderPass, nullptr);
+ }
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.fragMs, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.frag2D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.frag1D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.fragMs, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag2D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag1D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.fragMs, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag2D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag1D, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr);
+
+ m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr);
+ }
+
+
+ VkFormat DxvkMetaCopyObjects::getCopyDestinationFormat(
+ VkImageAspectFlags dstAspect,
+ VkImageAspectFlags srcAspect,
+ VkFormat srcFormat) const {
+ if (srcAspect == dstAspect)
+ return srcFormat;
+
+ if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT
+ && srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
+ switch (srcFormat) {
+ case VK_FORMAT_D16_UNORM: return VK_FORMAT_R16_UNORM;
+ case VK_FORMAT_D32_SFLOAT: return VK_FORMAT_R32_SFLOAT;
+ default: return VK_FORMAT_UNDEFINED;
+ }
+ }
+
+ if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT
+ && srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
+ switch (srcFormat) {
+ case VK_FORMAT_R16_UNORM: return VK_FORMAT_D16_UNORM;
+ case VK_FORMAT_R32_SFLOAT: return VK_FORMAT_D32_SFLOAT;
+ default: return VK_FORMAT_UNDEFINED;
+ }
+ }
+
+ return VK_FORMAT_UNDEFINED;
+ }
+
+
+ DxvkMetaCopyPipeline DxvkMetaCopyObjects::getPipeline(
+ VkImageViewType viewType,
+ VkFormat dstFormat,
+ VkSampleCountFlagBits dstSamples) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ DxvkMetaCopyPipelineKey key;
+ key.viewType = viewType;
+ key.format = dstFormat;
+ key.samples = dstSamples;
+
+ auto entry = m_pipelines.find(key);
+ if (entry != m_pipelines.end())
+ return entry->second;
+
+ DxvkMetaCopyPipeline pipeline = createPipeline(key);
+ m_pipelines.insert({ key, pipeline });
+ return pipeline;
+ }
+
+
+ DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyBufferImagePipeline() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (!m_copyBufferImagePipeline.pipeHandle)
+ m_copyBufferImagePipeline = createCopyBufferImagePipeline();
+
+ return m_copyBufferImagePipeline;
+ }
+
+
+ VkSampler DxvkMetaCopyObjects::createSampler() const {
+ VkSamplerCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.magFilter = VK_FILTER_NEAREST;
+ info.minFilter = VK_FILTER_NEAREST;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.mipLodBias = 0.0f;
+ info.anisotropyEnable = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.compareEnable = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_ALWAYS;
+ info.minLod = 0.0f;
+ info.maxLod = 0.0f;
+ info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ info.unnormalizedCoordinates = VK_FALSE;
+
+ VkSampler result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create sampler");
+ return result;
+ }
+
+
+ VkShaderModule DxvkMetaCopyObjects::createShaderModule(
+ const SpirvCodeBuffer& code) const {
+ VkShaderModuleCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.codeSize = code.size();
+ info.pCode = code.data();
+
+ VkShaderModule result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create shader module");
+ return result;
+ }
+
+
+ DxvkMetaCopyPipeline DxvkMetaCopyObjects::createCopyBufferImagePipeline() {
+ DxvkMetaCopyPipeline pipeline;
+ pipeline.renderPass = VK_NULL_HANDLE;
+
+ std::array<VkDescriptorSetLayoutBinding, 2> bindings = {{
+ { 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ { 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ }};
+
+ VkDescriptorSetLayoutCreateInfo setLayoutInfo;
+ setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ setLayoutInfo.pNext = nullptr;
+ setLayoutInfo.flags = 0;
+ setLayoutInfo.bindingCount = bindings.size();
+ setLayoutInfo.pBindings = bindings.data();
+
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &setLayoutInfo, nullptr, &pipeline.dsetLayout) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout");
+
+ VkPushConstantRange pushRange = { VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(DxvkCopyBufferImageArgs) };
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo;
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipelineLayoutInfo.pNext = nullptr;
+ pipelineLayoutInfo.flags = 0;
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &pipeline.dsetLayout;
+ pipelineLayoutInfo.pushConstantRangeCount = 1;
+ pipelineLayoutInfo.pPushConstantRanges = &pushRange;
+
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &pipelineLayoutInfo, nullptr, &pipeline.pipeLayout) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create pipeline layout");
+
+ VkShaderModule shaderModule = createShaderModule(dxvk_copy_buffer_image);
+
+ VkComputePipelineCreateInfo pipelineInfo;
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ pipelineInfo.pNext = nullptr;
+ pipelineInfo.flags = 0;
+ pipelineInfo.layout = pipeline.pipeLayout;
+ pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ pipelineInfo.stage.pNext = nullptr;
+ pipelineInfo.stage.flags = 0;
+ pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ pipelineInfo.stage.module = shaderModule;
+ pipelineInfo.stage.pName = "main";
+ pipelineInfo.stage.pSpecializationInfo = nullptr;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipelineInfo.basePipelineIndex = -1;
+
+ if (m_vkd->vkCreateComputePipelines(m_vkd->device(), VK_NULL_HANDLE,
+ 1, &pipelineInfo, nullptr, &pipeline.pipeHandle) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create compute pipeline");
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), shaderModule, nullptr);
+ return pipeline;
+ }
+
+
+ DxvkMetaCopyPipeline DxvkMetaCopyObjects::createPipeline(
+ const DxvkMetaCopyPipelineKey& key) {
+ DxvkMetaCopyPipeline pipeline;
+ pipeline.renderPass = this->createRenderPass(key);
+ pipeline.dsetLayout = this->createDescriptorSetLayout(key);
+ pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout);
+ pipeline.pipeHandle = this->createPipelineObject(key, pipeline.pipeLayout, pipeline.renderPass);
+ return pipeline;
+ }
+
+
+ VkRenderPass DxvkMetaCopyObjects::createRenderPass(
+ const DxvkMetaCopyPipelineKey& key) const {
+ auto aspect = imageFormatInfo(key.format)->aspectMask;
+
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = key.format;
+ attachment.samples = key.samples;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
+ attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT)
+ ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 0;
+ subpass.pColorAttachments = nullptr;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = nullptr;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &attachmentRef;
+ } else {
+ subpass.pDepthStencilAttachment = &attachmentRef;
+ }
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = 0;
+ info.pDependencies = nullptr;
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create render pass");
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaCopyObjects::createDescriptorSetLayout(
+ const DxvkMetaCopyPipelineKey& key) const {
+ std::array<VkDescriptorSetLayoutBinding, 2> bindings;
+
+ for (uint32_t i = 0; i < 2; i++) {
+ bindings[i].binding = i;
+ bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ bindings[i].descriptorCount = 1;
+ bindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ bindings[i].pImmutableSamplers = &m_sampler;
+ }
+
+ VkDescriptorSetLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.bindingCount = 1;
+ info.pBindings = bindings.data();
+
+ auto format = imageFormatInfo(key.format);
+
+ if (format->aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
+ info.bindingCount = 2;
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout");
+ return result;
+ }
+
+
+ VkPipelineLayout DxvkMetaCopyObjects::createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout) const {
+ VkPushConstantRange push;
+ push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ push.offset = 0;
+ push.size = sizeof(VkOffset2D);
+
+ VkPipelineLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.setLayoutCount = 1;
+ info.pSetLayouts = &descriptorSetLayout;
+ info.pushConstantRangeCount = 1;
+ info.pPushConstantRanges = &push;
+
+ VkPipelineLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create pipeline layout");
+ return result;
+ }
+
+
+ VkPipeline DxvkMetaCopyObjects::createPipelineObject(
+ const DxvkMetaCopyPipelineKey& key,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass) {
+ auto aspect = imageFormatInfo(key.format)->aspectMask;
+
+ std::array<VkPipelineShaderStageCreateInfo, 3> stages;
+ uint32_t stageCount = 0;
+
+ VkPipelineShaderStageCreateInfo& vsStage = stages[stageCount++];
+ vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vsStage.pNext = nullptr;
+ vsStage.flags = 0;
+ vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vsStage.module = m_shaderVert;
+ vsStage.pName = "main";
+ vsStage.pSpecializationInfo = nullptr;
+
+ if (m_shaderGeom) {
+ VkPipelineShaderStageCreateInfo& gsStage = stages[stageCount++];
+ gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ gsStage.pNext = nullptr;
+ gsStage.flags = 0;
+ gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
+ gsStage.module = m_shaderGeom;
+ gsStage.pName = "main";
+ gsStage.pSpecializationInfo = nullptr;
+ }
+
+ VkPipelineShaderStageCreateInfo& psStage = stages[stageCount++];
+ psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ psStage.pNext = nullptr;
+ psStage.flags = 0;
+ psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ psStage.module = VK_NULL_HANDLE;
+ psStage.pName = "main";
+ psStage.pSpecializationInfo = nullptr;
+
+ std::array<std::pair<const FragShaders*, VkImageAspectFlags>, 3> shaderSets = {{
+ { &m_color, VK_IMAGE_ASPECT_COLOR_BIT },
+ { &m_depth, VK_IMAGE_ASPECT_DEPTH_BIT },
+ { &m_depthStencil, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
+ }};
+
+ const FragShaders* shaderSet = nullptr;
+
+ for (const auto& pair : shaderSets) {
+ if (pair.second == aspect)
+ shaderSet = pair.first;
+ }
+
+ if (!shaderSet)
+ throw DxvkError("DxvkMetaCopyObjects: Unsupported aspect mask");
+
+ if (key.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
+ psStage.module = shaderSet->frag1D;
+ else if (key.samples == VK_SAMPLE_COUNT_1_BIT)
+ psStage.module = shaderSet->frag2D;
+ else
+ psStage.module = shaderSet->fragMs;
+
+ std::array<VkDynamicState, 2> dynStates = {{
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ }};
+
+ VkPipelineDynamicStateCreateInfo dynState;
+ dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynState.pNext = nullptr;
+ dynState.flags = 0;
+ dynState.dynamicStateCount = dynStates.size();
+ dynState.pDynamicStates = dynStates.data();
+
+ VkPipelineVertexInputStateCreateInfo viState;
+ viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ viState.pNext = nullptr;
+ viState.flags = 0;
+ viState.vertexBindingDescriptionCount = 0;
+ viState.pVertexBindingDescriptions = nullptr;
+ viState.vertexAttributeDescriptionCount = 0;
+ viState.pVertexAttributeDescriptions = nullptr;
+
+ VkPipelineInputAssemblyStateCreateInfo iaState;
+ iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaState.pNext = nullptr;
+ iaState.flags = 0;
+ iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ iaState.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineViewportStateCreateInfo vpState;
+ vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vpState.pNext = nullptr;
+ vpState.flags = 0;
+ vpState.viewportCount = 1;
+ vpState.pViewports = nullptr;
+ vpState.scissorCount = 1;
+ vpState.pScissors = nullptr;
+
+ VkPipelineRasterizationStateCreateInfo rsState;
+ rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsState.pNext = nullptr;
+ rsState.flags = 0;
+ rsState.depthClampEnable = VK_TRUE;
+ rsState.rasterizerDiscardEnable = VK_FALSE;
+ rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ rsState.cullMode = VK_CULL_MODE_NONE;
+ rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rsState.depthBiasEnable = VK_FALSE;
+ rsState.depthBiasConstantFactor = 0.0f;
+ rsState.depthBiasClamp = 0.0f;
+ rsState.depthBiasSlopeFactor = 0.0f;
+ rsState.lineWidth = 1.0f;
+
+ uint32_t msMask = 0xFFFFFFFF;
+ VkPipelineMultisampleStateCreateInfo msState;
+ msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msState.pNext = nullptr;
+ msState.flags = 0;
+ msState.rasterizationSamples = key.samples;
+ msState.sampleShadingEnable = key.samples != VK_SAMPLE_COUNT_1_BIT;
+ msState.minSampleShading = 1.0f;
+ msState.pSampleMask = &msMask;
+ msState.alphaToCoverageEnable = VK_FALSE;
+ msState.alphaToOneEnable = VK_FALSE;
+
+ VkPipelineColorBlendAttachmentState cbAttachment;
+ cbAttachment.blendEnable = VK_FALSE;
+ cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.colorBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.colorWriteMask =
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineColorBlendStateCreateInfo cbState;
+ cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cbState.pNext = nullptr;
+ cbState.flags = 0;
+ cbState.logicOpEnable = VK_FALSE;
+ cbState.logicOp = VK_LOGIC_OP_NO_OP;
+ cbState.attachmentCount = 1;
+ cbState.pAttachments = &cbAttachment;
+
+ for (uint32_t i = 0; i < 4; i++)
+ cbState.blendConstants[i] = 0.0f;
+
+ VkStencilOpState stencilOp;
+ stencilOp.failOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.passOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.depthFailOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
+ stencilOp.compareMask = 0xFFFFFFFF;
+ stencilOp.writeMask = 0xFFFFFFFF;
+ stencilOp.reference = 0;
+
+ VkPipelineDepthStencilStateCreateInfo dsState;
+ dsState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ dsState.pNext = nullptr;
+ dsState.flags = 0;
+ dsState.depthTestEnable = VK_TRUE;
+ dsState.depthWriteEnable = VK_TRUE;
+ dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
+ dsState.depthBoundsTestEnable = VK_FALSE;
+ dsState.stencilTestEnable = VK_TRUE;
+ dsState.front = stencilOp;
+ dsState.back = stencilOp;
+ dsState.minDepthBounds = 0.0f;
+ dsState.maxDepthBounds = 1.0f;
+
+ VkGraphicsPipelineCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.stageCount = stageCount;
+ info.pStages = stages.data();
+ info.pVertexInputState = &viState;
+ info.pInputAssemblyState = &iaState;
+ info.pTessellationState = nullptr;
+ info.pViewportState = &vpState;
+ info.pRasterizationState = &rsState;
+ info.pMultisampleState = &msState;
+ info.pColorBlendState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? &cbState : nullptr;
+ info.pDepthStencilState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? nullptr : &dsState;
+ info.pDynamicState = &dynState;
+ info.layout = pipelineLayout;
+ info.renderPass = renderPass;
+ info.subpass = 0;
+ info.basePipelineHandle = VK_NULL_HANDLE;
+ info.basePipelineIndex = -1;
+
+ VkPipeline result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create graphics pipeline");
+ return result;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.h
new file mode 100644
index 00000000..c80b7f79
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_copy.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "../spirv/spirv_code_buffer.h"
+
+#include "dxvk_barrier.h"
+#include "dxvk_cmdlist.h"
+#include "dxvk_hash.h"
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Push constants for buffer image copies
+ */
+ struct DxvkCopyBufferImageArgs {
+ VkOffset3D dstOffset; uint32_t pad0;
+ VkOffset3D srcOffset; uint32_t pad1;
+ VkExtent3D extent; uint32_t pad2;
+ VkExtent2D dstSize;
+ VkExtent2D srcSize;
+ };
+
+ /**
+ * \brief Copy pipeline
+ *
+ * Stores the objects for a single pipeline
+ * that is used for fragment shader copies.
+ */
+ struct DxvkMetaCopyPipeline {
+ VkRenderPass renderPass;
+ VkDescriptorSetLayout dsetLayout;
+ VkPipelineLayout pipeLayout;
+ VkPipeline pipeHandle;
+ };
+
+ /**
+ * \brief Copy pipeline key
+ *
+ * Used to look up copy pipelines based
+ * on the copy operation they support.
+ */
+ struct DxvkMetaCopyPipelineKey {
+ VkImageViewType viewType;
+ VkFormat format;
+ VkSampleCountFlagBits samples;
+
+ bool eq(const DxvkMetaCopyPipelineKey& other) const {
+ return this->viewType == other.viewType
+ && this->format == other.format
+ && this->samples == other.samples;
+ }
+
+ size_t hash() const {
+ return (uint32_t(format) << 8)
+ ^ (uint32_t(samples) << 4)
+ ^ (uint32_t(viewType));
+ }
+ };
+
+ /**
+ * \brief Copy framebuffer and render pass
+ *
+ * Creates a framebuffer and render
+ * pass object for an image view.
+ */
+ class DxvkMetaCopyRenderPass : public DxvkResource {
+
+ public:
+
+ DxvkMetaCopyRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ const Rc<DxvkImageView>& srcStencilView,
+ bool discardDst);
+
+ ~DxvkMetaCopyRenderPass();
+
+ VkRenderPass renderPass() const {
+ return m_renderPass;
+ }
+
+ VkFramebuffer framebuffer() const {
+ return m_framebuffer;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ Rc<DxvkImageView> m_dstImageView;
+ Rc<DxvkImageView> m_srcImageView;
+ Rc<DxvkImageView> m_srcStencilView;
+
+ VkRenderPass m_renderPass = VK_NULL_HANDLE;
+ VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
+
+ VkRenderPass createRenderPass(bool discard) const;
+
+ VkFramebuffer createFramebuffer() const;
+
+ };
+
+ /**
+ * \brief Meta copy objects
+ *
+ * Meta copy operations are necessary in order
+ * to copy data between color and depth images.
+ */
+ class DxvkMetaCopyObjects {
+
+ public:
+
+ DxvkMetaCopyObjects(const DxvkDevice* device);
+ ~DxvkMetaCopyObjects();
+
+ /**
+ * \brief Queries color format for d->c copies
+ *
+ * Returns the color format that we need to use
+ * as the destination image view format in case
+ * of depth to color image copies.
+ * \param [in] format Depth format
+ * \returns Corresponding color format
+ */
+ VkFormat getCopyDestinationFormat(
+ VkImageAspectFlags dstAspect,
+ VkImageAspectFlags srcAspect,
+ VkFormat srcFormat) const;
+
+ /**
+ * \brief Creates pipeline for meta copy operation
+ *
+ * \param [in] viewType Image view type
+ * \param [in] dstFormat Destination image format
+ * \param [in] dstSamples Destination sample count
+ * \returns Compatible pipeline for the operation
+ */
+ DxvkMetaCopyPipeline getPipeline(
+ VkImageViewType viewType,
+ VkFormat dstFormat,
+ VkSampleCountFlagBits dstSamples);
+
+ /**
+ * \brief Creates pipeline for buffer image copy
+ * \returns Compute pipeline for buffer image copies
+ */
+ DxvkMetaCopyPipeline getCopyBufferImagePipeline();
+
+ private:
+
+ struct FragShaders {
+ VkShaderModule frag1D = VK_NULL_HANDLE;
+ VkShaderModule frag2D = VK_NULL_HANDLE;
+ VkShaderModule fragMs = VK_NULL_HANDLE;
+ };
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkSampler m_sampler;
+
+ VkShaderModule m_shaderVert = VK_NULL_HANDLE;
+ VkShaderModule m_shaderGeom = VK_NULL_HANDLE;
+
+ FragShaders m_color;
+ FragShaders m_depth;
+ FragShaders m_depthStencil;
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkMetaCopyPipelineKey,
+ DxvkMetaCopyPipeline,
+ DxvkHash, DxvkEq> m_pipelines;
+
+ DxvkMetaCopyPipeline m_copyBufferImagePipeline = { };
+
+ VkSampler createSampler() const;
+
+ VkShaderModule createShaderModule(
+ const SpirvCodeBuffer& code) const;
+
+ DxvkMetaCopyPipeline createCopyBufferImagePipeline();
+
+ DxvkMetaCopyPipeline createPipeline(
+ const DxvkMetaCopyPipelineKey& key);
+
+ VkRenderPass createRenderPass(
+ const DxvkMetaCopyPipelineKey& key) const;
+
+ VkDescriptorSetLayout createDescriptorSetLayout(
+ const DxvkMetaCopyPipelineKey& key) const;
+
+ VkPipelineLayout createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout) const;
+
+ VkPipeline createPipelineObject(
+ const DxvkMetaCopyPipelineKey& key,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.cpp
new file mode 100644
index 00000000..297da07e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.cpp
@@ -0,0 +1,181 @@
+#include "dxvk_meta_mipgen.h"
+
+namespace dxvk {
+
+ DxvkMetaMipGenRenderPass::DxvkMetaMipGenRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& view)
+ : m_vkd(vkd), m_view(view), m_renderPass(createRenderPass()) {
+ // Determine view type based on image type
+ const std::array<std::pair<VkImageViewType, VkImageViewType>, 3> viewTypes = {{
+ { VK_IMAGE_VIEW_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_1D_ARRAY },
+ { VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY },
+ { VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_2D_ARRAY },
+ }};
+
+ m_srcViewType = viewTypes.at(uint32_t(view->imageInfo().type)).first;
+ m_dstViewType = viewTypes.at(uint32_t(view->imageInfo().type)).second;
+
+ // Create image views and framebuffers
+ m_passes.resize(view->info().numLevels - 1);
+
+ for (uint32_t i = 0; i < m_passes.size(); i++)
+ m_passes.at(i) = this->createFramebuffer(i);
+ }
+
+
+ DxvkMetaMipGenRenderPass::~DxvkMetaMipGenRenderPass() {
+ for (const auto& pass : m_passes) {
+ m_vkd->vkDestroyFramebuffer(m_vkd->device(), pass.framebuffer, nullptr);
+ m_vkd->vkDestroyImageView(m_vkd->device(), pass.dstView, nullptr);
+ m_vkd->vkDestroyImageView(m_vkd->device(), pass.srcView, nullptr);
+ }
+
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), m_renderPass, nullptr);
+ }
+
+
+ VkExtent3D DxvkMetaMipGenRenderPass::passExtent(uint32_t passId) const {
+ VkExtent3D extent = m_view->mipLevelExtent(passId + 1);
+
+ if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D)
+ extent.depth = m_view->info().numLayers;
+
+ return extent;
+ }
+
+
+ VkRenderPass DxvkMetaMipGenRenderPass::createRenderPass() const {
+ std::array<VkSubpassDependency, 2> subpassDeps = {{
+ { VK_SUBPASS_EXTERNAL, 0,
+ m_view->imageInfo().stages,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0 },
+ { 0, VK_SUBPASS_EXTERNAL,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ m_view->imageInfo().stages,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ m_view->imageInfo().access, 0 },
+ }};
+
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = m_view->info().format;
+ attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attachment.finalLayout = m_view->imageInfo().layout;
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &attachmentRef;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = nullptr;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = subpassDeps.size();
+ info.pDependencies = subpassDeps.data();
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create render pass");
+ return result;
+ }
+
+
+ DxvkMetaBlitPass DxvkMetaMipGenRenderPass::createFramebuffer(uint32_t pass) const {
+ DxvkMetaBlitPass result;
+ result.srcView = VK_NULL_HANDLE;
+ result.dstView = VK_NULL_HANDLE;
+ result.renderPass = m_renderPass;
+ result.framebuffer = VK_NULL_HANDLE;
+
+ // Common image view info
+ VkImageViewCreateInfo viewInfo;
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.pNext = nullptr;
+ viewInfo.flags = 0;
+ viewInfo.image = m_view->imageHandle();
+ viewInfo.format = m_view->info().format;
+ viewInfo.components = {
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+
+ // Create source image view, which points to
+ // the one mip level we're going to sample.
+ VkImageSubresourceRange srcSubresources;
+ srcSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ srcSubresources.baseMipLevel = m_view->info().minLevel + pass;
+ srcSubresources.levelCount = 1;
+ srcSubresources.baseArrayLayer = m_view->info().minLayer;
+ srcSubresources.layerCount = m_view->info().numLayers;
+
+ viewInfo.viewType = m_srcViewType;
+ viewInfo.subresourceRange = srcSubresources;
+
+ if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.srcView) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create source image view");
+
+ // Create destination image view, which points
+ // to the mip level we're going to render to.
+ VkExtent3D dstExtent = m_view->mipLevelExtent(pass + 1);
+
+ VkImageSubresourceRange dstSubresources;
+ dstSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ dstSubresources.baseMipLevel = m_view->info().minLevel + pass + 1;
+ dstSubresources.levelCount = 1;
+
+ if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D) {
+ dstSubresources.baseArrayLayer = m_view->info().minLayer;
+ dstSubresources.layerCount = m_view->info().numLayers;
+ } else {
+ dstSubresources.baseArrayLayer = 0;
+ dstSubresources.layerCount = dstExtent.depth;
+ }
+
+ viewInfo.viewType = m_dstViewType;
+ viewInfo.subresourceRange = dstSubresources;
+
+ if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.dstView) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target image view");
+
+ // Create framebuffer using the destination
+ // image view as its color attachment.
+ VkFramebufferCreateInfo fboInfo;
+ fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fboInfo.pNext = nullptr;
+ fboInfo.flags = 0;
+ fboInfo.renderPass = m_renderPass;
+ fboInfo.attachmentCount = 1;
+ fboInfo.pAttachments = &result.dstView;
+ fboInfo.width = dstExtent.width;
+ fboInfo.height = dstExtent.height;
+ fboInfo.layers = dstSubresources.layerCount;
+
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result.framebuffer) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target framebuffer");
+
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.h
new file mode 100644
index 00000000..a5d2d60f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_mipgen.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_meta_blit.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Mip map generation render pass
+ *
+ * Stores image views, framebuffer objects and
+ * a render pass object for mip map generation.
+ * This must be created per image view.
+ */
+ class DxvkMetaMipGenRenderPass : public DxvkResource {
+
+ public:
+
+ DxvkMetaMipGenRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& view);
+
+ ~DxvkMetaMipGenRenderPass();
+
+ /**
+ * \brief Render pass handle
+ * \returns Render pass handle
+ */
+ VkRenderPass renderPass() const {
+ return m_renderPass;
+ }
+
+ /**
+ * \brief Source image view type
+ *
+ * Use this to figure out which type the
+ * resource descriptor needs to have.
+ * \returns Source image view type
+ */
+ VkImageViewType viewType() const {
+ return m_srcViewType;
+ }
+
+ /**
+ * \brief Render pass count
+ *
+ * Number of mip levels to generate.
+ * \returns Render pass count
+ */
+ uint32_t passCount() const {
+ return m_passes.size();
+ }
+
+ /**
+ * \brief Framebuffer handles
+ *
+ * Returns image view and framebuffer handles
+ * required to generate a single mip level.
+ * \param [in] pass Render pass index
+ * \returns Object handles for the given pass
+ */
+ DxvkMetaBlitPass pass(uint32_t passId) const {
+ return m_passes.at(passId);
+ }
+
+ /**
+ * \brief Framebuffer size for a given pass
+ *
+ * Stores the width, height, and layer count
+ * of the framebuffer for the given pass ID.
+ */
+ VkExtent3D passExtent(uint32_t passId) const;
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ Rc<DxvkImageView> m_view;
+
+ VkRenderPass m_renderPass;
+
+ VkImageViewType m_srcViewType;
+ VkImageViewType m_dstViewType;
+
+ std::vector<DxvkMetaBlitPass> m_passes;
+
+ VkRenderPass createRenderPass() const;
+
+ DxvkMetaBlitPass createFramebuffer(uint32_t pass) const;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.cpp
new file mode 100644
index 00000000..dbf4999b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.cpp
@@ -0,0 +1,287 @@
+#include "dxvk_meta_pack.h"
+#include "dxvk_device.h"
+
+#include <dxvk_pack_d24s8.h>
+#include <dxvk_pack_d32s8.h>
+
+#include <dxvk_unpack_d24s8_as_d32s8.h>
+#include <dxvk_unpack_d24s8.h>
+#include <dxvk_unpack_d32s8.h>
+
+namespace dxvk {
+
+ DxvkMetaPackObjects::DxvkMetaPackObjects(const DxvkDevice* device)
+ : m_vkd (device->vkd()),
+ m_sampler (createSampler()),
+ m_dsetLayoutPack (createPackDescriptorSetLayout()),
+ m_dsetLayoutUnpack(createUnpackDescriptorSetLayout()),
+ m_pipeLayoutPack (createPipelineLayout(m_dsetLayoutPack, sizeof(DxvkMetaPackArgs))),
+ m_pipeLayoutUnpack(createPipelineLayout(m_dsetLayoutUnpack, sizeof(DxvkMetaPackArgs))),
+ m_templatePack (createPackDescriptorUpdateTemplate()),
+ m_templateUnpack (createUnpackDescriptorUpdateTemplate()),
+ m_pipePackD24S8 (createPipeline(m_pipeLayoutPack, dxvk_pack_d24s8)),
+ m_pipePackD32S8 (createPipeline(m_pipeLayoutPack, dxvk_pack_d32s8)),
+ m_pipeUnpackD24S8AsD32S8(createPipeline(m_pipeLayoutUnpack, dxvk_unpack_d24s8_as_d32s8)),
+ m_pipeUnpackD24S8 (createPipeline(m_pipeLayoutUnpack, dxvk_unpack_d24s8)),
+ m_pipeUnpackD32S8 (createPipeline(m_pipeLayoutUnpack, dxvk_unpack_d32s8)) {
+
+ }
+
+
+ DxvkMetaPackObjects::~DxvkMetaPackObjects() {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeUnpackD32S8, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeUnpackD24S8, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipeUnpackD24S8AsD32S8, nullptr);
+
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipePackD32S8, nullptr);
+ m_vkd->vkDestroyPipeline(m_vkd->device(), m_pipePackD24S8, nullptr);
+
+ m_vkd->vkDestroyDescriptorUpdateTemplate(m_vkd->device(), m_templatePack, nullptr);
+ m_vkd->vkDestroyDescriptorUpdateTemplate(m_vkd->device(), m_templateUnpack, nullptr);
+
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipeLayoutPack, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipeLayoutUnpack, nullptr);
+
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_dsetLayoutPack, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_dsetLayoutUnpack, nullptr);
+
+ m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr);
+ }
+
+
+ DxvkMetaPackPipeline DxvkMetaPackObjects::getPackPipeline(VkFormat format) {
+ DxvkMetaPackPipeline result;
+ result.dsetTemplate = m_templatePack;
+ result.dsetLayout = m_dsetLayoutPack;
+ result.pipeLayout = m_pipeLayoutPack;
+ result.pipeHandle = VK_NULL_HANDLE;
+
+ switch (format) {
+ case VK_FORMAT_D24_UNORM_S8_UINT: result.pipeHandle = m_pipePackD24S8; break;
+ case VK_FORMAT_D32_SFLOAT_S8_UINT: result.pipeHandle = m_pipePackD32S8; break;
+ default: Logger::err(str::format("DxvkMetaPackObjects: Unknown format: ", format));
+ }
+
+ return result;
+ }
+
+
+ DxvkMetaPackPipeline DxvkMetaPackObjects::getUnpackPipeline(
+ VkFormat dstFormat,
+ VkFormat srcFormat) {
+ DxvkMetaPackPipeline result;
+ result.dsetTemplate = m_templateUnpack;
+ result.dsetLayout = m_dsetLayoutUnpack;
+ result.pipeLayout = m_pipeLayoutUnpack;
+ result.pipeHandle = VK_NULL_HANDLE;
+
+ std::array<std::tuple<VkFormat, VkFormat, VkPipeline>, 3> pipeSelector = {{
+ { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, m_pipeUnpackD24S8 },
+ { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, m_pipeUnpackD24S8AsD32S8 },
+ { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, m_pipeUnpackD32S8 },
+ }};
+
+ for (const auto& e : pipeSelector) {
+ if (std::get<0>(e) == dstFormat
+ && std::get<1>(e) == srcFormat)
+ result.pipeHandle = std::get<2>(e);
+ }
+
+ return result;
+ }
+
+
+ VkSampler DxvkMetaPackObjects::createSampler() {
+ VkSamplerCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.magFilter = VK_FILTER_NEAREST;
+ info.minFilter = VK_FILTER_NEAREST;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.mipLodBias = 0.0f;
+ info.anisotropyEnable = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.compareEnable = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_ALWAYS;
+ info.minLod = 0.0f;
+ info.maxLod = 0.0f;
+ info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ info.unnormalizedCoordinates = VK_FALSE;
+
+ VkSampler result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create sampler");
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaPackObjects::createPackDescriptorSetLayout() {
+ std::array<VkDescriptorSetLayoutBinding, 3> bindings = {{
+ { 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &m_sampler },
+ { 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, &m_sampler },
+ }};
+
+ VkDescriptorSetLayoutCreateInfo dsetInfo;
+ dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsetInfo.pNext = nullptr;
+ dsetInfo.flags = 0;
+ dsetInfo.bindingCount = bindings.size();
+ dsetInfo.pBindings = bindings.data();
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &dsetInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create descriptor set layout");
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaPackObjects::createUnpackDescriptorSetLayout() {
+ std::array<VkDescriptorSetLayoutBinding, 3> bindings = {{
+ { 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ { 1, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ { 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
+ }};
+
+ VkDescriptorSetLayoutCreateInfo dsetInfo;
+ dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsetInfo.pNext = nullptr;
+ dsetInfo.flags = 0;
+ dsetInfo.bindingCount = bindings.size();
+ dsetInfo.pBindings = bindings.data();
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &dsetInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create descriptor set layout");
+ return result;
+ }
+
+
+ VkPipelineLayout DxvkMetaPackObjects::createPipelineLayout(
+ VkDescriptorSetLayout dsetLayout,
+ size_t pushLayout) {
+ VkPushConstantRange push;
+ push.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ push.offset = 0;
+ push.size = pushLayout;
+
+ VkPipelineLayoutCreateInfo layoutInfo;
+ layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layoutInfo.pNext = nullptr;
+ layoutInfo.flags = 0;
+ layoutInfo.setLayoutCount = 1;
+ layoutInfo.pSetLayouts = &dsetLayout;
+ layoutInfo.pushConstantRangeCount = 1;
+ layoutInfo.pPushConstantRanges = &push;
+
+ VkPipelineLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &layoutInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create pipeline layout");
+ return result;
+ }
+
+
+ VkDescriptorUpdateTemplate DxvkMetaPackObjects::createPackDescriptorUpdateTemplate() {
+ std::array<VkDescriptorUpdateTemplateEntry, 3> bindings = {{
+ { 0, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, offsetof(DxvkMetaPackDescriptors, dstBuffer), 0 },
+ { 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, offsetof(DxvkMetaPackDescriptors, srcDepth), 0 },
+ { 2, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, offsetof(DxvkMetaPackDescriptors, srcStencil), 0 },
+ }};
+
+ VkDescriptorUpdateTemplateCreateInfo templateInfo;
+ templateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
+ templateInfo.pNext = nullptr;
+ templateInfo.flags = 0;
+ templateInfo.descriptorUpdateEntryCount = bindings.size();
+ templateInfo.pDescriptorUpdateEntries = bindings.data();
+ templateInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
+ templateInfo.descriptorSetLayout = m_dsetLayoutPack;
+ templateInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
+ templateInfo.pipelineLayout = m_pipeLayoutPack;
+ templateInfo.set = 0;
+
+ VkDescriptorUpdateTemplate result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorUpdateTemplate(m_vkd->device(),
+ &templateInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create descriptor update template");
+ return result;
+ }
+
+
+ VkDescriptorUpdateTemplate DxvkMetaPackObjects::createUnpackDescriptorUpdateTemplate() {
+ std::array<VkDescriptorUpdateTemplateEntry, 3> bindings = {{
+ { 0, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, offsetof(DxvkMetaUnpackDescriptors, dstDepth), 0 },
+ { 1, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, offsetof(DxvkMetaUnpackDescriptors, dstStencil), 0 },
+ { 2, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, offsetof(DxvkMetaUnpackDescriptors, srcBuffer), 0 },
+ }};
+
+ VkDescriptorUpdateTemplateCreateInfo templateInfo;
+ templateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
+ templateInfo.pNext = nullptr;
+ templateInfo.flags = 0;
+ templateInfo.descriptorUpdateEntryCount = bindings.size();
+ templateInfo.pDescriptorUpdateEntries = bindings.data();
+ templateInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
+ templateInfo.descriptorSetLayout = m_dsetLayoutUnpack;
+ templateInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
+ templateInfo.pipelineLayout = m_pipeLayoutUnpack;
+ templateInfo.set = 0;
+
+ VkDescriptorUpdateTemplate result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorUpdateTemplate(m_vkd->device(),
+ &templateInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create descriptor update template");
+ return result;
+ }
+
+
+ VkPipeline DxvkMetaPackObjects::createPipeline(
+ VkPipelineLayout pipeLayout,
+ const SpirvCodeBuffer& code) {
+ VkShaderModuleCreateInfo shaderInfo;
+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shaderInfo.pNext = nullptr;
+ shaderInfo.flags = 0;
+ shaderInfo.codeSize = code.size();
+ shaderInfo.pCode = code.data();
+
+ VkShaderModule module = VK_NULL_HANDLE;
+
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(), &shaderInfo, nullptr, &module) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create shader module");
+
+ VkPipelineShaderStageCreateInfo stageInfo;
+ stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stageInfo.pNext = nullptr;
+ stageInfo.flags = 0;
+ stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ stageInfo.module = module;
+ stageInfo.pName = "main";
+ stageInfo.pSpecializationInfo = nullptr;
+
+ VkComputePipelineCreateInfo pipeInfo;
+ pipeInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ pipeInfo.pNext = nullptr;
+ pipeInfo.flags = 0;
+ pipeInfo.stage = stageInfo;
+ pipeInfo.layout = pipeLayout;
+ pipeInfo.basePipelineHandle = VK_NULL_HANDLE;
+ pipeInfo.basePipelineIndex = -1;
+
+ VkPipeline result = VK_NULL_HANDLE;
+
+ VkResult status = m_vkd->vkCreateComputePipelines(
+ m_vkd->device(), VK_NULL_HANDLE, 1, &pipeInfo, nullptr, &result);
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), module, nullptr);
+
+ if (status != VK_SUCCESS)
+ throw DxvkError("DxvkMetaPackObjects: Failed to create pipeline");
+ return result;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.h
new file mode 100644
index 00000000..7c69d8c3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_pack.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#include "../spirv/spirv_code_buffer.h"
+
+#include "dxvk_cmdlist.h"
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Packing arguments
+ *
+ * Passed in as push constants
+ * to the compute shader.
+ */
+ struct DxvkMetaPackArgs {
+ VkOffset2D srcOffset;
+ VkExtent2D srcExtent;
+ VkOffset2D dstOffset;
+ VkExtent2D dstExtent;
+ };
+
+
+ /**
+ * \brief Packing pipeline
+ *
+ * Stores the objects for a single pipeline
+ * that is used to pack depth-stencil image
+ * data into a linear buffer.
+ */
+ struct DxvkMetaPackPipeline {
+ VkDescriptorUpdateTemplateKHR dsetTemplate;
+ VkDescriptorSetLayout dsetLayout;
+ VkPipelineLayout pipeLayout;
+ VkPipeline pipeHandle;
+ };
+
+
+ /**
+ * \brief Packing descriptors
+ */
+ struct DxvkMetaPackDescriptors {
+ VkDescriptorBufferInfo dstBuffer;
+ VkDescriptorImageInfo srcDepth;
+ VkDescriptorImageInfo srcStencil;
+ };
+
+
+ /**
+ * \brief Unpacking descriptors
+ */
+ struct DxvkMetaUnpackDescriptors {
+ VkBufferView dstDepth;
+ VkBufferView dstStencil;
+ VkDescriptorBufferInfo srcBuffer;
+ };
+
+
+ /**
+ * \brief Depth-stencil pack objects
+ *
+ * Stores compute shaders and related objects
+ * for depth-stencil image packing operations.
+ */
+ class DxvkMetaPackObjects {
+
+ public:
+
+ DxvkMetaPackObjects(const DxvkDevice* device);
+ ~DxvkMetaPackObjects();
+
+ /**
+ * \brief Retrieves depth-stencil packing pipeline
+ *
+ * \param [in] format Destination format
+ * \returns Data packing pipeline
+ */
+ DxvkMetaPackPipeline getPackPipeline(VkFormat format);
+
+ /**
+ * \brief Retrieves depth-stencil unpacking pipeline
+ *
+ * \param [in] dstFormat Destination image format
+ * \param [in] srcFormat Source buffer format
+ * \returns Data unpacking pipeline
+ */
+ DxvkMetaPackPipeline getUnpackPipeline(
+ VkFormat dstFormat,
+ VkFormat srcFormat);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkSampler m_sampler;
+
+ VkDescriptorSetLayout m_dsetLayoutPack;
+ VkDescriptorSetLayout m_dsetLayoutUnpack;
+
+ VkPipelineLayout m_pipeLayoutPack;
+ VkPipelineLayout m_pipeLayoutUnpack;
+
+ VkDescriptorUpdateTemplateKHR m_templatePack;
+ VkDescriptorUpdateTemplateKHR m_templateUnpack;
+
+ VkPipeline m_pipePackD24S8;
+ VkPipeline m_pipePackD32S8;
+
+ VkPipeline m_pipeUnpackD24S8AsD32S8;
+ VkPipeline m_pipeUnpackD24S8;
+ VkPipeline m_pipeUnpackD32S8;
+
+ VkSampler createSampler();
+
+ VkDescriptorSetLayout createPackDescriptorSetLayout();
+
+ VkDescriptorSetLayout createUnpackDescriptorSetLayout();
+
+ VkPipelineLayout createPipelineLayout(
+ VkDescriptorSetLayout dsetLayout,
+ size_t pushLayout);
+
+ VkDescriptorUpdateTemplateKHR createPackDescriptorUpdateTemplate();
+
+ VkDescriptorUpdateTemplateKHR createUnpackDescriptorUpdateTemplate();
+
+ VkPipeline createPipeline(
+ VkPipelineLayout pipeLayout,
+ const SpirvCodeBuffer& code);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.cpp
new file mode 100644
index 00000000..55dde83c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.cpp
@@ -0,0 +1,714 @@
+#include "dxvk_device.h"
+#include "dxvk_meta_resolve.h"
+
+#include <dxvk_fullscreen_geom.h>
+#include <dxvk_fullscreen_vert.h>
+#include <dxvk_fullscreen_layer_vert.h>
+
+#include <dxvk_resolve_frag_d.h>
+#include <dxvk_resolve_frag_ds.h>
+#include <dxvk_resolve_frag_f.h>
+#include <dxvk_resolve_frag_f_amd.h>
+#include <dxvk_resolve_frag_u.h>
+#include <dxvk_resolve_frag_i.h>
+
+namespace dxvk {
+
+ DxvkMetaResolveRenderPass::DxvkMetaResolveRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ const Rc<DxvkImageView>& srcStencilView,
+ bool discardDst)
+ : m_vkd(vkd),
+ m_dstImageView(dstImageView),
+ m_srcImageView(srcImageView),
+ m_srcStencilView(srcStencilView),
+ m_renderPass (createShaderRenderPass(discardDst)),
+ m_framebuffer (createShaderFramebuffer()) { }
+
+
+ DxvkMetaResolveRenderPass::DxvkMetaResolveRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ VkResolveModeFlagBitsKHR modeD,
+ VkResolveModeFlagBitsKHR modeS)
+ : m_vkd(vkd),
+ m_dstImageView(dstImageView),
+ m_srcImageView(srcImageView),
+ m_renderPass (createAttachmentRenderPass(modeD, modeS)),
+ m_framebuffer (createAttachmentFramebuffer()) { }
+
+
+ DxvkMetaResolveRenderPass::~DxvkMetaResolveRenderPass() {
+ m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr);
+ m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr);
+ }
+
+
+ VkRenderPass DxvkMetaResolveRenderPass::createShaderRenderPass(bool discard) const {
+ auto formatInfo = m_dstImageView->formatInfo();
+ bool isColorImage = (formatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT);
+
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = m_dstImageView->info().format;
+ attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.initialLayout = m_dstImageView->imageInfo().layout;
+ attachment.finalLayout = m_dstImageView->imageInfo().layout;
+
+ if (discard) {
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ VkImageLayout layout = isColorImage
+ ? m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
+ : m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ VkAttachmentReference dstRef;
+ dstRef.attachment = 0;
+ dstRef.layout = layout;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = isColorImage ? 1 : 0;
+ subpass.pColorAttachments = isColorImage ? &dstRef : nullptr;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = isColorImage ? nullptr : &dstRef;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkPipelineStageFlags cpyStages = 0;
+ VkAccessFlags cpyAccess = 0;
+
+ if (isColorImage) {
+ cpyStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ if (!discard)
+ cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ } else {
+ cpyStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+
+ if (!discard)
+ cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+ }
+
+ // Resolve targets are required to be render targets
+ VkPipelineStageFlags extStages = m_dstImageView->imageInfo().stages | m_srcImageView->imageInfo().stages;
+ VkAccessFlags extAccess = m_dstImageView->imageInfo().access;
+
+ std::array<VkSubpassDependency, 2> dependencies = {{
+ { VK_SUBPASS_EXTERNAL, 0, cpyStages, cpyStages, 0, cpyAccess, 0 },
+ { 0, VK_SUBPASS_EXTERNAL, cpyStages, extStages, cpyAccess, extAccess, 0 },
+ }};
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = dependencies.size();
+ info.pDependencies = dependencies.data();
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveRenderPass: Failed to create render pass");
+ return result;
+ }
+
+
+ VkRenderPass DxvkMetaResolveRenderPass::createAttachmentRenderPass(
+ VkResolveModeFlagBitsKHR modeD,
+ VkResolveModeFlagBitsKHR modeS) const {
+ std::array<VkAttachmentDescription2KHR, 2> attachments;
+ attachments[0].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
+ attachments[0].pNext = nullptr;
+ attachments[0].flags = 0;
+ attachments[0].format = m_srcImageView->info().format;
+ attachments[0].samples = m_srcImageView->imageInfo().sampleCount;
+ attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[0].initialLayout = m_srcImageView->imageInfo().layout;
+ attachments[0].finalLayout = m_srcImageView->imageInfo().layout;
+
+ attachments[1].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR;
+ attachments[1].pNext = nullptr;
+ attachments[1].flags = 0;
+ attachments[1].format = m_dstImageView->info().format;
+ attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
+ attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[1].initialLayout = m_dstImageView->imageInfo().layout;
+ attachments[1].finalLayout = m_dstImageView->imageInfo().layout;
+
+ if (modeD != VK_RESOLVE_MODE_NONE_KHR && modeS != VK_RESOLVE_MODE_NONE_KHR) {
+ attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ VkAttachmentReference2KHR srcRef;
+ srcRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ srcRef.pNext = nullptr;
+ srcRef.attachment = 0;
+ srcRef.layout = m_srcImageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ srcRef.aspectMask = m_srcImageView->formatInfo()->aspectMask;
+
+ VkAttachmentReference2KHR dstRef;
+ dstRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ dstRef.pNext = nullptr;
+ dstRef.attachment = 1;
+ dstRef.layout = m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ dstRef.aspectMask = m_dstImageView->formatInfo()->aspectMask;
+
+ VkSubpassDescriptionDepthStencilResolveKHR subpassResolve;
+ subpassResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
+ subpassResolve.pNext = nullptr;
+ subpassResolve.depthResolveMode = modeD;
+ subpassResolve.stencilResolveMode = modeS;
+ subpassResolve.pDepthStencilResolveAttachment = &dstRef;
+
+ VkSubpassDescription2KHR subpass;
+ subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
+ subpass.pNext = &subpassResolve;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.viewMask = 0;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = 0;
+ subpass.pColorAttachments = nullptr;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = &srcRef;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkPipelineStageFlags cpyStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ VkPipelineStageFlags extStages = m_dstImageView->imageInfo().stages | m_srcImageView->imageInfo().stages;
+ VkAccessFlags cpyAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+ VkAccessFlags extAccess = m_dstImageView->imageInfo().access;
+
+ std::array<VkSubpassDependency2KHR, 2> dependencies = {{
+ { VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR, nullptr, VK_SUBPASS_EXTERNAL, 0, cpyStages, cpyStages, 0, cpyAccess, 0 },
+ { VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR, nullptr, 0, VK_SUBPASS_EXTERNAL, cpyStages, extStages, cpyAccess, extAccess, 0 },
+ }};
+
+ VkRenderPassCreateInfo2KHR info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = attachments.size();
+ info.pAttachments = attachments.data();
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = dependencies.size();
+ info.pDependencies = dependencies.data();
+ info.correlatedViewMaskCount = 0;
+ info.pCorrelatedViewMasks = nullptr;
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass2KHR(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveRenderPass: Failed to create render pass");
+ return result;
+ }
+
+
+ VkFramebuffer DxvkMetaResolveRenderPass::createShaderFramebuffer() const {
+ VkImageSubresourceRange dstSubresources = m_dstImageView->subresources();
+ VkExtent3D dstExtent = m_dstImageView->mipLevelExtent(0);
+ VkImageView dstHandle = m_dstImageView->handle();
+
+ VkFramebufferCreateInfo fboInfo;
+ fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fboInfo.pNext = nullptr;
+ fboInfo.flags = 0;
+ fboInfo.renderPass = m_renderPass;
+ fboInfo.attachmentCount = 1;
+ fboInfo.pAttachments = &dstHandle;
+ fboInfo.width = dstExtent.width;
+ fboInfo.height = dstExtent.height;
+ fboInfo.layers = dstSubresources.layerCount;
+
+ VkFramebuffer result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveRenderPass: Failed to create target framebuffer");
+ return result;
+ }
+
+
+ VkFramebuffer DxvkMetaResolveRenderPass::createAttachmentFramebuffer() const {
+ VkImageSubresourceRange dstSubresources = m_dstImageView->subresources();
+ VkExtent3D dstExtent = m_dstImageView->mipLevelExtent(0);
+
+ std::array<VkImageView, 2> handles = {{
+ m_srcImageView->handle(),
+ m_dstImageView->handle(),
+ }};
+
+ VkFramebufferCreateInfo fboInfo;
+ fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fboInfo.pNext = nullptr;
+ fboInfo.flags = 0;
+ fboInfo.renderPass = m_renderPass;
+ fboInfo.attachmentCount = handles.size();
+ fboInfo.pAttachments = handles.data();
+ fboInfo.width = dstExtent.width;
+ fboInfo.height = dstExtent.height;
+ fboInfo.layers = dstSubresources.layerCount;
+
+ VkFramebuffer result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveRenderPass: Failed to create target framebuffer");
+ return result;
+ }
+
+
+
+ DxvkMetaResolveObjects::DxvkMetaResolveObjects(const DxvkDevice* device)
+ : m_vkd (device->vkd()),
+ m_sampler (createSampler()),
+ m_shaderFragF (device->extensions().amdShaderFragmentMask
+ ? createShaderModule(dxvk_resolve_frag_f_amd)
+ : createShaderModule(dxvk_resolve_frag_f)),
+ m_shaderFragU (createShaderModule(dxvk_resolve_frag_u)),
+ m_shaderFragI (createShaderModule(dxvk_resolve_frag_i)),
+ m_shaderFragD (createShaderModule(dxvk_resolve_frag_d)) {
+ if (device->extensions().extShaderStencilExport)
+ m_shaderFragDS = createShaderModule(dxvk_resolve_frag_ds);
+
+ if (device->extensions().extShaderViewportIndexLayer) {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_layer_vert);
+ } else {
+ m_shaderVert = createShaderModule(dxvk_fullscreen_vert);
+ m_shaderGeom = createShaderModule(dxvk_fullscreen_geom);
+ }
+ }
+
+
+ DxvkMetaResolveObjects::~DxvkMetaResolveObjects() {
+ for (const auto& pair : m_pipelines) {
+ m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr);
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), pair.second.dsetLayout, nullptr);
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second.renderPass, nullptr);
+ }
+
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragDS, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragD, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragF, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragI, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragU, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr);
+ m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr);
+
+ m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr);
+ }
+
+
+ DxvkMetaResolvePipeline DxvkMetaResolveObjects::getPipeline(
+ VkFormat format,
+ VkSampleCountFlagBits samples,
+ VkResolveModeFlagBitsKHR depthResolveMode,
+ VkResolveModeFlagBitsKHR stencilResolveMode) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ DxvkMetaResolvePipelineKey key;
+ key.format = format;
+ key.samples = samples;
+ key.modeD = depthResolveMode;
+ key.modeS = stencilResolveMode;
+
+ auto entry = m_pipelines.find(key);
+ if (entry != m_pipelines.end())
+ return entry->second;
+
+ DxvkMetaResolvePipeline pipeline = createPipeline(key);
+ m_pipelines.insert({ key, pipeline });
+ return pipeline;
+ }
+
+
+ VkSampler DxvkMetaResolveObjects::createSampler() const {
+ VkSamplerCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.magFilter = VK_FILTER_NEAREST;
+ info.minFilter = VK_FILTER_NEAREST;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.mipLodBias = 0.0f;
+ info.anisotropyEnable = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.compareEnable = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_ALWAYS;
+ info.minLod = 0.0f;
+ info.maxLod = 0.0f;
+ info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ info.unnormalizedCoordinates = VK_FALSE;
+
+ VkSampler result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveObjects: Failed to create sampler");
+ return result;
+ }
+
+
+ VkShaderModule DxvkMetaResolveObjects::createShaderModule(
+ const SpirvCodeBuffer& code) const {
+ VkShaderModuleCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.codeSize = code.size();
+ info.pCode = code.data();
+
+ VkShaderModule result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create shader module");
+ return result;
+ }
+
+
+ DxvkMetaResolvePipeline DxvkMetaResolveObjects::createPipeline(
+ const DxvkMetaResolvePipelineKey& key) {
+ DxvkMetaResolvePipeline pipeline;
+ pipeline.renderPass = this->createRenderPass(key);
+ pipeline.dsetLayout = this->createDescriptorSetLayout(key);
+ pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout);
+ pipeline.pipeHandle = this->createPipelineObject(key, pipeline.pipeLayout, pipeline.renderPass);
+ return pipeline;
+ }
+
+
+ VkRenderPass DxvkMetaResolveObjects::createRenderPass(
+ const DxvkMetaResolvePipelineKey& key) {
+ auto formatInfo = imageFormatInfo(key.format);
+ bool isColorImage = (formatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT);
+
+ VkAttachmentDescription attachment;
+ attachment.flags = 0;
+ attachment.format = key.format;
+ attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
+ attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ VkImageLayout layout = isColorImage
+ ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
+ : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ VkAttachmentReference attachmentRef;
+ attachmentRef.attachment = 0;
+ attachmentRef.layout = layout;
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = isColorImage ? 1 : 0;
+ subpass.pColorAttachments = isColorImage ? &attachmentRef : nullptr;
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = isColorImage ? nullptr : &attachmentRef;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = 1;
+ info.pAttachments = &attachment;
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = 0;
+ info.pDependencies = nullptr;
+
+ VkRenderPass result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveObjects: Failed to create render pass");
+ return result;
+ }
+
+
+ VkDescriptorSetLayout DxvkMetaResolveObjects::createDescriptorSetLayout(
+ const DxvkMetaResolvePipelineKey& key) {
+ auto formatInfo = imageFormatInfo(key.format);
+
+ std::array<VkDescriptorSetLayoutBinding, 2> bindings = {{
+ { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &m_sampler },
+ { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &m_sampler },
+ }};
+
+ VkDescriptorSetLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.bindingCount = 1;
+ info.pBindings = bindings.data();
+
+ if ((formatInfo->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && key.modeS != VK_RESOLVE_MODE_NONE_KHR)
+ info.bindingCount = 2;
+
+ VkDescriptorSetLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaResolveObjects: Failed to create descriptor set layout");
+ return result;
+ }
+
+
+ VkPipelineLayout DxvkMetaResolveObjects::createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout) {
+ VkPushConstantRange push;
+ push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ push.offset = 0;
+ push.size = sizeof(VkOffset2D);
+
+ VkPipelineLayoutCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.setLayoutCount = 1;
+ info.pSetLayouts = &descriptorSetLayout;
+ info.pushConstantRangeCount = 1;
+ info.pPushConstantRanges = &push;
+
+ VkPipelineLayout result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create pipeline layout");
+ return result;
+ }
+
+
+ VkPipeline DxvkMetaResolveObjects::createPipelineObject(
+ const DxvkMetaResolvePipelineKey& key,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass) {
+ auto formatInfo = imageFormatInfo(key.format);
+ bool isColorImage = formatInfo->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT;
+
+ std::array<VkPipelineShaderStageCreateInfo, 3> stages;
+ uint32_t stageCount = 0;
+
+ std::array<VkSpecializationMapEntry, 3> specEntries = {{
+ { 0, offsetof(DxvkMetaResolvePipelineKey, samples), sizeof(VkSampleCountFlagBits) },
+ { 1, offsetof(DxvkMetaResolvePipelineKey, modeD), sizeof(VkResolveModeFlagBitsKHR) },
+ { 2, offsetof(DxvkMetaResolvePipelineKey, modeS), sizeof(VkResolveModeFlagBitsKHR) },
+ }};
+
+ VkSpecializationInfo specInfo;
+ specInfo.mapEntryCount = specEntries.size();
+ specInfo.pMapEntries = specEntries.data();
+ specInfo.dataSize = sizeof(key);
+ specInfo.pData = &key;
+
+ VkPipelineShaderStageCreateInfo& vsStage = stages[stageCount++];
+ vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vsStage.pNext = nullptr;
+ vsStage.flags = 0;
+ vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vsStage.module = m_shaderVert;
+ vsStage.pName = "main";
+ vsStage.pSpecializationInfo = nullptr;
+
+ if (m_shaderGeom) {
+ VkPipelineShaderStageCreateInfo& gsStage = stages[stageCount++];
+ gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ gsStage.pNext = nullptr;
+ gsStage.flags = 0;
+ gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
+ gsStage.module = m_shaderGeom;
+ gsStage.pName = "main";
+ gsStage.pSpecializationInfo = nullptr;
+ }
+
+ VkPipelineShaderStageCreateInfo& psStage = stages[stageCount++];
+ psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ psStage.pNext = nullptr;
+ psStage.flags = 0;
+ psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ psStage.module = VK_NULL_HANDLE;
+ psStage.pName = "main";
+ psStage.pSpecializationInfo = &specInfo;
+
+ if ((formatInfo->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && key.modeS != VK_RESOLVE_MODE_NONE_KHR) {
+ if (m_shaderFragDS) {
+ psStage.module = m_shaderFragDS;
+ } else {
+ psStage.module = m_shaderFragD;
+ Logger::err("DXVK: Stencil export not supported by device, skipping stencil resolve");
+ }
+ } else if (formatInfo->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
+ psStage.module = m_shaderFragD;
+ else if (formatInfo->flags.test(DxvkFormatFlag::SampledUInt))
+ psStage.module = m_shaderFragU;
+ else if (formatInfo->flags.test(DxvkFormatFlag::SampledSInt))
+ psStage.module = m_shaderFragI;
+ else
+ psStage.module = m_shaderFragF;
+
+ std::array<VkDynamicState, 2> dynStates = {{
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ }};
+
+ VkPipelineDynamicStateCreateInfo dynState;
+ dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynState.pNext = nullptr;
+ dynState.flags = 0;
+ dynState.dynamicStateCount = dynStates.size();
+ dynState.pDynamicStates = dynStates.data();
+
+ VkPipelineVertexInputStateCreateInfo viState;
+ viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ viState.pNext = nullptr;
+ viState.flags = 0;
+ viState.vertexBindingDescriptionCount = 0;
+ viState.pVertexBindingDescriptions = nullptr;
+ viState.vertexAttributeDescriptionCount = 0;
+ viState.pVertexAttributeDescriptions = nullptr;
+
+ VkPipelineInputAssemblyStateCreateInfo iaState;
+ iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ iaState.pNext = nullptr;
+ iaState.flags = 0;
+ iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ iaState.primitiveRestartEnable = VK_FALSE;
+
+ VkPipelineViewportStateCreateInfo vpState;
+ vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vpState.pNext = nullptr;
+ vpState.flags = 0;
+ vpState.viewportCount = 1;
+ vpState.pViewports = nullptr;
+ vpState.scissorCount = 1;
+ vpState.pScissors = nullptr;
+
+ VkPipelineRasterizationStateCreateInfo rsState;
+ rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsState.pNext = nullptr;
+ rsState.flags = 0;
+ rsState.depthClampEnable = VK_TRUE;
+ rsState.rasterizerDiscardEnable = VK_FALSE;
+ rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ rsState.cullMode = VK_CULL_MODE_NONE;
+ rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rsState.depthBiasEnable = VK_FALSE;
+ rsState.depthBiasConstantFactor = 0.0f;
+ rsState.depthBiasClamp = 0.0f;
+ rsState.depthBiasSlopeFactor = 0.0f;
+ rsState.lineWidth = 1.0f;
+
+ uint32_t msMask = 0xFFFFFFFF;
+ VkPipelineMultisampleStateCreateInfo msState;
+ msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msState.pNext = nullptr;
+ msState.flags = 0;
+ msState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ msState.sampleShadingEnable = VK_FALSE;
+ msState.minSampleShading = 1.0f;
+ msState.pSampleMask = &msMask;
+ msState.alphaToCoverageEnable = VK_FALSE;
+ msState.alphaToOneEnable = VK_FALSE;
+
+ VkPipelineColorBlendAttachmentState cbAttachment;
+ cbAttachment.blendEnable = VK_FALSE;
+ cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.colorBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
+ cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
+ cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
+ cbAttachment.colorWriteMask =
+ VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ VkPipelineColorBlendStateCreateInfo cbState;
+ cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cbState.pNext = nullptr;
+ cbState.flags = 0;
+ cbState.logicOpEnable = VK_FALSE;
+ cbState.logicOp = VK_LOGIC_OP_NO_OP;
+ cbState.attachmentCount = 1;
+ cbState.pAttachments = &cbAttachment;
+
+ for (uint32_t i = 0; i < 4; i++)
+ cbState.blendConstants[i] = 0.0f;
+
+ VkStencilOpState stencilOp;
+ stencilOp.failOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.passOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.depthFailOp = VK_STENCIL_OP_REPLACE;
+ stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
+ stencilOp.compareMask = 0xFFFFFFFF;
+ stencilOp.writeMask = 0xFFFFFFFF;
+ stencilOp.reference = 0;
+
+ VkPipelineDepthStencilStateCreateInfo dsState;
+ dsState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ dsState.pNext = nullptr;
+ dsState.flags = 0;
+ dsState.depthTestEnable = key.modeD != VK_RESOLVE_MODE_NONE_KHR;
+ dsState.depthWriteEnable = key.modeD != VK_RESOLVE_MODE_NONE_KHR;
+ dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
+ dsState.depthBoundsTestEnable = VK_FALSE;
+ dsState.stencilTestEnable = key.modeS != VK_RESOLVE_MODE_NONE_KHR;
+ dsState.front = stencilOp;
+ dsState.back = stencilOp;
+ dsState.minDepthBounds = 0.0f;
+ dsState.maxDepthBounds = 1.0f;
+
+ VkGraphicsPipelineCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.stageCount = stageCount;
+ info.pStages = stages.data();
+ info.pVertexInputState = &viState;
+ info.pInputAssemblyState = &iaState;
+ info.pTessellationState = nullptr;
+ info.pViewportState = &vpState;
+ info.pRasterizationState = &rsState;
+ info.pMultisampleState = &msState;
+ info.pColorBlendState = isColorImage ? &cbState : nullptr;
+ info.pDepthStencilState = isColorImage ? nullptr : &dsState;
+ info.pDynamicState = &dynState;
+ info.layout = pipelineLayout;
+ info.renderPass = renderPass;
+ info.subpass = 0;
+ info.basePipelineHandle = VK_NULL_HANDLE;
+ info.basePipelineIndex = -1;
+
+ VkPipeline result = VK_NULL_HANDLE;
+ if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS)
+ throw DxvkError("DxvkMetaCopyObjects: Failed to create graphics pipeline");
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.h
new file mode 100644
index 00000000..72161325
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_meta_resolve.h
@@ -0,0 +1,185 @@
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "../spirv/spirv_code_buffer.h"
+
+#include "dxvk_barrier.h"
+#include "dxvk_cmdlist.h"
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Resolve pipeline
+ *
+ * Stores the objects for a single pipeline
+ * that is used for fragment shader resolve.
+ */
+ struct DxvkMetaResolvePipeline {
+ VkRenderPass renderPass;
+ VkDescriptorSetLayout dsetLayout;
+ VkPipelineLayout pipeLayout;
+ VkPipeline pipeHandle;
+ };
+
+ /**
+ * \brief Copy pipeline key
+ *
+ * Used to look up copy pipelines based
+ * on the copy operation they support.
+ */
+ struct DxvkMetaResolvePipelineKey {
+ VkFormat format;
+ VkSampleCountFlagBits samples;
+ VkResolveModeFlagBitsKHR modeD;
+ VkResolveModeFlagBitsKHR modeS;
+
+ bool eq(const DxvkMetaResolvePipelineKey& other) const {
+ return this->format == other.format
+ && this->samples == other.samples
+ && this->modeD == other.modeD
+ && this->modeS == other.modeS;
+ }
+
+ size_t hash() const {
+ return (uint32_t(format) << 4)
+ ^ (uint32_t(samples) << 0)
+ ^ (uint32_t(modeD) << 12)
+ ^ (uint32_t(modeS) << 16);
+ }
+ };
+
+ /**
+ * \brief Meta resolve render pass
+ *
+ * Stores a framebuffer and image view objects
+ * for a meta resolve operation. Can be tracked.
+ */
+ class DxvkMetaResolveRenderPass : public DxvkResource {
+
+ public:
+
+ DxvkMetaResolveRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ const Rc<DxvkImageView>& srcStencilView,
+ bool discardDst);
+
+ DxvkMetaResolveRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkImageView>& dstImageView,
+ const Rc<DxvkImageView>& srcImageView,
+ VkResolveModeFlagBitsKHR modeD,
+ VkResolveModeFlagBitsKHR modeS);
+
+ ~DxvkMetaResolveRenderPass();
+
+ VkRenderPass renderPass() const {
+ return m_renderPass;
+ }
+
+ VkFramebuffer framebuffer() const {
+ return m_framebuffer;
+ }
+
+ private:
+
+ const Rc<vk::DeviceFn> m_vkd;
+
+ const Rc<DxvkImageView> m_dstImageView;
+ const Rc<DxvkImageView> m_srcImageView;
+ const Rc<DxvkImageView> m_srcStencilView;
+
+ VkRenderPass m_renderPass = VK_NULL_HANDLE;
+ VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
+
+ VkRenderPass createShaderRenderPass(bool discard) const;
+
+ VkRenderPass createAttachmentRenderPass(
+ VkResolveModeFlagBitsKHR modeD,
+ VkResolveModeFlagBitsKHR modeS) const;
+
+ VkFramebuffer createShaderFramebuffer() const;
+
+ VkFramebuffer createAttachmentFramebuffer() const;
+
+ };
+
+
+ /**
+ * \brief Meta resolve objects
+ *
+ * Implements resolve operations in fragment
+ * shaders when using different formats.
+ */
+ class DxvkMetaResolveObjects {
+
+ public:
+
+ DxvkMetaResolveObjects(const DxvkDevice* device);
+ ~DxvkMetaResolveObjects();
+
+ /**
+ * \brief Creates pipeline for meta copy operation
+ *
+ * \param [in] format Destination image format
+ * \param [in] samples Destination sample count
+ * \param [in] depthResolveMode Depth resolve mode
+ * \param [in] stencilResolveMode Stencil resolve mode
+ * \returns Compatible pipeline for the operation
+ */
+ DxvkMetaResolvePipeline getPipeline(
+ VkFormat format,
+ VkSampleCountFlagBits samples,
+ VkResolveModeFlagBitsKHR depthResolveMode,
+ VkResolveModeFlagBitsKHR stencilResolveMode);
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkSampler m_sampler;
+
+ VkShaderModule m_shaderVert = VK_NULL_HANDLE;
+ VkShaderModule m_shaderGeom = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFragF = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFragU = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFragI = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFragD = VK_NULL_HANDLE;
+ VkShaderModule m_shaderFragDS = VK_NULL_HANDLE;
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkMetaResolvePipelineKey,
+ DxvkMetaResolvePipeline,
+ DxvkHash, DxvkEq> m_pipelines;
+
+ VkSampler createSampler() const;
+
+ VkShaderModule createShaderModule(
+ const SpirvCodeBuffer& code) const;
+
+ DxvkMetaResolvePipeline createPipeline(
+ const DxvkMetaResolvePipelineKey& key);
+
+ VkRenderPass createRenderPass(
+ const DxvkMetaResolvePipelineKey& key);
+
+ VkDescriptorSetLayout createDescriptorSetLayout(
+ const DxvkMetaResolvePipelineKey& key);
+
+ VkPipelineLayout createPipelineLayout(
+ VkDescriptorSetLayout descriptorSetLayout);
+
+ VkPipeline createPipelineObject(
+ const DxvkMetaResolvePipelineKey& key,
+ VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_objects.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_objects.h
new file mode 100644
index 00000000..aaa9e19b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_objects.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "dxvk_gpu_event.h"
+#include "dxvk_gpu_query.h"
+#include "dxvk_memory.h"
+#include "dxvk_meta_blit.h"
+#include "dxvk_meta_clear.h"
+#include "dxvk_meta_copy.h"
+#include "dxvk_meta_mipgen.h"
+#include "dxvk_meta_pack.h"
+#include "dxvk_meta_resolve.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_renderpass.h"
+#include "dxvk_unbound.h"
+
+#include "../util/util_lazy.h"
+
+namespace dxvk {
+
+ class DxvkObjects {
+
+ public:
+
+ DxvkObjects(DxvkDevice* device)
+ : m_device (device),
+ m_memoryManager (device),
+ m_renderPassPool (device),
+ m_pipelineManager (device, &m_renderPassPool),
+ m_eventPool (device),
+ m_queryPool (device),
+ m_dummyResources (device) {
+
+ }
+
+ DxvkMemoryAllocator& memoryManager() {
+ return m_memoryManager;
+ }
+
+ DxvkRenderPassPool& renderPassPool() {
+ return m_renderPassPool;
+ }
+
+ DxvkPipelineManager& pipelineManager() {
+ return m_pipelineManager;
+ }
+
+ DxvkGpuEventPool& eventPool() {
+ return m_eventPool;
+ }
+
+ DxvkGpuQueryPool& queryPool() {
+ return m_queryPool;
+ }
+
+ DxvkUnboundResources& dummyResources() {
+ return m_dummyResources;
+ }
+
+ DxvkMetaBlitObjects& metaBlit() {
+ return m_metaBlit.get(m_device);
+ }
+
+ DxvkMetaClearObjects& metaClear() {
+ return m_metaClear.get(m_device);
+ }
+
+ DxvkMetaCopyObjects& metaCopy() {
+ return m_metaCopy.get(m_device);
+ }
+
+ DxvkMetaResolveObjects& metaResolve() {
+ return m_metaResolve.get(m_device);
+ }
+
+ DxvkMetaPackObjects& metaPack() {
+ return m_metaPack.get(m_device);
+ }
+
+ private:
+
+ DxvkDevice* m_device;
+
+ DxvkMemoryAllocator m_memoryManager;
+ DxvkRenderPassPool m_renderPassPool;
+ DxvkPipelineManager m_pipelineManager;
+
+ DxvkGpuEventPool m_eventPool;
+ DxvkGpuQueryPool m_queryPool;
+
+ DxvkUnboundResources m_dummyResources;
+
+ Lazy<DxvkMetaBlitObjects> m_metaBlit;
+ Lazy<DxvkMetaClearObjects> m_metaClear;
+ Lazy<DxvkMetaCopyObjects> m_metaCopy;
+ Lazy<DxvkMetaResolveObjects> m_metaResolve;
+ Lazy<DxvkMetaPackObjects> m_metaPack;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.cpp
new file mode 100644
index 00000000..48b0dea9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.cpp
@@ -0,0 +1,327 @@
+#include "dxvk_instance.h"
+#include "dxvk_openvr.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+#include <openvr/openvr.hpp>
+
+using VR_InitInternalProc = vr::IVRSystem* (VR_CALLTYPE *)(vr::EVRInitError*, vr::EVRApplicationType);
+using VR_ShutdownInternalProc = void (VR_CALLTYPE *)();
+using VR_GetGenericInterfaceProc = void* (VR_CALLTYPE *)(const char*, vr::EVRInitError*);
+
+namespace dxvk {
+
+ struct VrFunctions {
+ VR_InitInternalProc initInternal = nullptr;
+ VR_ShutdownInternalProc shutdownInternal = nullptr;
+ VR_GetGenericInterfaceProc getGenericInterface = nullptr;
+ };
+
+ VrFunctions g_vrFunctions;
+ VrInstance VrInstance::s_instance;
+
+ VrInstance:: VrInstance() {
+ m_no_vr = env::getEnvVar("DXVK_NO_VR") == "1";
+ }
+ VrInstance::~VrInstance() { }
+
+
+ std::string_view VrInstance::getName() {
+ return "OpenVR";
+ }
+
+
+ DxvkNameSet VrInstance::getInstanceExtensions() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ return m_insExtensions;
+ }
+
+
+ DxvkNameSet VrInstance::getDeviceExtensions(uint32_t adapterId) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (adapterId < m_devExtensions.size())
+ return m_devExtensions[adapterId];
+
+ return DxvkNameSet();
+ }
+
+
+ void VrInstance::initInstanceExtensions() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_no_vr || m_initializedDevExt)
+ return;
+
+ if (!m_vr_key)
+ {
+ LSTATUS status;
+
+ if ((status = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\VR", 0, KEY_READ, &m_vr_key)))
+ Logger::info(str::format("OpenVR: could not open registry key, status ", status));
+ }
+
+ if (!m_vr_key && !m_compositor)
+ m_compositor = this->getCompositor();
+
+ if (!m_vr_key && !m_compositor)
+ return;
+
+ m_insExtensions = this->queryInstanceExtensions();
+ m_initializedInsExt = true;
+ }
+
+
+ void VrInstance::initDeviceExtensions(const DxvkInstance* instance) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_no_vr || (!m_vr_key && !m_compositor) || m_initializedDevExt)
+ return;
+
+ for (uint32_t i = 0; instance->enumAdapters(i) != nullptr; i++) {
+ m_devExtensions.push_back(this->queryDeviceExtensions(
+ instance->enumAdapters(i)));
+ }
+
+ m_initializedDevExt = true;
+ this->shutdown();
+ }
+
+ bool VrInstance::waitVrKeyReady() const {
+ DWORD type, value, wait_status, size;
+ LSTATUS status;
+ HANDLE event;
+
+ size = sizeof(value);
+ if ((status = RegQueryValueExA(m_vr_key, "state", nullptr, &type, reinterpret_cast<BYTE*>(&value), &size)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ return false;
+ }
+ if (type != REG_DWORD)
+ {
+ Logger::err(str::format("OpenVR: unexpected value type ", type));
+ return false;
+ }
+
+ if (value)
+ return value == 1;
+
+ event = CreateEventA(nullptr, FALSE, FALSE, nullptr);
+ while (1)
+ {
+ if (RegNotifyChangeKeyValue(m_vr_key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, event, TRUE))
+ {
+ Logger::err("Error registering registry change notification");
+ goto done;
+ }
+ size = sizeof(value);
+ if ((status = RegQueryValueExA(m_vr_key, "state", nullptr, &type, reinterpret_cast<BYTE*>(&value), &size)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ goto done;
+ }
+ if (value)
+ break;
+ while ((wait_status = WaitForSingleObject(event, 1000)) == WAIT_TIMEOUT)
+ Logger::warn("VR state wait timeout (retrying)");
+
+ if (wait_status != WAIT_OBJECT_0)
+ {
+ Logger::err(str::format("Got unexpected wait status ", wait_status));
+ break;
+ }
+ }
+
+ done:
+ CloseHandle(event);
+ return value == 1;
+ }
+
+ DxvkNameSet VrInstance::queryInstanceExtensions() const {
+ std::vector<char> extensionList;
+ DWORD len;
+
+ if (m_vr_key)
+ {
+ LSTATUS status;
+ DWORD type;
+
+ if (!this->waitVrKeyReady())
+ return DxvkNameSet();
+
+ len = 0;
+ if ((status = RegQueryValueExA(m_vr_key, "openvr_vulkan_instance_extensions", nullptr, &type, nullptr, &len)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ return DxvkNameSet();
+ }
+ extensionList.resize(len);
+ if ((status = RegQueryValueExA(m_vr_key, "openvr_vulkan_instance_extensions", nullptr, &type, reinterpret_cast<BYTE*>(extensionList.data()), &len)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ return DxvkNameSet();
+ }
+ }
+ else
+ {
+ len = m_compositor->GetVulkanInstanceExtensionsRequired(nullptr, 0);
+ extensionList.resize(len);
+ len = m_compositor->GetVulkanInstanceExtensionsRequired(extensionList.data(), len);
+ }
+ return parseExtensionList(std::string(extensionList.data(), len));
+ }
+
+
+ DxvkNameSet VrInstance::queryDeviceExtensions(Rc<DxvkAdapter> adapter) const {
+ std::vector<char> extensionList;
+ DWORD len;
+
+ if (m_vr_key)
+ {
+ LSTATUS status;
+ char name[256];
+ DWORD type;
+
+ if (!this->waitVrKeyReady())
+ return DxvkNameSet();
+
+ sprintf(name, "PCIID:%04x:%04x", adapter->deviceProperties().vendorID, adapter->deviceProperties().deviceID);
+ len = 0;
+ if ((status = RegQueryValueExA(m_vr_key, name, nullptr, &type, nullptr, &len)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ return DxvkNameSet();
+ }
+ extensionList.resize(len);
+ if ((status = RegQueryValueExA(m_vr_key, name, nullptr, &type, reinterpret_cast<BYTE*>(extensionList.data()), &len)))
+ {
+ Logger::err(str::format("OpenVR: could not query value, status ", status));
+ return DxvkNameSet();
+ }
+ }
+ else
+ {
+ len = m_compositor->GetVulkanDeviceExtensionsRequired(adapter->handle(), nullptr, 0);
+ extensionList.resize(len);
+ len = m_compositor->GetVulkanDeviceExtensionsRequired(adapter->handle(), extensionList.data(), len);
+ }
+ return parseExtensionList(std::string(extensionList.data(), len));
+ }
+
+
+ DxvkNameSet VrInstance::parseExtensionList(const std::string& str) const {
+ DxvkNameSet result;
+
+ std::stringstream strstream(str);
+ std::string section;
+
+ while (std::getline(strstream, section, ' '))
+ result.add(section.c_str());
+
+ return result;
+ }
+
+
+ vr::IVRCompositor* VrInstance::getCompositor() {
+ // Skip OpenVR initialization if requested
+
+ // Locate the OpenVR DLL if loaded by the process. Some
+ // applications may not have OpenVR loaded at the time
+ // they create the DXGI instance, so we try our own DLL.
+ m_ovrApi = this->loadLibrary();
+
+ if (!m_ovrApi) {
+ Logger::info("OpenVR: Failed to locate module");
+ return nullptr;
+ }
+
+ // Load method used to retrieve the IVRCompositor interface
+ g_vrFunctions.initInternal = reinterpret_cast<VR_InitInternalProc> (this->getSym("VR_InitInternal"));
+ g_vrFunctions.shutdownInternal = reinterpret_cast<VR_ShutdownInternalProc> (this->getSym("VR_ShutdownInternal"));
+ g_vrFunctions.getGenericInterface = reinterpret_cast<VR_GetGenericInterfaceProc>(this->getSym("VR_GetGenericInterface"));
+
+ if (!g_vrFunctions.getGenericInterface) {
+ Logger::warn("OpenVR: VR_GetGenericInterface not found");
+ return nullptr;
+ }
+
+ // Retrieve the compositor interface
+ vr::EVRInitError error = vr::VRInitError_None;
+
+ vr::IVRCompositor* compositor = reinterpret_cast<vr::IVRCompositor*>(
+ g_vrFunctions.getGenericInterface(vr::IVRCompositor_Version, &error));
+
+ if (error != vr::VRInitError_None || !compositor) {
+ if (!g_vrFunctions.initInternal
+ || !g_vrFunctions.shutdownInternal) {
+ Logger::warn("OpenVR: VR_InitInternal or VR_ShutdownInternal not found");
+ return nullptr;
+ }
+
+ // If the app has not initialized OpenVR yet, we need
+ // to do it now in order to grab a compositor instance
+ g_vrFunctions.initInternal(&error, vr::VRApplication_Background);
+ m_initializedOpenVr = error == vr::VRInitError_None;
+
+ if (error != vr::VRInitError_None) {
+ Logger::warn("OpenVR: Failed to initialize OpenVR");
+ return nullptr;
+ }
+
+ compositor = reinterpret_cast<vr::IVRCompositor*>(
+ g_vrFunctions.getGenericInterface(vr::IVRCompositor_Version, &error));
+
+ if (error != vr::VRInitError_None || !compositor) {
+ Logger::warn("OpenVR: Failed to query compositor interface");
+ this->shutdown();
+ return nullptr;
+ }
+ }
+
+ Logger::info("OpenVR: Compositor interface found");
+ return compositor;
+ }
+
+
+ void VrInstance::shutdown() {
+ if (m_vr_key)
+ {
+ RegCloseKey(m_vr_key);
+ m_vr_key = nullptr;
+ }
+
+ if (m_initializedOpenVr)
+ g_vrFunctions.shutdownInternal();
+
+ if (m_loadedOvrApi)
+ this->freeLibrary();
+
+ m_initializedOpenVr = false;
+ m_loadedOvrApi = false;
+ }
+
+
+ HMODULE VrInstance::loadLibrary() {
+ HMODULE handle = nullptr;
+ if (!(handle = ::GetModuleHandle("openvr_api.dll"))) {
+ handle = ::LoadLibrary("openvr_api_dxvk.dll");
+ m_loadedOvrApi = handle != nullptr;
+ }
+ return handle;
+ }
+
+
+ void VrInstance::freeLibrary() {
+ ::FreeLibrary(m_ovrApi);
+ }
+
+
+ void* VrInstance::getSym(const char* sym) {
+ return reinterpret_cast<void*>(
+ ::GetProcAddress(m_ovrApi, sym));
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.h
new file mode 100644
index 00000000..a7d1042c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openvr.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include "dxvk_extension_provider.h"
+
+namespace vr {
+ class IVRCompositor;
+ class IVRSystem;
+}
+
+namespace dxvk {
+
+ class DxvkInstance;
+
+ /**
+ * \brief OpenVR instance
+ *
+ * Loads Initializes OpenVR to provide
+ * access to Vulkan extension queries.
+ */
+ class VrInstance : public DxvkExtensionProvider {
+
+ public:
+
+ VrInstance();
+ ~VrInstance();
+
+ std::string_view getName();
+
+ DxvkNameSet getInstanceExtensions();
+
+ DxvkNameSet getDeviceExtensions(
+ uint32_t adapterId);
+
+ void initInstanceExtensions();
+
+ void initDeviceExtensions(
+ const DxvkInstance* instance);
+
+ static VrInstance s_instance;
+
+ private:
+
+ dxvk::mutex m_mutex;
+ HKEY m_vr_key = nullptr;
+ vr::IVRCompositor* m_compositor = nullptr;
+ HMODULE m_ovrApi = nullptr;
+
+ bool m_no_vr;
+ bool m_loadedOvrApi = false;
+ bool m_initializedOpenVr = false;
+ bool m_initializedInsExt = false;
+ bool m_initializedDevExt = false;
+
+ DxvkNameSet m_insExtensions;
+ std::vector<DxvkNameSet> m_devExtensions;
+
+ DxvkNameSet queryInstanceExtensions() const;
+
+ DxvkNameSet queryDeviceExtensions(
+ Rc<DxvkAdapter> adapter) const;
+
+ DxvkNameSet parseExtensionList(
+ const std::string& str) const;
+
+ vr::IVRCompositor* getCompositor();
+
+ void shutdown();
+
+ HMODULE loadLibrary();
+
+ void freeLibrary();
+
+ void* getSym(const char* sym);
+
+ bool waitVrKeyReady() const;
+ };
+
+ extern VrInstance g_vrInstance;
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.cpp
new file mode 100644
index 00000000..98f2dd9a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.cpp
@@ -0,0 +1,168 @@
+#include "dxvk_instance.h"
+#include "dxvk_openxr.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+using PFN___wineopenxr_GetVulkanInstanceExtensions = int (WINAPI *)(uint32_t, uint32_t *, char *);
+using PFN___wineopenxr_GetVulkanDeviceExtensions = int (WINAPI *)(uint32_t, uint32_t *, char *);
+
+namespace dxvk {
+
+ struct WineXrFunctions {
+ PFN___wineopenxr_GetVulkanInstanceExtensions __wineopenxr_GetVulkanInstanceExtensions = nullptr;
+ PFN___wineopenxr_GetVulkanDeviceExtensions __wineopenxr_GetVulkanDeviceExtensions = nullptr;
+ };
+
+ WineXrFunctions g_winexrFunctions;
+ DxvkXrProvider DxvkXrProvider::s_instance;
+
+ DxvkXrProvider:: DxvkXrProvider() { }
+
+ DxvkXrProvider::~DxvkXrProvider() { }
+
+
+ std::string_view DxvkXrProvider::getName() {
+ return "OpenXR";
+ }
+
+
+ DxvkNameSet DxvkXrProvider::getInstanceExtensions() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ return m_insExtensions;
+ }
+
+
+ DxvkNameSet DxvkXrProvider::getDeviceExtensions(uint32_t adapterId) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+ return m_devExtensions;
+ }
+
+
+ void DxvkXrProvider::initInstanceExtensions() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (!m_wineOxr)
+ m_wineOxr = this->loadLibrary();
+
+ if (!m_wineOxr || m_initializedInsExt)
+ return;
+
+ if (!this->loadFunctions()) {
+ this->shutdown();
+ return;
+ }
+
+ m_insExtensions = this->queryInstanceExtensions();
+ m_initializedInsExt = true;
+ }
+
+
+ bool DxvkXrProvider::loadFunctions() {
+ g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions =
+ reinterpret_cast<PFN___wineopenxr_GetVulkanInstanceExtensions>(this->getSym("__wineopenxr_GetVulkanInstanceExtensions"));
+ g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions =
+ reinterpret_cast<PFN___wineopenxr_GetVulkanDeviceExtensions>(this->getSym("__wineopenxr_GetVulkanDeviceExtensions"));
+ return g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions != nullptr
+ && g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions != nullptr;
+ }
+
+
+ void DxvkXrProvider::initDeviceExtensions(const DxvkInstance* instance) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (!m_wineOxr || m_initializedDevExt)
+ return;
+
+ m_devExtensions = this->queryDeviceExtensions();
+ m_initializedDevExt = true;
+
+ this->shutdown();
+ }
+
+
+ DxvkNameSet DxvkXrProvider::queryInstanceExtensions() const {
+ int res;
+ uint32_t len;
+
+ res = g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions(0, &len, nullptr);
+ if (res != 0) {
+ Logger::warn("OpenXR: Unable to get required Vulkan instance extensions size");
+ return DxvkNameSet();
+ }
+
+ std::vector<char> extensionList(len);
+ res = g_winexrFunctions.__wineopenxr_GetVulkanInstanceExtensions(len, &len, &extensionList[0]);
+ if (res != 0) {
+ Logger::warn("OpenXR: Unable to get required Vulkan instance extensions");
+ return DxvkNameSet();
+ }
+
+ return parseExtensionList(std::string(extensionList.data(), len));
+ }
+
+
+ DxvkNameSet DxvkXrProvider::queryDeviceExtensions() const {
+ int res;
+
+ uint32_t len;
+ res = g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions(0, &len, nullptr);
+ if (res != 0) {
+ Logger::warn("OpenXR: Unable to get required Vulkan Device extensions size");
+ return DxvkNameSet();
+ }
+
+ std::vector<char> extensionList(len);
+ res = g_winexrFunctions.__wineopenxr_GetVulkanDeviceExtensions(len, &len, &extensionList[0]);
+ if (res != 0) {
+ Logger::warn("OpenXR: Unable to get required Vulkan Device extensions");
+ return DxvkNameSet();
+ }
+
+ return parseExtensionList(std::string(extensionList.data(), len));
+ }
+
+
+ DxvkNameSet DxvkXrProvider::parseExtensionList(const std::string& str) const {
+ DxvkNameSet result;
+
+ std::stringstream strstream(str);
+ std::string section;
+
+ while (std::getline(strstream, section, ' '))
+ result.add(section.c_str());
+
+ return result;
+ }
+
+
+ void DxvkXrProvider::shutdown() {
+ if (m_loadedOxrApi)
+ this->freeLibrary();
+
+ m_loadedOxrApi = false;
+ m_wineOxr = nullptr;
+ }
+
+
+ HMODULE DxvkXrProvider::loadLibrary() {
+ HMODULE handle = nullptr;
+ if (!(handle = ::GetModuleHandle("wineopenxr.dll"))) {
+ handle = ::LoadLibrary("wineopenxr.dll");
+ m_loadedOxrApi = handle != nullptr;
+ }
+ return handle;
+ }
+
+
+ void DxvkXrProvider::freeLibrary() {
+ ::FreeLibrary(m_wineOxr);
+ }
+
+
+ void* DxvkXrProvider::getSym(const char* sym) {
+ return reinterpret_cast<void*>(
+ ::GetProcAddress(m_wineOxr, sym));
+ }
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.h
new file mode 100644
index 00000000..a3680350
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_openxr.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include "dxvk_extension_provider.h"
+
+namespace dxvk {
+
+ class DxvkInstance;
+
+ /**
+ * \brief OpenXR instance
+ *
+ * Loads OpenXR to provide access to Vulkan extension queries.
+ */
+ class DxvkXrProvider : public DxvkExtensionProvider {
+
+ public:
+
+ DxvkXrProvider();
+ ~DxvkXrProvider();
+
+ std::string_view getName();
+
+ DxvkNameSet getInstanceExtensions();
+
+ DxvkNameSet getDeviceExtensions(
+ uint32_t adapterId);
+
+ void initInstanceExtensions();
+
+ void initDeviceExtensions(
+ const DxvkInstance* instance);
+
+ static DxvkXrProvider s_instance;
+
+ private:
+
+ dxvk::mutex m_mutex;
+ HMODULE m_wineOxr = nullptr;
+
+ bool m_loadedOxrApi = false;
+ bool m_initializedInsExt = false;
+ bool m_initializedDevExt = false;
+
+ DxvkNameSet m_insExtensions;
+ DxvkNameSet m_devExtensions;
+
+ DxvkNameSet queryInstanceExtensions() const;
+
+ DxvkNameSet queryDeviceExtensions() const;
+
+ DxvkNameSet parseExtensionList(
+ const std::string& str) const;
+
+ bool loadFunctions();
+
+ void shutdown();
+
+ HMODULE loadLibrary();
+
+ void freeLibrary();
+
+ void* getSym(const char* sym);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.cpp
new file mode 100644
index 00000000..8b62af16
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.cpp
@@ -0,0 +1,15 @@
+#include "dxvk_options.h"
+
+namespace dxvk {
+
+ DxvkOptions::DxvkOptions(const Config& config) {
+ enableStateCache = config.getOption<bool> ("dxvk.enableStateCache", true);
+ enableOpenVR = config.getOption<bool> ("dxvk.enableOpenVR", true);
+ enableOpenXR = config.getOption<bool> ("dxvk.enableOpenXR", true);
+ numCompilerThreads = config.getOption<int32_t> ("dxvk.numCompilerThreads", 0);
+ useRawSsbo = config.getOption<Tristate>("dxvk.useRawSsbo", Tristate::Auto);
+ halveNvidiaHVVHeap = config.getOption<Tristate>("dxvk.halveNvidiaHVVHeap", Tristate::Auto);
+ hud = config.getOption<std::string>("dxvk.hud", "");
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.h
new file mode 100644
index 00000000..343cba0a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_options.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "../util/config/config.h"
+
+namespace dxvk {
+
+ struct DxvkOptions {
+ DxvkOptions() { }
+ DxvkOptions(const Config& config);
+
+ /// Enable state cache
+ bool enableStateCache;
+
+ /// Enables OpenVR loading
+ bool enableOpenVR;
+
+ /// Enables OpenXR loading
+ bool enableOpenXR;
+
+ /// Number of compiler threads
+ /// when using the state cache
+ int32_t numCompilerThreads;
+
+ /// Shader-related options
+ Tristate useRawSsbo;
+
+ /// Workaround for NVIDIA driver
+ /// bug 3114283. Cut usable HVV
+ /// (Host-Visible Vidmem) heap
+ /// in half to avoid crash
+ Tristate halveNvidiaHVVHeap;
+
+ /// HUD elements
+ std::string hud;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.cpp
new file mode 100644
index 00000000..0ea775bc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.cpp
@@ -0,0 +1,26 @@
+#include "dxvk_pipecache.h"
+
+namespace dxvk {
+
+ DxvkPipelineCache::DxvkPipelineCache(
+ const Rc<vk::DeviceFn>& vkd)
+ : m_vkd(vkd) {
+ VkPipelineCacheCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.initialDataSize = 0;
+ info.pInitialData = nullptr;
+
+ if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
+ &info, nullptr, &m_handle) != VK_SUCCESS)
+ throw DxvkError("DxvkPipelineCache: Failed to create cache");
+ }
+
+
+ DxvkPipelineCache::~DxvkPipelineCache() {
+ m_vkd->vkDestroyPipelineCache(
+ m_vkd->device(), m_handle, nullptr);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.h
new file mode 100644
index 00000000..b39bf47c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipecache.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <fstream>
+
+#include "dxvk_include.h"
+
+#include "../util/sha1/sha1_util.h"
+#include "../util/util_env.h"
+#include "../util/util_time.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Pipeline cache
+ *
+ * Allows the Vulkan implementation to
+ * re-use previously compiled pipelines.
+ */
+ class DxvkPipelineCache : public RcObject {
+
+ public:
+
+ DxvkPipelineCache(const Rc<vk::DeviceFn>& vkd);
+ ~DxvkPipelineCache();
+
+ /**
+ * \brief Pipeline cache handle
+ * \returns Pipeline cache handle
+ */
+ VkPipelineCache handle() const {
+ return m_handle;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ VkPipelineCache m_handle;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.cpp
new file mode 100644
index 00000000..72b319a1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.cpp
@@ -0,0 +1,197 @@
+#include <cstring>
+
+#include "dxvk_descriptor.h"
+#include "dxvk_limits.h"
+#include "dxvk_pipelayout.h"
+
+namespace dxvk {
+
+ DxvkDescriptorSlotMapping:: DxvkDescriptorSlotMapping() { }
+ DxvkDescriptorSlotMapping::~DxvkDescriptorSlotMapping() { }
+
+
+ void DxvkDescriptorSlotMapping::defineSlot(
+ VkShaderStageFlagBits stage,
+ const DxvkResourceSlot& desc) {
+ uint32_t bindingId = this->getBindingId(desc.slot);
+
+ if (bindingId != InvalidBinding) {
+ m_descriptorSlots[bindingId].stages |= stage;
+ m_descriptorSlots[bindingId].access |= desc.access;
+ } else {
+ DxvkDescriptorSlot slotInfo;
+ slotInfo.slot = desc.slot;
+ slotInfo.type = desc.type;
+ slotInfo.view = desc.view;
+ slotInfo.stages = stage;
+ slotInfo.access = desc.access;
+ m_descriptorSlots.push_back(slotInfo);
+ }
+ }
+
+
+ void DxvkDescriptorSlotMapping::definePushConstRange(
+ VkShaderStageFlagBits stage,
+ uint32_t offset,
+ uint32_t size) {
+ m_pushConstRange.stageFlags |= stage;
+ m_pushConstRange.size = std::max(
+ m_pushConstRange.size, offset + size);
+ }
+
+
+ uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) const {
+ // This won't win a performance competition, but the number
+ // of bindings used by a shader is usually much smaller than
+ // the number of resource slots available to the system.
+ for (uint32_t i = 0; i < m_descriptorSlots.size(); i++) {
+ if (m_descriptorSlots[i].slot == slot)
+ return i;
+ }
+
+ return InvalidBinding;
+ }
+
+
+ void DxvkDescriptorSlotMapping::makeDescriptorsDynamic(
+ uint32_t uniformBuffers,
+ uint32_t storageBuffers) {
+ if (this->countDescriptors(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) <= uniformBuffers)
+ this->replaceDescriptors(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
+ }
+
+
+ uint32_t DxvkDescriptorSlotMapping::countDescriptors(
+ VkDescriptorType type) const {
+ uint32_t count = 0;
+
+ for (const auto& slot : m_descriptorSlots)
+ count += slot.type == type ? 1 : 0;
+
+ return count;
+ }
+
+
+ void DxvkDescriptorSlotMapping::replaceDescriptors(
+ VkDescriptorType oldType,
+ VkDescriptorType newType) {
+ for (auto& slot : m_descriptorSlots) {
+ if (slot.type == oldType)
+ slot.type = newType;
+ }
+ }
+
+
+ DxvkPipelineLayout::DxvkPipelineLayout(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDescriptorSlotMapping& slotMapping,
+ VkPipelineBindPoint pipelineBindPoint)
+ : m_vkd (vkd),
+ m_pushConstRange(slotMapping.pushConstRange()),
+ m_bindingSlots (slotMapping.bindingCount()) {
+
+ auto bindingCount = slotMapping.bindingCount();
+ auto bindingInfos = slotMapping.bindingInfos();
+
+ if (bindingCount > MaxNumActiveBindings)
+ throw DxvkError(str::format("Too many active bindings in pipeline layout (", bindingCount, ")"));
+
+ for (uint32_t i = 0; i < bindingCount; i++)
+ m_bindingSlots[i] = bindingInfos[i];
+
+ std::vector<VkDescriptorSetLayoutBinding> bindings(bindingCount);
+ std::vector<VkDescriptorUpdateTemplateEntry> tEntries(bindingCount);
+
+ for (uint32_t i = 0; i < bindingCount; i++) {
+ bindings[i].binding = i;
+ bindings[i].descriptorType = bindingInfos[i].type;
+ bindings[i].descriptorCount = 1;
+ bindings[i].stageFlags = bindingInfos[i].stages;
+ bindings[i].pImmutableSamplers = nullptr;
+
+ tEntries[i].dstBinding = i;
+ tEntries[i].dstArrayElement = 0;
+ tEntries[i].descriptorCount = 1;
+ tEntries[i].descriptorType = bindingInfos[i].type;
+ tEntries[i].offset = sizeof(DxvkDescriptorInfo) * i;
+ tEntries[i].stride = 0;
+
+ if (bindingInfos[i].type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
+ m_dynamicSlots.push_back(i);
+
+ m_descriptorTypes.set(bindingInfos[i].type);
+ }
+
+ // Create descriptor set layout. We do not need to
+ // create one if there are no active resource bindings.
+ if (bindingCount > 0) {
+ VkDescriptorSetLayoutCreateInfo dsetInfo;
+ dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ dsetInfo.pNext = nullptr;
+ dsetInfo.flags = 0;
+ dsetInfo.bindingCount = bindings.size();
+ dsetInfo.pBindings = bindings.data();
+
+ if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(),
+ &dsetInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS)
+ throw DxvkError("DxvkPipelineLayout: Failed to create descriptor set layout");
+ }
+
+ // Create pipeline layout with the given descriptor set layout
+ VkPipelineLayoutCreateInfo pipeInfo;
+ pipeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipeInfo.pNext = nullptr;
+ pipeInfo.flags = 0;
+ pipeInfo.setLayoutCount = bindingCount > 0 ? 1 : 0;
+ pipeInfo.pSetLayouts = &m_descriptorSetLayout;
+ pipeInfo.pushConstantRangeCount = 0;
+ pipeInfo.pPushConstantRanges = nullptr;
+
+ if (m_pushConstRange.size) {
+ pipeInfo.pushConstantRangeCount = 1;
+ pipeInfo.pPushConstantRanges = &m_pushConstRange;
+ }
+
+ if (m_vkd->vkCreatePipelineLayout(m_vkd->device(),
+ &pipeInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr);
+ throw DxvkError("DxvkPipelineLayout: Failed to create pipeline layout");
+ }
+
+ // Create descriptor update template. If there are no active
+ // resource bindings, there won't be any descriptors to update.
+ if (bindingCount > 0) {
+ VkDescriptorUpdateTemplateCreateInfo templateInfo;
+ templateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO;
+ templateInfo.pNext = nullptr;
+ templateInfo.flags = 0;
+ templateInfo.descriptorUpdateEntryCount = tEntries.size();
+ templateInfo.pDescriptorUpdateEntries = tEntries.data();
+ templateInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
+ templateInfo.descriptorSetLayout = m_descriptorSetLayout;
+ templateInfo.pipelineBindPoint = pipelineBindPoint;
+ templateInfo.pipelineLayout = m_pipelineLayout;
+ templateInfo.set = 0;
+
+ if (m_vkd->vkCreateDescriptorUpdateTemplate(
+ m_vkd->device(), &templateInfo, nullptr, &m_descriptorTemplate) != VK_SUCCESS) {
+ m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr);
+ m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipelineLayout, nullptr);
+ throw DxvkError("DxvkPipelineLayout: Failed to create descriptor update template");
+ }
+ }
+ }
+
+
+ DxvkPipelineLayout::~DxvkPipelineLayout() {
+ m_vkd->vkDestroyDescriptorUpdateTemplate(
+ m_vkd->device(), m_descriptorTemplate, nullptr);
+
+ m_vkd->vkDestroyPipelineLayout(
+ m_vkd->device(), m_pipelineLayout, nullptr);
+
+ m_vkd->vkDestroyDescriptorSetLayout(
+ m_vkd->device(), m_descriptorSetLayout, nullptr);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.h
new file mode 100644
index 00000000..9e96b34b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipelayout.h
@@ -0,0 +1,281 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Resource slot
+ *
+ * Describes the type of a single resource
+ * binding that a shader can access.
+ */
+ struct DxvkResourceSlot {
+ uint32_t slot;
+ VkDescriptorType type;
+ VkImageViewType view;
+ VkAccessFlags access;
+ };
+
+ /**
+ * \brief Shader interface binding
+ *
+ * Corresponds to a single descriptor binding in
+ * Vulkan. DXVK does not use descriptor arrays.
+ * Instead, each binding stores one descriptor.
+ */
+ struct DxvkDescriptorSlot {
+ uint32_t slot; ///< Resource slot index for the context
+ VkDescriptorType type; ///< Descriptor type (aka resource type)
+ VkImageViewType view; ///< Compatible image view type
+ VkShaderStageFlags stages; ///< Stages that can use the resource
+ VkAccessFlags access; ///< Access flags
+ };
+
+
+ /**
+ * \brief Descriptor slot mapping
+ *
+ * Convenience class that generates descriptor slot
+ * index to binding index mappings. This is required
+ * when generating Vulkan pipeline and descriptor set
+ * layouts.
+ */
+ class DxvkDescriptorSlotMapping {
+ constexpr static uint32_t InvalidBinding = 0xFFFFFFFFu;
+ public:
+
+ DxvkDescriptorSlotMapping();
+ ~DxvkDescriptorSlotMapping();
+
+ /**
+ * \brief Number of descriptor bindings
+ * \returns Descriptor binding count
+ */
+ uint32_t bindingCount() const {
+ return m_descriptorSlots.size();
+ }
+
+ /**
+ * \brief Descriptor binding infos
+ * \returns Descriptor binding infos
+ */
+ const DxvkDescriptorSlot* bindingInfos() const {
+ return m_descriptorSlots.data();
+ }
+
+ /**
+ * \brief Push constant range
+ * \returns Push constant range
+ */
+ VkPushConstantRange pushConstRange() const {
+ return m_pushConstRange;
+ }
+
+ /**
+ * \brief Defines a new slot
+ *
+ * Adds a slot to the mapping. If the slot is already
+ * defined by another shader stage, this will extend
+ * the stage mask by the given stage. Otherwise, an
+ * entirely new binding is added.
+ * \param [in] stage Shader stage
+ * \param [in] desc Slot description
+ */
+ void defineSlot(
+ VkShaderStageFlagBits stage,
+ const DxvkResourceSlot& desc);
+
+ /**
+ * \brief Defines new push constant range
+ *
+ * \param [in] stage Shader stage
+ * \param [in] offset Range offset
+ * \param [in] size Range size
+ */
+ void definePushConstRange(
+ VkShaderStageFlagBits stage,
+ uint32_t offset,
+ uint32_t size);
+
+ /**
+ * \brief Gets binding ID for a slot
+ *
+ * \param [in] slot Resource slot
+ * \returns Binding index, or \c InvalidBinding
+ */
+ uint32_t getBindingId(
+ uint32_t slot) const;
+
+ /**
+ * \brief Makes static descriptors dynamic
+ *
+ * Replaces static uniform and storage buffer bindings by
+ * their dynamic equivalent if the number of bindings of
+ * the respective type lies within supported device limits.
+ * Using dynamic descriptor types may improve performance.
+ * \param [in] uniformBuffers Max number of uniform buffers
+ * \param [in] storageBuffers Max number of storage buffers
+ */
+ void makeDescriptorsDynamic(
+ uint32_t uniformBuffers,
+ uint32_t storageBuffers);
+
+ private:
+
+ std::vector<DxvkDescriptorSlot> m_descriptorSlots;
+ VkPushConstantRange m_pushConstRange = { };
+
+ uint32_t countDescriptors(
+ VkDescriptorType type) const;
+
+ void replaceDescriptors(
+ VkDescriptorType oldType,
+ VkDescriptorType newType);
+
+ };
+
+
+ /**
+ * \brief Shader interface
+ *
+ * Describes shader resource bindings
+ * for a graphics or compute pipeline.
+ */
+ class DxvkPipelineLayout : public RcObject {
+
+ public:
+
+ DxvkPipelineLayout(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDescriptorSlotMapping& slotMapping,
+ VkPipelineBindPoint pipelineBindPoint);
+
+ ~DxvkPipelineLayout();
+
+ /**
+ * \brief Number of resource bindings
+ * \returns Resource binding count
+ */
+ uint32_t bindingCount() const {
+ return m_bindingSlots.size();
+ }
+
+ /**
+ * \brief Resource binding info
+ *
+ * \param [in] id Binding index
+ * \returns Resource binding info
+ */
+ const DxvkDescriptorSlot& binding(uint32_t id) const {
+ return m_bindingSlots[id];
+ }
+
+ /**
+ * \brief Resource binding info
+ * \returns Resource binding info
+ */
+ const DxvkDescriptorSlot* bindings() const {
+ return m_bindingSlots.data();
+ }
+
+ /**
+ * \brief Push constant range
+ * \returns Push constant range
+ */
+ const VkPushConstantRange& pushConstRange() const {
+ return m_pushConstRange;
+ }
+
+ /**
+ * \brief Descriptor set layout handle
+ * \returns Descriptor set layout handle
+ */
+ VkDescriptorSetLayout descriptorSetLayout() const {
+ return m_descriptorSetLayout;
+ }
+
+ /**
+ * \brief Pipeline layout handle
+ * \returns Pipeline layout handle
+ */
+ VkPipelineLayout pipelineLayout() const {
+ return m_pipelineLayout;
+ }
+
+ /**
+ * \brief Descriptor update template
+ * \returns Descriptor update template
+ */
+ VkDescriptorUpdateTemplateKHR descriptorTemplate() const {
+ return m_descriptorTemplate;
+ }
+
+ /**
+ * \brief Number of dynamic bindings
+ * \returns Dynamic binding count
+ */
+ uint32_t dynamicBindingCount() const {
+ return m_dynamicSlots.size();
+ }
+
+ /**
+ * \brief Returns a dynamic binding
+ *
+ * \param [in] id Dynamic binding ID
+ * \returns Reference to that binding
+ */
+ const DxvkDescriptorSlot& dynamicBinding(uint32_t id) const {
+ return this->binding(m_dynamicSlots[id]);
+ }
+
+ /**
+ * \brief Checks for static buffer bindings
+ *
+ * Returns \c true if there is at least one
+ * descriptor of the static uniform buffer
+ * type.
+ */
+ bool hasStaticBufferBindings() const {
+ return m_descriptorTypes.test(
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
+ }
+
+ /**
+ * \brief Checks whether buffers or images are written to
+ *
+ * It is assumed that storage images and buffers
+ * will be written to if they are present. Used
+ * for synchronization purposes.
+ * \param [in] stages Shader stages to check
+ */
+ VkShaderStageFlags getStorageDescriptorStages() const {
+ VkShaderStageFlags stages = 0;
+
+ for (const auto& slot : m_bindingSlots) {
+ if (slot.access & VK_ACCESS_SHADER_WRITE_BIT)
+ stages |= slot.stages;
+ }
+
+ return stages;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+
+ VkPushConstantRange m_pushConstRange = { };
+ VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ VkDescriptorUpdateTemplateKHR m_descriptorTemplate = VK_NULL_HANDLE;
+
+ std::vector<DxvkDescriptorSlot> m_bindingSlots;
+ std::vector<uint32_t> m_dynamicSlots;
+
+ Flags<VkDescriptorType> m_descriptorTypes;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.cpp
new file mode 100644
index 00000000..dc20803d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.cpp
@@ -0,0 +1,90 @@
+#include "dxvk_device.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_state_cache.h"
+
+namespace dxvk {
+
+ DxvkPipelineManager::DxvkPipelineManager(
+ const DxvkDevice* device,
+ DxvkRenderPassPool* passManager)
+ : m_device (device),
+ m_cache (new DxvkPipelineCache(device->vkd())) {
+#ifndef VBOX
+ std::string useStateCache = env::getEnvVar("DXVK_STATE_CACHE");
+
+ if (useStateCache != "0" && device->config().enableStateCache)
+ m_stateCache = new DxvkStateCache(device, this, passManager);
+#endif
+ }
+
+
+ DxvkPipelineManager::~DxvkPipelineManager() {
+
+ }
+
+
+ DxvkComputePipeline* DxvkPipelineManager::createComputePipeline(
+ const DxvkComputePipelineShaders& shaders) {
+ if (shaders.cs == nullptr)
+ return nullptr;
+
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ auto pair = m_computePipelines.find(shaders);
+ if (pair != m_computePipelines.end())
+ return &pair->second;
+
+ auto iter = m_computePipelines.emplace(
+ std::piecewise_construct,
+ std::tuple(shaders),
+ std::tuple(this, shaders));
+ return &iter.first->second;
+ }
+
+
+ DxvkGraphicsPipeline* DxvkPipelineManager::createGraphicsPipeline(
+ const DxvkGraphicsPipelineShaders& shaders) {
+ if (shaders.vs == nullptr)
+ return nullptr;
+
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ auto pair = m_graphicsPipelines.find(shaders);
+ if (pair != m_graphicsPipelines.end())
+ return &pair->second;
+
+ auto iter = m_graphicsPipelines.emplace(
+ std::piecewise_construct,
+ std::tuple(shaders),
+ std::tuple(this, shaders));
+ return &iter.first->second;
+ }
+
+
+ void DxvkPipelineManager::registerShader(
+ const Rc<DxvkShader>& shader) {
+ if (m_stateCache != nullptr)
+ m_stateCache->registerShader(shader);
+ }
+
+
+ DxvkPipelineCount DxvkPipelineManager::getPipelineCount() const {
+ DxvkPipelineCount result;
+ result.numComputePipelines = m_numComputePipelines.load();
+ result.numGraphicsPipelines = m_numGraphicsPipelines.load();
+ return result;
+ }
+
+
+ bool DxvkPipelineManager::isCompilingShaders() const {
+ return m_stateCache != nullptr
+ && m_stateCache->isCompilingShaders();
+ }
+
+
+ void DxvkPipelineManager::stopWorkerThreads() const {
+ if (m_stateCache != nullptr)
+ m_stateCache->stopWorkerThreads();
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.h
new file mode 100644
index 00000000..f32a8913
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_pipemanager.h
@@ -0,0 +1,121 @@
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include "dxvk_compute.h"
+#include "dxvk_graphics.h"
+
+namespace dxvk {
+
+ class DxvkStateCache;
+
+ /**
+ * \brief Pipeline count
+ *
+ * Stores number of graphics and
+ * compute pipelines, individually.
+ */
+ struct DxvkPipelineCount {
+ uint32_t numGraphicsPipelines;
+ uint32_t numComputePipelines;
+ };
+
+
+ /**
+ * \brief Pipeline manager
+ *
+ * Creates and stores graphics pipelines and compute
+ * pipelines for each combination of shaders that is
+ * used within the application. This is necessary
+ * because DXVK does not expose the concept of shader
+ * pipeline objects to the client API.
+ */
+ class DxvkPipelineManager {
+ friend class DxvkComputePipeline;
+ friend class DxvkGraphicsPipeline;
+ public:
+
+ DxvkPipelineManager(
+ const DxvkDevice* device,
+ DxvkRenderPassPool* passManager);
+
+ ~DxvkPipelineManager();
+
+ /**
+ * \brief Retrieves a compute pipeline object
+ *
+ * If a pipeline for the given shader stage object
+ * already exists, it will be returned. Otherwise,
+ * a new pipeline will be created.
+ * \param [in] shaders Shaders for the pipeline
+ * \returns Compute pipeline object
+ */
+ DxvkComputePipeline* createComputePipeline(
+ const DxvkComputePipelineShaders& shaders);
+
+ /**
+ * \brief Retrieves a graphics pipeline object
+ *
+ * If a pipeline for the given shader stage objects
+ * already exists, it will be returned. Otherwise,
+ * a new pipeline will be created.
+ * \param [in] shaders Shaders for the pipeline
+ * \returns Graphics pipeline object
+ */
+ DxvkGraphicsPipeline* createGraphicsPipeline(
+ const DxvkGraphicsPipelineShaders& shaders);
+
+ /*
+ * \brief Registers a shader
+ *
+ * Starts compiling pipelines asynchronously
+ * in case the state cache contains state
+ * vectors for this shader.
+ * \param [in] shader Newly compiled shader
+ */
+ void registerShader(
+ const Rc<DxvkShader>& shader);
+
+ /**
+ * \brief Retrieves total pipeline count
+ * \returns Number of compute/graphics pipelines
+ */
+ DxvkPipelineCount getPipelineCount() const;
+
+ /**
+ * \brief Checks whether async compiler is busy
+ * \returns \c true if shaders are being compiled
+ */
+ bool isCompilingShaders() const;
+
+ /**
+ * \brief Stops async compiler threads
+ */
+ void stopWorkerThreads() const;
+
+ private:
+
+ const DxvkDevice* m_device;
+ Rc<DxvkPipelineCache> m_cache;
+ Rc<DxvkStateCache> m_stateCache;
+
+ std::atomic<uint32_t> m_numComputePipelines = { 0 };
+ std::atomic<uint32_t> m_numGraphicsPipelines = { 0 };
+
+ dxvk::mutex m_mutex;
+
+ std::unordered_map<
+ DxvkComputePipelineShaders,
+ DxvkComputePipeline,
+ DxvkHash, DxvkEq> m_computePipelines;
+
+ std::unordered_map<
+ DxvkGraphicsPipelineShaders,
+ DxvkGraphicsPipeline,
+ DxvkHash, DxvkEq> m_graphicsPipelines;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_platform_exts.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_platform_exts.h
new file mode 100644
index 00000000..f6f03067
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_platform_exts.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "dxvk_extension_provider.h"
+
+namespace dxvk {
+
+ class DxvkPlatformExts : public DxvkExtensionProvider {
+
+ public:
+
+ std::string_view getName();
+
+ DxvkNameSet getInstanceExtensions();
+
+ DxvkNameSet getDeviceExtensions(
+ uint32_t adapterId);
+
+ void initInstanceExtensions();
+
+ void initDeviceExtensions(
+ const DxvkInstance* instance);
+
+ static DxvkPlatformExts s_instance;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.cpp
new file mode 100644
index 00000000..5b383fc3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.cpp
@@ -0,0 +1,187 @@
+#include "dxvk_device.h"
+#include "dxvk_queue.h"
+
+namespace dxvk {
+
+ DxvkSubmissionQueue::DxvkSubmissionQueue(DxvkDevice* device)
+ : m_device(device),
+ m_submitThread([this] () { submitCmdLists(); }),
+ m_finishThread([this] () { finishCmdLists(); }) {
+
+ }
+
+
+ DxvkSubmissionQueue::~DxvkSubmissionQueue() {
+ { std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_stopped.store(true);
+ }
+
+ m_appendCond.notify_all();
+ m_submitCond.notify_all();
+
+ m_submitThread.join();
+ m_finishThread.join();
+ }
+
+
+ void DxvkSubmissionQueue::submit(DxvkSubmitInfo submitInfo) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ m_finishCond.wait(lock, [this] {
+ return m_submitQueue.size() + m_finishQueue.size() <= MaxNumQueuedCommandBuffers;
+ });
+
+ DxvkSubmitEntry entry = { };
+ entry.submit = std::move(submitInfo);
+
+ m_pending += 1;
+ m_submitQueue.push(std::move(entry));
+ m_appendCond.notify_all();
+ }
+
+
+ void DxvkSubmissionQueue::present(DxvkPresentInfo presentInfo, DxvkSubmitStatus* status) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ DxvkSubmitEntry entry = { };
+ entry.status = status;
+ entry.present = std::move(presentInfo);
+
+ m_submitQueue.push(std::move(entry));
+ m_appendCond.notify_all();
+ }
+
+
+ void DxvkSubmissionQueue::synchronizeSubmission(
+ DxvkSubmitStatus* status) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ m_submitCond.wait(lock, [status] {
+ return status->result.load() != VK_NOT_READY;
+ });
+ }
+
+
+ void DxvkSubmissionQueue::synchronize() {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ m_submitCond.wait(lock, [this] {
+ return m_submitQueue.empty();
+ });
+ }
+
+
+ void DxvkSubmissionQueue::lockDeviceQueue() {
+ m_mutexQueue.lock();
+ }
+
+
+ void DxvkSubmissionQueue::unlockDeviceQueue() {
+ m_mutexQueue.unlock();
+ }
+
+
+ void DxvkSubmissionQueue::submitCmdLists() {
+ env::setThreadName("dxvk-submit");
+
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ while (!m_stopped.load()) {
+ m_appendCond.wait(lock, [this] {
+ return m_stopped.load() || !m_submitQueue.empty();
+ });
+
+ if (m_stopped.load())
+ return;
+
+ DxvkSubmitEntry entry = std::move(m_submitQueue.front());
+ lock.unlock();
+
+ // Submit command buffer to device
+ VkResult status = VK_NOT_READY;
+
+ if (m_lastError != VK_ERROR_DEVICE_LOST) {
+ std::lock_guard<dxvk::mutex> lock(m_mutexQueue);
+
+ if (entry.submit.cmdList != nullptr) {
+ status = entry.submit.cmdList->submit(
+ entry.submit.waitSync,
+ entry.submit.wakeSync);
+ } else if (entry.present.presenter != nullptr) {
+ status = entry.present.presenter->presentImage();
+ }
+ } else {
+ // Don't submit anything after device loss
+ // so that drivers get a chance to recover
+ status = VK_ERROR_DEVICE_LOST;
+ }
+
+ if (entry.status)
+ entry.status->result = status;
+
+ // On success, pass it on to the queue thread
+ lock = std::unique_lock<dxvk::mutex>(m_mutex);
+
+ if (status == VK_SUCCESS) {
+ if (entry.submit.cmdList != nullptr)
+ m_finishQueue.push(std::move(entry));
+ } else if (status == VK_ERROR_DEVICE_LOST || entry.submit.cmdList != nullptr) {
+ Logger::err(str::format("DxvkSubmissionQueue: Command submission failed: ", status));
+ m_lastError = status;
+ m_device->waitForIdle();
+ }
+
+ m_submitQueue.pop();
+ m_submitCond.notify_all();
+ }
+ }
+
+
+ void DxvkSubmissionQueue::finishCmdLists() {
+ env::setThreadName("dxvk-queue");
+
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ while (!m_stopped.load()) {
+ if (m_finishQueue.empty()) {
+ auto t0 = dxvk::high_resolution_clock::now();
+
+ m_submitCond.wait(lock, [this] {
+ return m_stopped.load() || !m_finishQueue.empty();
+ });
+
+ auto t1 = dxvk::high_resolution_clock::now();
+ m_gpuIdle += std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count();
+ }
+
+ if (m_stopped.load())
+ return;
+
+ DxvkSubmitEntry entry = std::move(m_finishQueue.front());
+ lock.unlock();
+
+ VkResult status = m_lastError.load();
+
+ if (status != VK_ERROR_DEVICE_LOST)
+ status = entry.submit.cmdList->synchronize();
+
+ if (status != VK_SUCCESS) {
+ Logger::err(str::format("DxvkSubmissionQueue: Failed to sync fence: ", status));
+ m_lastError = status;
+ m_device->waitForIdle();
+ }
+
+ entry.submit.cmdList->notifySignals();
+ entry.submit.cmdList->reset();
+
+ m_device->recycleCommandList(entry.submit.cmdList);
+
+ lock = std::unique_lock<dxvk::mutex>(m_mutex);
+ m_pending -= 1;
+
+ m_finishQueue.pop();
+ m_finishCond.notify_all();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.h
new file mode 100644
index 00000000..337c5fac
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_queue.h
@@ -0,0 +1,198 @@
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+
+#include "../util/thread.h"
+
+#include "../vulkan/vulkan_presenter.h"
+
+#include "dxvk_cmdlist.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Submission status
+ *
+ * Stores the result of a queue
+ * submission or a present call.
+ */
+ struct DxvkSubmitStatus {
+ std::atomic<VkResult> result = { VK_SUCCESS };
+ };
+
+
+ /**
+ * \brief Queue submission info
+ *
+ * Stores parameters used to submit
+ * a command buffer to the device.
+ */
+ struct DxvkSubmitInfo {
+ Rc<DxvkCommandList> cmdList;
+ VkSemaphore waitSync;
+ VkSemaphore wakeSync;
+ };
+
+
+ /**
+ * \brief Present info
+ *
+ * Stores parameters used to present
+ * a swap chain image on the device.
+ */
+ struct DxvkPresentInfo {
+ Rc<vk::Presenter> presenter;
+ };
+
+
+ /**
+ * \brief Submission queue entry
+ */
+ struct DxvkSubmitEntry {
+ DxvkSubmitStatus* status;
+ DxvkSubmitInfo submit;
+ DxvkPresentInfo present;
+ };
+
+
+ /**
+ * \brief Submission queue
+ */
+ class DxvkSubmissionQueue {
+
+ public:
+
+ DxvkSubmissionQueue(DxvkDevice* device);
+ ~DxvkSubmissionQueue();
+
+ /**
+ * \brief Number of pending submissions
+ *
+ * A return value of 0 indicates
+ * that the GPU is currently idle.
+ * \returns Pending submission count
+ */
+ uint32_t pendingSubmissions() const {
+ return m_pending.load();
+ }
+
+ /**
+ * \brief Retrieves estimated GPU idle time
+ *
+ * This is a monotonically increasing counter
+ * which can be evaluated periodically in order
+ * to calculate the GPU load.
+ * \returns Accumulated GPU idle time, in us
+ */
+ uint64_t gpuIdleTicks() const {
+ return m_gpuIdle.load();
+ }
+
+ /**
+ * \brief Retrieves last submission error
+ *
+ * In case an error occured during asynchronous command
+ * submission, it will be returned by this function.
+ * \returns Last error from command submission
+ */
+ VkResult getLastError() const {
+ return m_lastError.load();
+ }
+
+ /**
+ * \brief Submits a command list asynchronously
+ *
+ * Queues a command list for submission on the
+ * dedicated submission thread. Use this to take
+ * the submission overhead off the calling thread.
+ * \param [in] submitInfo Submission parameters
+ */
+ void submit(
+ DxvkSubmitInfo submitInfo);
+
+ /**
+ * \brief Presents an image synchronously
+ *
+ * Waits for queued command lists to be submitted
+ * and then presents the current swap chain image
+ * of the presenter. May stall the calling thread.
+ * \param [in] present Present parameters
+ * \returns Status of the operation
+ */
+ void present(
+ DxvkPresentInfo presentInfo,
+ DxvkSubmitStatus* status);
+
+ /**
+ * \brief Synchronizes with one queue submission
+ *
+ * Waits for the result of the given submission
+ * or present operation to become available.
+ * \param [in,out] status Submission status
+ */
+ void synchronizeSubmission(
+ DxvkSubmitStatus* status);
+
+ /**
+ * \brief Synchronizes with queue submissions
+ *
+ * Waits for all pending command lists to be
+ * submitted to the GPU before returning.
+ */
+ void synchronize();
+
+ /**
+ * \brief Locks device queue
+ *
+ * Locks the mutex that protects the Vulkan queue
+ * that DXVK uses for command buffer submission.
+ * This is needed when the app submits its own
+ * command buffers to the queue.
+ */
+ void lockDeviceQueue();
+
+ /**
+ * \brief Unlocks device queue
+ *
+ * Unlocks the mutex that protects the Vulkan
+ * queue used for command buffer submission.
+ */
+ void unlockDeviceQueue();
+
+ private:
+
+ DxvkDevice* m_device;
+
+ std::atomic<VkResult> m_lastError = { VK_SUCCESS };
+
+ std::atomic<bool> m_stopped = { false };
+ std::atomic<uint32_t> m_pending = { 0u };
+ std::atomic<uint64_t> m_gpuIdle = { 0ull };
+
+ dxvk::mutex m_mutex;
+ dxvk::mutex m_mutexQueue;
+
+ dxvk::condition_variable m_appendCond;
+ dxvk::condition_variable m_submitCond;
+ dxvk::condition_variable m_finishCond;
+
+ std::queue<DxvkSubmitEntry> m_submitQueue;
+ std::queue<DxvkSubmitEntry> m_finishQueue;
+
+ dxvk::thread m_submitThread;
+ dxvk::thread m_finishThread;
+
+ VkResult submitToQueue(
+ const DxvkSubmitInfo& submission);
+
+ void submitCmdLists();
+
+ void finishCmdLists();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_recycler.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_recycler.h
new file mode 100644
index 00000000..b90befd4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_recycler.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+namespace dxvk {
+
+ /**
+ * \brief Object recycler
+ *
+ * Implements a thread-safe buffer that can store up to
+ * a given number of objects of a certain type. This way,
+ * DXVK can efficiently reuse and reset objects instead
+ * of destroying them and creating them anew.
+ * \tparam T Type of the objects to store
+ * \tparam N Maximum number of objects to store
+ */
+ template<typename T, size_t N>
+ class DxvkRecycler {
+
+ public:
+
+ /**
+ * \brief Retrieves an object if possible
+ *
+ * Returns an object that was returned to the recycler
+ * earier. In case no objects are available, this will
+ * return \c nullptr and a new object has to be created.
+ * \return An object, or \c nullptr
+ */
+ Rc<T> retrieveObject() {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_objectId == 0)
+ return nullptr;
+
+ return m_objects.at(--m_objectId);
+ }
+
+ /**
+ * \brief Returns an object to the recycler
+ *
+ * If the buffer is full, the object will be destroyed
+ * once the last reference runs out of scope. No further
+ * action needs to be taken in this case.
+ * \param [in] object The object to return
+ */
+ void returnObject(const Rc<T>& object) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (m_objectId < N)
+ m_objects.at(m_objectId++) = object;
+ }
+
+ private:
+
+ dxvk::mutex m_mutex;
+ std::array<Rc<T>, N> m_objects;
+ size_t m_objectId = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.cpp
new file mode 100644
index 00000000..0dae186e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.cpp
@@ -0,0 +1,282 @@
+#include <algorithm>
+
+#include "dxvk_device.h"
+#include "dxvk_renderpass.h"
+
+namespace dxvk {
+
+ bool DxvkRenderPassFormat::eq(const DxvkRenderPassFormat& fmt) const {
+ bool eq = sampleCount == fmt.sampleCount;
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
+ eq &= color[i].format == fmt.color[i].format
+ && color[i].layout == fmt.color[i].layout;
+ }
+
+ eq &= depth.format == fmt.depth.format
+ && depth.layout == fmt.depth.layout;
+
+ return eq;
+ }
+
+
+ size_t DxvkRenderPassFormat::hash() const {
+ DxvkHashState state;
+ state.add(uint32_t(sampleCount));
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ state.add(uint32_t(color[i].format));
+ state.add(uint32_t(color[i].layout));
+ }
+
+ state.add(uint32_t(depth.format));
+ state.add(uint32_t(depth.layout));
+ return state;
+ }
+
+
+ DxvkRenderPass::DxvkRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkRenderPassFormat& fmt)
+ : m_vkd(vkd), m_format(fmt),
+ m_default(createRenderPass(DxvkRenderPassOps())) {
+
+ }
+
+
+ DxvkRenderPass::~DxvkRenderPass() {
+ m_vkd->vkDestroyRenderPass(m_vkd->device(), m_default, nullptr);
+
+ for (const auto& i : m_instances) {
+ m_vkd->vkDestroyRenderPass(
+ m_vkd->device(), i.handle, nullptr);
+ }
+ }
+
+
+ bool DxvkRenderPass::hasCompatibleFormat(const DxvkRenderPassFormat& fmt) const {
+ return m_format.eq(fmt);
+ }
+
+
+ VkRenderPass DxvkRenderPass::getHandle(const DxvkRenderPassOps& ops) {
+ std::lock_guard<sync::Spinlock> lock(m_mutex);
+
+ for (const auto& i : m_instances) {
+ if (compareOps(i.ops, ops))
+ return i.handle;
+ }
+
+ VkRenderPass handle = this->createRenderPass(ops);
+ m_instances.push_back({ ops, handle });
+ return handle;
+ }
+
+
+ VkRenderPass DxvkRenderPass::createRenderPass(const DxvkRenderPassOps& ops) {
+ std::vector<VkAttachmentDescription> attachments;
+
+ VkAttachmentReference depthRef;
+ std::array<VkAttachmentReference, MaxNumRenderTargets> colorRef;
+
+ // Render passes may not require the previous
+ // contents of the attachments to be preserved.
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (m_format.color[i].format != VK_FORMAT_UNDEFINED) {
+ VkAttachmentDescription desc;
+ desc.flags = 0;
+ desc.format = m_format.color[i].format;
+ desc.samples = m_format.sampleCount;
+ desc.loadOp = ops.colorOps[i].loadOp;
+ desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ desc.initialLayout = ops.colorOps[i].loadLayout;
+ desc.finalLayout = ops.colorOps[i].storeLayout;
+
+ colorRef[i].attachment = attachments.size();
+ colorRef[i].layout = m_format.color[i].layout;
+
+ attachments.push_back(desc);
+ } else {
+ colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
+ colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+ }
+
+ if (m_format.depth.format != VK_FORMAT_UNDEFINED) {
+ VkAttachmentDescription desc;
+ desc.flags = 0;
+ desc.format = m_format.depth.format;
+ desc.samples = m_format.sampleCount;
+ desc.loadOp = ops.depthOps.loadOpD;
+ desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ desc.stencilLoadOp = ops.depthOps.loadOpS;
+ desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ desc.initialLayout = ops.depthOps.loadLayout;
+ desc.finalLayout = ops.depthOps.storeLayout;
+
+ depthRef.attachment = attachments.size();
+ depthRef.layout = m_format.depth.layout;
+
+ attachments.push_back(desc);
+ } else {
+ depthRef.attachment = VK_ATTACHMENT_UNUSED;
+ depthRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ VkSubpassDescription subpass;
+ subpass.flags = 0;
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.inputAttachmentCount = 0;
+ subpass.pInputAttachments = nullptr;
+ subpass.colorAttachmentCount = colorRef.size();
+ subpass.pColorAttachments = colorRef.data();
+ subpass.pResolveAttachments = nullptr;
+ subpass.pDepthStencilAttachment = &depthRef;
+ subpass.preserveAttachmentCount = 0;
+ subpass.pPreserveAttachments = nullptr;
+
+ if (m_format.depth.format == VK_FORMAT_UNDEFINED)
+ subpass.pDepthStencilAttachment = nullptr;
+
+ std::array<VkSubpassDependency, 3> subpassDeps;
+ uint32_t subpassDepCount = 0;
+
+ VkPipelineStageFlags renderStages = 0;
+ VkAccessFlags renderAccess = 0;
+
+ if (m_format.depth.format) {
+ renderStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+ | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+
+ VkImageAspectFlags loadAspects = 0;
+
+ if (ops.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_LOAD)
+ loadAspects = VK_IMAGE_ASPECT_DEPTH_BIT;
+ if (ops.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_LOAD)
+ loadAspects = VK_IMAGE_ASPECT_STENCIL_BIT;
+
+ if (loadAspects & imageFormatInfo(m_format.depth.format)->aspectMask)
+ renderAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+ if (m_format.depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
+ renderAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+
+ if (m_format.depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
+ renderStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ renderAccess |= VK_ACCESS_SHADER_READ_BIT;
+ }
+ }
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (!m_format.color[i].format)
+ continue;
+
+ renderStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ renderAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+
+ if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
+ renderAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ }
+
+ if (renderStages) {
+ subpassDeps[subpassDepCount++] = {
+ VK_SUBPASS_EXTERNAL, 0,
+ renderStages, renderStages,
+ 0, renderAccess };
+ }
+
+ if (ops.barrier.srcStages & (
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
+ VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT |
+ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
+ subpassDeps[subpassDepCount++] = { 0, 0,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_ACCESS_SHADER_READ_BIT,
+ VK_DEPENDENCY_BY_REGION_BIT };
+ }
+
+ if (ops.barrier.srcStages && ops.barrier.dstStages) {
+ subpassDeps[subpassDepCount++] = {
+ 0, VK_SUBPASS_EXTERNAL,
+ ops.barrier.srcStages,
+ ops.barrier.dstStages,
+ ops.barrier.srcAccess,
+ ops.barrier.dstAccess, 0 };
+ }
+
+ VkRenderPassCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.attachmentCount = attachments.size();
+ info.pAttachments = attachments.data();
+ info.subpassCount = 1;
+ info.pSubpasses = &subpass;
+ info.dependencyCount = subpassDepCount;
+ info.pDependencies = subpassDepCount ? subpassDeps.data() : nullptr;
+
+ VkRenderPass renderPass = VK_NULL_HANDLE;
+
+ if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &renderPass) != VK_SUCCESS) {
+ Logger::err("DxvkRenderPass: Failed to create render pass object");
+ return VK_NULL_HANDLE;
+ }
+
+ return renderPass;
+ }
+
+
+ bool DxvkRenderPass::compareOps(
+ const DxvkRenderPassOps& a,
+ const DxvkRenderPassOps& b) {
+ bool eq = a.barrier.srcStages == b.barrier.srcStages
+ && a.barrier.srcAccess == b.barrier.srcAccess
+ && a.barrier.dstStages == b.barrier.dstStages
+ && a.barrier.dstAccess == b.barrier.dstAccess;
+
+ if (eq) {
+ eq &= a.depthOps.loadOpD == b.depthOps.loadOpD
+ && a.depthOps.loadOpS == b.depthOps.loadOpS
+ && a.depthOps.loadLayout == b.depthOps.loadLayout
+ && a.depthOps.storeLayout == b.depthOps.storeLayout;
+ }
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
+ eq &= a.colorOps[i].loadOp == b.colorOps[i].loadOp
+ && a.colorOps[i].loadLayout == b.colorOps[i].loadLayout
+ && a.colorOps[i].storeLayout == b.colorOps[i].storeLayout;
+ }
+
+ return eq;
+ }
+
+
+ DxvkRenderPassPool::DxvkRenderPassPool(const DxvkDevice* device)
+ : m_vkd(device->vkd()) {
+
+ }
+
+
+ DxvkRenderPassPool::~DxvkRenderPassPool() {
+
+ }
+
+
+ DxvkRenderPass* DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ auto entry = m_renderPasses.find(fmt);
+ if (entry != m_renderPasses.end())
+ return &entry->second;
+
+ auto result = m_renderPasses.emplace(std::piecewise_construct,
+ std::tuple(fmt),
+ std::tuple(m_vkd, fmt));
+ return &result.first->second;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.h
new file mode 100644
index 00000000..a5e10550
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_renderpass.h
@@ -0,0 +1,230 @@
+#pragma once
+
+#include <mutex>
+#include <vector>
+#include <unordered_map>
+
+#include "dxvk_hash.h"
+#include "dxvk_include.h"
+#include "dxvk_limits.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Format and layout for a render target
+ *
+ * Stores the image format of the attachment and
+ * the image layout that is used while rendering.
+ */
+ struct DxvkAttachmentFormat {
+ VkFormat format = VK_FORMAT_UNDEFINED;
+ VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
+ };
+
+
+ /**
+ * \brief Render pass format
+ *
+ * Stores the attachment formats for all depth and
+ * color attachments, as well as the sample count.
+ */
+ struct DxvkRenderPassFormat {
+ VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ DxvkAttachmentFormat depth;
+ DxvkAttachmentFormat color[MaxNumRenderTargets];
+
+ bool eq(const DxvkRenderPassFormat& fmt) const;
+
+ size_t hash() const;
+ };
+
+
+ /**
+ * \brief Color attachment transitions
+ *
+ * Stores the load/store ops and the initial
+ * and final layout of a single attachment.
+ */
+ struct DxvkColorAttachmentOps {
+ VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VkImageLayout storeLayout = VK_IMAGE_LAYOUT_GENERAL;
+ };
+
+
+ /**
+ * \brief Depth attachment transitions
+ *
+ * Stores the load/store ops and the initial and
+ * final layout of the depth-stencil attachment.
+ */
+ struct DxvkDepthAttachmentOps {
+ VkAttachmentLoadOp loadOpD = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ VkAttachmentLoadOp loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VkImageLayout storeLayout = VK_IMAGE_LAYOUT_GENERAL;
+ };
+
+
+ /**
+ * \brief Render pass barrier
+ *
+ * External subpass dependency that is to be
+ * executed after a render pass has completed.
+ */
+ struct DxvkRenderPassBarrier {
+ VkPipelineStageFlags srcStages = 0;
+ VkAccessFlags srcAccess = 0;
+ VkPipelineStageFlags dstStages = 0;
+ VkAccessFlags dstAccess = 0;
+ };
+
+
+ /**
+ * \brief Render pass transitions
+ *
+ * Stores transitions for all depth and color attachments.
+ * This is used to select a specific render pass object
+ * from a group of render passes with the same format.
+ */
+ struct DxvkRenderPassOps {
+ DxvkRenderPassBarrier barrier;
+ DxvkDepthAttachmentOps depthOps;
+ DxvkColorAttachmentOps colorOps[MaxNumRenderTargets];
+ };
+
+
+ /**
+ * \brief Render pass object
+ *
+ * Manages a set of compatible render passes, i.e.
+ * render passes which share the same format but
+ * may differ in their attachment operations.
+ */
+ class DxvkRenderPass {
+
+ public:
+
+ DxvkRenderPass(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkRenderPassFormat& fmt);
+
+ ~DxvkRenderPass();
+
+ /**
+ * \brief Retrieves render pass format
+ * \returns The render pass format
+ */
+ DxvkRenderPassFormat format() const {
+ return m_format;
+ }
+
+ /**
+ * \brief Checks whether a format is compatible
+ *
+ * Two render pass formats are considered compatible
+ * if all the relevant attachment formats match.
+ * \param [in] fmt The render pass format to check
+ * \returns \c true if this render pass is compatible.
+ */
+ bool hasCompatibleFormat(
+ const DxvkRenderPassFormat& fmt) const;
+
+ /**
+ * \brief Retrieves sample count
+ *
+ * If no sample count has been explicitly specitied,
+ * this will return \c VK_SAMPLE_COUNT_1_BIT.
+ * \returns Sample count
+ */
+ VkSampleCountFlagBits getSampleCount() const {
+ return m_format.sampleCount;
+ }
+
+ /**
+ * \brief Returns handle of default render pass
+ *
+ * The default render pass handle should be used to
+ * create pipelines and framebuffer objects. It can
+ * \e not be used for \c vkCmdBeginRenderPass calls.
+ * \returns The default render pass handle
+ */
+ VkRenderPass getDefaultHandle() const {
+ return m_default;
+ }
+
+ /**
+ * \brief Returns handle to a specialized render pass
+ *
+ * Returns a handle to a render pass with the given
+ * set of parameters. This should be used for calls
+ * to \c vkCmdBeginRenderPass.
+ * \param [in] ops Attachment ops
+ * \returns Render pass handle
+ */
+ VkRenderPass getHandle(
+ const DxvkRenderPassOps& ops);
+
+ private:
+
+ struct Instance {
+ DxvkRenderPassOps ops;
+ VkRenderPass handle;
+ };
+
+ Rc<vk::DeviceFn> m_vkd;
+ DxvkRenderPassFormat m_format;
+ VkRenderPass m_default;
+
+ sync::Spinlock m_mutex;
+ std::vector<Instance> m_instances;
+
+ VkRenderPass createRenderPass(
+ const DxvkRenderPassOps& ops);
+
+ static bool compareOps(
+ const DxvkRenderPassOps& a,
+ const DxvkRenderPassOps& b);
+
+ };
+
+
+ /**
+ * \brief Render pass pool
+ *
+ * Manages render pass objects. For each render
+ * pass format, a new render pass object will
+ * be created, but no two render pass objects
+ * will have the same format.
+ */
+ class DxvkRenderPassPool {
+
+ public:
+
+ DxvkRenderPassPool(const DxvkDevice* device);
+ ~DxvkRenderPassPool();
+
+ /**
+ * \brief Retrieves a render pass object
+ *
+ * \param [in] fmt The render pass format
+ * \returns Matching render pass object
+ */
+ DxvkRenderPass* getRenderPass(
+ const DxvkRenderPassFormat& fmt);
+
+ private:
+
+ const Rc<vk::DeviceFn> m_vkd;
+
+ dxvk::mutex m_mutex;
+ std::unordered_map<
+ DxvkRenderPassFormat,
+ DxvkRenderPass,
+ DxvkHash, DxvkEq> m_renderPasses;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.cpp
new file mode 100644
index 00000000..af7a2ea4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.cpp
@@ -0,0 +1,9 @@
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ DxvkResource::~DxvkResource() {
+
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.h
new file mode 100644
index 00000000..9a73ed81
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_resource.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ enum class DxvkAccess {
+ Read = 0,
+ Write = 1,
+ None = 2,
+ };
+
+ using DxvkAccessFlags = Flags<DxvkAccess>;
+
+ /**
+ * \brief DXVK resource
+ *
+ * Keeps track of whether the resource is currently in use
+ * by the GPU. As soon as a command that uses the resource
+ * is recorded, it will be marked as 'in use'.
+ */
+ class DxvkResource : public RcObject {
+
+ public:
+
+ virtual ~DxvkResource();
+
+ /**
+ * \brief Checks whether resource is in use
+ *
+ * Returns \c true if there are pending accesses to
+ * the resource by the GPU matching the given access
+ * type. Note that checking for reads will also return
+ * \c true if the resource is being written to.
+ * \param [in] access Access type to check for
+ * \returns \c true if the resource is in use
+ */
+ bool isInUse(DxvkAccess access = DxvkAccess::Read) const {
+ bool result = m_useCountW.load() != 0;
+ if (access == DxvkAccess::Read)
+ result |= m_useCountR.load() != 0;
+ return result;
+ }
+
+ /**
+ * \brief Acquires resource
+ *
+ * Increments use count for the given access type.
+ * \param Access Resource access type
+ */
+ void acquire(DxvkAccess access) {
+ if (access != DxvkAccess::None) {
+ (access == DxvkAccess::Read
+ ? m_useCountR
+ : m_useCountW) += 1;
+ }
+ }
+
+ /**
+ * \brief Releases resource
+ *
+ * Decrements use count for the given access type.
+ * \param Access Resource access type
+ */
+ void release(DxvkAccess access) {
+ if (access != DxvkAccess::None) {
+ (access == DxvkAccess::Read
+ ? m_useCountR
+ : m_useCountW) -= 1;
+ }
+ }
+
+ /**
+ * \brief Waits for resource to become unused
+ *
+ * Blocks calling thread until the GPU finishes
+ * using the resource with the given access type.
+ * \param [in] access Access type to check for
+ */
+ void waitIdle(DxvkAccess access = DxvkAccess::Read) const {
+ sync::spin(50000, [this, access] {
+ return !isInUse(access);
+ });
+ }
+
+ private:
+
+ std::atomic<uint32_t> m_useCountR = { 0u };
+ std::atomic<uint32_t> m_useCountW = { 0u };
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.cpp
new file mode 100644
index 00000000..ca82a297
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.cpp
@@ -0,0 +1,84 @@
+#include "dxvk_sampler.h"
+#include "dxvk_device.h"
+
+namespace dxvk {
+
+ DxvkSampler::DxvkSampler(
+ DxvkDevice* device,
+ const DxvkSamplerCreateInfo& info)
+ : m_vkd(device->vkd()) {
+ VkSamplerCustomBorderColorCreateInfoEXT borderColorInfo;
+ borderColorInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;
+ borderColorInfo.pNext = nullptr;
+ borderColorInfo.customBorderColor = info.borderColor;
+ borderColorInfo.format = VK_FORMAT_UNDEFINED;
+
+ VkSamplerCreateInfo samplerInfo;
+ samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ samplerInfo.pNext = nullptr;
+ samplerInfo.flags = 0;
+ samplerInfo.magFilter = info.magFilter;
+ samplerInfo.minFilter = info.minFilter;
+ samplerInfo.mipmapMode = info.mipmapMode;
+ samplerInfo.addressModeU = info.addressModeU;
+ samplerInfo.addressModeV = info.addressModeV;
+ samplerInfo.addressModeW = info.addressModeW;
+ samplerInfo.mipLodBias = info.mipmapLodBias;
+ samplerInfo.anisotropyEnable = info.useAnisotropy;
+ samplerInfo.maxAnisotropy = info.maxAnisotropy;
+ samplerInfo.compareEnable = info.compareToDepth;
+ samplerInfo.compareOp = info.compareOp;
+ samplerInfo.minLod = info.mipmapLodMin;
+ samplerInfo.maxLod = info.mipmapLodMax;
+ samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ samplerInfo.unnormalizedCoordinates = info.usePixelCoord;
+
+ if (!device->features().core.features.samplerAnisotropy)
+ samplerInfo.anisotropyEnable = VK_FALSE;
+
+ if (samplerInfo.addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
+ || samplerInfo.addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
+ || samplerInfo.addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)
+ samplerInfo.borderColor = getBorderColor(device, info);
+
+ if (samplerInfo.borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT)
+ samplerInfo.pNext = &borderColorInfo;
+
+ if (m_vkd->vkCreateSampler(m_vkd->device(),
+ &samplerInfo, nullptr, &m_sampler) != VK_SUCCESS)
+ throw DxvkError("DxvkSampler::DxvkSampler: Failed to create sampler");
+ }
+
+
+ DxvkSampler::~DxvkSampler() {
+ m_vkd->vkDestroySampler(
+ m_vkd->device(), m_sampler, nullptr);
+ }
+
+
+ VkBorderColor DxvkSampler::getBorderColor(const Rc<DxvkDevice>& device, const DxvkSamplerCreateInfo& info) {
+ static const std::array<std::pair<VkClearColorValue, VkBorderColor>, 3> s_borderColors = {{
+ { { { 0.0f, 0.0f, 0.0f, 0.0f } }, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK },
+ { { { 0.0f, 0.0f, 0.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK },
+ { { { 1.0f, 1.0f, 1.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE },
+ }};
+
+ // Ignore G/B/A components for shadow samplers
+ size_t size = !info.compareToDepth
+ ? sizeof(VkClearColorValue)
+ : sizeof(float);
+
+ for (const auto& e : s_borderColors) {
+ if (!std::memcmp(&e.first, &info.borderColor, size))
+ return e.second;
+ }
+
+ if (!device->features().extCustomBorderColor.customBorderColorWithoutFormat) {
+ Logger::warn("DXVK: Custom border colors not supported");
+ return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ }
+
+ return VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.h
new file mode 100644
index 00000000..5ed268f3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_sampler.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include "dxvk_resource.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Sampler properties
+ */
+ struct DxvkSamplerCreateInfo {
+ /// Texture filter propertoes
+ VkFilter magFilter;
+ VkFilter minFilter;
+
+ /// Mipmapping properties
+ VkSamplerMipmapMode mipmapMode;
+ float mipmapLodBias;
+ float mipmapLodMin;
+ float mipmapLodMax;
+
+ /// Anisotropic filtering
+ VkBool32 useAnisotropy;
+ float maxAnisotropy;
+
+ /// Address modes
+ VkSamplerAddressMode addressModeU;
+ VkSamplerAddressMode addressModeV;
+ VkSamplerAddressMode addressModeW;
+
+ /// Compare op for shadow textures
+ VkBool32 compareToDepth;
+ VkCompareOp compareOp;
+
+ /// Texture border color
+ VkClearColorValue borderColor;
+
+ /// Enables unnormalized coordinates
+ VkBool32 usePixelCoord;
+ };
+
+
+ /**
+ * \brief Sampler
+ *
+ * Manages a sampler object that can be bound to
+ * a pipeline. Sampler objects provide parameters
+ * for texture lookups within a shader.
+ */
+ class DxvkSampler : public DxvkResource {
+
+ public:
+
+ DxvkSampler(
+ DxvkDevice* device,
+ const DxvkSamplerCreateInfo& info);
+ ~DxvkSampler();
+
+ /**
+ * \brief Sampler handle
+ * \returns Sampler handle
+ */
+ VkSampler handle() const {
+ return m_sampler;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ VkSampler m_sampler = VK_NULL_HANDLE;
+
+ static VkBorderColor getBorderColor(
+ const Rc<DxvkDevice>& device,
+ const DxvkSamplerCreateInfo& info);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.cpp
new file mode 100644
index 00000000..20acd073
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.cpp
@@ -0,0 +1,386 @@
+#include "dxvk_shader.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace dxvk {
+
+ DxvkShaderConstData::DxvkShaderConstData()
+ : m_size(0), m_data(nullptr) {
+
+ }
+
+
+ DxvkShaderConstData::DxvkShaderConstData(
+ size_t dwordCount,
+ const uint32_t* dwordArray)
+ : m_size(dwordCount), m_data(new uint32_t[dwordCount]) {
+ for (size_t i = 0; i < dwordCount; i++)
+ m_data[i] = dwordArray[i];
+ }
+
+
+ DxvkShaderConstData::DxvkShaderConstData(DxvkShaderConstData&& other)
+ : m_size(other.m_size), m_data(other.m_data) {
+ other.m_size = 0;
+ other.m_data = nullptr;
+ }
+
+
+ DxvkShaderConstData& DxvkShaderConstData::operator = (DxvkShaderConstData&& other) {
+ delete[] m_data;
+ this->m_size = other.m_size;
+ this->m_data = other.m_data;
+ other.m_size = 0;
+ other.m_data = nullptr;
+ return *this;
+ }
+
+
+ DxvkShaderConstData::~DxvkShaderConstData() {
+ delete[] m_data;
+ }
+
+
+ DxvkShaderModule::DxvkShaderModule()
+ : m_vkd(nullptr), m_stage() {
+
+ }
+
+
+ DxvkShaderModule::DxvkShaderModule(DxvkShaderModule&& other)
+ : m_vkd(std::move(other.m_vkd)) {
+ this->m_stage = other.m_stage;
+ other.m_stage = VkPipelineShaderStageCreateInfo();
+ }
+
+
+ DxvkShaderModule::DxvkShaderModule(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkShader>& shader,
+ const SpirvCodeBuffer& code)
+ : m_vkd(vkd), m_stage() {
+ m_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ m_stage.pNext = nullptr;
+ m_stage.flags = 0;
+ m_stage.stage = shader->stage();
+ m_stage.module = VK_NULL_HANDLE;
+ m_stage.pName = "main";
+ m_stage.pSpecializationInfo = nullptr;
+
+ VkShaderModuleCreateInfo info;
+ info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.codeSize = code.size();
+ info.pCode = code.data();
+
+ if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &m_stage.module) != VK_SUCCESS)
+ throw DxvkError("DxvkComputePipeline::DxvkComputePipeline: Failed to create shader module");
+ }
+
+
+ DxvkShaderModule::~DxvkShaderModule() {
+ if (m_vkd != nullptr) {
+ m_vkd->vkDestroyShaderModule(
+ m_vkd->device(), m_stage.module, nullptr);
+ }
+ }
+
+
+ DxvkShaderModule& DxvkShaderModule::operator = (DxvkShaderModule&& other) {
+ this->m_vkd = std::move(other.m_vkd);
+ this->m_stage = other.m_stage;
+ other.m_stage = VkPipelineShaderStageCreateInfo();
+ return *this;
+ }
+
+
+ DxvkShader::DxvkShader(
+ VkShaderStageFlagBits stage,
+ uint32_t slotCount,
+ const DxvkResourceSlot* slotInfos,
+ const DxvkInterfaceSlots& iface,
+ SpirvCodeBuffer code,
+ const DxvkShaderOptions& options,
+ DxvkShaderConstData&& constData)
+ : m_stage(stage), m_code(code), m_interface(iface),
+ m_options(options), m_constData(std::move(constData)) {
+ // Write back resource slot infos
+ for (uint32_t i = 0; i < slotCount; i++)
+ m_slots.push_back(slotInfos[i]);
+
+ // Gather the offsets where the binding IDs
+ // are stored so we can quickly remap them.
+ uint32_t o1VarId = 0;
+
+ for (auto ins : code) {
+ if (ins.opCode() == spv::OpDecorate) {
+ if (ins.arg(2) == spv::DecorationBinding
+ || ins.arg(2) == spv::DecorationSpecId)
+ m_idOffsets.push_back(ins.offset() + 3);
+
+ if (ins.arg(2) == spv::DecorationLocation && ins.arg(3) == 1) {
+ m_o1LocOffset = ins.offset() + 3;
+ o1VarId = ins.arg(1);
+ }
+
+ if (ins.arg(2) == spv::DecorationIndex && ins.arg(1) == o1VarId)
+ m_o1IdxOffset = ins.offset() + 3;
+ }
+
+ if (ins.opCode() == spv::OpExecutionMode) {
+ if (ins.arg(2) == spv::ExecutionModeStencilRefReplacingEXT)
+ m_flags.set(DxvkShaderFlag::ExportsStencilRef);
+
+ if (ins.arg(2) == spv::ExecutionModeXfb)
+ m_flags.set(DxvkShaderFlag::HasTransformFeedback);
+ }
+
+ if (ins.opCode() == spv::OpCapability) {
+ if (ins.arg(1) == spv::CapabilitySampleRateShading)
+ m_flags.set(DxvkShaderFlag::HasSampleRateShading);
+
+ if (ins.arg(1) == spv::CapabilityShaderViewportIndexLayerEXT)
+ m_flags.set(DxvkShaderFlag::ExportsViewportIndexLayerFromVertexStage);
+ }
+ }
+ }
+
+
+ DxvkShader::~DxvkShader() {
+
+ }
+
+
+ void DxvkShader::defineResourceSlots(
+ DxvkDescriptorSlotMapping& mapping) const {
+ for (const auto& slot : m_slots)
+ mapping.defineSlot(m_stage, slot);
+
+ if (m_interface.pushConstSize) {
+ mapping.definePushConstRange(m_stage,
+ m_interface.pushConstOffset,
+ m_interface.pushConstSize);
+ }
+ }
+
+
+ DxvkShaderModule DxvkShader::createShaderModule(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDescriptorSlotMapping& mapping,
+ const DxvkShaderModuleCreateInfo& info) {
+ SpirvCodeBuffer spirvCode = m_code.decompress();
+ uint32_t* code = spirvCode.data();
+
+ // Remap resource binding IDs
+ for (uint32_t ofs : m_idOffsets) {
+ if (code[ofs] < MaxNumResourceSlots)
+ code[ofs] = mapping.getBindingId(code[ofs]);
+ }
+
+ // For dual-source blending we need to re-map
+ // location 1, index 0 to location 0, index 1
+ if (info.fsDualSrcBlend && m_o1IdxOffset && m_o1LocOffset)
+ std::swap(code[m_o1IdxOffset], code[m_o1LocOffset]);
+
+ // Replace undefined input variables with zero
+ for (uint32_t u : bit::BitMask(info.undefinedInputs))
+ eliminateInput(spirvCode, u);
+
+ return DxvkShaderModule(vkd, this, spirvCode);
+ }
+
+
+ void DxvkShader::dump(std::ostream& outputStream) const {
+ m_code.decompress().store(outputStream);
+ }
+
+
+ void DxvkShader::eliminateInput(SpirvCodeBuffer& code, uint32_t location) {
+ struct SpirvTypeInfo {
+ spv::Op op = spv::OpNop;
+ uint32_t baseTypeId = 0;
+ uint32_t compositeSize = 0;
+ spv::StorageClass storageClass = spv::StorageClassMax;
+ };
+
+ std::unordered_map<uint32_t, SpirvTypeInfo> types;
+ std::unordered_map<uint32_t, uint32_t> constants;
+ std::unordered_set<uint32_t> candidates;
+
+ // Find the input variable in question
+ size_t inputVarOffset = 0;
+ uint32_t inputVarTypeId = 0;
+ uint32_t inputVarId = 0;
+
+ for (auto ins : code) {
+ if (ins.opCode() == spv::OpDecorate) {
+ if (ins.arg(2) == spv::DecorationLocation
+ && ins.arg(3) == location)
+ candidates.insert(ins.arg(1));
+ }
+
+ if (ins.opCode() == spv::OpConstant)
+ constants.insert({ ins.arg(2), ins.arg(3) });
+
+ if (ins.opCode() == spv::OpTypeFloat || ins.opCode() == spv::OpTypeInt)
+ types.insert({ ins.arg(1), { ins.opCode(), 0, ins.arg(2), spv::StorageClassMax }});
+
+ if (ins.opCode() == spv::OpTypeVector)
+ types.insert({ ins.arg(1), { ins.opCode(), ins.arg(2), ins.arg(3), spv::StorageClassMax }});
+
+ if (ins.opCode() == spv::OpTypeArray) {
+ auto constant = constants.find(ins.arg(3));
+ if (constant == constants.end())
+ continue;
+ types.insert({ ins.arg(1), { ins.opCode(), ins.arg(2), constant->second, spv::StorageClassMax }});
+ }
+
+ if (ins.opCode() == spv::OpTypePointer)
+ types.insert({ ins.arg(1), { ins.opCode(), ins.arg(3), 0, spv::StorageClass(ins.arg(2)) }});
+
+ if (ins.opCode() == spv::OpVariable && spv::StorageClass(ins.arg(3)) == spv::StorageClassInput) {
+ if (candidates.find(ins.arg(2)) != candidates.end()) {
+ inputVarOffset = ins.offset();
+ inputVarTypeId = ins.arg(1);
+ inputVarId = ins.arg(2);
+ break;
+ }
+ }
+ }
+
+ if (!inputVarId)
+ return;
+
+ // Declare private pointer types
+ auto pointerType = types.find(inputVarTypeId);
+ if (pointerType == types.end())
+ return;
+
+ code.beginInsertion(inputVarOffset);
+ std::vector<std::pair<uint32_t, SpirvTypeInfo>> privateTypes;
+
+ for (auto p = types.find(pointerType->second.baseTypeId);
+ p != types.end();
+ p = types.find(p->second.baseTypeId)) {
+ std::pair<uint32_t, SpirvTypeInfo> info = *p;
+ info.first = 0;
+ info.second.baseTypeId = p->first;
+ info.second.storageClass = spv::StorageClassPrivate;
+
+ for (auto t : types) {
+ if (t.second.op == info.second.op
+ && t.second.baseTypeId == info.second.baseTypeId
+ && t.second.storageClass == info.second.storageClass)
+ info.first = t.first;
+ }
+
+ if (!info.first) {
+ info.first = code.allocId();
+
+ code.putIns(spv::OpTypePointer, 4);
+ code.putWord(info.first);
+ code.putWord(info.second.storageClass);
+ code.putWord(info.second.baseTypeId);
+ }
+
+ privateTypes.push_back(info);
+ }
+
+ // Define zero constants
+ uint32_t constantId = 0;
+
+ for (auto i = privateTypes.rbegin(); i != privateTypes.rend(); i++) {
+ if (constantId) {
+ uint32_t compositeSize = i->second.compositeSize;
+ uint32_t compositeId = code.allocId();
+
+ code.putIns(spv::OpConstantComposite, 3 + compositeSize);
+ code.putWord(i->second.baseTypeId);
+ code.putWord(compositeId);
+
+ for (uint32_t i = 0; i < compositeSize; i++)
+ code.putWord(constantId);
+
+ constantId = compositeId;
+ } else {
+ constantId = code.allocId();
+
+ code.putIns(spv::OpConstant, 4);
+ code.putWord(i->second.baseTypeId);
+ code.putWord(constantId);
+ code.putWord(0);
+ }
+ }
+
+ // Erase and re-declare variable
+ code.erase(4);
+
+ code.putIns(spv::OpVariable, 5);
+ code.putWord(privateTypes[0].first);
+ code.putWord(inputVarId);
+ code.putWord(spv::StorageClassPrivate);
+ code.putWord(constantId);
+
+ code.endInsertion();
+
+ // Remove variable from interface list
+ for (auto ins : code) {
+ if (ins.opCode() == spv::OpEntryPoint) {
+ uint32_t argIdx = 2 + code.strLen(ins.chr(2));
+
+ while (argIdx < ins.length()) {
+ if (ins.arg(argIdx) == inputVarId) {
+ ins.setArg(0, spv::OpEntryPoint | ((ins.length() - 1) << spv::WordCountShift));
+
+ code.beginInsertion(ins.offset() + argIdx);
+ code.erase(1);
+ code.endInsertion();
+ break;
+ }
+
+ argIdx += 1;
+ }
+ }
+ }
+
+ // Remove location declarations
+ for (auto ins : code) {
+ if (ins.opCode() == spv::OpDecorate
+ && ins.arg(2) == spv::DecorationLocation
+ && ins.arg(1) == inputVarId) {
+ code.beginInsertion(ins.offset());
+ code.erase(4);
+ code.endInsertion();
+ break;
+ }
+ }
+
+ // Fix up pointer types used in access chain instructions
+ std::unordered_map<uint32_t, uint32_t> accessChainIds;
+
+ for (auto ins : code) {
+ if (ins.opCode() == spv::OpAccessChain
+ || ins.opCode() == spv::OpInBoundsAccessChain) {
+ uint32_t depth = ins.length() - 4;
+
+ if (ins.arg(3) == inputVarId) {
+ // Access chains accessing the variable directly
+ ins.setArg(1, privateTypes.at(depth).first);
+ accessChainIds.insert({ ins.arg(2), depth });
+ } else {
+ // Access chains derived from the variable
+ auto entry = accessChainIds.find(ins.arg(2));
+ if (entry != accessChainIds.end()) {
+ depth += entry->second;
+ ins.setArg(1, privateTypes.at(depth).first);
+ accessChainIds.insert({ ins.arg(2), depth });
+ }
+ }
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.h
new file mode 100644
index 00000000..17967cff
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader.h
@@ -0,0 +1,355 @@
+#pragma once
+
+#include <vector>
+
+#include "dxvk_include.h"
+#include "dxvk_limits.h"
+#include "dxvk_pipelayout.h"
+#include "dxvk_shader_key.h"
+
+#include "../spirv/spirv_code_buffer.h"
+#include "../spirv/spirv_compression.h"
+
+namespace dxvk {
+
+ class DxvkShader;
+ class DxvkShaderModule;
+
+ /**
+ * \brief Built-in specialization constants
+ *
+ * These specialization constants allow the SPIR-V
+ * shaders to access some pipeline state like D3D
+ * shaders do. They need to be filled in by the
+ * implementation at pipeline compilation time.
+ */
+ enum class DxvkSpecConstantId : uint32_t {
+ /// Special constant ranges that do not count
+ /// towards the spec constant min/max values
+ ColorComponentMappings = MaxNumResourceSlots,
+
+ // Specialization constants for pipeline state
+ SpecConstantRangeStart = ColorComponentMappings + MaxNumRenderTargets,
+ RasterizerSampleCount = SpecConstantRangeStart + 0,
+ FirstPipelineConstant
+ };
+
+ /**
+ * \brief Shader flags
+ *
+ * Provides extra information about the features
+ * used by a shader.
+ */
+ enum DxvkShaderFlag : uint64_t {
+ HasSampleRateShading,
+ HasTransformFeedback,
+ ExportsStencilRef,
+ ExportsViewportIndexLayerFromVertexStage,
+ };
+
+ using DxvkShaderFlags = Flags<DxvkShaderFlag>;
+
+ /**
+ * \brief Shader interface slots
+ *
+ * Stores a bit mask of which shader
+ * interface slots are defined. Used
+ * purely for validation purposes.
+ */
+ struct DxvkInterfaceSlots {
+ uint32_t inputSlots = 0;
+ uint32_t outputSlots = 0;
+ uint32_t pushConstOffset = 0;
+ uint32_t pushConstSize = 0;
+ };
+
+
+ /**
+ * \brief Additional shader options
+ *
+ * Contains additional properties that should be
+ * taken into account when creating pipelines.
+ */
+ struct DxvkShaderOptions {
+ /// Rasterized stream, or -1
+ int32_t rasterizedStream;
+ /// Xfb vertex strides
+ uint32_t xfbStrides[MaxNumXfbBuffers];
+ };
+
+
+ /**
+ * \brief Shader constants
+ *
+ * Each shader can have constant data associated
+ * with it, which needs to be copied to a uniform
+ * buffer. The client API must then bind that buffer
+ * to an API-specific buffer binding when using the
+ * shader for rendering.
+ */
+ class DxvkShaderConstData {
+
+ public:
+
+ DxvkShaderConstData();
+ DxvkShaderConstData(
+ size_t dwordCount,
+ const uint32_t* dwordArray);
+
+ DxvkShaderConstData (DxvkShaderConstData&& other);
+ DxvkShaderConstData& operator = (DxvkShaderConstData&& other);
+
+ ~DxvkShaderConstData();
+
+ const uint32_t* data() const {
+ return m_data;
+ }
+
+ size_t sizeInBytes() const {
+ return m_size * sizeof(uint32_t);
+ }
+
+ private:
+
+ size_t m_size = 0;
+ uint32_t* m_data = nullptr;
+
+ };
+
+
+ /**
+ * \brief Shader module create info
+ */
+ struct DxvkShaderModuleCreateInfo {
+ bool fsDualSrcBlend = false;
+ uint32_t undefinedInputs = 0;
+ };
+
+
+ /**
+ * \brief Shader object
+ *
+ * Stores a SPIR-V shader and information on the
+ * bindings that the shader uses. In order to use
+ * the shader with a pipeline, a shader module
+ * needs to be created from he shader object.
+ */
+ class DxvkShader : public RcObject {
+
+ public:
+
+ DxvkShader(
+ VkShaderStageFlagBits stage,
+ uint32_t slotCount,
+ const DxvkResourceSlot* slotInfos,
+ const DxvkInterfaceSlots& iface,
+ SpirvCodeBuffer code,
+ const DxvkShaderOptions& options,
+ DxvkShaderConstData&& constData);
+
+ ~DxvkShader();
+
+ /**
+ * \brief Shader stage
+ * \returns Shader stage
+ */
+ VkShaderStageFlagBits stage() const {
+ return m_stage;
+ }
+
+ /**
+ * \brief Retrieves shader flags
+ * \returns Shader flags
+ */
+ DxvkShaderFlags flags() const {
+ return m_flags;
+ }
+
+ /**
+ * \brief Adds resource slots definitions to a mapping
+ *
+ * Used to generate the exact descriptor set layout when
+ * compiling a graphics or compute pipeline. Slot indices
+ * have to be mapped to actual binding numbers.
+ */
+ void defineResourceSlots(
+ DxvkDescriptorSlotMapping& mapping) const;
+
+ /**
+ * \brief Creates a shader module
+ *
+ * Maps the binding slot numbers
+ * \param [in] vkd Vulkan device functions
+ * \param [in] mapping Resource slot mapping
+ * \param [in] info Module create info
+ * \returns The shader module
+ */
+ DxvkShaderModule createShaderModule(
+ const Rc<vk::DeviceFn>& vkd,
+ const DxvkDescriptorSlotMapping& mapping,
+ const DxvkShaderModuleCreateInfo& info);
+
+ /**
+ * \brief Inter-stage interface slots
+ *
+ * Retrieves the input and output
+ * registers used by the shader.
+ * \returns Shader interface slots
+ */
+ DxvkInterfaceSlots interfaceSlots() const {
+ return m_interface;
+ }
+
+ /**
+ * \brief Shader options
+ * \returns Shader options
+ */
+ DxvkShaderOptions shaderOptions() const {
+ return m_options;
+ }
+
+ /**
+ * \brief Shader constant data
+ *
+ * Returns a read-only reference to the
+ * constant data associated with this
+ * shader object.
+ * \returns Shader constant data
+ */
+ const DxvkShaderConstData& shaderConstants() const {
+ return m_constData;
+ }
+
+ /**
+ * \brief Dumps SPIR-V shader
+ *
+ * Can be used to store the SPIR-V code in a file.
+ * \param [in] outputStream Stream to write to
+ */
+ void dump(std::ostream& outputStream) const;
+
+ /**
+ * \brief Sets the shader key
+ * \param [in] key Unique key
+ */
+ void setShaderKey(const DxvkShaderKey& key) {
+ m_key = key;
+ m_hash = key.hash();
+ }
+
+ /**
+ * \brief Retrieves shader key
+ * \returns The unique shader key
+ */
+ DxvkShaderKey getShaderKey() const {
+ return m_key;
+ }
+
+ /**
+ * \brief Get lookup hash
+ *
+ * Retrieves a non-unique hash value derived from the
+ * shader key which can be used to perform lookups.
+ * This is better than relying on the pointer value.
+ * \returns Hash value for map lookups
+ */
+ size_t getHash() const {
+ return m_hash;
+ }
+
+ /**
+ * \brief Retrieves debug name
+ * \returns The shader's name
+ */
+ std::string debugName() const {
+ return m_key.toString();
+ }
+
+ /**
+ * \brief Get lookup hash for a shader
+ *
+ * Convenience method that returns \c 0 for a null
+ * pointer, and the shader's lookup hash otherwise.
+ * \param [in] shader The shader
+ * \returns The shader's lookup hash, or 0
+ */
+ static size_t getHash(const Rc<DxvkShader>& shader) {
+ return shader != nullptr ? shader->getHash() : 0;
+ }
+
+ private:
+
+ VkShaderStageFlagBits m_stage;
+ SpirvCompressedBuffer m_code;
+
+ std::vector<DxvkResourceSlot> m_slots;
+ std::vector<size_t> m_idOffsets;
+ DxvkInterfaceSlots m_interface;
+ DxvkShaderFlags m_flags;
+ DxvkShaderOptions m_options;
+ DxvkShaderConstData m_constData;
+ DxvkShaderKey m_key;
+ size_t m_hash = 0;
+
+ size_t m_o1IdxOffset = 0;
+ size_t m_o1LocOffset = 0;
+
+ static void eliminateInput(SpirvCodeBuffer& code, uint32_t location);
+
+ };
+
+
+ /**
+ * \brief Shader module object
+ *
+ * Manages a Vulkan shader module. This will not
+ * perform any shader compilation. Instead, the
+ * context will create pipeline objects on the
+ * fly when executing draw calls.
+ */
+ class DxvkShaderModule {
+
+ public:
+
+ DxvkShaderModule();
+
+ DxvkShaderModule(DxvkShaderModule&& other);
+
+ DxvkShaderModule(
+ const Rc<vk::DeviceFn>& vkd,
+ const Rc<DxvkShader>& shader,
+ const SpirvCodeBuffer& code);
+
+ ~DxvkShaderModule();
+
+ DxvkShaderModule& operator = (DxvkShaderModule&& other);
+
+ /**
+ * \brief Shader stage creation info
+ *
+ * \param [in] specInfo Specialization info
+ * \returns Shader stage create info
+ */
+ VkPipelineShaderStageCreateInfo stageInfo(
+ const VkSpecializationInfo* specInfo) const {
+ VkPipelineShaderStageCreateInfo stage = m_stage;
+ stage.pSpecializationInfo = specInfo;
+ return stage;
+ }
+
+ /**
+ * \brief Checks whether module is valid
+ * \returns \c true if module is valid
+ */
+ operator bool () const {
+ return m_stage.module != VK_NULL_HANDLE;
+ }
+
+ private:
+
+ Rc<vk::DeviceFn> m_vkd;
+ VkPipelineShaderStageCreateInfo m_stage;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.cpp
new file mode 100644
index 00000000..0272a071
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.cpp
@@ -0,0 +1,43 @@
+#include "dxvk_shader_key.h"
+
+namespace dxvk {
+
+ DxvkShaderKey::DxvkShaderKey()
+ : m_type(0),
+ m_sha1(Sha1Hash::compute(nullptr, 0)) { }
+
+
+ std::string DxvkShaderKey::toString() const {
+ const char* prefix = nullptr;
+
+ switch (m_type) {
+ case VK_SHADER_STAGE_VERTEX_BIT: prefix = "VS_"; break;
+ case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: prefix = "TCS_"; break;
+ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: prefix = "TES_"; break;
+ case VK_SHADER_STAGE_GEOMETRY_BIT: prefix = "GS_"; break;
+ case VK_SHADER_STAGE_FRAGMENT_BIT: prefix = "FS_"; break;
+ case VK_SHADER_STAGE_COMPUTE_BIT: prefix = "CS_"; break;
+ default: prefix = "";
+ }
+
+ return str::format(prefix, m_sha1.toString());
+ }
+
+
+ size_t DxvkShaderKey::hash() const {
+ DxvkHashState result;
+ result.add(uint32_t(m_type));
+
+ for (uint32_t i = 0; i < 5; i++)
+ result.add(m_sha1.dword(i));
+
+ return result;
+ }
+
+
+ bool DxvkShaderKey::eq(const DxvkShaderKey& key) const {
+ return m_type == key.m_type
+ && m_sha1 == key.m_sha1;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.h
new file mode 100644
index 00000000..4a66e528
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_shader_key.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "dxvk_hash.h"
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Shader key
+ *
+ * Provides a unique key that can be used
+ * to look up a specific shader within a
+ * structure. This consists of the shader
+ * stage and the source hash, which should
+ * be generated from the original code.
+ */
+ class DxvkShaderKey {
+
+ public:
+
+ /**
+ * \brief Creates default shader key
+ */
+ DxvkShaderKey();
+
+ /**
+ * \brief Creates shader key
+ *
+ * \param [in] stage Shader stage
+ * \param [in] hash Shader hash
+ */
+ DxvkShaderKey(
+ VkShaderStageFlagBits stage,
+ Sha1Hash hash)
+ : m_type(stage), m_sha1(hash) { }
+
+ /**
+ * \brief Generates string from shader key
+ * \returns String representation of the key
+ */
+ std::string toString() const;
+
+ /**
+ * \brief Computes lookup hash
+ * \returns Lookup hash
+ */
+ size_t hash() const;
+
+ /**
+ * \brief Shader type
+ * \returns Shader type
+ */
+ VkShaderStageFlags type() const { return m_type; }
+
+ /**
+ * \brief Shader SHA1
+ * \returns Shader SHA1
+ */
+ const Sha1Hash& sha1() const { return m_sha1; }
+
+ /**
+ * \brief Checks whether two keys are equal
+ *
+ * \param [in] key The shader key to compare to
+ * \returns \c true if the two keys are equal
+ */
+ bool eq(const DxvkShaderKey& key) const;
+
+ private:
+
+ VkShaderStageFlags m_type;
+ Sha1Hash m_sha1;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.cpp
new file mode 100644
index 00000000..3bb87452
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.cpp
@@ -0,0 +1,30 @@
+#include "dxvk_signal.h"
+
+namespace dxvk {
+
+ DxvkSignalTracker::DxvkSignalTracker() {
+
+ }
+
+
+ DxvkSignalTracker::~DxvkSignalTracker() {
+
+ }
+
+
+ void DxvkSignalTracker::add(const Rc<sync::Signal>& signal, uint64_t value) {
+ m_signals.push_back({ signal, value });
+ }
+
+
+ void DxvkSignalTracker::notify() {
+ for (const auto& pair : m_signals)
+ pair.first->signal(pair.second);
+ }
+
+
+ void DxvkSignalTracker::reset() {
+ m_signals.clear();
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.h
new file mode 100644
index 00000000..fa99f781
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_signal.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Signal tracker
+ */
+ class DxvkSignalTracker {
+
+ public:
+
+ DxvkSignalTracker();
+ ~DxvkSignalTracker();
+
+ /**
+ * \brief Adds a signal to track
+ *
+ * \param [in] signal The signal
+ * \param [in] value Target value
+ */
+ void add(const Rc<sync::Signal>& signal, uint64_t value);
+
+ /**
+ * \brief Notifies tracked signals
+ */
+ void notify();
+
+ /**
+ * \brief Resets signal tracker
+ */
+ void reset();
+
+ private:
+
+ std::vector<std::pair<Rc<sync::Signal>, uint64_t>> m_signals;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.cpp
new file mode 100644
index 00000000..eec6d8ae
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.cpp
@@ -0,0 +1,36 @@
+#include "dxvk_spec_const.h"
+
+namespace dxvk {
+
+ DxvkSpecConstants::DxvkSpecConstants() {
+
+ }
+
+
+ DxvkSpecConstants::~DxvkSpecConstants() {
+
+ }
+
+
+ VkSpecializationInfo DxvkSpecConstants::getSpecInfo() const {
+ VkSpecializationInfo specInfo;
+ specInfo.mapEntryCount = m_map.size();
+ specInfo.pMapEntries = m_map.data();
+ specInfo.dataSize = m_data.size() * sizeof(uint32_t);
+ specInfo.pData = m_data.data();
+ return specInfo;
+ }
+
+
+ void DxvkSpecConstants::setAsUint32(uint32_t specId, uint32_t value) {
+ uint32_t index = m_data.size();
+ m_data.push_back(value);
+
+ VkSpecializationMapEntry mapEntry;
+ mapEntry.constantID = specId;
+ mapEntry.offset = sizeof(uint32_t) * index;
+ mapEntry.size = sizeof(uint32_t);
+ m_map.push_back(mapEntry);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.h
new file mode 100644
index 00000000..df4f041c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_spec_const.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "dxvk_limits.h"
+#include "dxvk_shader.h"
+
+namespace dxvk {
+
+ /**
+ * \briefS Specialization constant entry
+ *
+ * Used to pass a list of user-defined
+ * specialization constants to shaders.
+ */
+ struct DxvkSpecConstant {
+ uint32_t specId;
+ uint32_t value;
+ };
+
+
+ /**
+ * \brief Specialization constant info
+ *
+ * Accumulates specialization constant data for
+ * constants that use non-default values.
+ */
+ class DxvkSpecConstants {
+
+ public:
+
+ DxvkSpecConstants();
+
+ ~DxvkSpecConstants();
+
+ /**
+ * \brief Sets specialization constant value
+ *
+ * If the given value is different from the constant's
+ * default value, this will store the new value and add
+ * a map entry so that it gets applied properly. Each
+ * constant may only be set once.
+ * \param [in] specId Specialization constant ID
+ * \param [in] value Specialization constant value
+ * \param [in] defaultValue Default value
+ */
+ template<typename T>
+ void set(uint32_t specId, T value, T defaultValue) {
+ if (value != defaultValue)
+ setAsUint32(specId, uint32_t(value));
+ }
+
+ /**
+ * \brief Sets specialization constant value
+ *
+ * Always passes the constant value to the driver.
+ * \param [in] specId Specialization constant ID
+ * \param [in] value Specialization constant value
+ */
+ template<typename T>
+ void set(uint32_t specId, T value) {
+ setAsUint32(specId, uint32_t(value));
+ }
+
+ /**
+ * \brief Generates specialization info structure
+ * \returns Specialization info for shader module
+ */
+ VkSpecializationInfo getSpecInfo() const;
+
+ private:
+
+ std::vector<uint32_t> m_data = { };
+ std::vector<VkSpecializationMapEntry> m_map = { };
+
+ void setAsUint32(uint32_t specId, uint32_t value);
+
+ };
+
+
+ /**
+ * \brief Computes specialization constant ID
+ *
+ * Computest the specId to use within shaders
+ * for a given pipeline specialization constant.
+ * \param [in] index Spec constant index
+ * \returns Specialization constant ID
+ */
+ inline uint32_t getSpecId(uint32_t index) {
+ return uint32_t(DxvkSpecConstantId::FirstPipelineConstant) + index;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.cpp
new file mode 100644
index 00000000..dd2a1fd2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.cpp
@@ -0,0 +1,70 @@
+#include "dxvk_device.h"
+#include "dxvk_staging.h"
+
+namespace dxvk {
+
+ DxvkStagingDataAlloc::DxvkStagingDataAlloc(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ DxvkStagingDataAlloc::~DxvkStagingDataAlloc() {
+
+ }
+
+
+ DxvkBufferSlice DxvkStagingDataAlloc::alloc(VkDeviceSize align, VkDeviceSize size) {
+ if (size > MaxBufferSize)
+ return DxvkBufferSlice(createBuffer(size));
+
+ if (m_buffer == nullptr)
+ m_buffer = createBuffer(MaxBufferSize);
+
+ if (!m_buffer->isInUse())
+ m_offset = 0;
+
+ m_offset = dxvk::align(m_offset, align);
+
+ if (m_offset + size > MaxBufferSize) {
+ m_offset = 0;
+
+ if (m_buffers.size() < MaxBufferCount)
+ m_buffers.push(std::move(m_buffer));
+
+ if (!m_buffers.front()->isInUse()) {
+ m_buffer = std::move(m_buffers.front());
+ m_buffers.pop();
+ } else {
+ m_buffer = createBuffer(MaxBufferSize);
+ }
+ }
+
+ DxvkBufferSlice slice(m_buffer, m_offset, size);
+ m_offset = dxvk::align(m_offset + size, align);
+ return slice;
+ }
+
+
+ void DxvkStagingDataAlloc::trim() {
+ m_buffer = nullptr;
+ m_offset = 0;
+
+ while (!m_buffers.empty())
+ m_buffers.pop();
+ }
+
+
+ Rc<DxvkBuffer> DxvkStagingDataAlloc::createBuffer(VkDeviceSize size) {
+ DxvkBufferCreateInfo info;
+ info.size = size;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ info.access = VK_ACCESS_TRANSFER_READ_BIT;
+
+ return m_device->createBuffer(info,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.h
new file mode 100644
index 00000000..8eccd4f5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_staging.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <queue>
+
+#include "dxvk_buffer.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief Staging data allocator
+ *
+ * Allocates buffer slices for resource uploads,
+ * while trying to keep the number of allocations
+ * but also the amount of allocated memory low.
+ */
+ class DxvkStagingDataAlloc {
+ constexpr static VkDeviceSize MaxBufferSize = 1 << 25; // 32 MiB
+ constexpr static uint32_t MaxBufferCount = 2;
+ public:
+
+ DxvkStagingDataAlloc(const Rc<DxvkDevice>& device);
+
+ ~DxvkStagingDataAlloc();
+
+ /**
+ * \brief Alloctaes a staging buffer slice
+ *
+ * \param [in] align Alignment of the allocation
+ * \param [in] size Size of the allocation
+ * \returns Staging buffer slice
+ */
+ DxvkBufferSlice alloc(VkDeviceSize align, VkDeviceSize size);
+
+ /**
+ * \brief Deletes all staging buffers
+ *
+ * Destroys allocated buffers and
+ * releases all buffer memory.
+ */
+ void trim();
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+ Rc<DxvkBuffer> m_buffer;
+ VkDeviceSize m_offset = 0;
+
+ std::queue<Rc<DxvkBuffer>> m_buffers;
+
+ Rc<DxvkBuffer> createBuffer(VkDeviceSize size);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.cpp
new file mode 100644
index 00000000..0e230ff0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.cpp
@@ -0,0 +1,1059 @@
+#include "dxvk_device.h"
+#include "dxvk_pipemanager.h"
+#include "dxvk_state_cache.h"
+
+namespace dxvk {
+
+ static const Sha1Hash g_nullHash = Sha1Hash::compute(nullptr, 0);
+ static const DxvkShaderKey g_nullShaderKey = DxvkShaderKey();
+
+
+ /**
+ * \brief Packed entry header
+ */
+ struct DxvkStateCacheEntryHeader {
+ uint32_t stageMask : 8;
+ uint32_t entrySize : 24;
+ };
+
+
+ /**
+ * \brief State cache entry data
+ *
+ * Stores data for a single cache entry and
+ * provides convenience methods to access it.
+ */
+ class DxvkStateCacheEntryData {
+ constexpr static size_t MaxSize = 1024;
+ public:
+
+ size_t size() const {
+ return m_size;
+ }
+
+ const char* data() const {
+ return m_data;
+ }
+
+ Sha1Hash computeHash() const {
+ return Sha1Hash::compute(m_data, m_size);
+ }
+
+ template<typename T>
+ bool read(T& data, uint32_t version) {
+ return read(data);
+ }
+
+ bool read(DxvkBindingMask& data, uint32_t version) {
+ if (version < 9) {
+ DxvkBindingMaskV8 v8;
+
+ if (!read(v8))
+ return false;
+
+ data = v8.convert();
+ return true;
+ }
+
+ return read(data);
+ }
+
+ bool read(DxvkIlBinding& data, uint32_t version) {
+ if (version < 10) {
+ DxvkIlBindingV9 v9;
+
+ if (!read(v9))
+ return false;
+
+ data = v9.convert();
+ return true;
+ }
+
+ return read(data);
+ }
+
+ template<typename T>
+ bool write(const T& data) {
+ if (m_size + sizeof(T) > MaxSize)
+ return false;
+
+ std::memcpy(&m_data[m_size], &data, sizeof(T));
+ m_size += sizeof(T);
+ return true;
+ }
+
+ bool readFromStream(std::istream& stream, size_t size) {
+ if (size > MaxSize)
+ return false;
+
+ if (!stream.read(m_data, size))
+ return false;
+
+ m_size = size;
+ m_read = 0;
+ return true;
+ }
+
+ private:
+
+ size_t m_size = 0;
+ size_t m_read = 0;
+ char m_data[MaxSize];
+
+ template<typename T>
+ bool read(T& data) {
+ if (m_read + sizeof(T) > m_size)
+ return false;
+
+ std::memcpy(&data, &m_data[m_read], sizeof(T));
+ m_read += sizeof(T);
+ return true;
+ }
+
+ };
+
+
+ template<typename T>
+ bool readCacheEntryTyped(std::istream& stream, T& entry) {
+ auto data = reinterpret_cast<char*>(&entry);
+ auto size = sizeof(entry);
+
+ if (!stream.read(data, size))
+ return false;
+
+ Sha1Hash expectedHash = std::exchange(entry.hash, g_nullHash);
+ Sha1Hash computedHash = Sha1Hash::compute(entry);
+ return expectedHash == computedHash;
+ }
+
+
+ bool DxvkStateCacheKey::eq(const DxvkStateCacheKey& key) const {
+ return this->vs.eq(key.vs)
+ && this->tcs.eq(key.tcs)
+ && this->tes.eq(key.tes)
+ && this->gs.eq(key.gs)
+ && this->fs.eq(key.fs)
+ && this->cs.eq(key.cs);
+ }
+
+
+ size_t DxvkStateCacheKey::hash() const {
+ DxvkHashState hash;
+ hash.add(this->vs.hash());
+ hash.add(this->tcs.hash());
+ hash.add(this->tes.hash());
+ hash.add(this->gs.hash());
+ hash.add(this->fs.hash());
+ hash.add(this->cs.hash());
+ return hash;
+ }
+
+
+ DxvkStateCache::DxvkStateCache(
+ const DxvkDevice* device,
+ DxvkPipelineManager* pipeManager,
+ DxvkRenderPassPool* passManager)
+ : m_pipeManager(pipeManager),
+ m_passManager(passManager) {
+ bool newFile = !readCacheFile();
+
+ if (newFile) {
+ Logger::warn("DXVK: Creating new state cache file");
+
+ // Start with an empty file
+ std::ofstream file(getCacheFileName().c_str(),
+ std::ios_base::binary |
+ std::ios_base::trunc);
+
+ if (!file && env::createDirectory(getCacheDir())) {
+ file = std::ofstream(getCacheFileName().c_str(),
+ std::ios_base::binary |
+ std::ios_base::trunc);
+ }
+
+ // Write header with the current version number
+ DxvkStateCacheHeader header;
+
+ auto data = reinterpret_cast<const char*>(&header);
+ auto size = sizeof(header);
+
+ file.write(data, size);
+
+ // Write all valid entries to the cache file in
+ // case we're recovering a corrupted cache file
+ for (auto& e : m_entries)
+ writeCacheEntry(file, e);
+ }
+
+ // Use half the available CPU cores for pipeline compilation
+ uint32_t numCpuCores = dxvk::thread::hardware_concurrency();
+ uint32_t numWorkers = ((std::max(1u, numCpuCores) - 1) * 5) / 7;
+
+ if (numWorkers < 1) numWorkers = 1;
+ if (numWorkers > 32) numWorkers = 32;
+
+ if (device->config().numCompilerThreads > 0)
+ numWorkers = device->config().numCompilerThreads;
+
+ Logger::info(str::format("DXVK: Using ", numWorkers, " compiler threads"));
+
+ // Start the worker threads and the file writer
+ m_workerBusy.store(numWorkers);
+
+ for (uint32_t i = 0; i < numWorkers; i++) {
+ m_workerThreads.emplace_back([this] () { workerFunc(); });
+
+ // TODO: better solution for this.
+#ifndef DXVK_NATIVE
+ m_workerThreads[i].set_priority(ThreadPriority::Lowest);
+#endif
+ }
+
+ m_writerThread = dxvk::thread([this] () { writerFunc(); });
+ }
+
+
+ DxvkStateCache::~DxvkStateCache() {
+ this->stopWorkerThreads();
+ }
+
+
+ void DxvkStateCache::addGraphicsPipeline(
+ const DxvkStateCacheKey& shaders,
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPassFormat& format) {
+ if (shaders.vs.eq(g_nullShaderKey))
+ return;
+
+ // Do not add an entry that is already in the cache
+ auto entries = m_entryMap.equal_range(shaders);
+
+ for (auto e = entries.first; e != entries.second; e++) {
+ const DxvkStateCacheEntry& entry = m_entries[e->second];
+
+ if (entry.format.eq(format) && entry.gpState == state)
+ return;
+ }
+
+ // Queue a job to write this pipeline to the cache
+ std::unique_lock<dxvk::mutex> lock(m_writerLock);
+
+ m_writerQueue.push({ shaders, state,
+ DxvkComputePipelineStateInfo(),
+ format, g_nullHash });
+ m_writerCond.notify_one();
+ }
+
+
+ void DxvkStateCache::addComputePipeline(
+ const DxvkStateCacheKey& shaders,
+ const DxvkComputePipelineStateInfo& state) {
+ if (shaders.cs.eq(g_nullShaderKey))
+ return;
+
+ // Do not add an entry that is already in the cache
+ auto entries = m_entryMap.equal_range(shaders);
+
+ for (auto e = entries.first; e != entries.second; e++) {
+ if (m_entries[e->second].cpState == state)
+ return;
+ }
+
+ // Queue a job to write this pipeline to the cache
+ std::unique_lock<dxvk::mutex> lock(m_writerLock);
+
+ m_writerQueue.push({ shaders,
+ DxvkGraphicsPipelineStateInfo(), state,
+ DxvkRenderPassFormat(), g_nullHash });
+ m_writerCond.notify_one();
+ }
+
+
+ void DxvkStateCache::registerShader(const Rc<DxvkShader>& shader) {
+ DxvkShaderKey key = shader->getShaderKey();
+
+ if (key.eq(g_nullShaderKey))
+ return;
+
+ // Add the shader so we can look it up by its key
+ std::unique_lock<dxvk::mutex> entryLock(m_entryLock);
+ m_shaderMap.insert({ key, shader });
+
+ // Deferred lock, don't stall workers unless we have to
+ std::unique_lock<dxvk::mutex> workerLock;
+
+ auto pipelines = m_pipelineMap.equal_range(key);
+
+ for (auto p = pipelines.first; p != pipelines.second; p++) {
+ WorkerItem item;
+
+ if (!getShaderByKey(p->second.vs, item.gp.vs)
+ || !getShaderByKey(p->second.tcs, item.gp.tcs)
+ || !getShaderByKey(p->second.tes, item.gp.tes)
+ || !getShaderByKey(p->second.gs, item.gp.gs)
+ || !getShaderByKey(p->second.fs, item.gp.fs)
+ || !getShaderByKey(p->second.cs, item.cp.cs))
+ continue;
+
+ if (!workerLock)
+ workerLock = std::unique_lock<dxvk::mutex>(m_workerLock);
+
+ m_workerQueue.push(item);
+ }
+
+ if (workerLock)
+ m_workerCond.notify_all();
+ }
+
+
+ void DxvkStateCache::stopWorkerThreads() {
+ { std::lock_guard<dxvk::mutex> workerLock(m_workerLock);
+ std::lock_guard<dxvk::mutex> writerLock(m_writerLock);
+
+ if (m_stopThreads.exchange(true))
+ return;
+
+ m_workerCond.notify_all();
+ m_writerCond.notify_all();
+ }
+
+ for (auto& worker : m_workerThreads)
+ worker.join();
+
+ m_writerThread.join();
+ }
+
+
+ DxvkShaderKey DxvkStateCache::getShaderKey(const Rc<DxvkShader>& shader) const {
+ return shader != nullptr ? shader->getShaderKey() : g_nullShaderKey;
+ }
+
+
+ bool DxvkStateCache::getShaderByKey(
+ const DxvkShaderKey& key,
+ Rc<DxvkShader>& shader) const {
+ if (key.eq(g_nullShaderKey))
+ return true;
+
+ auto entry = m_shaderMap.find(key);
+ if (entry == m_shaderMap.end())
+ return false;
+
+ shader = entry->second;
+ return true;
+ }
+
+
+ void DxvkStateCache::mapPipelineToEntry(
+ const DxvkStateCacheKey& key,
+ size_t entryId) {
+ m_entryMap.insert({ key, entryId });
+ }
+
+
+ void DxvkStateCache::mapShaderToPipeline(
+ const DxvkShaderKey& shader,
+ const DxvkStateCacheKey& key) {
+ if (!shader.eq(g_nullShaderKey))
+ m_pipelineMap.insert({ shader, key });
+ }
+
+
+ void DxvkStateCache::compilePipelines(const WorkerItem& item) {
+ DxvkStateCacheKey key;
+ key.vs = getShaderKey(item.gp.vs);
+ key.tcs = getShaderKey(item.gp.tcs);
+ key.tes = getShaderKey(item.gp.tes);
+ key.gs = getShaderKey(item.gp.gs);
+ key.fs = getShaderKey(item.gp.fs);
+ key.cs = getShaderKey(item.cp.cs);
+
+ if (item.cp.cs == nullptr) {
+ auto pipeline = m_pipeManager->createGraphicsPipeline(item.gp);
+ auto entries = m_entryMap.equal_range(key);
+
+ for (auto e = entries.first; e != entries.second; e++) {
+ const auto& entry = m_entries[e->second];
+
+ auto rp = m_passManager->getRenderPass(entry.format);
+ pipeline->compilePipeline(entry.gpState, rp);
+ }
+ } else {
+ auto pipeline = m_pipeManager->createComputePipeline(item.cp);
+ auto entries = m_entryMap.equal_range(key);
+
+ for (auto e = entries.first; e != entries.second; e++) {
+ const auto& entry = m_entries[e->second];
+ pipeline->compilePipeline(entry.cpState);
+ }
+ }
+ }
+
+
+ bool DxvkStateCache::readCacheFile() {
+ // Open state file and just fail if it doesn't exist
+ std::ifstream ifile(getCacheFileName().c_str(), std::ios_base::binary);
+
+ if (!ifile) {
+ Logger::warn("DXVK: No state cache file found");
+ return false;
+ }
+
+ // The header stores the state cache version,
+ // we need to regenerate it if it's outdated
+ DxvkStateCacheHeader newHeader;
+ DxvkStateCacheHeader curHeader;
+
+ if (!readCacheHeader(ifile, curHeader)) {
+ Logger::warn("DXVK: Failed to read state cache header");
+ return false;
+ }
+
+ // Struct size hasn't changed between v2 and v4
+ size_t expectedSize = newHeader.entrySize;
+
+ if (curHeader.version <= 4)
+ expectedSize = sizeof(DxvkStateCacheEntryV4);
+ else if (curHeader.version <= 5)
+ expectedSize = sizeof(DxvkStateCacheEntryV5);
+ else if (curHeader.version <= 6)
+ expectedSize = sizeof(DxvkStateCacheEntryV6);
+ else if (curHeader.version <= 7)
+ expectedSize = sizeof(DxvkStateCacheEntry);
+
+ if (curHeader.entrySize != expectedSize) {
+ Logger::warn("DXVK: State cache entry size changed");
+ return false;
+ }
+
+ // Discard caches of unsupported versions
+ if (curHeader.version < 2 || curHeader.version > newHeader.version) {
+ Logger::warn("DXVK: State cache version not supported");
+ return false;
+ }
+
+ // Notify user about format conversion
+ if (curHeader.version != newHeader.version)
+ Logger::warn(str::format("DXVK: Updating state cache version to v", newHeader.version));
+
+ // Read actual cache entries from the file.
+ // If we encounter invalid entries, we should
+ // regenerate the entire state cache file.
+ uint32_t numInvalidEntries = 0;
+
+ while (ifile) {
+ DxvkStateCacheEntry entry;
+
+ if (readCacheEntry(curHeader.version, ifile, entry)) {
+ size_t entryId = m_entries.size();
+ m_entries.push_back(entry);
+
+ mapPipelineToEntry(entry.shaders, entryId);
+
+ mapShaderToPipeline(entry.shaders.vs, entry.shaders);
+ mapShaderToPipeline(entry.shaders.tcs, entry.shaders);
+ mapShaderToPipeline(entry.shaders.tes, entry.shaders);
+ mapShaderToPipeline(entry.shaders.gs, entry.shaders);
+ mapShaderToPipeline(entry.shaders.fs, entry.shaders);
+ mapShaderToPipeline(entry.shaders.cs, entry.shaders);
+ } else if (ifile) {
+ numInvalidEntries += 1;
+ }
+ }
+
+ Logger::info(str::format(
+ "DXVK: Read ", m_entries.size(),
+ " valid state cache entries"));
+
+ if (numInvalidEntries) {
+ Logger::warn(str::format(
+ "DXVK: Skipped ", numInvalidEntries,
+ " invalid state cache entries"));
+ return false;
+ }
+
+ // Rewrite entire state cache if it is outdated
+ return curHeader.version == newHeader.version;
+ }
+
+
+ bool DxvkStateCache::readCacheHeader(
+ std::istream& stream,
+ DxvkStateCacheHeader& header) const {
+ DxvkStateCacheHeader expected;
+
+ auto data = reinterpret_cast<char*>(&header);
+ auto size = sizeof(header);
+
+ if (!stream.read(data, size))
+ return false;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ if (expected.magic[i] != header.magic[i])
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool DxvkStateCache::readCacheEntryV7(
+ uint32_t version,
+ std::istream& stream,
+ DxvkStateCacheEntry& entry) const {
+ if (version <= 6) {
+ DxvkStateCacheEntryV6 v6;
+
+ if (version <= 4) {
+ DxvkStateCacheEntryV4 v4;
+
+ if (!readCacheEntryTyped(stream, v4))
+ return false;
+
+ if (version == 2)
+ convertEntryV2(v4);
+
+ if (!convertEntryV4(v4, v6))
+ return false;
+ } else if (version <= 5) {
+ DxvkStateCacheEntryV5 v5;
+
+ if (!readCacheEntryTyped(stream, v5))
+ return false;
+
+ if (!convertEntryV5(v5, v6))
+ return false;
+ } else {
+ if (!readCacheEntryTyped(stream, v6))
+ return false;
+ }
+
+ return convertEntryV6(v6, entry);
+ } else {
+ return readCacheEntryTyped(stream, entry);
+ }
+ }
+
+
+ bool DxvkStateCache::readCacheEntry(
+ uint32_t version,
+ std::istream& stream,
+ DxvkStateCacheEntry& entry) const {
+ if (version < 8)
+ return readCacheEntryV7(version, stream, entry);
+
+ // Read entry metadata and actual data
+ DxvkStateCacheEntryHeader header;
+ DxvkStateCacheEntryData data;
+ Sha1Hash hash;
+
+ if (!stream.read(reinterpret_cast<char*>(&header), sizeof(header))
+ || !stream.read(reinterpret_cast<char*>(&hash), sizeof(hash))
+ || !data.readFromStream(stream, header.entrySize))
+ return false;
+
+ // Validate hash, skip entry if invalid
+ if (hash != data.computeHash())
+ return false;
+
+ // Read shader hashes
+ VkShaderStageFlags stageMask = VkShaderStageFlags(header.stageMask);
+ auto keys = &entry.shaders.vs;
+
+ for (uint32_t i = 0; i < 6; i++) {
+ if (stageMask & VkShaderStageFlagBits(1 << i))
+ data.read(keys[i], version);
+ else
+ keys[i] = g_nullShaderKey;
+ }
+
+ if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT) {
+ if (!data.read(entry.cpState.bsBindingMask, version))
+ return false;
+ } else {
+ // Read packed render pass format
+ uint8_t sampleCount = 0;
+ uint8_t imageFormat = 0;
+ uint8_t imageLayout = 0;
+
+ if (!data.read(sampleCount, version)
+ || !data.read(imageFormat, version)
+ || !data.read(imageLayout, version))
+ return false;
+
+ entry.format.sampleCount = VkSampleCountFlagBits(sampleCount);
+ entry.format.depth.format = VkFormat(imageFormat);
+ entry.format.depth.layout = unpackImageLayout(imageLayout);
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (!data.read(imageFormat, version)
+ || !data.read(imageLayout, version))
+ return false;
+
+ entry.format.color[i].format = VkFormat(imageFormat);
+ entry.format.color[i].layout = unpackImageLayout(imageLayout);
+ }
+
+ if (!validateRenderPassFormat(entry.format))
+ return false;
+
+ // Read common pipeline state
+ if (!data.read(entry.gpState.bsBindingMask, version)
+ || !data.read(entry.gpState.ia, version)
+ || !data.read(entry.gpState.il, version)
+ || !data.read(entry.gpState.rs, version)
+ || !data.read(entry.gpState.ms, version)
+ || !data.read(entry.gpState.ds, version)
+ || !data.read(entry.gpState.om, version)
+ || !data.read(entry.gpState.dsFront, version)
+ || !data.read(entry.gpState.dsBack, version))
+ return false;
+
+ if (entry.gpState.il.attributeCount() > MaxNumVertexAttributes
+ || entry.gpState.il.bindingCount() > MaxNumVertexBindings)
+ return false;
+
+ // Read render target swizzles
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (!data.read(entry.gpState.omSwizzle[i], version))
+ return false;
+ }
+
+ // Read render target blend info
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ if (!data.read(entry.gpState.omBlend[i], version))
+ return false;
+ }
+
+ // Read defined vertex attributes
+ for (uint32_t i = 0; i < entry.gpState.il.attributeCount(); i++) {
+ if (!data.read(entry.gpState.ilAttributes[i], version))
+ return false;
+ }
+
+ // Read defined vertex bindings
+ for (uint32_t i = 0; i < entry.gpState.il.bindingCount(); i++) {
+ if (!data.read(entry.gpState.ilBindings[i], version))
+ return false;
+ }
+ }
+
+ // Read non-zero spec constants
+ auto& sc = (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
+ ? entry.cpState.sc
+ : entry.gpState.sc;
+
+ uint32_t specConstantMask = 0;
+
+ if (!data.read(specConstantMask, version))
+ return false;
+
+ for (uint32_t i = 0; i < MaxNumSpecConstants; i++) {
+ if (specConstantMask & (1 << i)) {
+ if (!data.read(sc.specConstants[i], version))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ void DxvkStateCache::writeCacheEntry(
+ std::ostream& stream,
+ DxvkStateCacheEntry& entry) const {
+ DxvkStateCacheEntryData data;
+ VkShaderStageFlags stageMask = 0;
+
+ // Write shader hashes
+ auto keys = &entry.shaders.vs;
+
+ for (uint32_t i = 0; i < 6; i++) {
+ if (!keys[i].eq(g_nullShaderKey)) {
+ stageMask |= VkShaderStageFlagBits(1 << i);
+ data.write(keys[i]);
+ }
+ }
+
+ if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT) {
+ // Nothing else here to write out
+ data.write(entry.cpState.bsBindingMask);
+ } else {
+ // Pack render pass format
+ data.write(uint8_t(entry.format.sampleCount));
+ data.write(uint8_t(entry.format.depth.format));
+ data.write(packImageLayout(entry.format.depth.layout));
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
+ data.write(uint8_t(entry.format.color[i].format));
+ data.write(packImageLayout(entry.format.color[i].layout));
+ }
+
+ // Write out common pipeline state
+ data.write(entry.gpState.bsBindingMask);
+ data.write(entry.gpState.ia);
+ data.write(entry.gpState.il);
+ data.write(entry.gpState.rs);
+ data.write(entry.gpState.ms);
+ data.write(entry.gpState.ds);
+ data.write(entry.gpState.om);
+ data.write(entry.gpState.dsFront);
+ data.write(entry.gpState.dsBack);
+
+ // Write out render target swizzles and blend info
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
+ data.write(entry.gpState.omSwizzle[i]);
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
+ data.write(entry.gpState.omBlend[i]);
+
+ // Write out input layout for defined attributes
+ for (uint32_t i = 0; i < entry.gpState.il.attributeCount(); i++)
+ data.write(entry.gpState.ilAttributes[i]);
+
+ for (uint32_t i = 0; i < entry.gpState.il.bindingCount(); i++)
+ data.write(entry.gpState.ilBindings[i]);
+ }
+
+ // Write out all non-zero spec constants
+ auto& sc = (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
+ ? entry.cpState.sc
+ : entry.gpState.sc;
+
+ uint32_t specConstantMask = 0;
+
+ for (uint32_t i = 0; i < MaxNumSpecConstants; i++)
+ specConstantMask |= sc.specConstants[i] ? (1 << i) : 0;
+
+ data.write(specConstantMask);
+
+ for (uint32_t i = 0; i < MaxNumSpecConstants; i++) {
+ if (specConstantMask & (1 << i))
+ data.write(sc.specConstants[i]);
+ }
+
+ // General layout: header -> hash -> data
+ DxvkStateCacheEntryHeader header;
+ header.stageMask = uint8_t(stageMask);
+ header.entrySize = data.size();
+
+ Sha1Hash hash = data.computeHash();
+
+ stream.write(reinterpret_cast<char*>(&header), sizeof(header));
+ stream.write(reinterpret_cast<char*>(&hash), sizeof(hash));
+ stream.write(data.data(), data.size());
+ stream.flush();
+ }
+
+
+ bool DxvkStateCache::convertEntryV2(
+ DxvkStateCacheEntryV4& entry) const {
+ // Semantics changed:
+ // v2: rsDepthClampEnable
+ // v3: rsDepthClipEnable
+ entry.gpState.rsDepthClipEnable = !entry.gpState.rsDepthClipEnable;
+
+ // Frontend changed: Depth bias
+ // will typically be disabled
+ entry.gpState.rsDepthBiasEnable = VK_FALSE;
+ return true;
+ }
+
+
+ bool DxvkStateCache::convertEntryV4(
+ const DxvkStateCacheEntryV4& in,
+ DxvkStateCacheEntryV6& out) const {
+ out.shaders = in.shaders;
+ out.format = in.format;
+ out.hash = in.hash;
+
+ out.cpState.bsBindingMask = in.cpState.bsBindingMask;
+ out.gpState.bsBindingMask = in.gpState.bsBindingMask;
+
+ out.gpState.iaPrimitiveTopology = in.gpState.iaPrimitiveTopology;
+ out.gpState.iaPrimitiveRestart = in.gpState.iaPrimitiveRestart;
+ out.gpState.iaPatchVertexCount = in.gpState.iaPatchVertexCount;
+
+ out.gpState.ilAttributeCount = in.gpState.ilAttributeCount;
+ out.gpState.ilBindingCount = in.gpState.ilBindingCount;
+
+ for (uint32_t i = 0; i < in.gpState.ilAttributeCount; i++)
+ out.gpState.ilAttributes[i] = in.gpState.ilAttributes[i];
+
+ for (uint32_t i = 0; i < in.gpState.ilBindingCount; i++) {
+ out.gpState.ilBindings[i] = in.gpState.ilBindings[i];
+ out.gpState.ilDivisors[i] = in.gpState.ilDivisors[i];
+ }
+
+ out.gpState.rsDepthClipEnable = in.gpState.rsDepthClipEnable;
+ out.gpState.rsDepthBiasEnable = in.gpState.rsDepthBiasEnable;
+ out.gpState.rsPolygonMode = in.gpState.rsPolygonMode;
+ out.gpState.rsCullMode = in.gpState.rsCullMode;
+ out.gpState.rsFrontFace = in.gpState.rsFrontFace;
+ out.gpState.rsViewportCount = in.gpState.rsViewportCount;
+ out.gpState.rsSampleCount = in.gpState.rsSampleCount;
+
+ out.gpState.msSampleCount = in.gpState.msSampleCount;
+ out.gpState.msSampleMask = in.gpState.msSampleMask;
+ out.gpState.msEnableAlphaToCoverage = in.gpState.msEnableAlphaToCoverage;
+
+ out.gpState.dsEnableDepthTest = in.gpState.dsEnableDepthTest;
+ out.gpState.dsEnableDepthWrite = in.gpState.dsEnableDepthWrite;
+ out.gpState.dsEnableStencilTest = in.gpState.dsEnableStencilTest;
+ out.gpState.dsDepthCompareOp = in.gpState.dsDepthCompareOp;
+ out.gpState.dsStencilOpFront = in.gpState.dsStencilOpFront;
+ out.gpState.dsStencilOpBack = in.gpState.dsStencilOpBack;
+
+ out.gpState.omEnableLogicOp = in.gpState.omEnableLogicOp;
+ out.gpState.omLogicOp = in.gpState.omLogicOp;
+
+ for (uint32_t i = 0; i < 8; i++) {
+ out.gpState.omBlendAttachments[i] = in.gpState.omBlendAttachments[i];
+ out.gpState.omComponentMapping[i] = in.gpState.omComponentMapping[i];
+ }
+
+ return true;
+ }
+
+
+ bool DxvkStateCache::convertEntryV5(
+ const DxvkStateCacheEntryV5& in,
+ DxvkStateCacheEntryV6& out) const {
+ out.shaders = in.shaders;
+ out.gpState = in.gpState;
+ out.format = in.format;
+ out.hash = in.hash;
+
+ out.cpState.bsBindingMask = in.cpState.bsBindingMask;
+ return true;
+ }
+
+
+ bool DxvkStateCache::convertEntryV6(
+ const DxvkStateCacheEntryV6& in,
+ DxvkStateCacheEntry& out) const {
+ out.shaders = in.shaders;
+ out.format = in.format;
+ out.hash = in.hash;
+
+ if (in.shaders.cs.eq(g_nullShaderKey)) {
+ // Binding mask
+ out.gpState.bsBindingMask = in.gpState.bsBindingMask.convert();
+
+ // Graphics state
+ out.gpState.ia = DxvkIaInfo(
+ in.gpState.iaPrimitiveTopology,
+ in.gpState.iaPrimitiveRestart,
+ in.gpState.iaPatchVertexCount);
+
+ out.gpState.il = DxvkIlInfo(
+ in.gpState.ilAttributeCount,
+ in.gpState.ilBindingCount);
+
+ for (uint32_t i = 0; i < in.gpState.ilAttributeCount; i++) {
+ out.gpState.ilAttributes[i] = DxvkIlAttribute(
+ in.gpState.ilAttributes[i].location,
+ in.gpState.ilAttributes[i].binding,
+ in.gpState.ilAttributes[i].format,
+ in.gpState.ilAttributes[i].offset);
+ }
+
+ for (uint32_t i = 0; i < in.gpState.ilBindingCount; i++) {
+ out.gpState.ilBindings[i] = DxvkIlBinding(
+ in.gpState.ilBindings[i].binding,
+ in.gpState.ilBindings[i].stride,
+ in.gpState.ilBindings[i].inputRate,
+ in.gpState.ilDivisors[i]);
+ }
+
+ out.gpState.rs = DxvkRsInfo(
+ in.gpState.rsDepthClipEnable,
+ in.gpState.rsDepthBiasEnable,
+ in.gpState.rsPolygonMode,
+ in.gpState.rsCullMode,
+ in.gpState.rsFrontFace,
+ in.gpState.rsViewportCount,
+ in.gpState.rsSampleCount,
+ VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
+
+ out.gpState.ms = DxvkMsInfo(
+ in.gpState.msSampleCount,
+ in.gpState.msSampleMask,
+ in.gpState.msEnableAlphaToCoverage);
+
+ out.gpState.ds = DxvkDsInfo(
+ in.gpState.dsEnableDepthTest,
+ in.gpState.dsEnableDepthWrite,
+ in.gpState.dsEnableDepthBoundsTest,
+ in.gpState.dsEnableStencilTest,
+ in.gpState.dsDepthCompareOp);
+
+ out.gpState.dsFront = DxvkDsStencilOp(in.gpState.dsStencilOpFront);
+ out.gpState.dsBack = DxvkDsStencilOp(in.gpState.dsStencilOpBack);
+
+ out.gpState.om = DxvkOmInfo(
+ in.gpState.omEnableLogicOp,
+ in.gpState.omLogicOp);
+
+ for (uint32_t i = 0; i < 8 && i < MaxNumRenderTargets; i++) {
+ out.gpState.omBlend[i] = DxvkOmAttachmentBlend(
+ in.gpState.omBlendAttachments[i].blendEnable,
+ in.gpState.omBlendAttachments[i].srcColorBlendFactor,
+ in.gpState.omBlendAttachments[i].dstColorBlendFactor,
+ in.gpState.omBlendAttachments[i].colorBlendOp,
+ in.gpState.omBlendAttachments[i].srcAlphaBlendFactor,
+ in.gpState.omBlendAttachments[i].dstAlphaBlendFactor,
+ in.gpState.omBlendAttachments[i].alphaBlendOp,
+ in.gpState.omBlendAttachments[i].colorWriteMask);
+
+ out.gpState.omSwizzle[i] = DxvkOmAttachmentSwizzle(
+ in.gpState.omComponentMapping[i]);
+ }
+
+ // Specialization constants
+ for (uint32_t i = 0; i < 8 && i < MaxNumSpecConstants; i++)
+ out.cpState.sc.specConstants[i] = in.cpState.scSpecConstants[i];
+ } else {
+ // Binding mask
+ out.cpState.bsBindingMask = in.cpState.bsBindingMask.convert();
+
+ for (uint32_t i = 0; i < 8 && i < MaxNumSpecConstants; i++)
+ out.gpState.sc.specConstants[i] = in.gpState.scSpecConstants[i];
+ }
+
+ return true;
+ }
+
+
+ void DxvkStateCache::workerFunc() {
+ env::setThreadName("dxvk-shader");
+
+ while (!m_stopThreads.load()) {
+ WorkerItem item;
+
+ { std::unique_lock<dxvk::mutex> lock(m_workerLock);
+
+ if (m_workerQueue.empty()) {
+ m_workerBusy -= 1;
+ m_workerCond.wait(lock, [this] () {
+ return m_workerQueue.size()
+ || m_stopThreads.load();
+ });
+
+ if (!m_workerQueue.empty())
+ m_workerBusy += 1;
+ }
+
+ if (m_workerQueue.empty())
+ break;
+
+ item = m_workerQueue.front();
+ m_workerQueue.pop();
+ }
+
+ compilePipelines(item);
+ }
+ }
+
+
+ void DxvkStateCache::writerFunc() {
+ env::setThreadName("dxvk-writer");
+
+ std::ofstream file;
+
+ while (!m_stopThreads.load()) {
+ DxvkStateCacheEntry entry;
+
+ { std::unique_lock<dxvk::mutex> lock(m_writerLock);
+
+ m_writerCond.wait(lock, [this] () {
+ return m_writerQueue.size()
+ || m_stopThreads.load();
+ });
+
+ if (m_writerQueue.size() == 0)
+ break;
+
+ entry = m_writerQueue.front();
+ m_writerQueue.pop();
+ }
+
+ if (!file) {
+ file = std::ofstream(getCacheFileName().c_str(),
+ std::ios_base::binary |
+ std::ios_base::app);
+ }
+
+ writeCacheEntry(file, entry);
+ }
+ }
+
+#ifdef _WIN32
+ std::wstring DxvkStateCache::getCacheFileName() const {
+#else
+ std::string DxvkStateCache::getCacheFileName() const {
+#endif
+ std::string path = getCacheDir();
+
+ if (!path.empty() && *path.rbegin() != '/')
+ path += '/';
+
+ std::string exeName = env::getExeBaseName();
+ path += exeName + ".dxvk-cache";
+
+#ifdef _WIN32
+ return str::tows(path.c_str());
+#else
+ return path;
+#endif
+ }
+
+
+ std::string DxvkStateCache::getCacheDir() const {
+ return env::getEnvVar("DXVK_STATE_CACHE_PATH");
+ }
+
+
+ uint8_t DxvkStateCache::packImageLayout(
+ VkImageLayout layout) {
+ switch (layout) {
+ case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: return 0x80;
+ case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: return 0x81;
+ default: return uint8_t(layout);
+ }
+ }
+
+
+ VkImageLayout DxvkStateCache::unpackImageLayout(
+ uint8_t layout) {
+ switch (layout) {
+ case 0x80: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
+ case 0x81: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
+ default: return VkImageLayout(layout);
+ }
+ }
+
+
+ bool DxvkStateCache::validateRenderPassFormat(
+ const DxvkRenderPassFormat& format) {
+ bool valid = true;
+
+ if (format.depth.format) {
+ valid &= format.depth.layout == VK_IMAGE_LAYOUT_GENERAL
+ || format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+ || format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ || format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
+ || format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
+ }
+
+ for (uint32_t i = 0; i < MaxNumRenderTargets && valid; i++) {
+ if (format.color[i].format) {
+ valid &= format.color[i].layout == VK_IMAGE_LAYOUT_GENERAL
+ || format.color[i].layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ }
+ }
+
+ return valid;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.h
new file mode 100644
index 00000000..00d08bc2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache.h
@@ -0,0 +1,203 @@
+#pragma once
+
+#include <atomic>
+#include <condition_variable>
+#include <fstream>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "dxvk_state_cache_types.h"
+
+namespace dxvk {
+
+ class DxvkDevice;
+
+ /**
+ * \brief State cache
+ *
+ * The shader state cache stores state vectors and
+ * render pass formats of all pipelines used in a
+ * game, which allows DXVK to compile them ahead
+ * of time instead of compiling them on the first
+ * draw.
+ */
+ class DxvkStateCache : public RcObject {
+
+ public:
+
+ DxvkStateCache(
+ const DxvkDevice* device,
+ DxvkPipelineManager* pipeManager,
+ DxvkRenderPassPool* passManager);
+
+ ~DxvkStateCache();
+
+ /**
+ * Adds a graphics pipeline to the cache
+ *
+ * If the pipeline is not already cached, this
+ * will write a new pipeline to the cache file.
+ * \param [in] shaders Shader keys
+ * \param [in] state Graphics pipeline state
+ * \param [in] format Render pass format
+ */
+ void addGraphicsPipeline(
+ const DxvkStateCacheKey& shaders,
+ const DxvkGraphicsPipelineStateInfo& state,
+ const DxvkRenderPassFormat& format);
+
+ /**
+ * Adds a compute pipeline to the cache
+ *
+ * If the pipeline is not already cached, this
+ * will write a new pipeline to the cache file.
+ * \param [in] shaders Shader keys
+ * \param [in] state Compute pipeline state
+ */
+ void addComputePipeline(
+ const DxvkStateCacheKey& shaders,
+ const DxvkComputePipelineStateInfo& state);
+
+ /**
+ * \brief Registers a newly compiled shader
+ *
+ * Makes the shader available to the pipeline
+ * compiler, and starts compiling all pipelines
+ * for which all shaders become available.
+ * \param [in] shader The shader to add
+ */
+ void registerShader(
+ const Rc<DxvkShader>& shader);
+
+ /**
+ * \brief Explicitly stops worker threads
+ */
+ void stopWorkerThreads();
+
+ /**
+ * \brief Checks whether compiler threads are busy
+ * \returns \c true if we're compiling shaders
+ */
+ bool isCompilingShaders() {
+ return m_workerBusy.load() > 0;
+ }
+
+ private:
+
+ using WriterItem = DxvkStateCacheEntry;
+
+ struct WorkerItem {
+ DxvkGraphicsPipelineShaders gp;
+ DxvkComputePipelineShaders cp;
+ };
+
+ DxvkPipelineManager* m_pipeManager;
+ DxvkRenderPassPool* m_passManager;
+
+ std::vector<DxvkStateCacheEntry> m_entries;
+ std::atomic<bool> m_stopThreads = { false };
+
+ dxvk::mutex m_entryLock;
+
+ std::unordered_multimap<
+ DxvkStateCacheKey, size_t,
+ DxvkHash, DxvkEq> m_entryMap;
+
+ std::unordered_multimap<
+ DxvkShaderKey, DxvkStateCacheKey,
+ DxvkHash, DxvkEq> m_pipelineMap;
+
+ std::unordered_map<
+ DxvkShaderKey, Rc<DxvkShader>,
+ DxvkHash, DxvkEq> m_shaderMap;
+
+ dxvk::mutex m_workerLock;
+ dxvk::condition_variable m_workerCond;
+ std::queue<WorkerItem> m_workerQueue;
+ std::atomic<uint32_t> m_workerBusy;
+ std::vector<dxvk::thread> m_workerThreads;
+
+ dxvk::mutex m_writerLock;
+ dxvk::condition_variable m_writerCond;
+ std::queue<WriterItem> m_writerQueue;
+ dxvk::thread m_writerThread;
+
+ DxvkShaderKey getShaderKey(
+ const Rc<DxvkShader>& shader) const;
+
+ bool getShaderByKey(
+ const DxvkShaderKey& key,
+ Rc<DxvkShader>& shader) const;
+
+ void mapPipelineToEntry(
+ const DxvkStateCacheKey& key,
+ size_t entryId);
+
+ void mapShaderToPipeline(
+ const DxvkShaderKey& shader,
+ const DxvkStateCacheKey& key);
+
+ void compilePipelines(
+ const WorkerItem& item);
+
+ bool readCacheFile();
+
+ bool readCacheHeader(
+ std::istream& stream,
+ DxvkStateCacheHeader& header) const;
+
+ bool readCacheEntryV7(
+ uint32_t version,
+ std::istream& stream,
+ DxvkStateCacheEntry& entry) const;
+
+ bool readCacheEntry(
+ uint32_t version,
+ std::istream& stream,
+ DxvkStateCacheEntry& entry) const;
+
+ void writeCacheEntry(
+ std::ostream& stream,
+ DxvkStateCacheEntry& entry) const;
+
+ bool convertEntryV2(
+ DxvkStateCacheEntryV4& entry) const;
+
+ bool convertEntryV4(
+ const DxvkStateCacheEntryV4& in,
+ DxvkStateCacheEntryV6& out) const;
+
+ bool convertEntryV5(
+ const DxvkStateCacheEntryV5& in,
+ DxvkStateCacheEntryV6& out) const;
+
+ bool convertEntryV6(
+ const DxvkStateCacheEntryV6& in,
+ DxvkStateCacheEntry& out) const;
+
+ void workerFunc();
+
+ void writerFunc();
+
+#ifdef _WIN32
+ std::wstring getCacheFileName() const;
+#else
+ std::string getCacheFileName() const;
+#endif
+
+ std::string getCacheDir() const;
+
+ static uint8_t packImageLayout(
+ VkImageLayout layout);
+
+ static VkImageLayout unpackImageLayout(
+ uint8_t layout);
+
+ static bool validateRenderPassFormat(
+ const DxvkRenderPassFormat& format);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache_types.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache_types.h
new file mode 100644
index 00000000..41ff4d47
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_state_cache_types.h
@@ -0,0 +1,233 @@
+#pragma once
+
+#include "dxvk_pipemanager.h"
+#include "dxvk_renderpass.h"
+
+namespace dxvk {
+
+ /**
+ * \brief State cache entry key
+ *
+ * Stores the shader keys for all
+ * graphics shader stages. Used to
+ * look up cached state entries.
+ */
+ struct DxvkStateCacheKey {
+ DxvkShaderKey vs;
+ DxvkShaderKey tcs;
+ DxvkShaderKey tes;
+ DxvkShaderKey gs;
+ DxvkShaderKey fs;
+ DxvkShaderKey cs;
+
+ bool eq(const DxvkStateCacheKey& key) const;
+
+ size_t hash() const;
+ };
+
+
+ /**
+ * \brief State entry
+ *
+ * Stores the shaders used in a pipeline, as well
+ * as the full state vector, including its render
+ * pass format. This also includes a SHA-1 hash
+ * that is used as a check sum to verify integrity.
+ */
+ struct DxvkStateCacheEntry {
+ DxvkStateCacheKey shaders;
+ DxvkGraphicsPipelineStateInfo gpState;
+ DxvkComputePipelineStateInfo cpState;
+ DxvkRenderPassFormat format;
+ Sha1Hash hash;
+ };
+
+
+ /**
+ * \brief State cache header
+ *
+ * Stores the state cache format version. If an
+ * existing cache file is incompatible to the
+ * current version, it will be discarded.
+ */
+ struct DxvkStateCacheHeader {
+ char magic[4] = { 'D', 'X', 'V', 'K' };
+ uint32_t version = 10;
+ uint32_t entrySize = 0; /* no longer meaningful */
+ };
+
+ static_assert(sizeof(DxvkStateCacheHeader) == 12);
+
+
+ class DxvkBindingMaskV8 : DxvkBindingSet<128> {
+
+ public:
+
+ DxvkBindingMask convert() const {
+ DxvkBindingMask result = { };
+ for (uint32_t i = 0; i < 128; i++)
+ result.set(i, test(i));
+ return result;
+ }
+
+ };
+
+ class DxvkIlBindingV9 {
+
+ public:
+
+ uint32_t m_binding : 5;
+ uint32_t m_stride : 12;
+ uint32_t m_inputRate : 1;
+ uint32_t m_reserved : 14;
+ uint32_t m_divisor;
+
+ DxvkIlBinding convert() const {
+ return DxvkIlBinding(m_binding, m_stride,
+ VkVertexInputRate(m_inputRate), m_divisor);
+ }
+
+ };
+
+ /**
+ * \brief Version 4 graphics pipeline state
+ */
+ struct DxvkGraphicsPipelineStateInfoV4 {
+ DxvkBindingMaskV8 bsBindingMask;
+
+ VkPrimitiveTopology iaPrimitiveTopology;
+ VkBool32 iaPrimitiveRestart;
+ uint32_t iaPatchVertexCount;
+
+ uint32_t ilAttributeCount;
+ uint32_t ilBindingCount;
+ VkVertexInputAttributeDescription ilAttributes[32];
+ VkVertexInputBindingDescription ilBindings[32];
+ uint32_t ilDivisors[32];
+
+ VkBool32 rsDepthClipEnable;
+ VkBool32 rsDepthBiasEnable;
+ VkPolygonMode rsPolygonMode;
+ VkCullModeFlags rsCullMode;
+ VkFrontFace rsFrontFace;
+ uint32_t rsViewportCount;
+ VkSampleCountFlags rsSampleCount;
+
+ VkSampleCountFlags msSampleCount;
+ uint32_t msSampleMask;
+ VkBool32 msEnableAlphaToCoverage;
+
+ VkCompareOp xsAlphaCompareOp;
+
+ VkBool32 dsEnableDepthTest;
+ VkBool32 dsEnableDepthWrite;
+ VkBool32 dsEnableStencilTest;
+ VkCompareOp dsDepthCompareOp;
+ VkStencilOpState dsStencilOpFront;
+ VkStencilOpState dsStencilOpBack;
+
+ VkBool32 omEnableLogicOp;
+ VkLogicOp omLogicOp;
+ VkPipelineColorBlendAttachmentState omBlendAttachments[8];
+ VkComponentMapping omComponentMapping[8];
+ };
+
+
+ /**
+ * \brief Version 6 graphics pipeline state
+ */
+ struct DxvkGraphicsPipelineStateInfoV6 {
+ DxvkBindingMaskV8 bsBindingMask;
+
+ VkPrimitiveTopology iaPrimitiveTopology;
+ VkBool32 iaPrimitiveRestart;
+ uint32_t iaPatchVertexCount;
+
+ uint32_t ilAttributeCount;
+ uint32_t ilBindingCount;
+ VkVertexInputAttributeDescription ilAttributes[32];
+ VkVertexInputBindingDescription ilBindings[32];
+ uint32_t ilDivisors[32];
+
+ VkBool32 rsDepthClipEnable;
+ VkBool32 rsDepthBiasEnable;
+ VkPolygonMode rsPolygonMode;
+ VkCullModeFlags rsCullMode;
+ VkFrontFace rsFrontFace;
+ uint32_t rsViewportCount;
+ VkSampleCountFlags rsSampleCount;
+
+ VkSampleCountFlags msSampleCount;
+ uint32_t msSampleMask;
+ VkBool32 msEnableAlphaToCoverage;
+
+ VkBool32 dsEnableDepthTest;
+ VkBool32 dsEnableDepthWrite;
+ VkBool32 dsEnableDepthBoundsTest;
+ VkBool32 dsEnableStencilTest;
+ VkCompareOp dsDepthCompareOp;
+ VkStencilOpState dsStencilOpFront;
+ VkStencilOpState dsStencilOpBack;
+
+ VkBool32 omEnableLogicOp;
+ VkLogicOp omLogicOp;
+ VkPipelineColorBlendAttachmentState omBlendAttachments[8];
+ VkComponentMapping omComponentMapping[8];
+
+ uint32_t scSpecConstants[8];
+ };
+
+
+ /**
+ * \brief Version 5 compute pipeline state
+ */
+ struct DxvkComputePipelineStateInfoV5 {
+ DxvkBindingMaskV8 bsBindingMask;
+ };
+
+
+ /**
+ * \brief Version 6 compute pipeline state
+ */
+ struct DxvkComputePipelineStateInfoV6 {
+ DxvkBindingMaskV8 bsBindingMask;
+ uint32_t scSpecConstants[8];
+ };
+
+
+ /**
+ * \brief Version 4 state cache entry
+ */
+ struct DxvkStateCacheEntryV4 {
+ DxvkStateCacheKey shaders;
+ DxvkGraphicsPipelineStateInfoV4 gpState;
+ DxvkComputePipelineStateInfoV5 cpState;
+ DxvkRenderPassFormat format;
+ Sha1Hash hash;
+ };
+
+
+ /**
+ * \brief Version 5 state cache entry
+ */
+ struct DxvkStateCacheEntryV5 {
+ DxvkStateCacheKey shaders;
+ DxvkGraphicsPipelineStateInfoV6 gpState;
+ DxvkComputePipelineStateInfoV5 cpState;
+ DxvkRenderPassFormat format;
+ Sha1Hash hash;
+ };
+
+
+ /**
+ * \brief Version 6 state cache entry
+ */
+ struct DxvkStateCacheEntryV6 {
+ DxvkStateCacheKey shaders;
+ DxvkGraphicsPipelineStateInfoV6 gpState;
+ DxvkComputePipelineStateInfoV6 cpState;
+ DxvkRenderPassFormat format;
+ Sha1Hash hash;
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.cpp
new file mode 100644
index 00000000..72e6f8a7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.cpp
@@ -0,0 +1,34 @@
+#include "dxvk_stats.h"
+
+namespace dxvk {
+
+ DxvkStatCounters::DxvkStatCounters() {
+ this->reset();
+ }
+
+
+ DxvkStatCounters::~DxvkStatCounters() {
+
+ }
+
+
+ DxvkStatCounters DxvkStatCounters::diff(const DxvkStatCounters& other) const {
+ DxvkStatCounters result;
+ for (size_t i = 0; i < m_counters.size(); i++)
+ result.m_counters[i] = m_counters[i] - other.m_counters[i];
+ return result;
+ }
+
+
+ void DxvkStatCounters::merge(const DxvkStatCounters& other) {
+ for (size_t i = 0; i < m_counters.size(); i++)
+ m_counters[i] += other.m_counters[i];
+ }
+
+
+ void DxvkStatCounters::reset() {
+ for (size_t i = 0; i < m_counters.size(); i++)
+ m_counters[i] = 0;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.h
new file mode 100644
index 00000000..77aa6b8f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_stats.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Named stat counters
+ *
+ * Enumerates available stat counters. Used
+ * thogether with \ref DxvkStatCounters.
+ */
+ enum class DxvkStatCounter : uint32_t {
+ CmdDrawCalls, ///< Number of draw calls
+ CmdDispatchCalls, ///< Number of compute calls
+ CmdRenderPassCount, ///< Number of render passes
+ PipeCountGraphics, ///< Number of graphics pipelines
+ PipeCountCompute, ///< Number of compute pipelines
+ PipeCompilerBusy, ///< Boolean indicating compiler activity
+ QueueSubmitCount, ///< Number of command buffer submissions
+ QueuePresentCount, ///< Number of present calls / frames
+ GpuIdleTicks, ///< GPU idle time in microseconds
+ NumCounters, ///< Number of counters available
+ };
+
+
+ /**
+ * \brief Stat counters
+ *
+ * Collects various statistics that may be
+ * useful to identify performance bottlenecks.
+ */
+ class DxvkStatCounters {
+
+ public:
+
+ DxvkStatCounters();
+ ~DxvkStatCounters();
+
+ /**
+ * \brief Retrieves a counter value
+ *
+ * \param [in] ctr The counter
+ * \returns Counter value
+ */
+ uint64_t getCtr(DxvkStatCounter ctr) const {
+ return m_counters[uint32_t(ctr)];
+ }
+
+ /**
+ * \brief Sets a counter value
+ *
+ * \param [in] ctr The counter
+ * \param [in] val Counter value
+ */
+ void setCtr(DxvkStatCounter ctr, uint64_t val) {
+ m_counters[uint32_t(ctr)] = val;
+ }
+
+ /**
+ * \brief Increments a counter value
+ *
+ * \param [in] ctr Counter to increment
+ * \param [in] val Number to add to counter value
+ */
+ void addCtr(DxvkStatCounter ctr, uint64_t val) {
+ m_counters[uint32_t(ctr)] += val;
+ }
+
+ /**
+ * \brief Resets a counter
+ * \param [in] ctr The counter
+ */
+ void clrCtr(DxvkStatCounter ctr) {
+ m_counters[uint32_t(ctr)] = 0;
+ }
+
+ /**
+ * \brief Computes difference
+ *
+ * Computes difference between counter values.
+ * \param [in] other Counters to subtract
+ * \returns Difference between counter sets
+ */
+ DxvkStatCounters diff(const DxvkStatCounters& other) const;
+
+ /**
+ * \brief Merges counters
+ *
+ * Adds counter values from another set
+ * of counters to this set of counters.
+ * \param [in] other Counters to add
+ */
+ void merge(const DxvkStatCounters& other);
+
+ /**
+ * \brief Resets counters
+ *
+ * Sets all counters to zero.
+ */
+ void reset();
+
+ private:
+
+ std::array<uint64_t, uint32_t(DxvkStatCounter::NumCounters)> m_counters;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.cpp
new file mode 100644
index 00000000..df1ce05a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.cpp
@@ -0,0 +1,373 @@
+#include "dxvk_swapchain_blitter.h"
+
+#include <dxvk_present_frag.h>
+#include <dxvk_present_frag_blit.h>
+#include <dxvk_present_frag_ms.h>
+#include <dxvk_present_frag_ms_amd.h>
+#include <dxvk_present_vert.h>
+
+namespace dxvk {
+
+ DxvkSwapchainBlitter::DxvkSwapchainBlitter(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+ this->createSampler();
+ this->createShaders();
+ }
+
+
+ DxvkSwapchainBlitter::~DxvkSwapchainBlitter() {
+
+ }
+
+
+ void DxvkSwapchainBlitter::presentImage(
+ DxvkContext* ctx,
+ const Rc<DxvkImageView>& dstView,
+ VkRect2D dstRect,
+ const Rc<DxvkImageView>& srcView,
+ VkRect2D srcRect) {
+ if (m_gammaDirty)
+ this->updateGammaTexture(ctx);
+
+ // Fix up default present areas if necessary
+ if (!dstRect.extent.width || !dstRect.extent.height) {
+ dstRect.offset = { 0, 0 };
+ dstRect.extent = {
+ dstView->imageInfo().extent.width,
+ dstView->imageInfo().extent.height };
+ }
+
+ if (!srcRect.extent.width || !srcRect.extent.height) {
+ srcRect.offset = { 0, 0 };
+ srcRect.extent = {
+ srcView->imageInfo().extent.width,
+ srcView->imageInfo().extent.height };
+ }
+
+ bool sameSize = dstRect.extent == srcRect.extent;
+ bool usedResolveImage = false;
+
+ if (srcView->imageInfo().sampleCount == VK_SAMPLE_COUNT_1_BIT) {
+ this->draw(ctx, sameSize ? m_fsCopy : m_fsBlit,
+ dstView, dstRect, srcView, srcRect);
+ } else if (sameSize) {
+ this->draw(ctx, m_fsResolve,
+ dstView, dstRect, srcView, srcRect);
+ } else {
+ if (m_resolveImage == nullptr
+ || m_resolveImage->info().extent != srcView->imageInfo().extent
+ || m_resolveImage->info().format != srcView->imageInfo().format)
+ this->createResolveImage(srcView->imageInfo());
+
+ this->resolve(ctx, m_resolveView, srcView);
+ this->draw(ctx, m_fsBlit, dstView, dstRect, m_resolveView, srcRect);
+
+ usedResolveImage = true;
+ }
+
+ if (!usedResolveImage)
+ this->destroyResolveImage();
+ }
+
+
+ void DxvkSwapchainBlitter::setGammaRamp(
+ uint32_t cpCount,
+ const DxvkGammaCp* cpData) {
+ m_gammaRamp.resize(cpCount);
+
+ for (uint32_t i = 0; i < cpCount; i++)
+ m_gammaRamp[i] = cpData[i];
+
+ m_gammaDirty = true;
+ }
+
+
+ void DxvkSwapchainBlitter::draw(
+ DxvkContext* ctx,
+ const Rc<DxvkShader>& fs,
+ const Rc<DxvkImageView>& dstView,
+ VkRect2D dstRect,
+ const Rc<DxvkImageView>& srcView,
+ VkRect2D srcRect) {
+ DxvkInputAssemblyState iaState;
+ iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ iaState.primitiveRestart = VK_FALSE;
+ iaState.patchVertexCount = 0;
+ ctx->setInputAssemblyState(iaState);
+ ctx->setInputLayout(0, nullptr, 0, nullptr);
+
+ DxvkRasterizerState rsState;
+ rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ rsState.cullMode = VK_CULL_MODE_BACK_BIT;
+ rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rsState.depthClipEnable = VK_FALSE;
+ rsState.depthBiasEnable = VK_FALSE;
+ rsState.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ ctx->setRasterizerState(rsState);
+
+ DxvkMultisampleState msState;
+ msState.sampleMask = 0xffffffff;
+ msState.enableAlphaToCoverage = VK_FALSE;
+ ctx->setMultisampleState(msState);
+
+ VkStencilOpState stencilOp;
+ stencilOp.failOp = VK_STENCIL_OP_KEEP;
+ stencilOp.passOp = VK_STENCIL_OP_KEEP;
+ stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
+ stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
+ stencilOp.compareMask = 0xFFFFFFFF;
+ stencilOp.writeMask = 0xFFFFFFFF;
+ stencilOp.reference = 0;
+
+ DxvkDepthStencilState dsState;
+ dsState.enableDepthTest = VK_FALSE;
+ dsState.enableDepthWrite = VK_FALSE;
+ dsState.enableStencilTest = VK_FALSE;
+ dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
+ dsState.stencilOpFront = stencilOp;
+ dsState.stencilOpBack = stencilOp;
+ ctx->setDepthStencilState(dsState);
+
+ DxvkLogicOpState loState;
+ loState.enableLogicOp = VK_FALSE;
+ loState.logicOp = VK_LOGIC_OP_NO_OP;
+ ctx->setLogicOpState(loState);
+
+ DxvkBlendMode blendMode;
+ blendMode.enableBlending = VK_FALSE;
+ blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
+ blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blendMode.colorBlendOp = VK_BLEND_OP_ADD;
+ blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
+ blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
+ blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ ctx->setBlendMode(0, blendMode);
+
+ VkViewport viewport;
+ viewport.x = float(dstRect.offset.x);
+ viewport.y = float(dstRect.offset.y);
+ viewport.width = float(dstRect.extent.width);
+ viewport.height = float(dstRect.extent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ ctx->setViewports(1, &viewport, &dstRect);
+
+ DxvkRenderTargets renderTargets;
+ renderTargets.color[0].view = dstView;
+ renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ ctx->bindRenderTargets(renderTargets);
+
+ VkExtent2D dstExtent = {
+ dstView->imageInfo().extent.width,
+ dstView->imageInfo().extent.height };
+
+ if (dstRect.extent == dstExtent)
+ ctx->discardImageView(dstView, VK_IMAGE_ASPECT_COLOR_BIT);
+ else
+ ctx->clearRenderTarget(dstView, VK_IMAGE_ASPECT_COLOR_BIT, VkClearValue());
+
+ ctx->bindResourceSampler(BindingIds::Image, m_samplerPresent);
+ ctx->bindResourceSampler(BindingIds::Gamma, m_samplerGamma);
+
+ ctx->bindResourceView(BindingIds::Image, srcView, nullptr);
+ ctx->bindResourceView(BindingIds::Gamma, m_gammaView, nullptr);
+
+ ctx->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vs);
+ ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, fs);
+
+ PresenterArgs args;
+ args.srcOffset = srcRect.offset;
+
+ if (dstRect.extent == srcRect.extent)
+ args.dstOffset = dstRect.offset;
+ else
+ args.srcExtent = srcRect.extent;
+
+ ctx->pushConstants(0, sizeof(args), &args);
+
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, srcView->imageInfo().sampleCount);
+ ctx->draw(3, 1, 0, 0);
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0);
+ }
+
+ void DxvkSwapchainBlitter::resolve(
+ DxvkContext* ctx,
+ const Rc<DxvkImageView>& dstView,
+ const Rc<DxvkImageView>& srcView) {
+ VkImageResolve resolve;
+ resolve.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ resolve.srcOffset = { 0, 0, 0 };
+ resolve.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ resolve.dstOffset = { 0, 0, 0 };
+ resolve.extent = dstView->imageInfo().extent;
+ ctx->resolveImage(dstView->image(), srcView->image(), resolve, VK_FORMAT_UNDEFINED);
+ }
+
+
+ void DxvkSwapchainBlitter::updateGammaTexture(DxvkContext* ctx) {
+ uint32_t n = uint32_t(m_gammaRamp.size());
+
+ if (n) {
+ // Reuse existing image if possible
+ if (m_gammaImage == nullptr || m_gammaImage->info().extent.width != n) {
+ DxvkImageCreateInfo imgInfo;
+ imgInfo.type = VK_IMAGE_TYPE_1D;
+ imgInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
+ imgInfo.flags = 0;
+ imgInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ imgInfo.extent = { n, 1, 1 };
+ imgInfo.numLayers = 1;
+ imgInfo.mipLevels = 1;
+ imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT;
+ imgInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ imgInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imgInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ m_gammaImage = m_device->createImage(
+ imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_1D;
+ viewInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
+ viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+
+ m_gammaView = m_device->createImageView(m_gammaImage, viewInfo);
+ }
+
+ ctx->updateImage(m_gammaImage,
+ VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
+ VkOffset3D { 0, 0, 0 },
+ VkExtent3D { n, 1, 1 },
+ m_gammaRamp.data(),
+ sizeof(DxvkGammaCp) * n,
+ sizeof(DxvkGammaCp) * n);
+ } else {
+ m_gammaImage = nullptr;
+ m_gammaView = nullptr;
+ }
+
+ m_gammaDirty = false;
+ }
+
+
+ void DxvkSwapchainBlitter::createSampler() {
+ DxvkSamplerCreateInfo samplerInfo;
+ samplerInfo.magFilter = VK_FILTER_LINEAR;
+ samplerInfo.minFilter = VK_FILTER_LINEAR;
+ samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ samplerInfo.mipmapLodBias = 0.0f;
+ samplerInfo.mipmapLodMin = 0.0f;
+ samplerInfo.mipmapLodMax = 0.0f;
+ samplerInfo.useAnisotropy = VK_FALSE;
+ samplerInfo.maxAnisotropy = 1.0f;
+ samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+ samplerInfo.compareToDepth = VK_FALSE;
+ samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
+ samplerInfo.borderColor = VkClearColorValue();
+ samplerInfo.usePixelCoord = VK_TRUE;
+ m_samplerPresent = m_device->createSampler(samplerInfo);
+
+ samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ samplerInfo.usePixelCoord = VK_FALSE;
+ m_samplerGamma = m_device->createSampler(samplerInfo);
+ }
+
+ void DxvkSwapchainBlitter::createShaders() {
+ const SpirvCodeBuffer vsCode(dxvk_present_vert);
+ const SpirvCodeBuffer fsCodeBlit(dxvk_present_frag_blit);
+ const SpirvCodeBuffer fsCodeCopy(dxvk_present_frag);
+ const SpirvCodeBuffer fsCodeResolve(dxvk_present_frag_ms);
+ const SpirvCodeBuffer fsCodeResolveAmd(dxvk_present_frag_ms_amd);
+
+ const std::array<DxvkResourceSlot, 2> fsResourceSlots = {{
+ { BindingIds::Image, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D },
+ { BindingIds::Gamma, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_1D },
+ }};
+
+ m_vs = m_device->createShader(
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0, nullptr, { 0u, 1u },
+ vsCode);
+
+ m_fsBlit = m_device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fsResourceSlots.size(),
+ fsResourceSlots.data(),
+ { 1u, 1u, 0u, sizeof(PresenterArgs) },
+ fsCodeBlit);
+
+ m_fsCopy = m_device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fsResourceSlots.size(),
+ fsResourceSlots.data(),
+ { 0u, 1u, 0u, sizeof(PresenterArgs) },
+ fsCodeCopy);
+
+ m_fsResolve = m_device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fsResourceSlots.size(),
+ fsResourceSlots.data(),
+ { 0u, 1u, 0u, sizeof(PresenterArgs) },
+ m_device->extensions().amdShaderFragmentMask
+ ? fsCodeResolveAmd : fsCodeResolve);
+ }
+
+ void DxvkSwapchainBlitter::createResolveImage(const DxvkImageCreateInfo& info) {
+ DxvkImageCreateInfo newInfo;
+ newInfo.type = VK_IMAGE_TYPE_2D;
+ newInfo.format = info.format;
+ newInfo.flags = 0;
+ newInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ newInfo.extent = info.extent;
+ newInfo.numLayers = 1;
+ newInfo.mipLevels = 1;
+ newInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT;
+ newInfo.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
+ | VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ newInfo.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
+ | VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ newInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ newInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ m_resolveImage = m_device->createImage(newInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = info.format;
+ viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+ m_resolveView = m_device->createImageView(m_resolveImage, viewInfo);
+ }
+
+
+ void DxvkSwapchainBlitter::destroyResolveImage() {
+ m_resolveImage = nullptr;
+ m_resolveView = nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.h
new file mode 100644
index 00000000..b6db5f81
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_swapchain_blitter.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "../dxvk/dxvk_device.h"
+#include "../dxvk/dxvk_context.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Gamma control point
+ */
+ struct DxvkGammaCp {
+ uint16_t r, g, b, a;
+ };
+
+ /**
+ * \brief Swap chain blitter
+ *
+ * Provides common rendering code for blitting
+ * rendered images to a swap chain image.
+ */
+ class DxvkSwapchainBlitter : public RcObject {
+
+ public:
+
+ DxvkSwapchainBlitter(const Rc<DxvkDevice>& device);
+ ~DxvkSwapchainBlitter();
+
+ /**
+ * \brief Records presentation commands
+ *
+ * \param [in] ctx Context
+ * \param [in] dstView Swap chain image view
+ * \param [in] srcView Image to present
+ * \param [in] dstRect Destination rectangle
+ * \param [in] srcRect Back buffer rectangle
+ */
+ void presentImage(
+ DxvkContext* ctx,
+ const Rc<DxvkImageView>& dstView,
+ VkRect2D dstRect,
+ const Rc<DxvkImageView>& srcView,
+ VkRect2D srcRect);
+
+ /**
+ * \brief Sets gamma ramp
+ *
+ * If the number of control points is non-zero, this
+ * will create a texture containing a gamma ramp that
+ * will be used for presentation.
+ * \param [in] cpCount Number of control points
+ * \param [in] cpData Control point data
+ */
+ void setGammaRamp(
+ uint32_t cpCount,
+ const DxvkGammaCp* cpData);
+
+ private:
+
+ enum BindingIds : uint32_t {
+ Image = 0,
+ Gamma = 1,
+ };
+
+ struct PresenterArgs {
+ VkOffset2D srcOffset;
+ union {
+ VkExtent2D srcExtent;
+ VkOffset2D dstOffset;
+ };
+ };
+
+ Rc<DxvkDevice> m_device;
+
+ Rc<DxvkShader> m_fsCopy;
+ Rc<DxvkShader> m_fsBlit;
+ Rc<DxvkShader> m_fsResolve;
+ Rc<DxvkShader> m_vs;
+
+ Rc<DxvkImage> m_gammaImage;
+ Rc<DxvkImageView> m_gammaView;
+ bool m_gammaDirty = false;
+ std::vector<DxvkGammaCp> m_gammaRamp;
+
+ Rc<DxvkImage> m_resolveImage;
+ Rc<DxvkImageView> m_resolveView;
+
+ Rc<DxvkSampler> m_samplerPresent;
+ Rc<DxvkSampler> m_samplerGamma;
+
+ void draw(
+ DxvkContext* ctx,
+ const Rc<DxvkShader>& fs,
+ const Rc<DxvkImageView>& dstView,
+ VkRect2D dstRect,
+ const Rc<DxvkImageView>& srcView,
+ VkRect2D srcRect);
+
+ void resolve(
+ DxvkContext* ctx,
+ const Rc<DxvkImageView>& dstView,
+ const Rc<DxvkImageView>& srcView);
+
+ void updateGammaTexture(DxvkContext* ctx);
+
+ void createSampler();
+
+ void createShaders();
+
+ void createResolveImage(
+ const DxvkImageCreateInfo& info);
+
+ void destroyResolveImage();
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.cpp
new file mode 100644
index 00000000..400ac2c1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.cpp
@@ -0,0 +1,197 @@
+#include "dxvk_device.h"
+
+namespace dxvk {
+
+ DxvkUnboundResources::DxvkUnboundResources(DxvkDevice* dev)
+ : m_sampler (createSampler(dev)),
+ m_buffer (createBuffer(dev)),
+ m_bufferView (createBufferView(dev, m_buffer)),
+ m_image1D (createImage(dev, VK_IMAGE_TYPE_1D, 1)),
+ m_image2D (createImage(dev, VK_IMAGE_TYPE_2D, 6)),
+ m_image3D (createImage(dev, VK_IMAGE_TYPE_3D, 1)),
+ m_viewsSampled (createImageViews(dev, VK_FORMAT_R32_SFLOAT)),
+ m_viewsStorage (createImageViews(dev, VK_FORMAT_R32_UINT)) {
+
+ }
+
+
+ DxvkUnboundResources::~DxvkUnboundResources() {
+
+ }
+
+
+ void DxvkUnboundResources::clearResources(DxvkDevice* dev) {
+ const Rc<DxvkContext> ctx = dev->createContext();
+ ctx->beginRecording(dev->createCommandList());
+
+ this->clearBuffer(ctx, m_buffer);
+ this->clearImage(ctx, m_image1D);
+ this->clearImage(ctx, m_image2D);
+ this->clearImage(ctx, m_image3D);
+
+ dev->submitCommandList(
+ ctx->endRecording(),
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE);
+ }
+
+
+ Rc<DxvkSampler> DxvkUnboundResources::createSampler(DxvkDevice* dev) {
+ DxvkSamplerCreateInfo info;
+ info.minFilter = VK_FILTER_LINEAR;
+ info.magFilter = VK_FILTER_LINEAR;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
+ info.mipmapLodBias = 0.0f;
+ info.mipmapLodMin = -256.0f;
+ info.mipmapLodMax = 256.0f;
+ info.useAnisotropy = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.compareToDepth = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_NEVER;
+ info.borderColor = VkClearColorValue();
+ info.usePixelCoord = VK_FALSE;
+
+ return dev->createSampler(info);
+ }
+
+
+ Rc<DxvkBuffer> DxvkUnboundResources::createBuffer(DxvkDevice* dev) {
+ DxvkBufferCreateInfo info;
+ info.size = MaxUniformBufferSize;
+ info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
+ | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
+ | VK_BUFFER_USAGE_INDEX_BUFFER_BIT
+ | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
+ | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | dev->getShaderPipelineStages();
+ info.access = VK_ACCESS_UNIFORM_READ_BIT
+ | VK_ACCESS_SHADER_READ_BIT
+ | VK_ACCESS_SHADER_WRITE_BIT;
+
+ return dev->createBuffer(info,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ Rc<DxvkBufferView> DxvkUnboundResources::createBufferView(
+ DxvkDevice* dev,
+ const Rc<DxvkBuffer>& buffer) {
+ DxvkBufferViewCreateInfo info;
+ info.format = VK_FORMAT_R32_UINT;
+ info.rangeOffset = 0;
+ info.rangeLength = buffer->info().size;
+
+ return dev->createBufferView(buffer, info);
+ }
+
+
+ Rc<DxvkImage> DxvkUnboundResources::createImage(
+ DxvkDevice* dev,
+ VkImageType type,
+ uint32_t layers) {
+ DxvkImageCreateInfo info;
+ info.type = type;
+ info.format = VK_FORMAT_R32_UINT;
+ info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+ info.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ info.extent = { 1, 1, 1 };
+ info.numLayers = layers;
+ info.mipLevels = 1;
+ info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT
+ | VK_IMAGE_USAGE_STORAGE_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | dev->getShaderPipelineStages();
+ info.access = VK_ACCESS_SHADER_READ_BIT;
+ info.layout = VK_IMAGE_LAYOUT_GENERAL;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+
+ if (type == VK_IMAGE_TYPE_2D)
+ info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+
+ return dev->createImage(info,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ Rc<DxvkImageView> DxvkUnboundResources::createImageView(
+ DxvkDevice* dev,
+ const Rc<DxvkImage>& image,
+ VkFormat format,
+ VkImageViewType type,
+ uint32_t layers) {
+ DxvkImageViewCreateInfo info;
+ info.type = type;
+ info.format = format;
+ info.usage = VK_IMAGE_USAGE_SAMPLED_BIT
+ | VK_IMAGE_USAGE_STORAGE_BIT;
+ info.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ info.minLevel = 0;
+ info.numLevels = 1;
+ info.minLayer = 0;
+ info.numLayers = layers;
+ info.swizzle = VkComponentMapping {
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
+ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO };
+
+ return dev->createImageView(image, info);
+ }
+
+
+ DxvkUnboundResources::UnboundViews DxvkUnboundResources::createImageViews(DxvkDevice* dev, VkFormat format) {
+ UnboundViews result;
+ result.view1D = createImageView(dev, m_image1D, format, VK_IMAGE_VIEW_TYPE_1D, 1);
+ result.view1DArr = createImageView(dev, m_image1D, format, VK_IMAGE_VIEW_TYPE_1D_ARRAY, 1);
+ result.view2D = createImageView(dev, m_image2D, format, VK_IMAGE_VIEW_TYPE_2D, 1);
+ result.view2DArr = createImageView(dev, m_image2D, format, VK_IMAGE_VIEW_TYPE_2D_ARRAY, 1);
+ result.viewCube = createImageView(dev, m_image2D, format, VK_IMAGE_VIEW_TYPE_CUBE, 6);
+ result.viewCubeArr = createImageView(dev, m_image2D, format, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, 6);
+ result.view3D = createImageView(dev, m_image3D, format, VK_IMAGE_VIEW_TYPE_3D, 1);
+ return result;
+ }
+
+
+ const DxvkImageView* DxvkUnboundResources::getImageView(VkImageViewType type, bool sampled) const {
+ auto views = sampled ? &m_viewsSampled : &m_viewsStorage;
+
+ switch (type) {
+ case VK_IMAGE_VIEW_TYPE_1D: return views->view1D.ptr();
+ case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return views->view1DArr.ptr();
+ // When implicit samplers are unbound -- we assume 2D in the shader.
+ case VK_IMAGE_VIEW_TYPE_MAX_ENUM:
+ case VK_IMAGE_VIEW_TYPE_2D: return views->view2D.ptr();
+ case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return views->view2DArr.ptr();
+ case VK_IMAGE_VIEW_TYPE_CUBE: return views->viewCube.ptr();
+ case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return views->viewCubeArr.ptr();
+ case VK_IMAGE_VIEW_TYPE_3D: return views->view3D.ptr();
+ default: return nullptr;
+ }
+ }
+
+
+ void DxvkUnboundResources::clearBuffer(
+ const Rc<DxvkContext>& ctx,
+ const Rc<DxvkBuffer>& buffer) {
+ ctx->clearBuffer(buffer, 0, buffer->info().size, 0);
+ }
+
+
+ void DxvkUnboundResources::clearImage(
+ const Rc<DxvkContext>& ctx,
+ const Rc<DxvkImage>& image) {
+ ctx->clearColorImage(image,
+ VkClearColorValue { },
+ VkImageSubresourceRange {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, image->info().mipLevels,
+ 0, image->info().numLayers });
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.h
new file mode 100644
index 00000000..d9ae01e0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_unbound.h
@@ -0,0 +1,191 @@
+#pragma once
+
+#include "dxvk_buffer.h"
+#include "dxvk_image.h"
+#include "dxvk_sampler.h"
+
+namespace dxvk {
+
+ class DxvkContext;
+
+ /**
+ * \brief Unbound resources
+ *
+ * Creates dummy resources that will be used
+ * for descriptor sets when the client API did
+ * not bind a compatible resource to a slot.
+ */
+ class DxvkUnboundResources {
+
+ public:
+
+ DxvkUnboundResources(DxvkDevice* dev);
+ ~DxvkUnboundResources();
+
+ /**
+ * \brief Dummy buffer handle
+ *
+ * Returns a handle to a buffer filled
+ * with zeroes. Use for unbound vertex
+ * and index buffers.
+ * \returns Dummy buffer handle
+ */
+ VkBuffer bufferHandle() const {
+ return m_buffer->getSliceHandle().handle;
+ }
+
+ /**
+ * \brief Dummy buffer descriptor
+ *
+ * Points to a small buffer filled with zeroes.
+ * Do not write to this buffer, and do not use
+ * it if out-of-bounds read access is possible.
+ * \returns Dummy buffer descriptor
+ */
+ VkDescriptorBufferInfo bufferDescriptor() const {
+ auto slice = m_buffer->getSliceHandle();
+
+ VkDescriptorBufferInfo result;
+ result.buffer = slice.handle;
+ result.offset = slice.offset;
+ result.range = slice.length;
+ return result;
+ }
+
+ /**
+ * \brief Dummy buffer view
+ *
+ * Returns an \c R32_UINT view into the
+ * dummy buffer, which will contain one
+ * element with undefined value.
+ * \returns Dummy buffer view
+ */
+ VkBufferView bufferViewDescriptor() const {
+ return m_bufferView->handle();
+ }
+
+ /**
+ * \brief Dummy sampler descriptor
+ *
+ * Points to a sampler which was created with
+ * reasonable default values. Client APIs may
+ * still require different behaviour.
+ * \returns Dummy sampler descriptor
+ */
+ VkDescriptorImageInfo samplerDescriptor() const {
+ VkDescriptorImageInfo result;
+ result.sampler = m_sampler->handle();
+ result.imageView = VK_NULL_HANDLE;
+ result.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ return result;
+ }
+
+ /**
+ * \brief Dummy combined image sampler descriptor
+ *
+ * Contains both an image view and a sampler
+ * descriptor for the given image view type.
+ * \param [in] type Image view type
+ * \returns Dummy image view descriptor
+ */
+ VkDescriptorImageInfo imageSamplerDescriptor(VkImageViewType type) const {
+ auto view = getImageView(type, true);
+
+ VkDescriptorImageInfo result;
+ result.sampler = m_sampler->handle();
+ result.imageView = view->handle();
+ result.imageLayout = view->imageInfo().layout;
+ return result;
+ }
+
+ /**
+ * \brief Dummy image view descriptor
+ *
+ * Points to an image view which, instead of
+ * reading image data, will return zeroes for
+ * all components unconditionally.
+ * \param [in] type Image view type
+ * \param [in] sampled Format selector
+ * \returns Dummy image view descriptor
+ */
+ VkDescriptorImageInfo imageViewDescriptor(VkImageViewType type, bool sampled) const {
+ auto view = getImageView(type, sampled);
+
+ VkDescriptorImageInfo result;
+ result.sampler = VK_NULL_HANDLE;
+ result.imageView = view->handle();
+ result.imageLayout = view->imageInfo().layout;
+ return result;
+ }
+
+ /**
+ * \brief Clears the resources
+ *
+ * Initializes all images and buffers to zero.
+ * \param [in] dev The DXVK device handle
+ */
+ void clearResources(DxvkDevice* dev);
+
+ private:
+
+ struct UnboundViews {
+ Rc<DxvkImageView> view1D;
+ Rc<DxvkImageView> view1DArr;
+ Rc<DxvkImageView> view2D;
+ Rc<DxvkImageView> view2DArr;
+ Rc<DxvkImageView> viewCube;
+ Rc<DxvkImageView> viewCubeArr;
+ Rc<DxvkImageView> view3D;
+ };
+
+ Rc<DxvkSampler> m_sampler;
+
+ Rc<DxvkBuffer> m_buffer;
+ Rc<DxvkBufferView> m_bufferView;
+
+ Rc<DxvkImage> m_image1D;
+ Rc<DxvkImage> m_image2D;
+ Rc<DxvkImage> m_image3D;
+
+ UnboundViews m_viewsSampled;
+ UnboundViews m_viewsStorage;
+
+ Rc<DxvkSampler> createSampler(DxvkDevice* dev);
+
+ Rc<DxvkBuffer> createBuffer(DxvkDevice* dev);
+
+ Rc<DxvkBufferView> createBufferView(
+ DxvkDevice* dev,
+ const Rc<DxvkBuffer>& buffer);
+
+ Rc<DxvkImage> createImage(
+ DxvkDevice* dev,
+ VkImageType type,
+ uint32_t layers);
+
+ Rc<DxvkImageView> createImageView(
+ DxvkDevice* dev,
+ const Rc<DxvkImage>& image,
+ VkFormat format,
+ VkImageViewType type,
+ uint32_t layers);
+
+ UnboundViews createImageViews(
+ DxvkDevice* dev,
+ VkFormat format);
+
+ const DxvkImageView* getImageView(
+ VkImageViewType type,
+ bool sampled) const;
+
+ void clearBuffer(
+ const Rc<DxvkContext>& ctx,
+ const Rc<DxvkBuffer>& buffer);
+
+ void clearImage(
+ const Rc<DxvkContext>& ctx,
+ const Rc<DxvkImage>& image);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.cpp
new file mode 100644
index 00000000..4dcf6aca
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.cpp
@@ -0,0 +1,346 @@
+#include <cstring>
+
+#include "dxvk_format.h"
+#include "dxvk_util.h"
+
+namespace dxvk::util {
+
+ VkPipelineStageFlags pipelineStages(
+ VkShaderStageFlags shaderStages) {
+ VkPipelineStageFlags result = 0;
+ if (shaderStages & VK_SHADER_STAGE_COMPUTE_BIT)
+ result |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ if (shaderStages & VK_SHADER_STAGE_VERTEX_BIT)
+ result |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+ if (shaderStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
+ result |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
+ if (shaderStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
+ result |= VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
+ if (shaderStages & VK_SHADER_STAGE_GEOMETRY_BIT)
+ result |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
+ if (shaderStages & VK_SHADER_STAGE_FRAGMENT_BIT)
+ result |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ return result;
+ }
+
+
+ uint32_t computeMipLevelCount(VkExtent3D imageSize) {
+ uint32_t maxDim = std::max(imageSize.width, imageSize.height);
+ maxDim = std::max(imageSize.depth, maxDim);
+ uint32_t mipCnt = 0;
+
+ while (maxDim > 0) {
+ mipCnt += 1;
+ maxDim /= 2;
+ }
+
+ return mipCnt;
+ }
+
+
+ void packImageData(
+ void* dstBytes,
+ const void* srcBytes,
+ VkExtent3D blockCount,
+ VkDeviceSize blockSize,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer) {
+ auto dstData = reinterpret_cast< char*>(dstBytes);
+ auto srcData = reinterpret_cast<const char*>(srcBytes);
+
+ const VkDeviceSize bytesPerRow = blockCount.width * blockSize;
+ const VkDeviceSize bytesPerLayer = blockCount.height * bytesPerRow;
+ const VkDeviceSize bytesTotal = blockCount.depth * bytesPerLayer;
+
+ const bool directCopy = ((bytesPerRow == pitchPerRow ) || (blockCount.height == 1))
+ && ((bytesPerLayer == pitchPerLayer) || (blockCount.depth == 1));
+
+ if (directCopy) {
+ std::memcpy(dstData, srcData, bytesTotal);
+ } else {
+ for (uint32_t i = 0; i < blockCount.depth; i++) {
+ for (uint32_t j = 0; j < blockCount.height; j++) {
+ std::memcpy(
+ dstData + j * bytesPerRow,
+ srcData + j * pitchPerRow,
+ bytesPerRow);
+ }
+
+ srcData += pitchPerLayer;
+ dstData += bytesPerLayer;
+ }
+ }
+ }
+
+
+ void packImageData(
+ void* dstBytes,
+ const void* srcBytes,
+ VkDeviceSize srcRowPitch,
+ VkDeviceSize srcSlicePitch,
+ VkDeviceSize dstRowPitchIn,
+ VkDeviceSize dstSlicePitchIn,
+ VkImageType imageType,
+ VkExtent3D imageExtent,
+ uint32_t imageLayers,
+ const DxvkFormatInfo* formatInfo,
+ VkImageAspectFlags aspectMask) {
+ for (uint32_t i = 0; i < imageLayers; i++) {
+ auto dstData = reinterpret_cast< char*>(dstBytes);
+ auto srcData = reinterpret_cast<const char*>(srcBytes);
+
+ for (auto aspects = aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto extent = imageExtent;
+ auto elementSize = formatInfo->elementSize;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ extent.width /= plane->blockSize.width;
+ extent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ auto blockCount = computeBlockCount(extent, formatInfo->blockSize);
+
+ VkDeviceSize bytesPerRow = blockCount.width * elementSize;
+ VkDeviceSize bytesPerSlice = blockCount.height * bytesPerRow;
+ VkDeviceSize bytesTotal = blockCount.depth * bytesPerSlice;
+
+ VkDeviceSize dstRowPitch = dstRowPitchIn ? dstRowPitchIn : bytesPerRow;
+ VkDeviceSize dstSlicePitch = dstSlicePitchIn ? dstSlicePitchIn : bytesPerSlice;
+
+ const bool directCopy = ((bytesPerRow == srcRowPitch && bytesPerRow == dstRowPitch ) || (blockCount.height == 1))
+ && ((bytesPerSlice == srcSlicePitch && bytesPerSlice == dstSlicePitch) || (blockCount.depth == 1));
+
+ if (directCopy) {
+ std::memcpy(dstData, srcData, bytesTotal);
+
+ switch (imageType) {
+ case VK_IMAGE_TYPE_1D:
+ srcData += srcRowPitch;
+ dstData += dstRowPitch;
+ break;
+ case VK_IMAGE_TYPE_2D:
+ srcData += blockCount.height * srcRowPitch;
+ dstData += blockCount.height * dstRowPitch;
+ break;
+ case VK_IMAGE_TYPE_3D:
+ srcData += blockCount.depth * srcSlicePitch;
+ dstData += blockCount.depth * dstSlicePitch;
+ break;
+ default: ;
+ }
+ } else {
+ for (uint32_t i = 0; i < blockCount.depth; i++) {
+ for (uint32_t j = 0; j < blockCount.height; j++) {
+ std::memcpy(
+ dstData + j * dstRowPitch,
+ srcData + j * srcRowPitch,
+ bytesPerRow);
+ }
+
+ switch (imageType) {
+ case VK_IMAGE_TYPE_1D:
+ srcData += srcRowPitch;
+ dstData += dstRowPitch;
+ break;
+ case VK_IMAGE_TYPE_2D:
+ srcData += blockCount.height * srcRowPitch;
+ dstData += blockCount.height * dstRowPitch;
+ break;
+ case VK_IMAGE_TYPE_3D:
+ srcData += srcSlicePitch;
+ dstData += dstSlicePitch;
+ break;
+ default: ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ VkDeviceSize computeImageDataSize(VkFormat format, VkExtent3D extent) {
+ const DxvkFormatInfo* formatInfo = imageFormatInfo(format);
+
+ VkDeviceSize size = 0;
+
+ for (auto aspects = formatInfo->aspectMask; aspects; ) {
+ auto aspect = vk::getNextAspect(aspects);
+ auto elementSize = formatInfo->elementSize;
+ auto planeExtent = extent;
+
+ if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
+ auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
+ planeExtent.width /= plane->blockSize.width;
+ planeExtent.height /= plane->blockSize.height;
+ elementSize = plane->elementSize;
+ }
+
+ size += elementSize * flattenImageExtent(computeBlockCount(planeExtent, formatInfo->blockSize));
+ }
+
+ return size;
+ }
+
+
+ static VkColorComponentFlags remapComponentFlag(
+ VkColorComponentFlags mask,
+ VkComponentSwizzle swizzle,
+ VkColorComponentFlagBits identity) {
+ VkColorComponentFlags bit;
+
+ switch (swizzle) {
+ case VK_COMPONENT_SWIZZLE_IDENTITY: bit = identity; break;
+ case VK_COMPONENT_SWIZZLE_R: bit = VK_COLOR_COMPONENT_R_BIT; break;
+ case VK_COMPONENT_SWIZZLE_G: bit = VK_COLOR_COMPONENT_G_BIT; break;
+ case VK_COMPONENT_SWIZZLE_B: bit = VK_COLOR_COMPONENT_B_BIT; break;
+ case VK_COMPONENT_SWIZZLE_A: bit = VK_COLOR_COMPONENT_A_BIT; break;
+ default: bit = 0; /* SWIZZLE_ZERO, SWIZZLE_ONE */
+ }
+
+ return (mask & bit) ? identity : 0;
+ }
+
+
+ VkColorComponentFlags remapComponentMask(
+ VkColorComponentFlags mask,
+ VkComponentMapping mapping) {
+ VkColorComponentFlags result = 0;
+ result |= remapComponentFlag(mask, mapping.r, VK_COLOR_COMPONENT_R_BIT);
+ result |= remapComponentFlag(mask, mapping.g, VK_COLOR_COMPONENT_G_BIT);
+ result |= remapComponentFlag(mask, mapping.b, VK_COLOR_COMPONENT_B_BIT);
+ result |= remapComponentFlag(mask, mapping.a, VK_COLOR_COMPONENT_A_BIT);
+ return result;
+ }
+
+
+ static VkComponentSwizzle findComponentSwizzle(
+ VkComponentSwizzle swizzle,
+ VkComponentSwizzle identity,
+ VkComponentMapping mapping) {
+ if (identity == VK_COMPONENT_SWIZZLE_IDENTITY)
+ return VK_COMPONENT_SWIZZLE_IDENTITY;
+
+ if (mapping.r == swizzle)
+ return VK_COMPONENT_SWIZZLE_R;
+ if (mapping.g == swizzle)
+ return VK_COMPONENT_SWIZZLE_G;
+ if (mapping.b == swizzle)
+ return VK_COMPONENT_SWIZZLE_B;
+ if (mapping.a == swizzle)
+ return VK_COMPONENT_SWIZZLE_A;
+
+ return VK_COMPONENT_SWIZZLE_ZERO;
+ }
+
+
+ VkComponentMapping invertComponentMapping(VkComponentMapping mapping) {
+ VkComponentMapping result;
+ result.r = findComponentSwizzle(VK_COMPONENT_SWIZZLE_R, mapping.r, mapping);
+ result.g = findComponentSwizzle(VK_COMPONENT_SWIZZLE_G, mapping.g, mapping);
+ result.b = findComponentSwizzle(VK_COMPONENT_SWIZZLE_B, mapping.b, mapping);
+ result.a = findComponentSwizzle(VK_COMPONENT_SWIZZLE_A, mapping.a, mapping);
+ return result;
+ }
+
+
+ static VkComponentMapping normalizeComponentMapping(
+ VkComponentMapping mapping) {
+ mapping.r = mapping.r == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_R : mapping.r;
+ mapping.g = mapping.g == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_G : mapping.g;
+ mapping.b = mapping.b == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_B : mapping.b;
+ mapping.a = mapping.a == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_A : mapping.a;
+ return mapping;
+ }
+
+
+ static VkComponentSwizzle resolveComponentSwizzle(
+ VkComponentSwizzle swizzle,
+ VkComponentMapping dstMapping,
+ VkComponentMapping srcMapping) {
+ VkComponentSwizzle dstSwizzle = VK_COMPONENT_SWIZZLE_IDENTITY;
+ if (dstMapping.r == swizzle) dstSwizzle = VK_COMPONENT_SWIZZLE_R;
+ if (dstMapping.g == swizzle) dstSwizzle = VK_COMPONENT_SWIZZLE_G;
+ if (dstMapping.b == swizzle) dstSwizzle = VK_COMPONENT_SWIZZLE_B;
+ if (dstMapping.a == swizzle) dstSwizzle = VK_COMPONENT_SWIZZLE_A;
+
+ switch (dstSwizzle) {
+ case VK_COMPONENT_SWIZZLE_R: return srcMapping.r;
+ case VK_COMPONENT_SWIZZLE_G: return srcMapping.g;
+ case VK_COMPONENT_SWIZZLE_B: return srcMapping.b;
+ case VK_COMPONENT_SWIZZLE_A: return srcMapping.a;
+ default: return VK_COMPONENT_SWIZZLE_IDENTITY;
+ }
+ }
+
+
+ VkComponentMapping resolveSrcComponentMapping(
+ VkComponentMapping dstMapping,
+ VkComponentMapping srcMapping) {
+ dstMapping = normalizeComponentMapping(dstMapping);
+
+ VkComponentMapping result;
+ result.r = resolveComponentSwizzle(VK_COMPONENT_SWIZZLE_R, dstMapping, srcMapping);
+ result.g = resolveComponentSwizzle(VK_COMPONENT_SWIZZLE_G, dstMapping, srcMapping);
+ result.b = resolveComponentSwizzle(VK_COMPONENT_SWIZZLE_B, dstMapping, srcMapping);
+ result.a = resolveComponentSwizzle(VK_COMPONENT_SWIZZLE_A, dstMapping, srcMapping);
+ return result;
+ }
+
+
+ bool isIdentityMapping(
+ VkComponentMapping mapping) {
+ return (mapping.r == VK_COMPONENT_SWIZZLE_R || mapping.r == VK_COMPONENT_SWIZZLE_IDENTITY)
+ && (mapping.g == VK_COMPONENT_SWIZZLE_G || mapping.g == VK_COMPONENT_SWIZZLE_IDENTITY)
+ && (mapping.b == VK_COMPONENT_SWIZZLE_B || mapping.b == VK_COMPONENT_SWIZZLE_IDENTITY)
+ && (mapping.a == VK_COMPONENT_SWIZZLE_A || mapping.a == VK_COMPONENT_SWIZZLE_IDENTITY);
+ }
+
+
+ uint32_t getComponentIndex(
+ VkComponentSwizzle component,
+ uint32_t identity) {
+ switch (component) {
+ case VK_COMPONENT_SWIZZLE_R: return 0;
+ case VK_COMPONENT_SWIZZLE_G: return 1;
+ case VK_COMPONENT_SWIZZLE_B: return 2;
+ case VK_COMPONENT_SWIZZLE_A: return 3;
+ default: return identity; /* identity, zero, one */
+ }
+ }
+
+
+ VkClearColorValue swizzleClearColor(
+ VkClearColorValue color,
+ VkComponentMapping mapping) {
+ VkClearColorValue result;
+ auto swizzles = &mapping.r;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ uint32_t index = getComponentIndex(swizzles[i], i);
+ result.uint32[i] = color.uint32[index];
+ }
+
+ return result;
+ }
+
+
+ bool isBlendConstantBlendFactor(VkBlendFactor factor) {
+ return factor == VK_BLEND_FACTOR_CONSTANT_COLOR
+ || factor == VK_BLEND_FACTOR_CONSTANT_ALPHA
+ || factor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR
+ || factor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
+ }
+
+
+ bool isDualSourceBlendFactor(VkBlendFactor factor) {
+ return factor == VK_BLEND_FACTOR_SRC1_COLOR
+ || factor == VK_BLEND_FACTOR_SRC1_ALPHA
+ || factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR
+ || factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.h
new file mode 100644
index 00000000..4527f14e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/dxvk_util.h
@@ -0,0 +1,338 @@
+#pragma once
+
+#include "dxvk_include.h"
+
+namespace dxvk::util {
+
+ /**
+ * \brief Gets pipeline stage flags for shader stages
+ *
+ * \param [in] shaderStages Shader stage flags
+ * \returns Corresponding pipeline stage flags
+ */
+ VkPipelineStageFlags pipelineStages(
+ VkShaderStageFlags shaderStages);
+
+ /**
+ * \brief Computes number of mip levels for an image
+ *
+ * \param [in] imageSize Size of the image
+ * \returns Number of mipmap layers
+ */
+ uint32_t computeMipLevelCount(VkExtent3D imageSize);
+
+ /**
+ * \brief Writes tightly packed image data to a buffer
+ *
+ * \param [in] dstBytes Destination buffer pointer
+ * \param [in] srcBytes Pointer to source data
+ * \param [in] blockCount Number of blocks to copy
+ * \param [in] blockSize Number of bytes per block
+ * \param [in] pitchPerRow Number of bytes between rows
+ * \param [in] pitchPerLayer Number of bytes between layers
+ */
+ void packImageData(
+ void* dstBytes,
+ const void* srcBytes,
+ VkExtent3D blockCount,
+ VkDeviceSize blockSize,
+ VkDeviceSize pitchPerRow,
+ VkDeviceSize pitchPerLayer);
+
+ /**
+ * \brief Repacks image data to a buffer
+ *
+ * Note that passing destination pitches of 0 means that the data is
+ * tightly packed, while a source pitch of 0 will not show this behaviour
+ * in order to match client API behaviour for initialization.
+ * \param [in] dstBytes Destination buffer pointer
+ * \param [in] srcBytes Pointer to source data
+ * \param [in] srcRowPitch Number of bytes between rows to read
+ * \param [in] srcSlicePitch Number of bytes between layers to read
+ * \param [in] dstRowPitch Number of bytes between rows to write
+ * \param [in] dstSlicePitch Number of bytes between layers to write
+ * \param [in] imageType Image type (2D, 3D etc)
+ * \param [in] imageExtent Image extent, in pixels
+ * \param [in] imageLayers Image layer count
+ * \param [in] formatInfo Image format info
+ * \param [in] aspectMask Image aspects to pack
+ */
+ void packImageData(
+ void* dstBytes,
+ const void* srcBytes,
+ VkDeviceSize srcRowPitch,
+ VkDeviceSize srcSlicePitch,
+ VkDeviceSize dstRowPitchIn,
+ VkDeviceSize dstSlicePitchIn,
+ VkImageType imageType,
+ VkExtent3D imageExtent,
+ uint32_t imageLayers,
+ const DxvkFormatInfo* formatInfo,
+ VkImageAspectFlags aspectMask);
+
+ /**
+ * \brief Computes minimum extent
+ *
+ * \param [in] a First value
+ * \param [in] b Second value
+ * \returns Component-wise \c min
+ */
+ inline VkExtent3D minExtent3D(VkExtent3D a, VkExtent3D b) {
+ return VkExtent3D {
+ std::min(a.width, b.width),
+ std::min(a.height, b.height),
+ std::min(a.depth, b.depth) };
+ }
+
+ /**
+ * \brief Checks whether an offset is block-aligned
+ *
+ * An offset is considered block-aligned if it is
+ * a multiple of the block size. Only non-negative
+ * offset values are valid.
+ * \param [in] offset The offset to check
+ * \param [in] blockSize Block size
+ * \returns \c true if \c offset is aligned
+ */
+ inline bool isBlockAligned(VkOffset3D offset, VkExtent3D blockSize) {
+ return (offset.x % blockSize.width == 0)
+ && (offset.y % blockSize.height == 0)
+ && (offset.z % blockSize.depth == 0);
+ }
+
+ /**
+ * \brief Checks whether an offset and extent are block-aligned
+ *
+ * A block-aligned extent can be used for image copy
+ * operations that involve block-compressed images.
+ * \param [in] offset The base offset
+ * \param [in] extent The extent to check
+ * \param [in] blockSize Compressed block size
+ * \param [in] imageSize Image size
+ * \returns \c true if all components of \c extent
+ * are aligned or touch the image border.
+ */
+ inline bool isBlockAligned(VkOffset3D offset, VkExtent3D extent, VkExtent3D blockSize, VkExtent3D imageSize) {
+ return ((extent.width % blockSize.width == 0) || (uint32_t(offset.x + extent.width) == imageSize.width))
+ && ((extent.height % blockSize.height == 0) || (uint32_t(offset.y + extent.height) == imageSize.height))
+ && ((extent.depth % blockSize.depth == 0) || (uint32_t(offset.z + extent.depth) == imageSize.depth))
+ && isBlockAligned(offset, blockSize);
+ }
+
+ /**
+ * \brief Computes mip level extent
+ *
+ * \param [in] size Base mip level extent
+ * \param [in] level mip level to compute
+ * \returns Extent of the given mip level
+ */
+ inline VkExtent3D computeMipLevelExtent(VkExtent3D size, uint32_t level) {
+ size.width = std::max(1u, size.width >> level);
+ size.height = std::max(1u, size.height >> level);
+ size.depth = std::max(1u, size.depth >> level);
+ return size;
+ }
+
+ /**
+ * \brief Computes mip level extent
+ *
+ * This function variant takes into account planar formats.
+ * \param [in] size Base mip level extent
+ * \param [in] level Mip level to compute
+ * \param [in] format Image format
+ * \param [in] aspect Image aspect to consider
+ * \returns Extent of the given mip level
+ */
+ inline VkExtent3D computeMipLevelExtent(VkExtent3D size, uint32_t level, VkFormat format, VkImageAspectFlags aspect) {
+ if (unlikely(!(aspect & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))) {
+ auto plane = &imageFormatInfo(format)->planes[vk::getPlaneIndex(aspect)];
+ size.width /= plane->blockSize.width;
+ size.height /= plane->blockSize.height;
+ }
+
+ size.width = std::max(1u, size.width >> level);
+ size.height = std::max(1u, size.height >> level);
+ size.depth = std::max(1u, size.depth >> level);
+ return size;
+ }
+
+ /**
+ * \brief Computes block offset for compressed images
+ *
+ * Convenience function to compute the block position
+ * within a compressed image based on the block size.
+ * \param [in] offset The offset
+ * \param [in] blockSize Size of a pixel block
+ * \returns The block offset
+ */
+ inline VkOffset3D computeBlockOffset(VkOffset3D offset, VkExtent3D blockSize) {
+ return VkOffset3D {
+ offset.x / int32_t(blockSize.width),
+ offset.y / int32_t(blockSize.height),
+ offset.z / int32_t(blockSize.depth) };
+ }
+
+ /**
+ * \brief Computes block count for compressed images
+ *
+ * Convenience function to compute the size, in
+ * blocks, of compressed images subresources.
+ * \param [in] extent The image size
+ * \param [in] blockSize Size of a pixel block
+ * \returns Number of blocks in the image
+ */
+ inline VkExtent3D computeBlockCount(VkExtent3D extent, VkExtent3D blockSize) {
+ return VkExtent3D {
+ (extent.width + blockSize.width - 1) / blockSize.width,
+ (extent.height + blockSize.height - 1) / blockSize.height,
+ (extent.depth + blockSize.depth - 1) / blockSize.depth };
+ }
+
+ /**
+ * \brief Computes block count for compressed images
+ *
+ * Given an aligned offset, this computes
+ * Convenience function to compute the size, in
+ * blocks, of compressed images subresources.
+ * \param [in] extent The image size
+ * \param [in] blockSize Size of a pixel block
+ * \returns Number of blocks in the image
+ */
+ inline VkExtent3D computeMaxBlockCount(VkOffset3D offset, VkExtent3D extent, VkExtent3D blockSize) {
+ return VkExtent3D {
+ (extent.width + blockSize.width - offset.x - 1) / blockSize.width,
+ (extent.height + blockSize.height - offset.y - 1) / blockSize.height,
+ (extent.depth + blockSize.depth - offset.z - 1) / blockSize.depth };
+ }
+
+ /**
+ * \brief Snaps block-aligned image extent to image edges
+ *
+ * Fixes up an image extent that is aligned to a compressed
+ * block so that it no longer exceeds the given image size.
+ * \param [in] offset Aligned pixel offset
+ * \param [in] extent Extent to clamp
+ * \param [in] imageExtent Image size
+ * \returns Number of blocks in the image
+ */
+ inline VkExtent3D snapExtent3D(VkOffset3D offset, VkExtent3D extent, VkExtent3D imageExtent) {
+ return VkExtent3D {
+ std::min(extent.width, imageExtent.width - uint32_t(offset.x)),
+ std::min(extent.height, imageExtent.height - uint32_t(offset.y)),
+ std::min(extent.depth, imageExtent.depth - uint32_t(offset.z)) };
+ }
+
+ /**
+ * \brief Computes block extent for compressed images
+ *
+ * \param [in] blockCount The number of blocks
+ * \param [in] blockSize Size of a pixel block
+ * \returns Extent of the given blocks
+ */
+ inline VkExtent3D computeBlockExtent(VkExtent3D blockCount, VkExtent3D blockSize) {
+ return VkExtent3D {
+ blockCount.width * blockSize.width,
+ blockCount.height * blockSize.height,
+ blockCount.depth * blockSize.depth };
+ }
+
+ /**
+ * \brief Computes number of pixels or blocks of an image
+ *
+ * Basically returns the product of width, height and depth.
+ * \param [in] extent Image extent, in pixels or blocks
+ * \returns Flattened number of pixels or blocks
+ */
+ inline uint32_t flattenImageExtent(VkExtent3D extent) {
+ return extent.width * extent.height * extent.depth;
+ }
+
+ /**
+ * \brief Checks whether the depth aspect is read-only in a layout
+ *
+ * \param [in] layout Image layout. Must be a valid depth-stencil attachment laoyut.
+ * \returns \c true if the depth aspect for images in this layout is read-only.
+ */
+ inline bool isDepthReadOnlyLayout(VkImageLayout layout) {
+ return layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
+ || layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
+ }
+
+ /**
+ * \brief Computes image data size, in bytes
+ *
+ * Convenience method that can be used to compute the number
+ * of bytes required to store image data in a given format.
+ * \param [in] format The image format
+ * \param [in] extent Image size, in pixels
+ * \returns Data size, in bytes
+ */
+ VkDeviceSize computeImageDataSize(VkFormat format, VkExtent3D extent);
+
+ /**
+ * \brief Applies a component mapping to a component mask
+ *
+ * For each component, the component specified in the mapping
+ * is used to look up the flag of the original component mask.
+ * If the component mapping is zero or one, the corresponding
+ * mask bit will be set to zero.
+ * \param [in] mask The original component mask
+ * \param [in] mapping Component mapping to apply
+ * \returns Remapped component mask
+ */
+ VkColorComponentFlags remapComponentMask(
+ VkColorComponentFlags mask,
+ VkComponentMapping mapping);
+
+ /**
+ * \brief Inverts a component mapping
+ *
+ * Transforms a component mapping so that components can
+ * be mapped back to their original location. Requires
+ * that each component is used only once.
+ *
+ * For example. when given a mapping of (0,0,0,R),
+ * this function will return the mapping (A,0,0,0).
+ * \returns Inverted component mapping
+ */
+ VkComponentMapping invertComponentMapping(
+ VkComponentMapping mapping);
+
+ /**
+ * \brief Resolves source component mapping
+ *
+ * Returns the source component mapping after rearranging
+ * the destination mapping to be the identity mapping.
+ * \param [in] dstMapping Destination mapping
+ * \param [in] srcMapping Source mapping
+ * \returns Adjusted src component mapping
+ */
+ VkComponentMapping resolveSrcComponentMapping(
+ VkComponentMapping dstMapping,
+ VkComponentMapping srcMapping);
+
+ bool isIdentityMapping(
+ VkComponentMapping mapping);
+
+ /**
+ * \brief Computes component index for a component swizzle
+ *
+ * \param [in] component The component swizzle
+ * \param [in] identity Value for SWIZZLE_IDENTITY
+ * \returns Component index
+ */
+ uint32_t getComponentIndex(
+ VkComponentSwizzle component,
+ uint32_t identity);
+
+ VkClearColorValue swizzleClearColor(
+ VkClearColorValue color,
+ VkComponentMapping mapping);
+
+ bool isBlendConstantBlendFactor(
+ VkBlendFactor factor);
+
+ bool isDualSourceBlendFactor(
+ VkBlendFactor factor);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.cpp
new file mode 100644
index 00000000..c4c3b549
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.cpp
@@ -0,0 +1,112 @@
+#include <cstring>
+
+#include "dxvk_hud.h"
+
+namespace dxvk::hud {
+
+ Hud::Hud(
+ const Rc<DxvkDevice>& device)
+ : m_device (device),
+ m_renderer (device),
+ m_hudItems (device),
+ m_scale (m_hudItems.getOption<float>("scale", 1.0f)) {
+ // Sanitize scaling factor
+ if (m_scale < 0.01f)
+ m_scale = 1.0f;
+
+ // Set up constant state
+ m_rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ m_rsState.cullMode = VK_CULL_MODE_BACK_BIT;
+ m_rsState.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ m_rsState.depthClipEnable = VK_FALSE;
+ m_rsState.depthBiasEnable = VK_FALSE;
+ m_rsState.conservativeMode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
+ m_rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+
+ m_blendMode.enableBlending = VK_TRUE;
+ m_blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
+ m_blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ m_blendMode.colorBlendOp = VK_BLEND_OP_ADD;
+ m_blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
+ m_blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ m_blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
+ m_blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
+ | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT
+ | VK_COLOR_COMPONENT_A_BIT;
+
+ addItem<HudVersionItem>("version", -1);
+ addItem<HudDeviceInfoItem>("devinfo", -1, m_device);
+ addItem<HudFpsItem>("fps", -1);
+ addItem<HudFrameTimeItem>("frametimes", -1);
+ addItem<HudSubmissionStatsItem>("submissions", -1, device);
+ addItem<HudDrawCallStatsItem>("drawcalls", -1, device);
+ addItem<HudPipelineStatsItem>("pipelines", -1, device);
+ addItem<HudMemoryStatsItem>("memory", -1, device);
+ addItem<HudGpuLoadItem>("gpuload", -1, device);
+ addItem<HudCompilerActivityItem>("compiler", -1, device);
+ }
+
+
+ Hud::~Hud() {
+
+ }
+
+
+ void Hud::update() {
+ m_hudItems.update();
+ }
+
+
+ void Hud::render(
+ const Rc<DxvkContext>& ctx,
+ VkSurfaceFormatKHR surfaceFormat,
+ VkExtent2D surfaceSize) {
+ this->setupRendererState(ctx, surfaceFormat, surfaceSize);
+ this->renderHudElements(ctx);
+ this->resetRendererState(ctx);
+ }
+
+
+ Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) {
+ return new Hud(device);
+ }
+
+
+ void Hud::setupRendererState(
+ const Rc<DxvkContext>& ctx,
+ VkSurfaceFormatKHR surfaceFormat,
+ VkExtent2D surfaceSize) {
+ bool isSrgb = imageFormatInfo(surfaceFormat.format)->flags.test(DxvkFormatFlag::ColorSpaceSrgb);
+
+ VkViewport viewport;
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = float(surfaceSize.width);
+ viewport.height = float(surfaceSize.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset = { 0, 0 };
+ scissor.extent = surfaceSize;
+
+ ctx->setViewports(1, &viewport, &scissor);
+ ctx->setRasterizerState(m_rsState);
+ ctx->setBlendMode(0, m_blendMode);
+
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, isSrgb);
+ m_renderer.beginFrame(ctx, surfaceSize, m_scale);
+ }
+
+
+ void Hud::resetRendererState(const Rc<DxvkContext>& ctx) {
+ ctx->setSpecConstant(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0);
+ }
+
+
+ void Hud::renderHudElements(const Rc<DxvkContext>& ctx) {
+ m_hudItems.render(m_renderer);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.h
new file mode 100644
index 00000000..d6217b8c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud.h
@@ -0,0 +1,101 @@
+#pragma once
+
+#include "../dxvk_device.h"
+
+#include "dxvk_hud_item.h"
+#include "dxvk_hud_renderer.h"
+
+namespace dxvk::hud {
+
+ /**
+ * \brief HUD uniform data
+ * Shader data for the HUD.
+ */
+ struct HudUniformData {
+ VkExtent2D surfaceSize;
+ };
+
+ /**
+ * \brief DXVK HUD
+ *
+ * Can be used by the presentation backend to
+ * display performance and driver information.
+ */
+ class Hud : public RcObject {
+
+ public:
+
+ Hud(const Rc<DxvkDevice>& device);
+
+ ~Hud();
+
+ /**
+ * \brief Update HUD
+ *
+ * Updates the data to display.
+ * Should be called once per frame.
+ */
+ void update();
+
+ /**
+ * \brief Render HUD
+ *
+ * Renders the HUD to the given context.
+ * \param [in] ctx Device context
+ * \param [in] surfaceSize Image size, in pixels
+ */
+ void render(
+ const Rc<DxvkContext>& ctx,
+ VkSurfaceFormatKHR surfaceFormat,
+ VkExtent2D surfaceSize);
+
+ /**
+ * \brief Adds a HUD item if enabled
+ *
+ * \tparam T The HUD item type
+ * \param [in] name HUD item name
+ * \param [in] args Constructor arguments
+ */
+ template<typename T, typename... Args>
+ void addItem(const char* name, int32_t at, Args... args) {
+ m_hudItems.add<T>(name, at, std::forward<Args>(args)...);
+ }
+
+ /**
+ * \brief Creates the HUD
+ *
+ * Creates and initializes the HUD if the
+ * \c DXVK_HUD environment variable is set.
+ * \param [in] device The DXVK device
+ * \returns HUD object, if it was created.
+ */
+ static Rc<Hud> createHud(
+ const Rc<DxvkDevice>& device);
+
+ private:
+
+ const Rc<DxvkDevice> m_device;
+
+ DxvkRasterizerState m_rsState;
+ DxvkBlendMode m_blendMode;
+
+ HudUniformData m_uniformData;
+ HudRenderer m_renderer;
+ HudItemSet m_hudItems;
+
+ float m_scale;
+
+ void setupRendererState(
+ const Rc<DxvkContext>& ctx,
+ VkSurfaceFormatKHR surfaceFormat,
+ VkExtent2D surfaceSize);
+
+ void resetRendererState(
+ const Rc<DxvkContext>& ctx);
+
+ void renderHudElements(
+ const Rc<DxvkContext>& ctx);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.cpp
new file mode 100644
index 00000000..ea7d4abb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.cpp
@@ -0,0 +1,1872 @@
+#include "dxvk_hud_font.h"
+
+namespace dxvk::hud {
+
+ // Data structures and character map generated with:
+ // https://evanw.github.io/font-texture-generator/
+ //
+ // Font texture and metadata generated from:
+ // 'Source Code Pro' by Adobe Systems Inc.
+ // SIL Open Font License Version 1.1
+ //
+ // See: https://github.com/adobe-fonts/source-code-pro
+ const HudGlyph g_hudFontGlyphs[] = {
+ {' ', 488, 144, 12, 12, 6, 6},
+ {'!', 309, 44, 19, 34, 0, 27},
+ {'"', 294, 144, 26, 24, 3, 28},
+ {'#', 27, 111, 27, 33, 4, 27},
+ {'$', 262, 0, 27, 39, 4, 30},
+ {'%', 450, 44, 30, 33, 5, 27},
+ {'&', 0, 44, 30, 34, 5, 27},
+ {'\'', 320, 144, 18, 24, -1, 28},
+ {'(', 41, 0, 22, 41, 0, 29},
+ {')', 63, 0, 21, 41, 2, 29},
+ {'*', 221, 144, 27, 27, 4, 24},
+ {'+', 194, 144, 27, 27, 4, 24},
+ {',', 248, 144, 20, 26, 0, 13},
+ {'-', 461, 144, 27, 15, 4, 18},
+ {'.', 365, 144, 20, 20, 4, 13},
+ {'/', 111, 0, 27, 40, 4, 29},
+ {'0', 88, 78, 28, 33, 4, 27},
+ {'1', 244, 111, 27, 32, 3, 26},
+ {'2', 396, 78, 28, 33, 4, 27},
+ {'3', 424, 78, 28, 33, 5, 27},
+ {'4', 187, 111, 29, 32, 5, 26},
+ {'5', 284, 78, 28, 33, 4, 26},
+ {'6', 116, 78, 28, 33, 4, 27},
+ {'7', 216, 111, 28, 32, 4, 26},
+ {'8', 172, 78, 28, 33, 4, 27},
+ {'9', 368, 78, 28, 33, 4, 27},
+ {':', 320, 111, 20, 30, 0, 23},
+ {';', 342, 0, 20, 36, 0, 23},
+ {'<', 271, 111, 25, 31, 2, 26},
+ {'=', 338, 144, 27, 23, 4, 22},
+ {'>', 296, 111, 24, 31, 3, 26},
+ {'?', 284, 44, 25, 34, 3, 28},
+ {'@', 289, 0, 29, 38, 5, 27},
+ {'A', 328, 44, 31, 33, 6, 27},
+ {'B', 144, 78, 28, 33, 4, 27},
+ {'C', 59, 44, 29, 34, 4, 27},
+ {'D', 200, 78, 28, 33, 4, 27},
+ {'E', 479, 78, 27, 33, 3, 27},
+ {'F', 161, 111, 26, 33, 3, 27},
+ {'G', 174, 44, 28, 34, 5, 27},
+ {'H', 54, 111, 27, 33, 4, 27},
+ {'I', 108, 111, 27, 33, 4, 27},
+ {'J', 452, 78, 27, 33, 4, 27},
+ {'K', 59, 78, 29, 33, 4, 27},
+ {'L', 135, 111, 26, 33, 3, 27},
+ {'M', 228, 78, 28, 33, 4, 27},
+ {'N', 0, 111, 27, 33, 4, 27},
+ {'O', 117, 44, 29, 34, 5, 27},
+ {'P', 312, 78, 28, 33, 4, 27},
+ {'Q', 232, 0, 30, 39, 5, 27},
+ {'R', 30, 78, 29, 33, 4, 27},
+ {'S', 202, 44, 28, 34, 4, 27},
+ {'T', 480, 44, 30, 33, 5, 27},
+ {'U', 81, 111, 27, 33, 4, 27},
+ {'V', 0, 78, 30, 33, 5, 27},
+ {'W', 359, 44, 31, 33, 6, 27},
+ {'X', 420, 44, 30, 33, 5, 27},
+ {'Y', 390, 44, 30, 33, 5, 27},
+ {'Z', 340, 78, 28, 33, 4, 27},
+ {'[', 210, 0, 22, 40, 0, 29},
+ {'\\', 84, 0, 27, 40, 4, 29},
+ {']', 188, 0, 22, 40, 3, 29},
+ {'^', 268, 144, 26, 25, 3, 27},
+ {'_', 433, 144, 28, 16, 4, 4},
+ {'`', 385, 144, 20, 20, 2, 32},
+ {'a', 396, 111, 28, 29, 4, 22},
+ {'b', 391, 0, 28, 35, 4, 28},
+ {'c', 452, 111, 27, 29, 4, 22},
+ {'d', 475, 0, 27, 35, 4, 28},
+ {'e', 368, 111, 28, 29, 4, 22},
+ {'f', 447, 0, 28, 35, 3, 29},
+ {'g', 362, 0, 29, 35, 4, 22},
+ {'h', 230, 44, 27, 34, 4, 28},
+ {'i', 318, 0, 24, 36, 3, 30},
+ {'j', 16, 0, 25, 43, 5, 30},
+ {'k', 30, 44, 29, 34, 4, 28},
+ {'l', 419, 0, 28, 35, 4, 28},
+ {'m', 58, 144, 29, 28, 5, 22},
+ {'n', 114, 144, 27, 28, 4, 22},
+ {'o', 424, 111, 28, 29, 4, 22},
+ {'p', 146, 44, 28, 34, 4, 22},
+ {'q', 257, 44, 27, 34, 4, 22},
+ {'r', 168, 144, 26, 28, 2, 22},
+ {'s', 340, 111, 28, 29, 4, 22},
+ {'t', 256, 78, 28, 33, 4, 27},
+ {'u', 87, 144, 27, 28, 4, 22},
+ {'v', 29, 144, 29, 28, 5, 22},
+ {'w', 479, 111, 31, 28, 6, 22},
+ {'x', 0, 144, 29, 28, 5, 22},
+ {'y', 88, 44, 29, 34, 5, 22},
+ {'z', 141, 144, 27, 28, 4, 22},
+ {'{', 138, 0, 25, 40, 3, 29},
+ {'|', 0, 0, 16, 44, -2, 30},
+ {'}', 163, 0, 25, 40, 3, 29},
+ {'~', 405, 144, 28, 18, 4, 20},
+ };
+
+ const uint8_t g_hudFontImage[] =
+ {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e
+ ,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x06,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19
+ ,0x21,0x28,0x2a,0x25,0x1d,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x25,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a
+ ,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0a,0x01
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x28,0x21,0x14
+ ,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15
+ ,0x1d,0x25,0x2a,0x28,0x21,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e
+ ,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37,0x40,0x42,0x3c,0x34,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x40,0x42,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31
+ ,0x3c,0x42,0x40,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x40,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x31,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42
+ ,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43
+ ,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02
+ ,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x3c,0x42,0x40,0x37,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21
+ ,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x37,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x38,0x34
+ ,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x46,0x4e,0x57,0x5a,0x51,0x4b,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x5a,0x51,0x40,0x2f,0x1e,0x0d
+ ,0x01,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x51,0x5a,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x46,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36
+ ,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00
+ ,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x40,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46
+ ,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x41,0x4b,0x51,0x5a,0x57,0x4e,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x38,0x27,0x16,0x04
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4f,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x38,0x46
+ ,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x51,0x5c,0x65,0x6b,0x71,0x67,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27
+ ,0x38,0x49,0x5a,0x6a,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x66,0x71,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x71,0x61,0x4c,0x36,0x21,0x0a
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c
+ ,0x66,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73
+ ,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x52,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67
+ ,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x51
+ ,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x57,0x61,0x67,0x71,0x6b,0x65,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62
+ ,0x71,0x73,0x73,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x67,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73
+ ,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x4c,0x5a,0x65,0x6b,0x73,0x73,0x73,0x73,0x73,0x6b,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34
+ ,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x71,0x7b,0x7f,0x84,0x7f,0x72,0x62,0x51,0x3c,0x25,0x0e
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x8a,0x8c,0x8c,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8a,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x71,0x7b,0x84,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49
+ ,0x5a,0x66,0x72,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8a,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x17,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x74,0x7f,0x84,0x7f,0x7b,0x6a,0x5a,0x46,0x30,0x19
+ ,0x04,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x8c,0x8c,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x51,0x61,0x6b,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x8a,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f
+ ,0x8e,0x97,0x99,0x93,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x8c,0x94,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8c,0x97,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1e,0x0a
+ ,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0x9f,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa1
+ ,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x8e,0x98,0x9d,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x9d,0x99,0x93,0x84,0x72,0x61,0x4b
+ ,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x98,0x98,0x9b,0xa2,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa2,0x9b,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x2b,0x43,0x5b,0x73,0x8c,0xa1,0x97,0x7f,0x67,0x4f
+ ,0x37,0x22,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x8e,0x97,0x9b,0x9e,0x9e,0x9b,0x97,0x8e,0x84,0x72,0x61,0x4c,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74
+ ,0x89,0x93,0x99,0x97,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa2,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8a,0x93,0x99,0x9f,0x9e,0x9f,0x99,0x98,0x98
+ ,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x72,0x7f,0x8c,0x97,0x9d,0xa4,0xa4,0xa4,0x9d,0x97,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x03,0x0a,0x11,0x12,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xad,0xb0,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8c,0x9c,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84
+ ,0x94,0xa2,0x9c,0x8a,0x74,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa1,0x9d,0x8e,0x84,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b
+ ,0x7f,0x7f,0x84,0x8e,0x9c,0xa2,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8e
+ ,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x98,0xa4,0xa9,0xa4,0xa4,0xa4,0xa9,0xa8,0x9c,0x8c,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31
+ ,0x3c,0x48,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x50,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6a,0x7b,0x8c,0x98,0x9b,0x93,0x8c,0x8c,0x8c,0x8c,0x94,0x9f,0x93,0x7f,0x6b,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0xb0,0xab,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa4,0xb5,0xb8,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b
+ ,0x8c,0x9c,0xa5,0x9d,0x93,0x8c,0x93,0x9d,0xa9,0xb0,0xa9,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x28,0x21,0x16,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x9d,0xae,0xb7,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x17,0x2b,0x41,0x57,0x6b,0x7f,0x92,0x9d,0xaa,0xa6,0xa4,0x9d,0x99,0xa2,0x99,0x84,0x71
+ ,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21,0x28,0x2a,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb5,0xb5,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0x9d,0x8c,0x7b,0x6a,0x5a,0x46,0x30
+ ,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x84,0x94,0xa1,0x94,0x84,0x72,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa2,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa8,0x98,0x7f,0x71,0x67,0x67,0x67,0x61,0x51,0x3c
+ ,0x25,0x0e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x71,0x7b,0x8e,0xa4,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xac,0xab,0x9c,0x8e,0x8c,0x8e,0x98,0xa4,0xab,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x51,0x5c,0x65,0x73,0x8c,0xa4,0x98,0x7f,0x6a,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x74,0x8a,0x9c,0x9c,0x8c,0x7f,0x74,0x73,0x73,0x74,0x84,0x94,0x9b
+ ,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x09,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xac,0xba,0xac,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xc5,0xc9,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x98,0xaa,0x9d,0x8c,0x7f,0x76,0x7f,0x8c,0x9c,0xab,0x9d,0x8e,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x43,0x40,0x36
+ ,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x34,0x4b,0x61,0x74,0x8a,0x9d
+ ,0xae,0xa4,0x94,0x8c,0x8a,0x84,0x8c,0x8c,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x36,0x40,0x43,0x43,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x2a,0x42,0x5a,0x71,0x84,0x94,0xa2,0xa2,0x94,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5c,0x71
+ ,0x84,0x98,0xa2,0x93,0x7f,0x6b,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x72,0x84,0x98,0xa2,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34
+ ,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x99,0xa2,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xaa,0x98,0x7f,0x67,0x53,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x51,0x5e,0x73,0x8c,0xa4,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x5b,0x73
+ ,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa8,0xae,0x9c,0x8c,0x7b,0x73,0x7b,0x84,0x94
+ ,0xa8,0xac,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8e,0xa4,0x99,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x03,0x16,0x2c,0x43,0x5a,0x71,0x84,0x94,0x9c
+ ,0x8c,0x7b,0x6b,0x61,0x5b,0x5b,0x62,0x72,0x84,0x98,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x21,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xa4,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97
+ ,0xac,0xbe,0xc5,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xae,0x98,0x7f,0x6c,0x64,0x6b,0x7b,0x8e,0xa4,0x99,0x84,0x76,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5c,0x5a,0x5b,0x5b,0x5b,0x57,0x4c,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c
+ ,0x1e,0x2f,0x3c,0x42,0x43,0x4f,0x67,0x7f,0x93,0xa8,0xa8,0x94,0x84,0x74,0x73,0x71,0x73,0x73,0x71,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4c,0x57,0x5b,0x5b,0x5b,0x5a,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x3e,0x51,0x62,0x72,0x84,0x8c,0x8c,0x84,0x72,0x62,0x51,0x3c,0x25,0x0e
+ ,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8e,0xa1,0x98,0x84,0x72,0x61,0x4c,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x52,0x66,0x7b,0x8c,0x9d,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40
+ ,0x57,0x6b,0x7f,0x97,0xa5,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa2,0x99,0x84,0x71,0x5a,0x43,0x2c,0x16,0x03,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x3a,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a
+ ,0x9d,0xb0,0xa3,0x8e,0x7b,0x6a,0x5e,0x66,0x74,0x8a,0x9d,0xb0,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6a,0x7b,0x84,0x8e,0x97,0x9d,0xae,0xa4,0x99,0x93,0x8a,0x7f,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00
+ ,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0x9f,0x93,0x7f,0x6b,0x5a,0x4c,0x43,0x44,0x52,0x66,0x7b,0x8e,0x9b,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x39,0x46,0x5a,0x6a,0x7b,0x8a,0x8c,0x8a,0x7b,0x6a,0x5a,0x46,0x30,0x19
+ ,0x04,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xac,0xae,0xa3,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x51,0x5c,0x73,0x8c,0xa4,0xa2,0x8c,0x73,0x5e,0x5a,0x51,0x40,0x2b,0x15,0x02
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x66,0x71,0x73,0x73,0x73,0x6b,0x61,0x57,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x64,0x61,0x60,0x61,0x60,0x5b,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x57,0x61,0x6b,0x73,0x73,0x73,0x71
+ ,0x6a,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x55,0x62
+ ,0x71,0x73,0x73,0x71,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9c,0xa1,0x8e,0x7b,0x66,0x52,0x40,0x2b,0x17,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa2,0x93,0x7f,0x6b,0x57,0x41
+ ,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa2,0x99,0x84,0x71,0x5a,0x43,0x2c,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa5,0x93,0x7f
+ ,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x21,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f
+ ,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x1e,0x1c,0x15,0x0a,0x01
+ ,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x4b,0x57,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x74,0x8a,0x98,0xa3,0xa7,0xa4,0xa4,0xa4,0xa4,0xa5,0x9d
+ ,0x93,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0x9c,0x8a,0x74,0x61,0x4c,0x42,0x46,0x4e,0x51,0x5f,0x73,0x8c,0x9e,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x51,0x5b
+ ,0x6a,0x73,0x73,0x73,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x97,0x97,0x8e,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x56,0x61,0x74,0x8c,0xa4
+ ,0xa4,0x8c,0x73,0x5b,0x45,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x7b,0x84,0x8c,0x8c,0x8a,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x73,0x73,0x73,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x35,0x20,0x0a,0x00,0x00,0x00,0x00,0x00,0x10,0x25
+ ,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x8a,0x8c,0x8c,0x84,0x7b,0x77,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x04,0x19
+ ,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0x98,0x84,0x71,0x5c,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38
+ ,0x4c,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x99,0xa2,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x08,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x51,0x3f,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84
+ ,0x94,0xa8,0xa4,0x98,0x8e,0x8c,0x8c,0x8e,0x98,0xa3,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0x97,0x7f,0x6b,0x57,0x4b,0x57,0x5c,0x65,0x67,0x71,0x76,0x8c,0x9e,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e
+ ,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x7f,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a
+ ,0x9d,0xac,0x99,0x84,0x72,0x68,0x71,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5b,0x43,0x2b,0x1b,0x0c,0x01,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x84,0x8e,0x98,0xa2,0xa4,0x9d,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00
+ ,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x8e,0x9d,0xb3,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8a,0x93,0x9d,0xa4,0xa2,0x98,0x8e,0x84,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x98,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x26,0x10,0x01,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x41,0x57,0x6b,0x7f,0x97,0xa5,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa2,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x21,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x38,0x46,0x5c,0x73,0x8c,0xa4,0xb1,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xae,0x99,0x84,0x7b,0x73,0x73,0x7b,0x84,0x8e,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0x9e,0x8e,0x7b,0x65,0x54,0x5c,0x6a,0x73,0x7b,0x7f,0x84,0x8c,0x94
+ ,0xa0,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x65,0x67,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a
+ ,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa4,0xa4,0x94,0x84,0x7f,0x84,0x8e,0x9d,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x99,0x9e,0xa2,0xa4,0xa4,0xab,0xa8,0x9c
+ ,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xa4,0xa4,0xa4,0xae,0xbe
+ ,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xa8,0xab,0xa4,0xa4,0xa2,0x9e,0x99,0x9d,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa2
+ ,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa4,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0x9d,0x8a,0x73,0x5c
+ ,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x3a,0x4f,0x67,0x7f,0x93
+ ,0xa6,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x3a,0x36,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x31,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x6d,0x62,0x5f,0x66,0x71,0x7b,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0x9e,0x8c,0x73
+ ,0x5e,0x62,0x71,0x7b,0x8a,0x8e,0x97,0x98,0x9e,0xa5,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x57
+ ,0x61,0x67,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x84,0x99,0xa6,0x9f,0x98,0x98,0x99,0x9e,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xb5,0xa4,0x98,0x8e,0x8c,0x8c,0x8e,0x9c,0xad,0xac,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a
+ ,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x9d,0xad,0xbb,0xae,0x9d,0x98,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xac,0xad,0x9c,0x8e,0x8c,0x8c,0x8e,0x98,0xa4,0xb7,0xb0,0x98,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa9,0xb0,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06
+ ,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa4,0xa2,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x00,0x00,0x00,0x00,0x00,0x02,0x15
+ ,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x10,0x25,0x38,0x46,0x4e,0x4f,0x53,0x66,0x7b,0x8e,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x57,0x4f,0x4e,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d
+ ,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x31,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xaf,0x9d,0x8c,0x7b,0x73,0x6b,0x65,0x61,0x65,0x65,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa2,0x8c,0x73,0x61,0x71,0x84,0x8e,0x9a,0x98,0x93,0x8c,0x8e,0x9d,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa6,0xad,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x74,0x7f,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x84,0x99,0x94,0x8c,0x8e,0x97,0x93,0x8c,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x17,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x7b,0x73,0x73,0x7b,0x8c,0x9d,0xb0,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x8c,0x9d,0xb2,0xa4,0x8e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0xb0,0x9d,0x8c,0x7b,0x73,0x73
+ ,0x7b,0x84,0x99,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e
+ ,0x9c,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa8,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xa4,0x8c,0x74,0x61
+ ,0x4b,0x34,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa2,0x93,0x7f,0x6b,0x57
+ ,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x72,0x84,0x98,0xa5,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0x99,0x84,0x74,0x6b
+ ,0x67,0x65,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x31,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x94,0xa6,0xab,0x9c,0x8e,0x8a,0x7f,0x7b,0x71,0x66
+ ,0x5c,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa2,0x8c,0x73,0x66,0x7b,0x8e,0x9f,0x94,0x84,0x7f,0x74,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x94,0xa4,0xb4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8a,0x93,0x97,0x8e,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0x9f,0x8c,0x76,0x7b,0x7f,0x7f,0x74,0x73,0x6b
+ ,0x61,0x53,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x66,0x5c,0x5c,0x6b,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x6c,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x11,0x28,0x40,0x57
+ ,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x69,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x1c
+ ,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11
+ ,0x28,0x40,0x57,0x6b,0x7f,0x98,0xa6,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30
+ ,0x46,0x5c,0x71,0x84,0x99,0xa2,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x84,0x94,0x9f,0x98,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x42,0x5a,0x71,0x84,0x93,0x9b,0x94,0x8a,0x7f,0x7f,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x46,0x33,0x43,0x5b,0x73,0x8c,0xa4,0xb4,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x74
+ ,0x89,0x94,0xa3,0xa8,0xa4,0x9d,0x97,0x8e,0x84,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x99,0x84,0x71,0x67,0x7f,0x97,0x9d,0x8a,0x74,0x67,0x69,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x11
+ ,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x74,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xa8,0xad,0xa3,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a
+ ,0x9d,0xa4,0x8c,0x74,0x6c,0x6d,0x6d,0x69,0x67,0x67,0x67,0x61,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x48,0x4f,0x67,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x52,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x4f,0x4f,0x4f,0x4e,0x46,0x38
+ ,0x25,0x10,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb1,0xa4,0x8c,0x74,0x61,0x4c,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5e,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa6,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa2,0x93,0x7f,0x67,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa1,0x98,0x84,0x71,0x5a,0x43,0x2c,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x99,0x9b,0x8e,0x84,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x7f,0x8c,0x9c,0x9d,0x98,0x97,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x39,0x46,0x5c,0x73,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6a,0x74,0x84,0x8e,0x98,0xa3,0xaa,0xaa,0xa3,0x98,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x99,0x84,0x71,0x71,0x84,0x99,0x98,0x7f,0x6f,0x5f,0x6b,0x7f,0x98
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xbc,0xc3,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xa7,0x94,0x84,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x74,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4b,0x61,0x74,0x8c,0xa4
+ ,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x3a,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x46,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4
+ ,0x8c,0x76,0x64,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa2,0x99,0x84
+ ,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x97,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x99,0xa2,0x99,0x84
+ ,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x7f,0x84,0x99,0xa4,0x9d,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xad,0x97,0x7f,0x67,0x51,0x3f,0x4e,0x65,0x7b
+ ,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x49,0x57,0x62,0x71,0x7b,0x84,0x8e,0x97,0x9d,0xa8,0xaa,0xa3,0x94,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa2,0x8c,0x73
+ ,0x6b,0x7f,0x98,0x9d,0x8c,0x7b,0x73,0x7b,0x8c,0x9d,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e
+ ,0xa3,0xb5,0xbc,0xb9,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x94,0xa4,0xa4,0x99,0x98,0x98,0x98,0x98,0x98,0x98,0x93,0x8c,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x44,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01
+ ,0x0a,0x15,0x1c,0x21,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa6,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x03,0x16,0x2c,0x43,0x5a,0x71,0x84,0x99,0xa2,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x84,0x8e,0x97,0x98,0x93,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x93,0x99,0x9a,0x8e,0x8a,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e
+ ,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x49,0x57,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x57,0x5b,0x5d,0x66,0x71,0x7b,0x7f,0x8a,0x93,0x9d,0xab,0xa4,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa0,0x8c,0x73,0x67,0x7f,0x93,0xa2,0x9c,0x8e,0x8c,0x8e,0x96,0x99,0x9f,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0xa2,0xa4,0xae,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x11,0x28,0x3d,0x51,0x62,0x72,0x84,0x99,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa6,0xa6,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4b,0x61,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a
+ ,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x08,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x4f
+ ,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x15,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xa6,0x93,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa5,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa5,0x97,0x7f,0x6b,0x57,0x40,0x28
+ ,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x71,0x7b,0x84,0x99,0xa2,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0x9d,0x8c,0x7b,0x73
+ ,0x6b,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x68,0x5e,0x66,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6a,0x71,0x62,0x5b,0x5d,0x65,0x6b,0x74,0x7f,0x8e,0xa4
+ ,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0x9e,0x8c,0x74,0x66,0x72,0x84,0x94,0xa1,0x9e,0x9b,0x93,0x84,0x84,0x95,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x8c,0x8e,0x9d,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8c,0x98,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x93
+ ,0x9d,0xab,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x47,0x52,0x67,0x7f,0x93,0xa8,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b
+ ,0x73,0x8a,0x9d,0xb1,0xa4,0x8c,0x74,0x61,0x4c,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x42,0x5a,0x71,0x84,0x99,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2c,0x43,0x5a
+ ,0x71,0x84,0x99,0xa2,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x51,0x5c,0x69,0x7f,0x93,0xa5,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x6b,0x5c,0x57,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa4,0xac,0x98,0x84,0x7b,0x73,0x7b,0x84,0x94,0xa8,0xa8,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x52,0x66,0x7b
+ ,0x84,0x74,0x71,0x66,0x5c,0x5e,0x64,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0x9f,0x93,0x7f,0x67,0x62,0x72,0x84,0x8c,0x8c,0x8a,0x7f,0x72,0x7b,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x73,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8c
+ ,0x9b,0x93,0x7f,0x73,0x73,0x73,0x73,0x73,0x74,0x7f,0x8c,0x9d,0xac,0x9a,0x88,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x62,0x5b,0x62,0x72,0x84,0x99,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb1,0xa4,0x8c,0x74,0x62,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x6b,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2c,0x43,0x5b,0x73,0x8c,0xa2,0xa2,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x97,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa2,0x99,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x3d,0x4e,0x65,0x7b,0x8e,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x40,0x38,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x84,0x98,0xab,0xa4,0x98,0x8e,0x8c,0x8e,0x98,0xa4,0xab,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00
+ ,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x84,0x91,0x8c,0x84,0x7b,0x73,0x73,0x73,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x98,0x99,0x84,0x71,0x5d,0x62,0x71,0x73,0x73,0x73,0x6b,0x61,0x65
+ ,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x37,0x45,0x53,0x5f,0x71,0x84,0x99,0x9d,0x8a,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x98,0xa2,0x8c,0x74,0x63,0x5e,0x5b,0x5b,0x5e,0x64,0x71,0x84,0x99,0xa9,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x74,0x73,0x74,0x84,0x94,0xa4,0xb0
+ ,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x74,0x73,0x73,0x73,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x93,0xa8,0xb1,0x9d,0x8c,0x7b,0x73,0x73,0x7b,0x8c,0x9d,0xb3,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2
+ ,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa4,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3
+ ,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa2,0x93,0x7f,0x67,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x37,0x4f,0x67,0x7f,0x97
+ ,0xa8,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x22,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x98,0xa3,0xa8,0xa4,0xa4,0xa4,0xab,0xa8
+ ,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x19,0x06,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa3,0xa2,0x98,0x8e,0x8c,0x8c,0x8c,0x8e,0x9c,0xab,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0x9e,0x8e
+ ,0x7b,0x66,0x56,0x5a,0x5b,0x5b,0x5b,0x57,0x4d,0x4e,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x61
+ ,0x6b,0x7b,0x8e,0xa0,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xa4,0x8e,0x7b,0x73,0x6b,0x67,0x67,0x6b,0x73,0x7b,0x8e,0xa3,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xad,0x9f,0x94,0x8c,0x8c,0x8c,0x94,0xa4,0xb1,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x93,0xa4,0xb2,0xa4,0x94,0x8c,0x8c,0x8c,0x89,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xad,0xad,0x9c,0x8e,0x8c,0x8c,0x8e,0x9b,0xa3,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06
+ ,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x99,0xa4,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x29,0x40,0x57,0x6b,0x7f,0x93,0xa2,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x08,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a
+ ,0x6a,0x7b,0x84,0x8e,0x98,0xa4,0xb5,0xb5,0xa4,0x94,0x8a,0x7b,0x6a,0x5a,0x4b,0x41,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x8c,0x98,0xa2,0xa5,0xa4,0xa4,0xa4,0xa4,0xa4,0xa5,0x9d,0x93,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00
+ ,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9c,0x98,0x84,0x72,0x62,0x57,0x4d,0x49,0x4a,0x4e,0x57,0x5b,0x57,0x49,0x3b,0x2d,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x74,0x7f,0x8c,0x9c,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa5,0x9c,0x8e,0x8a,0x7f,0x7f,0x7f,0x7f,0x8a,0x8e,0x9c,0xa1,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa9,0x9c,0x8e,0x94,0x9f,0xa4,0xa4,0xa8,0xab,0xa3,0x94,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x98,0xa8,0xae,0xa8,0xa4,0xa4,0xa2,0x93
+ ,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xac,0xab,0xa4,0xa4,0xa2
+ ,0x9b,0x93,0x8e,0x9d,0xab,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa5,0x97,0x7f,0x6b,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x49,0x5c,0x73,0x8a,0x9d,0xa2,0x8c,0x74,0x61,0x4b
+ ,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa2,0x93,0x7f,0x67,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x15,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x15,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x11,0x0a,0x02,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x5a,0x66,0x71,0x7b,0x84,0x98,0xad,0xb0,0x99,0x84,0x74,0x6a,0x5b,0x54,0x5a,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x6b,0x7b,0x84,0x8c,0x93,0x98,0x9d,0xae,0xa4,0x99,0x93,0x8a
+ ,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8e,0x9f,0x94,0x84,0x74,0x6b,0x61,0x5b,0x5c,0x65,0x6b,0x73,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8a,0x93,0x9c,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8a,0x93,0x9d,0x9f,0x9d,0x98,0x98,0x98,0x98,0x9b,0x9b
+ ,0x97,0x8e,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x8e,0x7b,0x84,0x93,0x99,0xa2,0xa2,0x98,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x52
+ ,0x66,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x95,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36
+ ,0x49,0x5a,0x6a,0x7b,0x8c,0x97,0x9d,0xa4,0x9d,0x97,0x8c,0x7f,0x7f,0x95,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x04,0x10,0x19,0x1e,0x1e,0x1b,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x74,0x62,0x51,0x3c,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41
+ ,0x57,0x6a,0x7b,0x8e,0xa3,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa2,0x99,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f
+ ,0x97,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a
+ ,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x46,0x51,0x5c,0x68,0x7b,0x8e,0xa3,0xaf,0x9d,0x8c,0x7b,0x71,0x67,0x67,0x71,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4c,0x5a,0x66
+ ,0x71,0x74,0x7f,0x7f,0x8e,0xa4,0x99,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5c,0x71,0x84,0x94,0x9f,0x94,0x8a,0x7f,0x74,0x73,0x73,0x7b,0x7f,0x88,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xad,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0x9c,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x74
+ ,0x7f,0x8a,0x8e,0x97,0x98,0x98,0x98,0x93,0x8c,0x8a,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x71,0x72,0x7f,0x84,0x8c,0x8c,0x84,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x7f,0x8a,0x8c,0x8a,0x7f,0x7b,0x6d,0x7b,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x36,0x30,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa2,0x94,0x84,0x71,0x5c,0x49,0x38,0x27,0x16
+ ,0x04,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x3c,0x51,0x62,0x74,0x8a,0x9c,0xa1,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2c,0x43,0x5a,0x71,0x84,0x99,0xa2,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00
+ ,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x43,0x43,0x40,0x36,0x27
+ ,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x48,0x5b,0x73,0x8c,0xa4,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x46,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x48,0x5c,0x71,0x84,0x94,0xa4,0xab,0x9c,0x8e,0x84,0x7f,0x7f,0x82,0x73,0x5b,0x43,0x2c,0x15
+ ,0x02,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x38,0x46,0x51,0x5a,0x61,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x6a,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x62,0x72,0x84,0x8e,0x9b,0x9c,0x93,0x8c,0x8c,0x8c,0x8e,0x97,0x96
+ ,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x8a,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02
+ ,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x61,0x6b,0x73,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x74,0x73,0x6b,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x61,0x61,0x67,0x71,0x73,0x73,0x71,0x66,0x5c
+ ,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x65,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73
+ ,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x5a,0x65,0x6b,0x73,0x73,0x73,0x6b,0x65,0x5e,0x65,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4e,0x46,0x42,0x47,0x5c,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x74
+ ,0x8a,0x9c,0xa1,0x8e,0x7b,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5c,0x71,0x84,0x94,0xa2,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f
+ ,0x93,0xa5,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa5,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xaa,0x98,0x7f,0x69,0x5c,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5c,0x66,0x74,0x8c,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5e,0x73
+ ,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x27,0x3c,0x51,0x62,0x72,0x84,0x94,0xa3,0xa8
+ ,0xa3,0x99,0x98,0x98,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x31,0x3c,0x43,0x4c,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x50,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71
+ ,0x7b,0x8a,0x93,0x98,0x98,0x9d,0x98,0x97,0x8e,0x8a,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b
+ ,0x74,0x6b,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x41,0x4c,0x57,0x5c,0x65,0x67,0x67,0x67,0x67,0x67,0x61,0x5b,0x57,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f
+ ,0x4f,0x4b,0x4b,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x57,0x4e,0x49,0x4e,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25
+ ,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x65,0x65,0x5c,0x5a,0x5a,0x66,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06
+ ,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8e,0xa1,0x9c,0x8c,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8e,0xa1,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x99,0xa2,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0x99,0x84,0x7b,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x7b,0x84,0x94,0xa5,0x97,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x05
+ ,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x76,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x08,0x1b,0x2f,0x40,0x51,0x62,0x72,0x84,0x8e,0x98,0xa2,0xa4,0xa5,0xa1,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x25,0x2e,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x22,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x5c,0x6a,0x74,0x7f,0x7f,0x84,0x8c,0x84,0x7f,0x7b,0x73,0x6b,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e
+ ,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x65,0x61,0x57,0x4c,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x36,0x40,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x43,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x34,0x34,0x3c,0x42,0x43,0x43,0x42,0x3c,0x31,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c
+ ,0x36,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x37,0x40,0x43,0x43,0x43,0x40
+ ,0x37,0x33,0x36,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x7b,0x73,0x71,0x71,0x74,0x84
+ ,0x98,0xad,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5c,0x71,0x84,0x94,0xa2,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8c,0x9c,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1b
+ ,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x97,0xa1,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0x9f,0x98,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x98,0x9f,0x98,0x8e,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8e,0x98,0x9f,0x9c,0x8c,0x7b,0x65,0x4e
+ ,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x94,0xa6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa6,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x62,0x71,0x7b,0x84,0x8c,0x8c,0x90,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x13,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x95,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x49,0x57,0x61,0x67,0x67,0x71,0x73,0x71,0x67,0x65,0x5c,0x57,0x4c,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46
+ ,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x4e,0x4b,0x41,0x36,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21,0x28,0x30,0x36,0x37,0x37,0x37,0x37,0x37,0x34,0x2c
+ ,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1c,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02
+ ,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x28,0x21,0x1b,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2c
+ ,0x43,0x5a,0x71,0x84,0x8e,0x8c,0x84,0x84,0x8c,0x94,0xa4,0xab,0x9c,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x62,0x72,0x84,0x94,0x98,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f
+ ,0x8c,0x98,0x8c,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8a,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8a,0x8c
+ ,0x8a,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x84,0x8e,0x97,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f
+ ,0x95,0x98,0x98,0x97,0x8e,0x8a,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98
+ ,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5c,0x66,0x71,0x73,0x74,0x7f,0x74,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x36,0x41,0x4b,0x4f,0x51,0x5a,0x5b,0x5a,0x51,0x4e,0x46,0x40,0x36,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x36,0x34,0x2b,0x21,0x16,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a
+ ,0x11,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x05,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x11,0x0a,0x05,0x06,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa0,0xa2,0x99,0x99,0xa2,0xa6,0xa7,0x9c,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x72,0x84,0x84,0x7b,0x6a,0x5a,0x46,0x30
+ ,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x6b,0x7b,0x88,0x7b,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05
+ ,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42
+ ,0x2a,0x12,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x73,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x51,0x5a,0x5b,0x61,0x67,0x61,0x5b,0x5a,0x51,0x40,0x2b,0x15
+ ,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2b,0x34,0x37,0x3c,0x42,0x43,0x42,0x3c,0x36,0x30
+ ,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1c,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x97,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f
+ ,0x40,0x51,0x62,0x71,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4c,0x5a,0x6a,0x73,0x6a,0x5a,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49
+ ,0x57,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x51
+ ,0x5c,0x65,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x65,0x5c,0x57,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x67
+ ,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x31,0x3c,0x42
+ ,0x43,0x4b,0x4f,0x4b,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b
+ ,0x15,0x1c,0x1e,0x25,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5a,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x38,0x49,0x57,0x5b,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x40,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x1b,0x25,0x2a,0x2c,0x34,0x37,0x34,0x2c,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x07,0x0e,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71
+ ,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x27,0x36,0x40,0x43,0x40,0x36,0x27,0x16,0x05,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x26,0x30,0x36,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x28,0x21,0x14,0x05
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x15,0x1c,0x1e,0x1c,0x15,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x19,0x10
+ ,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0a,0x1e
+ ,0x2f,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21
+ ,0x28,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12
+ ,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e
+ ,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e
+ ,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x0e,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e
+ ,0x06,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x06,0x06,0x06,0x06,0x05,0x06,0x0e,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x12,0x12,0x12,0x12,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x0a,0x11,0x12,0x11,0x0a,0x06
+ ,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12
+ ,0x12,0x11,0x0a,0x02,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x02,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x21,0x28,0x2a,0x2a
+ ,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x10,0x19,0x1e,0x21,0x28,0x2a,0x28,0x21,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00
+ ,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x0c,0x1b,0x25,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x37,0x40,0x43,0x43,0x43,0x40,0x37,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30
+ ,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x10,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x34,0x3c,0x42
+ ,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x34,0x31,0x3c,0x42,0x43,0x43,0x43,0x40,0x37,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x10,0x1e,0x2b,0x34,0x38,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x36,0x30,0x26,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x36,0x40,0x43,0x43,0x43,0x42,0x3c,0x33,0x36,0x37,0x37,0x37,0x36,0x30
+ ,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x26,0x30,0x36,0x38,0x40,0x43,0x40,0x38,0x36,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x0a,0x1e,0x2f,0x3c,0x42
+ ,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43
+ ,0x43,0x43,0x40,0x36,0x27,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x36,0x37,0x37,0x36,0x30,0x26,0x1b,0x10,0x04,0x04,0x10,0x19,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x38,0x27
+ ,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c
+ ,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2f,0x1e,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x16,0x25,0x31,0x40,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4b,0x46,0x51,0x5a,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x38,0x27,0x16,0x05
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x40,0x4b,0x4f,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51
+ ,0x4e,0x46,0x3c,0x2f,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4c,0x57,0x5b,0x5b
+ ,0x5b,0x5a,0x51,0x49,0x4e,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x46,0x4e,0x4f,0x57,0x5b,0x57,0x4f,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b
+ ,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b
+ ,0x57,0x49,0x36,0x21,0x0a,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00
+ ,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x4e,0x4f,0x4f,0x4e,0x46,0x3c,0x31,0x25,0x16,0x16,0x25
+ ,0x30,0x36,0x36,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a
+ ,0x65,0x6b,0x73,0x73,0x73,0x6b,0x65,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x71,0x62,0x51,0x3c,0x27,0x34,0x4b,0x61,0x71,0x73,0x73,0x73
+ ,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x52,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x61,0x5c,0x66,0x71
+ ,0x73,0x73,0x73,0x6b,0x65,0x5a,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x52,0x61,0x67,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40
+ ,0x4c,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x65,0x5c,0x51,0x41,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x04,0x16,0x27,0x38,0x49,0x57,0x61,0x6b,0x73,0x73,0x73,0x71,0x66,0x5e,0x65,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x46,0x51,0x5c,0x65,0x67,0x6b,0x73,0x6b,0x67,0x65,0x5c,0x51,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x00
+ ,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x5a,0x46,0x31,0x2b,0x41,0x57,0x6a,0x73
+ ,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x41,0x36,0x4c,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x5c,0x65
+ ,0x67,0x67,0x65,0x5c,0x51,0x46,0x38,0x25,0x27,0x38,0x46,0x4e,0x4e,0x46,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00
+ ,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x7f,0x8a,0x8c,0x8a,0x7f,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x8c,0x8c,0x8c,0x84,0x71
+ ,0x5c,0x46,0x30,0x3c,0x51,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x66,0x72,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x06,0x1e,0x36
+ ,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x72,0x71,0x7b,0x84,0x8c,0x8c,0x8a,0x7f,0x7b,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x5a,0x66,0x72,0x7f,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1b
+ ,0x06,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x61,0x6b,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x71,0x62,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x8a,0x8c,0x8c,0x84,0x7b,0x71,0x7b,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x7f,0x88,0x7f,0x7f,0x7b
+ ,0x71,0x66,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x6b,0x57,0x40
+ ,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x87,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x8c,0x8c,0x8c
+ ,0x8a,0x7b,0x66,0x51,0x3c,0x34,0x4b,0x61,0x74,0x89,0x8c,0x8c,0x8c,0x87,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x89,0x8c,0x8c,0x8c,0x89,0x74,0x61,0x4c,0x41,0x57,0x6b,0x7f,0x8c,0x8c,0x8c,0x8a,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00
+ ,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x7b,0x7f,0x7f,0x7b,0x71,0x66,0x5a,0x46,0x31,0x38,0x49,0x5a,0x65,0x65,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x97,0x9c,0x9e,0x9c,0x97,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x05,0x06,0x06,0x06,0x06,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0e
+ ,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa1,0xa1,0x8e,0x7b,0x65,0x4e,0x37,0x43,0x5a,0x71,0x84,0x99,0xa2,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49
+ ,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x92,0x7f,0x84,0x8e,0x98,0xa2,0xa4,0x9d,0x97,0x8c,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x84,0x93,0x98,0x9d,0xa4
+ ,0xa4,0x9d,0x97,0x8e,0x84,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x7f,0x8a,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x74,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x12,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8a,0x93,0x9d,0xa4,0xa2,0x98,0x8e,0x84,0x7f,0x95,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a
+ ,0x6a,0x7b,0x84,0x8e,0x97,0x98,0x9a,0x98,0x97,0x8e,0x84,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71
+ ,0x84,0x99,0xa4,0xa4,0xa4,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x21,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x9f,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0x9f,0xa4,0x98,0x84,0x71,0x5a,0x43,0x3c,0x51,0x67,0x7f,0x93,0xa2,0xa1,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xa2,0xa2,0x93,0x7f,0x6b,0x57,0x4c,0x61,0x74,0x8a,0x9d
+ ,0xa4,0x9b,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x8e,0x97,0x97,0x8e,0x84,0x7b,0x66,0x52,0x40,0x49,0x5a,0x6a,0x7b,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xa2,0x94,0x8c,0x94,0xa2,0x9c,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x18,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8c,0x98,0xa3,0xaa,0xa6,0xa4,0xa4,0xa4,0xa7,0xa3,0x98
+ ,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0xaa,0x97,0x7f,0x6b,0x57,0x41,0x4b,0x61,0x74,0x8c,0xa2,0xa4,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x98,0xa4,0xa9
+ ,0xa4,0xa4,0xa4,0xa9,0xa8,0x9c,0x8c,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xab,0x9d,0x8e,0x94,0x9e,0xa2,0xa4,0xa4,0xab,0xac,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36
+ ,0x49,0x5a,0x6a,0x7b,0x8c,0x98,0xa4,0xab,0xa6,0xa4,0xa4,0xa4,0xa7,0xa3,0x94,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x93,0x9d,0xa7,0xa6,0xa4,0xa4,0xa4,0xa6,0xa9,0xa3,0x94,0x8a,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x2a,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xa8,0xab,0xa4,0xa4,0xa2,0x9e,0x94,0x8e,0x9d,0xab,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x98,0xa1,0xa3,0xa4,0xa4,0xa6,0xaa,0xa3,0x98,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa2,0xb0,0xb0,0xb1,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x37,0x37,0x3a,0x4f,0x67,0x7f
+ ,0x98,0xaa,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x98,0xac,0xa2,0x8c,0x74,0x61,0x4c,0x46,0x5c,0x71,0x84,0x99,0xac,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8e,0xa3
+ ,0xaf,0x9d,0x8a,0x74,0x61,0x57,0x6b,0x7f,0x93,0xa8,0xa4,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0x9a,0x8e,0x8e,0x9a,0x97,0x84,0x72,0x61,0x4e,0x5a,0x6a,0x7b,0x8c,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb8,0xb8,0xae,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa5,0x98,0x84,0x76,0x84,0x98,0xa3,0x8e,0x7b,0x65
+ ,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2b,0x2b,0x34,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c
+ ,0xaa,0xa8,0x9d,0x93,0x8c,0x8c,0x8e,0x98,0xa0,0x94,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa6,0x9d,0x8a,0x74,0x61,0x4b,0x51,0x67,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x0a
+ ,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xac,0xab,0x9c,0x8e,0x8c,0x8e,0x98,0xa4,0xab,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xad,0x9f,0x98,0x8e,0x8c,0x8c,0x8e,0x9c,0xad,0xac,0x98,0x84,0x71,0x5a,0x43
+ ,0x2c,0x15,0x02,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xaa,0xa8,0x9d,0x93,0x8c,0x8c,0x8e,0x98,0x9f,0x8e,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0xaf,0xa4,0x94,0x8c,0x8c,0x8c,0x93,0x99
+ ,0xa3,0x98,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x44,0x42,0x43,0x43,0x43,0x40,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xac,0xad,0x9c,0x8e
+ ,0x8c,0x8c,0x8e,0x98,0x9f,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0x98,0x8e,0x8c,0x8c,0x93,0x9d,0xac,0xa8,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xae,0xa2
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0x9d,0x98,0x9d,0xa8,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c
+ ,0x74,0x61,0x4f,0x4f,0x4f,0x4f,0x4e,0x51,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0xa8,0x93,0x7f,0x6b,0x57,0x4e,0x65,0x7b,0x8e,0xa3,0xa8,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00
+ ,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x94,0xa8,0xa8,0x93,0x7f,0x6b,0x61,0x74,0x8a,0x9d,0xaa,0x98,0x84,0x72,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0x9b,0x8c,0x7b,0x7b,0x8c,0x9b,0x93,0x7f,0x67,0x56,0x66,0x7b
+ ,0x8c,0x9c,0x98,0x88,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9d,0xb3,0xb3,0x9d,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xa4,0x8e,0x7b,0x6b,0x7b,0x8e,0xa3,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x09,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x32,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00
+ ,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xab,0xa4,0x94,0x8a,0x7f,0x74,0x73,0x7b,0x84,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9d,0xa6,0x93,0x7f,0x67,0x51,0x5a,0x71,0x84,0x99,0xa9,0x97,0x7f
+ ,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa8,0xae,0x9c,0x8c,0x7b,0x73,0x7b,0x84,0x94,0xa8,0xac,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x7b,0x73
+ ,0x73,0x7b,0x8c,0x9d,0xb0,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xad,0xa8,0x94,0x8a,0x7f,0x74,0x73,0x7b,0x84,0x90,0x84,0x71,0x5c,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84
+ ,0x98,0xad,0xa8,0x94,0x84,0x74,0x73,0x74,0x7f,0x84,0x8e,0x8c,0x7b,0x66,0x52,0x40,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x51,0x5a,0x5b,0x5b,0x5b,0x57,0x4c,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x0a,0x21
+ ,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0xb0,0x9d,0x8c,0x7b,0x73,0x73,0x7b,0x84,0x99,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x84,0x7b,0x73,0x74,0x7f,0x8e,0xa3,0xb0,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa3,0x8e,0x7f,0x8e,0xa4,0x99,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xa8,0x93,0x7f,0x67,0x61,0x67,0x67,0x67,0x65,0x5f,0x71,0x84,0x99,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x98,0xaa,0x9d,0x8a,0x73,0x5c,0x57,0x6b,0x7f,0x97,0xaa
+ ,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x69,0x7f,0x93,0xa8,0xa3,0x8e,0x7b,0x66,0x52,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0x98,0x7f
+ ,0x6b,0x6b,0x7f,0x98,0x98,0x7f,0x67,0x62,0x72,0x84,0x98,0x9c,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x68,0x7f,0x93,0xa2,0x93,0x7f,0x67,0x4f,0x37,0x21,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x40,0x51,0x61,0x67,0x67,0x67
+ ,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa8,0xad,0x98,0x84,0x74,0x6b,0x61,0x5c,0x66,0x71,0x7b,0x72,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x97,0xa9,0x99
+ ,0x84,0x71,0x5a,0x61,0x74,0x8c,0xa2,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x6a,0x5e,0x66,0x74,0x8a,0x9d,0xb0,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x66,0x5c,0x5c,0x6b,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa8,0xae,0x9c,0x8a,0x76,0x6b,0x61,0x5c,0x66,0x72,0x7f,0x72,0x62,0x51,0x3c,0x27,0x14
+ ,0x02,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb0,0x9d,0x8a,0x74,0x62,0x5b,0x61,0x67,0x71,0x7b,0x7b,0x6a,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x63,0x67,0x71,0x73,0x73,0x73,0x6b,0x61
+ ,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x69,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x72,0x66,0x5c,0x61,0x71,0x84,0x99
+ ,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa2,0x8c,0x79,0x8c,0xa2,0xa2,0x8c,0x74,0x61
+ ,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x71,0x7f,0x7f,0x7f,0x7b,0x66,0x73,0x8c,0xa2,0xab,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8e
+ ,0xa3,0xa4,0x8e,0x7b,0x66,0x61,0x74,0x8a,0x9d,0xa6,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6b,0x7f,0x93,0xa8,0xa8,0x93,0x7f,0x73,0x84,0x99,0xa9,0x98,0x84,0x71,0x5c,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x98,0x7f,0x67,0x67,0x7f,0x98,0x99,0x84,0x71,0x72,0x84,0x94,0x94,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x5b
+ ,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8e,0x7b,0x72,0x84,0x99,0xa2,0x8c,0x74,0x61,0x4b,0x39,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x73,0x5b,0x47,0x51,0x62,0x72,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x66,0x57,0x4c,0x46,0x51,0x5c,0x65,0x61,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00
+ ,0x00,0x0b,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0xa2,0x8c,0x74,0x61,0x67,0x7f,0x93,0xa6,0x99,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x4b,0x57,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f
+ ,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x48,0x4f,0x67,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x6a,0x58,0x4c
+ ,0x46,0x52,0x61,0x67,0x61,0x51,0x41,0x34,0x25,0x16,0x04,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x99,0x84,0x72,0x62,0x5a,0x54,0x53,0x5c,0x65,0x65,0x5a,0x49,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x74,0x74,0x7f,0x84,0x8c,0x8c,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb1,0xa4,0x8c,0x74,0x61,0x4c,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x04,0x16,0x27,0x38
+ ,0x49,0x5a,0x65,0x61,0x52,0x4b,0x5c,0x71,0x84,0x99,0xa9,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e
+ ,0xa4,0x99,0x84,0x76,0x84,0x99,0xa6,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0x98,0x95,0x7f,0x67,0x73,0x8c,0xa4,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00
+ ,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x99,0xa9,0x98,0x84,0x71,0x6b,0x7f,0x93,0xa6,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xab,0x9d,0x8a,0x7c,0x8e,0xa3,0xa3,0x8e
+ ,0x7b,0x66,0x51,0x3c,0x26,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x98,0x7f,0x67,0x67,0x7f,0x98,0x98,0x7f,0x73,0x84,0x94,0x94,0x84,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa5,0x97,0x7f,0x84,0x94,0xa0,0x94,0x84,0x71,0x5a,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x51,0x62,0x72,0x84,0x93,0x98,0x95,0x8b,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x46,0x36,0x31,0x3c,0x46,0x4e,0x4b
+ ,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xa5,0x93,0x7f,0x67,0x6b,0x7f,0x98,0xa6,0x93,0x7f,0x67,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xad,0x97,0x7f,0x67
+ ,0x51,0x3f,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4b,0x61,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61
+ ,0x74,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x4b,0x4e,0x4f,0x4f,0x53,0x55,0x53,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb0,0xa4,0x94,0x84,0x74,0x71,0x66,0x5c,0x53,0x53,0x4e,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x7c,0x8a,0x93,0x99,0xa2,0xa4,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x4e,0x4b,0x4b,0x5a,0x6a,0x7b,0x8e,0xa3,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa7,0x97,0x7f,0x6d,0x7f,0x97,0xa9,0x99,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xae,0x98,0x7f,0x6c,0x7b,0x8e,0xa4,0x99,0x84,0x71,0x73,0x8c
+ ,0xa4,0xa4,0x8c,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xa2,0x8c,0x74,0x73,0x8a,0x9d,0xa6,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a
+ ,0x7b,0x8e,0xa3,0xa8,0x94,0x8e,0x9c,0xa5,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0x99,0x84,0x72,0x72,0x84,0x99,0x93,0x7f,0x73,0x8a,0x94,0x84,0x72,0x62,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00
+ ,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0x9d,0x8e,0x94,0xa0,0x94,0x84,0x72,0x62,0x61
+ ,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x62,0x72,0x84,0x94,0xa2,0x9c,0x8c,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa8,0x93
+ ,0x7f,0x67,0x51,0x3c,0x26,0x1b,0x26,0x30,0x36,0x34,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8e,0xa4,0x99,0x84,0x71,0x73,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x07,0x1e
+ ,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x39,0x46,0x5c,0x73,0x8c,0xa4,0xb1,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x46,0x5c,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67,0x54,0x5a,0x65,0x67,0x67,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xac,0xb3,0xa4,0x94,0x8c,0x84,0x7b,0x71,0x67
+ ,0x61,0x57,0x49,0x3c,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8e,0x9b,0xa0,0xa4,0xa4,0xae,0xb1,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b
+ ,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x49,0x5a,0x6a,0x7b,0x8c,0x9c,0xa2,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0x98
+ ,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8a,0x9d,0xa4,0x8e,0x7b,0x6b,0x7b,0x8e,0xa4,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xaa,0x98
+ ,0x7f,0x6d,0x7f,0x97,0xad,0xa2,0x8c,0x73,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9d,0xa6,0x93,0x7f,0x7b,0x8e,0xa4,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5c,0x71,0x84,0x98,0xab,0xa8,0xa4,0xab,0x9d,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9a,0x94,0x84,0x84,0x94,0x9a,0x8a,0x74,0x6a,0x7b,0x84,0x72
+ ,0x62,0x51,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x31,0x44,0x5a,0x71,0x84
+ ,0x99,0xaa,0xa4,0xa1,0x94,0x84,0x72,0x62,0x5d,0x71,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x64,0x72,0x84,0x94,0xa4,0xa3,0x8e,0x7b,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00
+ ,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x0a,0x10,0x19,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0xa2,0x8c,0x74,0x7b,0x8e,0xa3,0x97,0x7f,0x6b,0x57
+ ,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x46,0x33,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43
+ ,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x58,0x6a,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b
+ ,0x8c,0x9c,0xac,0xb2,0xa8,0xa2,0x98,0x8e,0x84,0x7f,0x74,0x6a,0x5c,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa5,0x9b,0x93,0x8c,0x8c,0x8e,0x9c,0xae,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a
+ ,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8c,0x9c,0xa2,0x94,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00
+ ,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xa2,0x8c,0x73,0x62,0x73,0x8c,0xa2,0xa8,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x6e,0x7f,0x98,0xad,0xa4,0x8e,0x7b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa6,0x9d,0x8c,0x84,0x98,0xa5,0x93,0x7f
+ ,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x66,0x7b,0x8e,0xa4,0xb9,0xb9,0xa8,0x93,0x7f,0x6b,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x97
+ ,0x98,0x98,0x97,0x8c,0x7b,0x6a,0x5d,0x6a,0x71,0x64,0x5b,0x51,0x4b,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x72,0x84,0x99,0xb0,0xb0,0x99,0x84,0x72,0x62,0x55,0x65,0x7b,0x8e,0x98,0x97,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x71,0x84,0x94,0xa4,0xa4,0x94,0x84,0x71
+ ,0x5c,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x04,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93
+ ,0xa2,0x93,0x7f,0x7f,0x97,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x31,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x47,0x52,0x67,0x7f,0x97,0xad,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x5b,0x73,0x8a,0x97,0x98,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x98,0xa3,0xad,0xb0,0xad,0xa3,0x99,0x93,0x8a,0x7b,0x71,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9c,0x8c,0x7f,0x74,0x73,0x7b,0x8e,0xa3,0xb4,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb1,0xa4,0x8c,0x74,0x61,0x4c,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xa2,0x94,0x84
+ ,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa6,0x99,0x84,0x71,0x60,0x71,0x84,0x99,0xaa,0x98,0x7f
+ ,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x73,0x8a,0x9b,0x99,0x9d,0x97,0x7f,0x73,0x8c,0xa4,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61
+ ,0x74,0x8a,0x9d,0xaa,0x9d,0x99,0xa4,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x74,0x8c,0xa4,0xbc,0xbc,0xa4,0x8c,0x76,0x65,0x51,0x3c,0x26,0x12,0x01,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x8c,0x8c,0x84,0x7b,0x6a,0x5e,0x66,0x71,0x73,0x73,0x71,0x67,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x94,0xa4,0xae,0xaf,0x9d,0x8c,0x7b,0x6a,0x5c,0x6b,0x7f,0x97,0xa8,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x74,0x7b,0x8e,0xa3,0xa4,0x94,0x84,0x72,0x62,0x51,0x3c,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x02,0x0a,0x11,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9d,0x99,0x84,0x8c,0x9d,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x31,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x62,0x5b,0x62,0x72,0x84,0x99,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x5b,0x73,0x8c
+ ,0xa4,0xaa,0xaa,0xae,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x84,0x8e,0x97,0x9d,0xa8,0xb0,0xb0,0xa8,0x9c,0x8e,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8e,0x7b,0x6b,0x61,0x5e,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x6b,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x42,0x5a,0x71,0x84,0x98,0xa8,0x98,0x84,0x72,0x62,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x99,0xaa
+ ,0x98,0x7f,0x6a,0x67,0x6a,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa8,0x98,0x7f,0x74,0x8c,0x98,0x84,0x8e,0x98,0x7f,0x74,0x8c,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa8,0xb2,0xb0,0xab,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa8,0xb0,0xb2,0xa8,0x94,0x84,0x71
+ ,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x66,0x71,0x73,0x73,0x71,0x66,0x5e,0x6a,0x7b,0x84,0x8c,0x8c,0x84,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0xa4,0xa4,0x99,0x9d,0xa9,0x9c,0x8a,0x76,0x6a,0x73,0x8a,0x9d,0xa6,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x7c,0x8c,0x9c,0xa9,0x99,0x84,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x0a,0x14,0x21,0x28,0x2a
+ ,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa1,0x99,0x9d,0xa5,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c
+ ,0x46,0x33,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7f,0x74,0x73,0x74,0x84,0x94,0xa4,0xb0,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x5b,0x73,0x8c,0x98,0x98,0x99,0xa4,0xae,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8a,0x93,0x9d,0xa8,0xb3,0xae,0xa1,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x4c,0x51,0x67,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x93,0xa8,0xb1,0x9d,0x8c,0x7b,0x73,0x73,0x7b,0x8c,0x9d,0xb3,0xb0,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x9f,0xa1,0x8e,0x7b,0x66,0x52,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xae,0x99,0x84,0x7f,0x7f,0x7f,0x84,0x99,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0x98,0x7f,0x7f,0x93,0x93,0x7f,0x8c,0x9b,0x8a,0x79,0x8c
+ ,0xa4,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9d,0xb3,0xb8,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x26,0x3c,0x51,0x66
+ ,0x7b,0x8c,0x9d,0xa4,0x99,0x9d,0xab,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x52,0x5f,0x6a,0x7b,0x7b,0x6a,0x6a,0x7b,0x8c,0x97,0x98,0x97,0x96,0x93,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xa7,0x94,0x84,0x8c,0x9c,0xa5,0x94,0x8a,0x7b,0x7b,0x8e
+ ,0xa4,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8e,0x9c,0xad,0xb0,0x98,0x7f,0x6b,0x5a,0x47,0x34,0x23,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x93
+ ,0x7f,0x67,0x51,0x3c,0x26,0x1b,0x27,0x36,0x40,0x42,0x3c,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa2,0xae,0xb0,0xa2,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e
+ ,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x39,0x46,0x5c,0x73,0x8c,0xa4,0xb1,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x93,0x8c,0x8c,0x8c,0x94,0xa4,0xb1,0xa4,0x93,0x7f,0x6b,0x57,0x40
+ ,0x28,0x11,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xb0,0x98,0x7f,0x67,0x5b,0x71,0x7f,0x7f,0x7f,0x84,0x99,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3f,0x4a,0x51,0x5c,0x65,0x6b,0x74,0x7f,0x8a,0x94,0xa4
+ ,0xb5,0xad,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xad,0xad,0x9c,0x8e
+ ,0x8c,0x8c,0x8e,0x9c,0xab,0xba,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x89,0x73,0x5c,0x46,0x31,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f
+ ,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xb6,0xa4,0x99,0x98,0x98,0x98,0x99,0xa4,0xb8,0xad,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa4,0x98
+ ,0x7f,0x7f,0x98,0x8c,0x79,0x8c,0x9d,0x8c,0x79,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x98,0xb0,0xb0,0x99,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5c,0x71,0x84,0x98,0xa8,0x98,0x84,0x8c,0x9d,0xaa,0x98,0x84,0x71,0x5c,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x8c,0x8c,0x7b,0x74,0x8a,0x9b,0x94,0x84,0x7f
+ ,0x8c,0x9b,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xab,0xa2
+ ,0x8c,0x74,0x7b,0x8e,0xa3,0xa7,0x9c,0x8c,0x84,0x98,0xa5,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa5,0xa4,0xab,0x9d,0x8c,0x7b,0x66,0x52,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xb0,0x99,0x84,0x71,0x5c,0x46,0x36,0x31,0x3c,0x49,0x57,0x5a,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1e,0x2c,0x43,0x5a,0x71,0x84,0x98,0xad,0xad,0x98,0x84,0x71,0x5a,0x43,0x2c
+ ,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xad,0x97,0x7f,0x67,0x51,0x3f,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x99,0x9f,0xa4
+ ,0xa4,0xa8,0xab,0xa3,0x94,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5d,0x61,0x67,0x67,0x6a,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51
+ ,0x5a,0x5a,0x53,0x50,0x57,0x61,0x6b,0x74,0x84,0x94,0xa4,0xb3,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x02,0x15
+ ,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xac,0xab,0xa4,0xa4,0xa2,0x9b,0x98,0x9d,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1b,0x2f,0x41,0x55,0x63,0x6c,0x6d,0x6c,0x63,0x55,0x41,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xae,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb2,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x84,0x98,0x8c,0x77,0x84,0x98,0x8e,0x7c,0x8c,0xa0,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x51
+ ,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x52,0x66,0x7b,0x8e,0xa3,0xa3,0x8e,0x7b,0x7f,0x93,0xa8,0xa3,0x8e,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x49,0x5a,0x6a,0x7b
+ ,0x8c,0x98,0x8c,0x7b,0x7f,0x93,0x9c,0x8a,0x74,0x6c,0x7f,0x98,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x99,0x84,0x71,0x71,0x84,0x94,0xa4,0xab,0x9d,0x99,0xa4,0x9d,0x8a,0x74,0x61,0x4c,0x3a,0x27,0x14,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xc2,0xb7,0xa4,0x94,0x8e,0x9c,0xa8,0x98,0x84,0x72,0x62
+ ,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xb3,0xa3,0x8e,0x7b,0x66,0x57,0x4c,0x46,0x51,0x5c,0x6a,0x71,0x62,0x51,0x3c,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x3e,0x51,0x66
+ ,0x7b,0x8e,0xa4,0xa4,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5c,0x4a,0x57,0x6b,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x84,0x93,0x99,0xa2,0xa2,0x98,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x66,0x55,0x53,0x52,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37
+ ,0x1e,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x71,0x71,0x66,0x5c,0x51,0x51,0x57,0x62,0x72,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8c,0x97,0x9d,0xa4,0x9d,0x97,0x8c,0x7f,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x51,0x61,0x6b,0x73,0x73,0x71,0x62,0x51
+ ,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x71,0x7b,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa2,0xac,0x9c,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9c,0xae,0xa4
+ ,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0x98,0x7f,0x8c,0x9a,0x8a,0x73,0x7f,0x98,0x97,0x7f,0x8c,0x9e,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x72,0x84,0x98,0xa9,0x99,0x84,0x71,0x74,0x8a,0x9d,0xab,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0d,0x00,0x00,0x00
+ ,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c,0x6a,0x7b,0x8c,0x98,0x8c,0x7b,0x6e,0x7f,0x98,0x98,0x7f,0x6b,0x67,0x7f,0x98,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x64,0x72,0x84,0x94,0xa4,0xb0,0xb0,0xae,0x98,0x7f,0x6f,0x61,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xbd
+ ,0xac,0x98,0x84,0x7b,0x8c,0x9d,0xa4,0x94,0x84,0x71,0x5c,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xac,0xad,0x98,0x84,0x74,0x6b,0x61,0x5c,0x66,0x71,0x7b,0x84,0x71,0x5c,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4e,0x57,0x6b,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x6a,0x5e,0x66,0x74,0x8a,0x9d,0xaf,0xa2,0x8c,0x74
+ ,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x77,0x7f,0x84,0x8c,0x8c,0x84,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa8,0xad,0x98,0x84,0x72,0x67,0x61
+ ,0x5c,0x6b,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x84,0x7b,0x71,0x67,0x61,0x5b,0x62,0x72,0x84,0x99,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x7f,0x8a,0x8c,0x8a,0x7f,0x7b,0x76,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x0a,0x21
+ ,0x36,0x4c,0x61,0x72,0x7f,0x8a,0x8c,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x8e,0x97,0x8e,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa4,0xa4,0x8e
+ ,0x7b,0x73,0x73,0x73,0x73,0x73,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0x9d,0x8e,0x94,0x98,0x7f,0x6e,0x7f,0x97,0x9d,0x8e,0x94,0xa0,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa4,0xa4,0x93,0x7f,0x67,0x6b,0x7f,0x93,0xa8,0xa8
+ ,0x93,0x7f,0x6b,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x7b,0x8c,0x9a,0x93,0x7f,0x6b,0x67,0x7f,0x98,0x98,0x7f,0x67,0x67,0x7f,0x98,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8e,0x7b,0x71,0x69,0x76,0x84,0x99,0xb0,0xbc,0xb2,0x9d,0x8c,0x7f,0x74,0x6a,0x57,0x40,0x28,0x11,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9c,0x8c,0x7b,0x6e,0x7f,0x93,0xa7,0xa3,0x8e,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8c,0x9d,0xb0,0xa4,0x94,0x8a,0x7f,0x74,0x73,0x7b,0x84,0x8e,0x8e
+ ,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x61,0x67,0x65,0x67,0x74,0x8a,0x9d,0xa6,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa4,0xac,0x9c,0x8c
+ ,0x7b,0x73,0x7b,0x84,0x94,0xa8,0xa8,0x94,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x71,0x73,0x73,0x71,0x66,0x5c,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c
+ ,0x61,0x74,0x8a,0x9c,0xac,0xa4,0x94,0x84,0x7f,0x74,0x73,0x7b,0x8c,0x9d,0xab,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0x98,0x8e,0x84,0x7f,0x74,0x73,0x74,0x84,0x94,0xa4,0xac,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x5a,0x65,0x6b,0x73,0x73,0x73,0x6b,0x6a,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x92,0x9d,0xa2,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa1,0xaa,0xa3,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00
+ ,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xab,0xa2,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5e,0x73,0x8c,0xa2,0xae,0x99,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xaa,0xa4,0xa5,0x97,0x7f,0x6c,0x7b,0x8e,0xa3,0xa4,0xa8
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9d
+ ,0xaa,0x98,0x84,0x72,0x61,0x61,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8e,0x9a,0x94,0x84,0x72,0x61,0x67,0x7f,0x97,0x99,0x84,0x71,0x67,0x7f,0x98,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xab,0x9c,0x8e,0x84,0x7f,0x84,0x8e,0x9d,0xaa,0xa4,0xa8
+ ,0xaa,0x9d,0x93,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x6a,0x62,0x74,0x8a,0x9c,0xa9,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa3
+ ,0xad,0xa8,0x9d,0x93,0x8c,0x8c,0x8e,0x98,0xa3,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x7f,0x7b,0x7f,0x84,0x94,0xa6,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a
+ ,0x21,0x36,0x4c,0x61,0x72,0x84,0x98,0xac,0xad,0x9c,0x8e,0x8c,0x8e,0x98,0xa4,0xab,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x3c,0x2f,0x1e,0x0d,0x01
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8e,0x9d,0xab,0xa4,0x99,0x93,0x8c,0x8c,0x8e,0x9c,0xad,0xac,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa1,0xaa,0xa3,0x99,0x93,0x8c,0x8c,0x8c,0x94,0xa4
+ ,0xb1,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x4e,0x57,0x5b,0x5b
+ ,0x5b,0x58,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb1,0xb5,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xbf,0xb0
+ ,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xac,0x99,0x84,0x71,0x5a,0x45,0x43,0x45,0x5a,0x71,0x84,0x99,0xae,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xb6,0xa4,0x8e,0x7b,0x66,0x73,0x8c,0xa4,0xb6,0xb2,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6b,0x7f,0x93,0xa8,0xa3,0x8e,0x7b,0x66,0x52,0x57,0x6b,0x7f,0x93,0xa8,0xa8,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8c,0x96,0x84,0x72,0x62,0x55,0x65,0x7b,0x8e,0x9e,0x8e,0x7b,0x74
+ ,0x84,0x99,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0xa3
+ ,0xa8,0xa3,0x99,0x98,0x99,0xa1,0xa1,0x98,0x8e,0x93,0x9d,0xa6,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x57,0x6a,0x7b,0x8e,0xa3,0xa7,0x94,0x84,0x71,0x5c,0x49,0x36,0x21,0x0b,0x00,0x00,0x00
+ ,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x8e,0x9c,0xa8,0xac,0xa8,0xa4,0xa4,0xa4,0xa7,0xa3,0x98,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x07,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x8e,0x97,0x99,0xa4,0xa4,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x98,0xa4,0xa9,0xa4,0xa4,0xa4,0xa9,0xa8,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46
+ ,0x43,0x43,0x42,0x3c,0x31,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5c,0x71,0x7f,0x8c,0x9c,0xa8,0xaa,0xa8,0xa4,0xa4,0xa4,0xa8,0xa3,0x98,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8a
+ ,0x93,0x9d,0xa8,0xaa,0xa8,0xa4,0xa4,0xa4,0xa6,0xa7,0x9d,0x93,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x16,0x25,0x30,0x37,0x40,0x43,0x43,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb8,0xbd,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xb7,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa1,0xa4,0x97,0x7f,0x67,0x51,0x3c,0x2d,0x3c,0x51,0x67,0x7f,0x97,0xa4,0xa1,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa2,0xa4,0xa1,0x8c,0x73,0x61,0x73,0x8a,0x9d,0xa4,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x74,0x8a,0x9b,0xa4,0x98,0x84,0x71,0x5c,0x46,0x4c,0x61,0x74,0x8a,0x9d,0xa4,0x9f,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x88,0x7b
+ ,0x66,0x52,0x48,0x5c,0x71,0x84,0x94,0x9a,0x8e,0x8c,0x94,0x97,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x7b,0x7f,0x8a,0x93,0x95,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xad,0xa4,0x8c,0x73,0x5b,0x4b,0x5c,0x71,0x84,0x94,0xa7,0xa2
+ ,0x8e,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x51,0x62,0x71,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x97,0xa4,0xa7,0xa4
+ ,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6a,0x7b,0x84,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xad,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x25,0x1b,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x61,0x6b,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x7b,0x6a,0x5a,0x46,0x30
+ ,0x19,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x74,0x7f,0x8a,0x93,0x99,0xa2,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xad,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xad,0xad
+ ,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x28,0x2a,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xad,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x98,0xa8,0xac,0x9c,0x8a,0x74
+ ,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x98,0xa2,0x9c,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8a,0x7b,0x65,0x4e,0x36,0x24,0x36,0x4e,0x65,0x7b,0x8a,0x8c
+ ,0x8c,0x8c,0x82,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x89,0x8c,0x8c,0x8c,0x89,0x73,0x5e,0x6b,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x8a,0x8c,0x8c,0x8a,0x7b,0x66,0x51,0x3c,0x41,0x57,0x6b,0x7f,0x8c,0x8c,0x8c,0x8c,0x82,0x71,0x5a,0x42,0x2a,0x12,0x00
+ ,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x73,0x6a,0x5a,0x46,0x3c,0x51,0x62,0x72,0x84,0x8e,0x97,0x97,0x8e,0x84,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x66,0x6b,0x74,0x7f,0x84,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98
+ ,0x8c,0x73,0x5b,0x45,0x51,0x62,0x74,0x8a,0x97,0x98,0x95,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x5c,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00
+ ,0x12,0x2a,0x42,0x5a,0x71,0x82,0x92,0x98,0x97,0x8e,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x5a,0x66,0x72,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38
+ ,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4c,0x5a,0x6a,0x74,0x7f,0x84,0x8c,0x8c
+ ,0x8c,0x8a,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x61,0x6b,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98
+ ,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x95,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x00,0x0e,0x25
+ ,0x3c,0x51,0x66,0x7b,0x8a,0x93,0x97,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x84,0x8c,0x8a,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a
+ ,0x5a,0x46,0x30,0x1f,0x30,0x46,0x5a,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x5a,0x46,0x31,0x36,0x4c,0x61,0x71,0x73
+ ,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x5b,0x57,0x49,0x38,0x2f,0x40,0x51,0x62,0x71,0x7b,0x7f,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34
+ ,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x57,0x61,0x67,0x71,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00
+ ,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x41,0x57,0x6a,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c
+ ,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x74,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x46,0x52,0x61,0x67,0x71
+ ,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c
+ ,0x1e,0x2b,0x38,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x41,0x4c,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x65
+ ,0x4e,0x36,0x1e,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x74,0x7f,0x7f,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x66,0x71,0x73,0x73,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x02
+ ,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x16,0x25,0x38,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x51,0x5a,0x5b,0x5b,0x5b
+ ,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x57,0x49,0x38,0x25,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x40,0x43,0x40,0x36,0x27,0x1e,0x2f,0x40,0x51,0x5c,0x65,0x67,0x67,0x65,0x5c,0x51,0x46,0x38,0x27,0x14,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x41
+ ,0x4b,0x51,0x5a,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x36,0x49,0x5a,0x65,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x36,0x41
+ ,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x61,0x67,0x67,0x67,0x65,0x5c,0x57,0x4c,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x16,0x25,0x31,0x40,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x27,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51
+ ,0x4b,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19
+ ,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x61,0x67,0x67,0x65,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x51,0x5a,0x5b,0x5b
+ ,0x57,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x08,0x16,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43
+ ,0x43,0x43,0x43,0x40,0x36,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x28,0x21,0x14,0x0d,0x1e,0x2f,0x3c,0x46,0x4e,0x4f,0x4f
+ ,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37
+ ,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x2b,0x34,0x3c,0x42,0x40,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x27,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x41,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f
+ ,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21
+ ,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x41,0x4b,0x4f,0x4f,0x4e,0x46,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x42,0x43,0x43,0x40,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b
+ ,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x11
+ ,0x0a,0x02,0x01,0x0c,0x1b,0x26,0x30,0x36,0x37,0x37,0x36,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x15,0x1d,0x25,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x16,0x25,0x30,0x36,0x37,0x37
+ ,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x37,0x37,0x37,0x36
+ ,0x30,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16
+ ,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x25,0x30,0x36,0x37,0x37,0x37
+ ,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x37,0x37,0x36,0x30,0x25
+ ,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x25,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12
+ ,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x02,0x06,0x0e,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e
+ ,0x1e,0x1c,0x15,0x0a,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x0b,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12
+ ,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e
+ ,0x1e,0x1c,0x15,0x0a,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x0b,0x15,0x1c,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12
+ ,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12
+ ,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15
+ ,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21,0x28
+ ,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x16,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x1c,0x15,0x0b,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x0c,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43
+ ,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x36,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x25,0x17,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x16,0x0a
+ ,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c
+ ,0x34,0x2b,0x1e,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x36,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42
+ ,0x3c,0x2f,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27
+ ,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0d,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x43
+ ,0x40,0x38,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43
+ ,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00
+ ,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x38,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4c,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x38,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x41,0x4c,0x57,0x5b
+ ,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f
+ ,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x40,0x31,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x02
+ ,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x38,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51
+ ,0x4b,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4b,0x51,0x5a
+ ,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2f,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e
+ ,0x2b,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x4f,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00
+ ,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x41,0x2b,0x25,0x3c,0x51,0x62,0x71
+ ,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73
+ ,0x6a,0x57,0x40,0x46,0x5a,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x61,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5a,0x4c,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x01,0x0d,0x1e,0x2f,0x40,0x4c,0x57,0x61,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x04,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x52,0x46,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x65,0x5c,0x51,0x46
+ ,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x46,0x5a,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73
+ ,0x71,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73
+ ,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00
+ ,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x41,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x04
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x4c,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x73,0x6b,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73
+ ,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x87,0x8c,0x8c,0x8c
+ ,0x89,0x74,0x61,0x4b,0x34,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x47,0x52,0x66,0x7b,0x8a,0x8c,0x8c,0x8c,0x87,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x6b,0x61,0x51,0x40
+ ,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x61,0x6b,0x74,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x72,0x66,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x51,0x4e,0x65,0x7b,0x8a,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02
+ ,0x0a,0x11,0x1a,0x30,0x46,0x5c,0x73,0x89,0x8c,0x8c,0x84,0x71,0x5a,0x42,0x2a,0x15,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x62,0x71,0x7b,0x7f,0x8a,0x8c,0x8c
+ ,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x61,0x6b,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x8a,0x7f,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa2,0xa2,0x93,0x7f,0x67,0x4f,0x38,0x30,0x46,0x5c,0x73,0x8c,0xa0,0xa4,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7b
+ ,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa1,0x8c,0x73,0x5b,0x51,0x62,0x72,0x84,0x98,0xa4,0x9b,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8a,0x93
+ ,0x9d,0xa4,0xa4,0x9d,0x97,0x8c,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x51,0x62,0x72,0x7f,0x8a,0x93,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7f,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x84,0x7b,0x66,0x52,0x40,0x2b,0x15,0x02,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x7b,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x99,0x84,0x71,0x5a,0x51,0x67,0x7f,0x97,0xa4,0xa4,0xa1,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x36,0x4e,0x65,0x7b,0x8e,0xa1,0xa0,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7f,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4
+ ,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x04,0x19,0x30
+ ,0x46,0x5a,0x6a,0x74,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x7f,0x8a,0x93,0x99,0xa2,0xa4,0xa4,0x9d,0x98,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f
+ ,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x6b,0x57,0x40,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xa8,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb7,0xae
+ ,0x9d,0x98,0x98,0x9d,0xa4,0xa4,0xa6,0xa7,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x5c,0x71,0x84,0x94,0xa4,0xa4,0x93,0x7f,0x6b,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00
+ ,0x03,0x16,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xa5,0xa3,0x99,0x98,0x9d,0xa5,0x9d,0x93,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x4c,0x61,0x72,0x84,0x93,0x9d,0xa5,0xa4,0xa4,0xa4,0xa4,0xa4,0xa5,0x9c,0x8f,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x98,0x98,0x98,0x9d,0xa4,0xa9,0xa8,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0xa3,0xa2,0x99,0x98,0x98,0x98,0x9d,0xa2
+ ,0x97,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb8,0xb3,0xa8,0xa4,0xa4,0xa4,0xa6,0xaa,0xa3,0x98,0x8c,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb7,0xa2,0x8c
+ ,0x73,0x5c,0x5a,0x71,0x84,0x99,0xb0,0xb9,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43
+ ,0x5b,0x73,0x8c,0xa4,0xb3,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb3,0xa4,0x99,0x98,0x99,0xa2,0xa4,0xa6,0xa7,0x9d,0x93,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa8,0xb3,0xb9,0xae,0x9c,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xa5,0xa2,0x99,0x98,0x99,0xa2,0xa5,0x9c,0x8c,0x7b,0x6a,0x57
+ ,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8a,0x94,0xa1,0xa3,0xa2,0x99,0x9d,0xa4,0xa6,0xa7,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x93,0x9d,0xa5,0xa4,0x9d,0x98,0x9d,0xa4
+ ,0xa9,0xa8,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb3,0xa8
+ ,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xad,0x9d,0x8a,0x73,0x5b,0x43,0x3c,0x51,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8e,0x7f,0x7f,0x8a,0x8c,0x8c,0x94,0xa4,0xab,0x9c,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5e,0x6a,0x7b,0x8e,0xa3,0xa7,0x94,0x84,0x72
+ ,0x61,0x4c,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8a,0x9c,0xa9,0x9c,0x8e,0x84,0x7f,0x8a,0x94,0xa4,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x03,0x16,0x2b,0x41,0x57,0x6b,0x7f,0x93,0xa4,0xaa,0x9c,0x8e
+ ,0x8c,0x8c,0x8c,0x8e,0x98,0x94,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7f,0x7f,0x7f,0x8a,0x8e,0x9c,0xad,0xac,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b
+ ,0x8e,0xa3,0xa4,0x94,0x84,0x7f,0x7f,0x7f,0x8c,0x9d,0xa4,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb7,0xa8,0x94,0x8c,0x8c,0x8c,0x93,0x9d,0xab,0xac,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xae,0xb0,0xa4,0x8e,0x7b,0x65,0x5c,0x73,0x8c,0xa2,0xaf,0xb5,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40
+ ,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x7f,0x84,0x8c,0x8c,0x94,0xa4
+ ,0xaf,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x94,0xa8,0xb5,0xa3,0x8e,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xa9,0x9c,0x8e
+ ,0x84,0x7f,0x84,0x8e,0x9c,0xa9,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa1,0x9c,0x8e,0x8c,0x84,0x8a,0x8c,0x94,0xa4,0xab,0x98,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57
+ ,0x6a,0x7b,0x8e,0x9f,0x98,0x8e,0x8a,0x7f,0x8a,0x8e,0x9c,0xad,0xac,0x98,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9d,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8a,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x42,0x5a,0x71,0x84,0x99
+ ,0xac,0x9d,0x8a,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x6b,0x73,0x73,0x74,0x84,0x94,0xa8,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c
+ ,0x73,0x64,0x74,0x8a,0x9c,0xa9,0x9c,0x8a,0x74,0x62,0x51,0x40,0x2b,0x17,0x05,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa5,0x9c,0x8c,0x7b,0x71,0x6b,0x74,0x84,0x98,0xa8,0x98,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x0a,0x21
+ ,0x36,0x4c,0x61,0x74,0x8a,0x9d,0xaa,0x9c,0x8c,0x7b,0x73,0x73,0x73,0x7b,0x84,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x6b,0x73,0x7b,0x8c,0x9d,0xb0,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa9,0x99,0x84,0x72,0x67,0x67,0x6c,0x7f,0x93,0xa6,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x76,0x73,0x74,0x7f,0x8c,0x9c,0xad,0xac,0x98
+ ,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x99,0x9d,0x97,0x7f,0x67,0x65,0x7b,0x8e,0x9b,0x99,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xb0,0xa4,0x8c,0x74,0x68,0x71,0x73,0x74,0x84,0x94,0xa8,0xad,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x74,0x7c,0x8e,0xa4,0xa8,0x94,0x84,0x71,0x5c,0x49,0x36,0x21,0x0a,0x00,0x00,0x07
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa3,0x8e,0x7b,0x71,0x68,0x71,0x7b,0x8c,0x9d,0xa6,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x93,0x8c,0x7b,0x73,0x71,0x73,0x74,0x84,0x98,0xac,0xa3,0x8e,0x7b,0x65,0x4e,0x36
+ ,0x1e,0x06,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5c,0x71,0x84,0x8e,0x84,0x7b,0x73,0x6f,0x73,0x7b,0x8c,0x9d,0xb0,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x7f,0x98
+ ,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x93,0xa8
+ ,0xa8,0x93,0x7f,0x67,0x4f,0x46,0x5c,0x73,0x8c,0xa2,0xab,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5d,0x5b,0x5b,0x62,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x72,0x84,0x94,0xa6,0x9d,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa4,0x8e,0x7b,0x6a,0x5c,0x57,0x66,0x7b,0x8e,0xa3,0xa3,0x8e,0x7b
+ ,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa6,0x9d,0x8c,0x7b,0x6a,0x5c,0x5b,0x5c,0x66,0x71,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x57,0x5c,0x6b
+ ,0x7f,0x98,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x53,0x4f,0x61,0x74,0x8c,0xa4,0xa0,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5e,0x61,0x6b,0x7b,0x8c,0x9d,0xb0,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x99,0x84,0x8e,0x98,0x84,0x71,0x6b,0x7f,0x97,0x8e,0x84,0x99,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43
+ ,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8e,0x9d,0xb3,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x5a,0x5b,0x62,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5c,0x64,0x74,0x8a,0x9c,0xa9,0x9c,0x8a
+ ,0x74,0x62,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xaa,0x99,0x84,0x71,0x5d,0x54,0x5c,0x6b,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x7f,0x7b,0x6a,0x5c,0x5a,0x5b
+ ,0x66,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x62,0x72,0x7b,0x71,0x66,0x5c,0x59,0x5c,0x6b,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57
+ ,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xae,0x98,0x7f,0x6b,0x57,0x4e,0x65,0x7b,0x8e,0xa4,0xa4,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x46,0x46,0x5b,0x73,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x74,0x7f,0x93,0xa4,0xa4,0x93,0x7f,0x6b,0x5a,0x49,0x36,0x21,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xa2,0x8c,0x73
+ ,0x5e,0x5a,0x5a,0x5d,0x71,0x84,0x99,0xa9,0x97,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8a,0x9d,0xaa,0x97,0x7f,0x6b,0x5b,0x57,0x5b,0x5a,0x57,0x5a,0x5a,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x4f,0x5a,0x6b,0x7f,0x98,0xaa,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa8,0x98,0x7f,0x6b,0x5b,0x51,0x61,0x74,0x8c,0xa4,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x4d,0x5a,0x6b,0x7f,0x93,0xa8,0xad,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0x9d,0x8a,0x84,0x98,0x8c,0x74,0x73,0x8a,0x98,0x8a,0x7f,0x98,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xae,0xbe,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x67,0x67,0x67
+ ,0x65,0x5c,0x57,0x4d,0x46,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46,0x44,0x56,0x6b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x42,0x43,0x43
+ ,0x44,0x4b,0x5c,0x71,0x84,0x94,0xa7,0xa3,0x8e,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xaa,0x98,0x7f,0x67,0x51,0x40,0x4c,0x61,0x74,0x8c,0xa4,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x0a,0x1e
+ ,0x2f,0x40,0x51,0x61,0x67,0x65,0x5a,0x49,0x42,0x48,0x5c,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x61,0x65,0x5c,0x51,0x4a,0x4c,0x53,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e
+ ,0x06,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x4a
+ ,0x3a,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x99,0xac,0x9d,0x8a,0x73,0x5b,0x51,0x67,0x7f,0x97,0xaa,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5b,0x4e,0x51,0x61,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x7c,0x8c,0x9d,0xac,0x99,0x84,0x72,0x61,0x4c,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa9,0x99,0x84,0x71,0x66,0x71,0x71,0x66,0x68,0x7f,0x98,0xaa,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xa4,0x8e,0x7b,0x68,0x67,0x6b,0x73,0x71,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e
+ ,0x0c,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x67,0x6b,0x7b,0x8c,0x9d,0xa4,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0x9d,0x8c,0x7b,0x71,0x67,0x6b,0x7f,0x93
+ ,0xa1,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x44,0x4c,0x61,0x74,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x7f,0x97
+ ,0x93,0x7f,0x74,0x8c,0x98,0x7f,0x84,0x99,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x9d,0xae,0xbd,0xae,0x9d,0x98,0x98,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e
+ ,0x65,0x7b,0x8e,0xa4,0xa4,0x8c,0x7c,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46,0x47,0x5c,0x71,0x84,0x99,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2b,0x33,0x46,0x5a,0x6a,0x7b,0x8e,0xa3,0xa7,0x94,0x84,0x71,0x5c,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xaa,0x98,0x7f,0x67,0x52,0x44,0x49,0x5c,0x73,0x8c,0xa4,0xad,0x97,0x7f
+ ,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x4b,0x4f,0x4e,0x46,0x38,0x33,0x46,0x5c,0x73,0x8c,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x4b,0x51,0x57,0x5b,0x5b,0x61,0x67,0x72
+ ,0x84,0x99,0xa9,0x9c,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c
+ ,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xa4,0x8c,0x74,0x61,0x5a,0x71,0x84,0x99,0xaa,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5f,0x65,0x67,0x71,0x7f,0x93,0xa8,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8e,0x84,0x98,0xac,0xb0,0x98,0x7f,0x68,0x55,0x41,0x2b
+ ,0x17,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x6e,0x7b,0x84,0x84,0x7b,0x6e,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa4,0x8c,0x73,0x72,0x7f
+ ,0x7f,0x8a,0x84,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7f,0x7f,0x7f,0x7f,0x8c,0x9a,0x99,0x93,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71
+ ,0x84,0x94,0xa2,0x9c,0x8e,0x84,0x7f,0x7b,0x8c,0x9b,0x94,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x43,0x5b,0x73,0x8c,0xa4,0xb4,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x7c,0x8e,0x98,0x7f,0x7f,0x93,0x93,0x7f,0x8c,0xa2,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0xb6,0xa4,0x8e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e
+ ,0x36,0x1e,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa8,0x94,0x8e,0x97,0x98,0x97,0x8e,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5c,0x68,0x7b,0x8e
+ ,0xa3,0xae,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x19,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9c,0xa9,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xaa,0x99,0x84,0x72
+ ,0x62,0x5b,0x61,0x6b,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x34,0x37,0x36,0x30,0x2e,0x40,0x52,0x66,0x7b,0x8e,0xa4,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d
+ ,0x1e,0x2d,0x40,0x57,0x6a,0x73,0x73,0x74,0x7f,0x84,0x94,0xa1,0x9c,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xa8,0x93,0x7f,0x67,0x5c,0x73,0x8c,0xa2,0xa8
+ ,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x76,0x73,0x7b,0x7f,0x84,0x8e,0x9d,0xaf,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb9,0xae,0x9d
+ ,0x99,0xa4,0xb8,0xb0,0x99,0x84,0x71,0x5c,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x73,0x8a,0x98,0x98,0x8c,0x7b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x7c,0x84,0x93,0x98,0x9d,0x99,0x97,0x8e,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x98,0x98,0x98,0x98,0x9d,0x99,0x84,0x7f,0x72,0x63,0x56,0x44,0x31,0x1e,0x0a
+ ,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x94,0xa5,0xa3,0x99,0x93,0x8e,0x9b,0x94,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x43,0x5b,0x73,0x8c,0xa4,0xb6
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x79,0x8c,0x98,0x84,0x7f,0x97,0x8c,0x79,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x67,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa9,0xa8,0xa0,0x9e,0xa2,0xa4,0xa5,0xa4,0x9d,0x93,0x84,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x7b,0x84,0x98,0xac,0xa4,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xaa,0xa3,0x8e,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x07
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa4,0x94,0x84,0x74,0x73,0x74,0x7f,0x8c,0x9c,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1f,0x27,0x38,0x4c,0x61,0x72,0x84,0x98,0xa8,0x98,0x84,0x71,0x5c,0x46,0x30
+ ,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x93,0x99,0xa1,0x94,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8a
+ ,0x9d,0xab,0x98,0x7f,0x6b,0x65,0x7b,0x8e,0xa4,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb7,0xa8,0x94,0x8c,0x8c,0x8e,0x97,0x99,0xa3,0xa9,0xa3,0x94,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbc,0xbe,0xb3,0xb0,0xb0,0xb0,0xb4,0xa3,0x8e,0x7b,0x66,0x52,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x7b,0x8e,0xa4,0xa9,0x97,0x7f,0x7f,0x98,0xb0,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8e,0x97,0x98,0x98,0x98,0x9d,0xa5,0xa3,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4
+ ,0x9c,0x8e,0x84,0x7b,0x71,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x69,0x76,0x8c,0xa1,0xa4,0xa6,0xa6,0xa4,0xa3,0x8e,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x77,0x84,0x98,0x94,0x8e,0x96,0x84,0x77,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1b,0x2f
+ ,0x40,0x4b,0x4f,0x4f,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8a,0x94,0x93,0x8c,0x8c,0x8c,0x8c,0x93,0x9d,0xaa,0xa4,0x94,0x84,0x71,0x5a,0x43,0x2c,0x15
+ ,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8e,0x98,0xa4,0xa8,0x98,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa4,0xa4,0x94,0x84,0x71,0x5c,0x49
+ ,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xaa,0xa4,0x94,0x8c,0x8c,0x8c,0x93,0x96,0x99,0xa4,0xae,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x09,0x16,0x27,0x38,0x49,0x5a,0x6b
+ ,0x7f,0x93,0xa4,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa6,0xac,0xa4,0x8c,0x79,0x6f,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04
+ ,0x06,0x06,0x04,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xaa,0x9d,0x8a,0x73,0x67,0x7f,0x97,0xa9,0x99,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbb,0xb5,0xa8,0xa4,0xa4,0xa4,0xad,0xb0,0xac,0x9c,0x8e,0x84
+ ,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbc,0xcb,0xbe,0xad,0x9d,0x99,0xa4,0xab,0x98,0x84,0x72,0x61,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x74
+ ,0x8a,0x9c,0x9d,0x8e,0x7b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb1,0xa1,0x98,0x8e,0x84,0x7f,0x7f,0x8a,0x94,0xa7,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x94,0x9f,0x98,0x8e,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x94,0x94,0x8c,0x93,0x99,0xa3,0xa9,0x9c,0x8e,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x7f,0x93,0xa4,0xa2,0x93,0x7f,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x74,0x84,0x7f,0x74,0x73,0x73,0x74,0x7f
+ ,0x8c,0x9d,0xaf,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa5,0xa2,0x94,0x8a,0x7b,0x66,0x52,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66
+ ,0x7b,0x8c,0x9d,0xaa,0x98,0x84,0x72,0x62,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x98,0xa2,0xa0,0xa0,0x9e,0x9b,0x93,0x84,0x84,0x99,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x16,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x8c,0x9d,0xa4,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x97,0x98,0x98,0x9d,0xa4,0x94,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x16
+ ,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x19,0x11,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b
+ ,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa4,0xa4,0x8c,0x74,0x71,0x84,0x99,0xa9,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb9,0xae
+ ,0x9d,0x98,0x98,0x99,0xa4,0xb4,0xa4,0x8e,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbc,0xbe,0xad,0x9c,0x8c,0x84,0x94,0xa8,0xa4,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x6e,0x7b,0x8a,0x8a,0x7f,0x71,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x7b,0x71,0x67,0x6b,0x76,0x8a,0x9d,0xaa,0x97,0x7f,0x6b,0x57
+ ,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x74,0x84,0x94,0xa2,0xa3,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x98,0x94,0x84,0x76,0x7f,0x84,0x8e,0x98,0xa2
+ ,0xa3,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x46,0x5c,0x73,0x8c,0xa4,0xb4,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x74
+ ,0x8c,0xa2,0xa2,0x8c,0x74,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38
+ ,0x49,0x57,0x62,0x71,0x6b,0x61,0x5b,0x5b,0x61,0x6c,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa4,0x99,0x98,0x98,0x98,0x98,0x93,0x8c,0x84,0x74,0x6a,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00
+ ,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xaa,0x9d,0x8c,0x7b,0x66,0x52,0x40,0x2f,0x1c,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x84,0x8c,0x8e,0x93,0x8c,0x8a,0x7f,0x76,0x84,0x99,0xaa,0x98,0x7f
+ ,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x38,0x49,0x5a,0x6a,0x7b,0x8c,0x9c,0xa2,0x94,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2c,0x40,0x57,0x6a,0x7b,0x7f,0x7f,0x7f,0x8a
+ ,0x93,0x9c,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x36,0x36,0x30,0x25,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c
+ ,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa6,0x93,0x7f,0x73,0x8c,0xa2,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8e,0x7f,0x7f,0x84,0x94,0xa8,0xa8,0x93,0x7f,0x6b,0x57,0x44,0x31,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbb,0xb3,0x9d,0x8c,0x7b,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x61
+ ,0x4c,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x6b,0x6a,0x73,0x73,0x6b,0x69,0x7f,0x98,0xaa,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x74,0x66,0x5c
+ ,0x51,0x58,0x6b,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x62,0x72,0x84,0x99,0xac,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a
+ ,0x9c,0x9d,0x8a,0x74,0x65,0x67,0x71,0x7b,0x84,0x94,0xa7,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x44,0x4e,0x65,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8c,0x73,0x71,0x84,0x99,0x99,0x84,0x71,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x02,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x1e,0x1e,0x19,0x10
+ ,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x46,0x4e,0x55,0x5a,0x57,0x4c,0x43,0x43,0x50,0x65,0x7b,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x84,0x7f,0x7f,0x7f,0x7f,0x7f,0x74
+ ,0x71,0x62,0x57,0x49,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa4,0xa4,0x93,0x7f,0x6b,0x5a,0x46,0x33,0x2b,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x66,0x71,0x73,0x7b
+ ,0x7f,0x74,0x73,0x6b,0x73,0x8c,0xa2,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x49,0x5a,0x6a,0x7b,0x8c,0x9c,0xa5,0x94,0x84,0x72,0x62,0x51,0x40,0x31,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27
+ ,0x36,0x40,0x43,0x4b,0x5a,0x65,0x67,0x67,0x6b,0x74,0x7f,0x8e,0xa4,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x4e,0x4e,0x46,0x38,0x2e,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x22,0x0f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xaa,0x98,0x7f,0x7b,0x8e,0xa4,0x9d,0x8a
+ ,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x67,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x61,0x4c,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb7,0xa8,0x93
+ ,0x7f,0x6b,0x6b,0x7f,0x93,0xa8,0xa8,0x93,0x7f,0x6b,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5f,0x5b,0x5b,0x5d,0x71,0x84,0x99,0xa9,0x97,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x06,0x1e,0x36
+ ,0x4e,0x65,0x7b,0x8e,0xa4,0xa4,0x8c,0x74,0x61,0x4d,0x3e,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x47,0x48,0x55,0x68,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa6,0x98,0x7f,0x6b,0x57,0x51,0x5c,0x66,0x74,0x8a,0x9d,0xaa,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x4d,0x5a,0x6b,0x7f,0x97,0xad,0xad
+ ,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x8e,0x7b,0x6c,0x7f,0x92,0x95,0x7f,0x67,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x35,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x65,0x67,0x61,0x52,0x46,0x43,0x43,0x50,0x65,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xb0,0xa4,0x8c,0x74,0x67,0x67,0x67,0x67,0x67,0x61,0x5a,0x51,0x41,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xaa,0x98,0x84,0x72,0x61,0x4d,0x44,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00
+ ,0x00,0x08,0x1a,0x2b,0x3c,0x4c,0x55,0x5a,0x5c,0x65,0x67,0x61,0x5c,0x66,0x7b,0x8e,0xa4,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5c,0x6a,0x7b,0x8c,0x9c,0xa2,0x98,0x8a,0x74,0x62,0x51,0x47,0x43,0x42,0x3c,0x2f
+ ,0x1e,0x0a,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x57,0x5b,0x5a,0x52,0x4e,0x4f,0x4f,0x57,0x62,0x73,0x8a,0x9d,0xad,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x65,0x65,0x5a,0x4c,0x41,0x43,0x5b,0x73,0x8a,0x9d
+ ,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x49,0x49,0x49,0x49,0x49,0x49,0x47,0x43,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67
+ ,0x7f,0x93,0xa6,0x9d,0x8a,0x7f,0x97,0xa7,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5e,0x6b,0x7f,0x93,0xa8,0xa8,0x93,0x7f,0x6b,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x74,0x61,0x61,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xa4,0x8e,0x7b,0x66,0x52,0x4d,0x61,0x74,0x8c,0xa2,0xa4,0x8e,0x7b
+ ,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xa6,0x93,0x7f,0x67,0x53,0x47,0x52,0x67,0x7f,0x98,0xab,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x51,0x5a,0x61
+ ,0x71,0x84,0x99,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x52,0x45,0x4a,0x57,0x6b,0x7f,0x98,0xaa,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5e,0x61,0x6b,0x7b,0x8c,0x9d,0xaf,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa8,0x97,0x7f,0x69,0x72,0x7f,0x7f,0x7b,0x66,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb4,0xa4,0x8c,0x73,0x5c,0x4e,0x4b,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x52,0x66,0x7b,0x7f,0x72,0x66,0x5c,0x5b,0x5b,0x61,0x6c,0x7f,0x97,0xad,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e
+ ,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x4f,0x4f,0x4f,0x4f,0x4b,0x43,0x3c,0x2f,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xaa,0x9d,0x8c,0x7b,0x66,0x5c,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x65,0x65,0x5c,0x56,0x55,0x54,0x5d,0x71,0x84,0x98,0xaa,0x9d,0x8a,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x71,0x7b,0x8c,0x9c,0xa2,0x94
+ ,0x84,0x7b,0x6a,0x5d,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6a,0x73,0x71,0x62,0x57,0x4f,0x4f,0x51,0x5d,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a
+ ,0x7b,0x7b,0x6b,0x61,0x57,0x51,0x61,0x74,0x8c,0xa4,0xb1,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xa4,0x8e,0x84,0x99,0xa4,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x61,0x74,0x8a,0x9d,0xad,0x9d,0x8c
+ ,0x7b,0x66,0x51,0x3c,0x26,0x10,0x01,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x57,0x6b,0x7f,0x93,0xa8,0xa8,0x93,0x7f,0x6b,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa8,0x98,0x84
+ ,0x72,0x66,0x61,0x6c,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa9,0x99,0x84,0x72,0x66,0x5e,0x66,0x72,0x84,0x99,0xa9,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x67,0x71,0x74,0x7f,0x8e,0xa3,0xae,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xa9,0x99,0x84,0x72,0x62,0x5b,0x5b,0x61,0x71,0x84,0x99,0xaa,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x76,0x73,0x74,0x7f,0x8c,0x9c,0xad,0xa8,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x61,0x67,0x67,0x65,0x5f,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8e,0x7b,0x6b,0x65,0x61,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x84,0x91,0x84,0x7b,0x73,0x73,0x73,0x74,0x7f
+ ,0x8c,0x9d,0xad,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x37,0x37,0x34,0x2c,0x25,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x93,0xa4
+ ,0xae,0x98,0x7f,0x74,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x7b,0x71,0x67,0x67,0x67,0x71,0x7b,0x8e,0xa3,0xa8,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x02,0x15,0x2b
+ ,0x40,0x51,0x62,0x72,0x84,0x8e,0x9c,0xa9,0x99,0x84,0x77,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x02,0x15,0x2b,0x40,0x52,0x66,0x7b,0x8a,0x84,0x74,0x6b,0x67,0x67,0x67,0x71,0x7b,0x8e,0xa3,0xb0,0x9d,0x8a,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x8c,0x7f,0x74,0x6b,0x67,0x71,0x7f,0x93,0xa8,0xad,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71
+ ,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x99,0xa9,0x9d,0x99,0xa4,0xa2,0x8c,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4
+ ,0x8c,0x73,0x5b,0x57,0x6b,0x7f,0x93,0xa8,0xac,0x98,0x84,0x71,0x5c,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x4d,0x61,0x74,0x8a,0x9d,0xad,0x9d,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00
+ ,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa3,0xa4,0x94,0x84,0x7b,0x74,0x7f,0x8c,0x9d,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8c,0x9d,0xa4,0x94,0x84,0x7b,0x73,0x7b,0x84,0x94,0xa4,0xa3,0x8e,0x7b,0x65,0x4e
+ ,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7f,0x7f,0x7f,0x84,0x8c,0x93,0x9d,0xab,0xa4,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xa4,0x94,0x84,0x74,0x73,0x73,0x74,0x7f,0x8e
+ ,0xa3,0xa8,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb7,0xa8,0x94,0x8c,0x8c,0x8c,0x93,0x9d,0xab,0xac,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67
+ ,0x51,0x4f,0x4f,0x4e,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xae,0x9c,0x8c,0x7f,0x7b,0x74,0x7f,0x7f,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x11,0x28,0x40,0x57,0x6b
+ ,0x7f,0x93,0xa0,0x98,0x8e,0x8c,0x8c,0x8c,0x8c,0x93,0x9d,0xaa,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x1e,0x1e,0x1c,0x15,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9d,0xb3,0xb3,0x9d,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x8e,0x84,0x7f,0x7f,0x7f,0x84,0x8e,0x9c,0xa9,0x9c,0x8a,0x74,0x61
+ ,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa3,0xae,0xb3,0x9d,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x98,0x94,0x8a,0x7f,0x7f,0x7f,0x7f,0x84
+ ,0x8e,0x9c,0xae,0xa8,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0x9d,0x93,0x8a,0x7f,0x7f,0x84,0x8e,0x9d,0xb0,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xb1,0xb0,0xae,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x4d,0x61,0x74,0x8a,0x9d,0xb0,0xa3,0x8e,0x7b,0x66,0x52,0x40,0x2b,0x15,0x02,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x47,0x57,0x6b,0x7f,0x93,0xa8,0xa8,0x94
+ ,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x94,0xa4,0xa4,0x98,0x8e,0x8c,0x93,0x9d,0xa5,0x98,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x93,0xa3,0xa2,0x98,0x8e
+ ,0x8c,0x8e,0x98,0xa4,0xa4,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9d,0x98,0x98,0x98,0x99,0xa2,0xa6,0xaa,0xa3,0x94,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84
+ ,0x97,0xa4,0xa4,0x94,0x8c,0x8c,0x8c,0x8c,0x93,0x9d,0xa5,0x9c,0x8a,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb8,0xb3,0xa8,0xa4,0xa4,0xa4,0xa6,0xaa,0xa3,0x98,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x3a,0x37,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xad,0xad,0x9d,0x97,0x8e,0x8c,0x93,0x95,0x7f,0x6b,0x57
+ ,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8e,0x98,0xa1,0xa3,0xa4,0xa4,0xa4,0xa4,0xa6,0xa6,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x06,0x05
+ ,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xac,0xb8,0xb8,0xae,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xa3,0x99,0x98
+ ,0x98,0x98,0x99,0xa3,0xa8,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa4,0xb3,0xb9,0xb8,0xae,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x90,0x9f,0xa5,0x9d,0x98,0x98,0x98,0x98,0x99,0xa3,0xab,0xaa,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xaa,0xa8,0x9d,0x98,0x98,0x99,0xa3,0xab,0xa4,0x97,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00
+ ,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb3,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa1,0xa4,0xa4,0xa2,0x93,0x7f,0x67
+ ,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa1,0x8c,0x73,0x5b,0x47,0x57,0x6b,0x7f,0x93,0xa2,0xa2,0x98,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa1,0x8c
+ ,0x73,0x5b,0x43,0x4c,0x61,0x74,0x8a,0x9d,0xa4,0x9f,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x72,0x84,0x93,0x9d,0xa5,0xa4,0xa4,0xa2,0xa2,0x94,0x8a,0x7b,0x66,0x52,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x10
+ ,0x25,0x38,0x4c,0x61,0x72,0x84,0x8e,0x98,0xa1,0xa3,0xa4,0xa3,0xa3,0x9d,0x93,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x15
+ ,0x02,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x84,0x93,0x9d,0xa0,0xa2,0xa4,0xa4,0xa2,0xa0,0x9d,0x93,0x8a,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x7b,0x6a
+ ,0x5a,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c
+ ,0xa4,0xaa,0xa8,0xa4,0xa2,0xa0,0x9b,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x7b,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98
+ ,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06
+ ,0x1e,0x36,0x4e,0x65,0x7b,0x84,0x93,0x9d,0xa4,0xa6,0xaa,0xaa,0xa6,0xa2,0x98,0x8c,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x8e,0x98,0xa2,0xa4,0xa8,0xaa,0xaa,0xa9,0xa4,0x9d,0x93,0x8a,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x98,0xa2,0xa6,0xaa,0xaa,0xa9,0xa4,0x9d,0x93
+ ,0x84,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43
+ ,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x89,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x4c,0x61,0x72,0x84,0x8c,0x8c,0x8c,0x8a,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x41,0x57,0x6b,0x7f,0x8c,0x8c,0x8c,0x8c,0x82,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x72,0x7f,0x8a,0x93,0x98,0x98,0x93,0x8c,0x84,0x74,0x6a,0x5a,0x46
+ ,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x51,0x62,0x71,0x7b,0x84,0x8e,0x97,0x98,0x97,0x8e,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x84,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x66,0x72,0x7f,0x8a,0x8e,0x97,0x98,0x98,0x97,0x8e,0x8a,0x7f,0x74,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8a,0x8e,0x97,0x98,0x98,0x97,0x8e,0x8c,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c,0x66,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6b,0x61,0x51,0x40,0x2f,0x1e,0x0a,0x00
+ ,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x66,0x72,0x7f,0x8a,0x8c,0x93,0x98,0x98,0x93,0x8c,0x84,0x7b,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x71,0x7b,0x84,0x8c,0x8e,0x97,0x98,0x98,0x97,0x8e,0x8a,0x7f,0x74,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a
+ ,0x7b,0x84,0x8c,0x93,0x98,0x98,0x97,0x8e,0x8a,0x7f,0x72,0x66,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x40,0x51,0x62,0x71,0x73,0x73
+ ,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x36,0x4c,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x61,0x6b,0x74
+ ,0x7f,0x7f,0x7f,0x7f,0x74,0x71,0x62,0x57,0x49,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x5c,0x66,0x71,0x7b,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61
+ ,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x52,0x61,0x6b,0x73,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x57,0x49,0x38,0x27,0x14,0x02,0x00,0x00
+ ,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x67,0x65,0x5c,0x51,0x46,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73
+ ,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x73,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x73,0x71,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x46,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71
+ ,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73
+ ,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x52,0x61,0x6b,0x73,0x74,0x7f,0x7f,0x7f,0x7f,0x74,0x71,0x66,0x5a,0x49,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34
+ ,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x5c,0x66,0x71,0x73,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x57,0x49,0x38,0x27,0x14,0x02
+ ,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x66,0x71,0x74,0x7f,0x7f,0x7f,0x7f,0x7b,0x73,0x6b,0x61,0x52,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71
+ ,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x57,0x49,0x36,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00
+ ,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x4c,0x57,0x61,0x67,0x67,0x67,0x67,0x61,0x5a,0x51,0x41,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x51,0x5c,0x65,0x67,0x67,0x67,0x65,0x5c,0x57,0x4c,0x40,0x2f,0x1e,0x0d
+ ,0x01,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x31,0x40,0x4c,0x57,0x5c,0x65,0x67,0x67,0x67,0x67,0x65,0x5c
+ ,0x57,0x4c,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51
+ ,0x40,0x2b,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x5c,0x65,0x67,0x67,0x67,0x67,0x65,0x5c,0x5a,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26
+ ,0x31,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x04,0x16,0x25,0x31,0x40,0x4c,0x57,0x5b,0x61,0x67,0x67,0x67,0x67,0x61,0x5a,0x51,0x46,0x38,0x27,0x16
+ ,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x51,0x5a,0x5c,0x65,0x67,0x67,0x67,0x67
+ ,0x65,0x5c,0x57,0x4c,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x51,0x5a,0x61,0x67,0x67,0x67,0x67,0x65,0x5c,0x57,0x4c,0x40,0x31,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43
+ ,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x41,0x4b,0x4f,0x4f,0x4f,0x4f,0x4b,0x43,0x3c,0x2f,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x31,0x3c,0x46,0x4e,0x4f
+ ,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x36,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b
+ ,0x36,0x40,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x36,0x30,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x40,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x42,0x3c,0x2f
+ ,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x36,0x40,0x43,0x4b,0x4f
+ ,0x4f,0x4f,0x4f,0x4b,0x43,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b
+ ,0x26,0x31,0x3c,0x42,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x43,0x4b,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x40,0x36,0x2b,0x1e,0x10,0x04,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21
+ ,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x28,0x21,0x14,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x34,0x37,0x37,0x37,0x37,0x34,0x2c,0x25,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x06,0x10,0x1b,0x26,0x30,0x36,0x37,0x37,0x37,0x36,0x30,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x28,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x28,0x21,0x16,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x30
+ ,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x01,0x0a,0x16,0x21,0x28,0x2c,0x34,0x37,0x37,0x37,0x37,0x34,0x2c,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b
+ ,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x1b,0x25,0x2a,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x28,0x21,0x16,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x25,0x2c,0x34,0x37,0x37,0x37,0x37,0x36,0x30,0x28
+ ,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02
+ ,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0e,0x06,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+ ,0x0e,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x11,0x0a,0x0e,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x01,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x01,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11
+ ,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12
+ ,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e
+ ,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x1b,0x25,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x28,0x21,0x25,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x11,0x1b,0x25
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x11,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c
+ ,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x0a,0x11,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1c,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1c,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x25,0x1d,0x15,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43
+ ,0x43,0x40,0x36,0x27,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x40,0x36,0x3c,0x42,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40
+ ,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x23,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x23,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00
+ ,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f
+ ,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x21,0x28,0x31,0x3c,0x42,0x43,0x43,0x43
+ ,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x34,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x34,0x2b,0x1e,0x10,0x04,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x36,0x30
+ ,0x26,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x16,0x21,0x2b,0x34,0x38,0x40,0x43,0x43
+ ,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10
+ ,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x34,0x2b,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x12,0x12,0x12,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00
+ ,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x57,0x49,0x51,0x5a,0x5b,0x5b,0x57,0x49,0x36,0x21
+ ,0x0a,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x31,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x31,0x40,0x51,0x5a,0x5b,0x5b
+ ,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21
+ ,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40
+ ,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x05,0x16,0x25
+ ,0x30,0x36,0x38,0x40,0x46,0x51,0x5a,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x36,0x41,0x4b,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1b,0x2f
+ ,0x40,0x4b,0x4f,0x4b,0x40,0x31,0x25,0x17,0x0b,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x46
+ ,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05
+ ,0x14,0x21,0x2b,0x36,0x41,0x4b,0x4f,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x31,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x41,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2f,0x2a,0x2a,0x2a,0x2d,0x40,0x51,0x5a
+ ,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x5a,0x46,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73
+ ,0x6a,0x57,0x61,0x71,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x3a,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73
+ ,0x73,0x71,0x61,0x4b,0x3a,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b
+ ,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x51,0x62,0x71,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b
+ ,0x34,0x1c,0x05,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x4e,0x4f,0x57,0x5c,0x66,0x71,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x31,0x40,0x4c,0x57,0x61,0x65
+ ,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x61,0x52,0x46,0x38,0x2b,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x71,0x73,0x73,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00
+ ,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x46,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x65,0x5c,0x51,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38
+ ,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x41,0x4c,0x57,0x61,0x67,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73
+ ,0x6b,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x46,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x71,0x67,0x61,0x57,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x71
+ ,0x62,0x51,0x41,0x43,0x43,0x43,0x42,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8a,0x7b,0x65,0x4e,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x8c,0x89,0x73,0x5b,0x67,0x7f,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73
+ ,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x65,0x67,0x6b,0x73,0x7b,0x84,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04
+ ,0x10,0x1e,0x2b,0x38,0x46,0x52,0x61,0x6b,0x74,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x72,0x66,0x5a,0x4c,0x41,0x36,0x27,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x8c
+ ,0x8c,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x71,0x66,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x6a,0x74,0x7f
+ ,0x84,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x61,0x6b,0x74,0x7f,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f
+ ,0x40,0x51,0x62,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x66,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8c,0x84,0x7f,0x74,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x87,0x8c,0x8c,0x8c,0x84,0x71,0x5a,0x57,0x5b,0x5b,0x5b,0x5a,0x54,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0x97,0x7f,0x6b,0x57,0x4f,0x67,0x7f,0x98,0xa4,0xa1
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x28,0x40,0x57,0x6b,0x7f,0x98,0x8c,0x73,0x5c,0x67,0x7f,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x01,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67
+ ,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4
+ ,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa2,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x7f,0x7f,0x8a,0x8e,0x98,0xa2,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x31,0x40,0x4c,0x5a,0x66,0x72,0x7f,0x8a,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x84,0x7b,0x6b,0x61,0x57,0x49,0x3c,0x2f,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa2,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00
+ ,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x74,0x7f,0x8a,0x93,0x98,0x9d,0xa4,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x31
+ ,0x1b,0x06,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x51,0x62,0x72,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0xa2,0x99
+ ,0x93,0x8a,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xa4,0xa0,0x8c,0x73,0x5e,0x6a,0x73,0x73,0x73,0x71,0x61,0x67,0x7f,0x98,0xa4,0x9b,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb9,0xb3
+ ,0x9d,0x8a,0x74,0x61,0x53,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x43,0x5b,0x73,0x8a,0x9a,0x8c,0x73,0x60,0x71,0x84,0x98,0x8c,0x73,0x5b,0x43,0x2d,0x1e,0x0c,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa8,0xb3,0xbb,0xb3,0xa8,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb3,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xae,0xb1,0xb8,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb6,0xac,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x97,0x98,0x9d,0xa4,0xad,0xb5,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x1e,0x2b,0x38,0x46,0x52,0x61,0x6b,0x7b,0x84,0x93,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x8c,0x7f,0x74,0x6a,0x5c,0x51
+ ,0x41,0x36,0x27,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa4,0xb5,0xb8,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x98,0xa3,0xa2,0x99,0x98,0x98,0x98,0x9d,0xa3,0xa1,0x96
+ ,0x88,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8c,0x9c,0xa5,0xa2,0x99,0x98,0x99,0xa2,0xa5,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x92,0x9d,0xa2,0xa4,0xa4,0xa4
+ ,0xa4,0xa4,0xa9,0xa8,0x9c,0x8c,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x94,0xa3,0xa8,0xa4,0xa4,0xa4,0xa4,0xa7,0xa3,0x94,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a
+ ,0x7b,0x8c,0x98,0xa3,0xa7,0xa4,0xa4,0xa4,0xa4,0xa4,0xa3,0x98,0x88,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x61,0x73,0x89,0x8c,0x8c,0x7f,0x67,0x67,0x7f,0x98,0xaa,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbc,0xbd,0xa8,0x93,0x7f,0x67,0x56,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x5b,0x73,0x8c,0x98,0x84,0x71,0x60,0x73,0x8c,0x9a,0x8a,0x73,0x5b,0x4c,0x40
+ ,0x2f,0x1b,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x94,0xa8,0xb9,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84
+ ,0x98,0xa2,0x99,0x9d,0xae,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9d,0xab,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b
+ ,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xae,0xb8,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x31,0x40,0x4c,0x5a,0x66,0x72,0x7f,0x8c,0x98,0xa2,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43
+ ,0x5b,0x73,0x8c,0x9f,0x9d,0x93,0x8a,0x7b,0x71,0x62,0x57,0x49,0x3c,0x2f,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xc5,0xc9,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8
+ ,0xa8,0x94,0x84,0x7f,0x7f,0x7f,0x8a,0x8e,0x98,0x8e,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xa9,0x9c,0x8e,0x84,0x7f,0x84,0x8e,0x9c,0xa9,0x9c,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x0e,0x25
+ ,0x3c,0x51,0x66,0x7b,0x8e,0x9c,0x93,0x8c,0x8c,0x8c,0x8c,0x8e,0x98,0xa4,0xab,0x98,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x93,0xa4,0xab,0x9c,0x8e,0x8c,0x8c,0x8e,0x98,0xa4,0xa4,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b
+ ,0x06,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xaa,0xa4,0x98,0x8e,0x8c,0x8c,0x8c,0x8e,0x97,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa4,0x8c,0x73,0x66,0x7b,0x8e,0xa1,0x98,0x7f,0x6b,0x6b,0x7f
+ ,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb8,0xb3,0xad,0x99,0x84,0x71,0x5c,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x73,0x8c,0x98,0x7f
+ ,0x6a,0x67,0x73,0x8c,0x98,0x7f,0x6e,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x76,0x8c,0xa4,0xb6,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa1,0x94,0x84,0x8e,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x77,0x84,0x99,0xa2,0x8e,0x7b,0x6a,0x5a,0x46
+ ,0x30,0x19,0x04,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8e,0x9d,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x52,0x61,0x6b,0x7b,0x84,0x93,0x9d,0xa2,0x98,0x8c,0x7b
+ ,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8e,0x9c,0xa2,0x9c,0x8e,0x84,0x74,0x6a,0x5c,0x51,0x41,0x36,0x27,0x1b,0x0c,0x01,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xac,0xbe,0xc5,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00
+ ,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x67,0x67,0x6b,0x73,0x7b,0x84,0x84,0x71,0x5c,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xaa,0x9d,0x8c,0x7b,0x71,0x68,0x71,0x7b,0x8c,0x9d,0xa6,0x93,0x7f
+ ,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x8a,0x7f,0x74,0x73,0x73,0x73,0x7b,0x84,0x98,0xac,0xa3,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x07,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9d,0xad,0x9d,0x8c,0x7b,0x73,0x73,0x7b
+ ,0x84,0x98,0xab,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xab,0xa4,0x94,0x84,0x7b,0x73,0x73,0x73,0x7b,0x84,0x7f,0x6b,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xa4,0x8e
+ ,0x7b,0x6c,0x7f,0x97,0xae,0x9d,0x8a,0x73,0x73,0x8a,0x9d,0xaa,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xae,0x9d,0x99,0x9f,0x8e,0x7b,0x66,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12
+ ,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x8e,0x99,0x84,0x7f,0x7f,0x7f,0x8e,0x99,0x84,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5e,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x57
+ ,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b
+ ,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x05,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0x9c,0x8a,0x79,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5f
+ ,0x6b,0x7f,0x93,0xa1,0x94,0x84,0x71,0x5c,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x5c,0x66
+ ,0x72,0x7f,0x8c,0x98,0xa1,0x9d,0x93,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x7b,0x8a,0x94,0xa1,0xa1,0x94,0x8a,0x7b,0x71,0x62,0x57,0x49,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xac
+ ,0xae,0xa3,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8e,0x7b,0x73,0x71,0x67,0x64,0x66,0x71,0x71,0x62,0x51,0x3c,0x27,0x14,0x02,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xa8,0x93,0x7f
+ ,0x6b,0x61,0x5d,0x61,0x6b,0x7f,0x98,0xaa,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x62,0x71,0x73,0x6b,0x64,0x66,0x67,0x67,0x6e,0x7c,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67
+ ,0x7f,0x97,0xac,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x68,0x7b,0x8e,0xa4,0xad,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x07,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xae,0x99,0x84,0x72,0x66,0x5c,0x5b,0x5c,0x66,0x71,0x71,0x61,0x4c,0x38,0x27,0x14,0x02,0x00,0x00
+ ,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0xa4,0xad,0x97,0x7f,0x6e,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x73,0x8c,0xa4,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8e,0x84,0x98,0x98,0x84,0x71,0x67,0x7f,0x98,0xb0,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x9d,0xa4,0x99,0x98,0x98,0x98,0x9d,0xa4,0x99,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x5b,0x5b,0x5b,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x46,0x5b,0x73,0x8c
+ ,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x49,0x49,0x49,0x49,0x49,0x49,0x47,0x41,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x4c,0x61,0x72,0x84,0x98,0xa1,0x8e,0x7b,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e
+ ,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x44,0x51,0x66,0x7b,0x8c,0x9d,0x9c,0x8a,0x74,0x62,0x51,0x3c,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x7b,0x84,0x93,0x9d,0xa1,0x94,0x8a,0x7f,0x72,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c,0x6a,0x74,0x84,0x8e,0x98,0xa1,0x9c,0x8e,0x84,0x74,0x6a,0x5c,0x51,0x40,0x2b,0x15,0x00
+ ,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x97,0x97,0x8e,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xae,0x9c,0x8e,0x8c,0x84,0x7f,0x74,0x73,0x6b,0x63,0x59,0x49,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x77,0x73,0x73,0x73,0x73,0x73,0x7f,0x98,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0d,0x20,0x33,0x45,0x56,0x60,0x66,0x71,0x73,0x7b,0x7f,0x7f,0x7f,0x8a,0x94,0xa8,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x61,0x4c,0x48,0x5c,0x73,0x8c,0xa2,0xb3,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x97,0xad,0xa8,0x93,0x7f,0x67,0x53,0x46,0x43,0x46,0x51
+ ,0x5a,0x5a,0x51,0x40,0x2b,0x17,0x05,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xab,0x98,0x7f,0x73,0x8a,0x98,0x8e,0x94,0x8e,0x7b,0x73,0x8c,0xa4,0xa4,0x8c,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8c
+ ,0x7c,0x8e,0x9e,0x8c,0x74,0x69,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x99,0xa4,0x9d,0x98,0x98,0x98,0x99,0xa4,0x9d,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x98,0x7f,0x73,0x73,0x73,0x73,0x73,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x01,0x0c,0x1b,0x25,0x2a,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x0d,0x21,0x36,0x49,0x5a,0x6b,0x7f,0x93,0xa1,0x94,0x84,0x71,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x33,0x46,0x5c,0x71,0x84,0x98,0xa1,0x8e,0x7b,0x6a,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x84,0x8e,0x98,0xa1,0x9c,0x8e,0x84,0x74,0x6b,0x61,0x52,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x49,0x57,0x62,0x71,0x7b,0x84,0x93,0x9d
+ ,0xa1,0x94,0x8a,0x7b,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x7f,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8a,0x98,0xa3,0xa8,0xa4,0xa2,0x99,0x93,0x8c,0x8a,0x7f,0x74
+ ,0x6a,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9d,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x71,0x7b,0x84,0x8c,0x8e,0x97
+ ,0x98,0x98,0x9b,0xa2,0xb1,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb4,0xa4,0x8c,0x73,0x5b,0x43,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99
+ ,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x35,0x2a,0x31,0x3c,0x42,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xaa,0x98,0x7f,0x73,0x8c,0x97,0x7f,0x8c,0x97,0x7f,0x74,0x8c,0xa4,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8e,0x7c,0x8a,0x9c,0x93,0x7f,0x6e,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x84,0x99,0x8e,0x7f,0x7f,0x7f,0x84,0x99,0x8e,0x7f,0x7f,0x7f,0x71,0x5a
+ ,0x42,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb1,0x9d,0x8e,0x8c,0x8c,0x8c,0x8c,0x8c,0x8e,0x9d,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x15,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x41,0x57,0x6a,0x7b,0x8c,0x9d,0x9c,0x8a
+ ,0x74,0x64,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x22,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x15,0x26,0x3c,0x51,0x66,0x7b,0x8e,0xa1,0x98,0x84,0x71,0x5c,0x49,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21
+ ,0x28,0x2a,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x94,0xa1,0x9d,0x93,0x8a,0x7b,0x71,0x62,0x57,0x4c,0x40,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x0c
+ ,0x1b,0x27,0x36,0x41,0x51,0x5c,0x66,0x72,0x7f,0x8c,0x98,0xa1,0x9c,0x8e,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x65,0x67,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x84
+ ,0x8e,0x98,0xa2,0xa4,0xa9,0xa6,0xa4,0x9d,0x93,0x8a,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb1,0xa2,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0xa2,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x10,0x26
+ ,0x3c,0x51,0x62,0x72,0x84,0x8e,0x98,0x9d,0x98,0x98,0x93,0x8c,0x8c,0x94,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x3e,0x54,0x68,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a
+ ,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xb3,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x19,0x21,0x2b,0x30,0x30,0x2c,0x23,0x15,0x05,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xaa,0x99,0x84,0x77,0x8c,0x8e,0x7c,0x8c,0x98,0x7f,0x7f,0x93
+ ,0xa6,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xad,0x97,0x7f,0x7f,0x93,0x9c,0x8a,0x73,0x7f,0x97,0xad,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x14,0x29,0x3d,0x51,0x61,0x67,0x6e,0x7f,0x98,0x8c,0x73
+ ,0x67,0x6a,0x7f,0x98,0x8c,0x73,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb8,0xae,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb8,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x02,0x14
+ ,0x27,0x3c,0x51,0x62,0x74,0x8a,0x9c,0xa1,0x8e,0x7b,0x6a,0x5e,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x71,0x84,0x98,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x27,0x14,0x02
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xa4,0x8e,0x7f,0x74,0x6a,0x5c,0x51,0x41,0x36,0x2b,0x1e
+ ,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2f,0x3c,0x46,0x52,0x61,0x6b,0x7b,0x84,0x99,0xa9,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x65,0x67,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00
+ ,0x00,0x00,0x00,0x0e,0x22,0x36,0x49,0x5a,0x66,0x71,0x7b,0x84,0x8c,0x8e,0x97,0x99,0xa3,0xab,0xa8,0x9c,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x07,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x94,0xa3,0x9d,0x8e,0x84,0x7f,0x7f,0x74,0x76,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb4,0xa4,0x8c,0x73,0x5b,0x43,0x42,0x5a
+ ,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x73,0x5c,0x44,0x31,0x2a,0x31,0x3c,0x42,0x43,0x40,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa2
+ ,0x8c,0x7f,0x93,0x8c,0x79,0x8c,0x9b,0x8a,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x74,0x8c,0x9e,0x8e,0x7b,0x7b,0x8e,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0a,0x21
+ ,0x36,0x49,0x57,0x5b,0x5e,0x73,0x8a,0x9a,0x8c,0x73,0x60,0x71,0x84,0x98,0x8c,0x73,0x5e,0x5a,0x53,0x44,0x30,0x1b,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbb,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xae,0xb8,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x5c,0x71,0x84,0x94,0xa2,0x94,0x84,0x71,0x5f,0x5e,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e
+ ,0xa3,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa5
+ ,0x94,0x84,0x7b,0x6b,0x61,0x57,0x49,0x3c,0x2f,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0d,0x1b,0x26,0x31,0x40,0x4c,0x5a,0x66,0x71,0x7b,0x8c,0x9d,0xa9,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x7f
+ ,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x51,0x61,0x65,0x61,0x66,0x71,0x73,0x7b,0x7f,0x84,0x8e,0x9c,0xae,0xac,0x97,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x77
+ ,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xa7,0x93,0x7f,0x71,0x67,0x67,0x63,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71
+ ,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x61,0x4c,0x48,0x5c,0x73,0x8c,0xa2,0xb3,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x66,0x52,0x46,0x43,0x46,0x51,0x5a,0x5b,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00
+ ,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xa4,0x8c,0x7f,0x98,0x8c,0x79,0x8a,0x9b,0x8c,0x7f,0x98,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x71,0x84,0x98,0x98,0x84,0x77,0x8c,0xa4,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x76,0x8c,0x98,0x84,0x76,0x73,0x76,0x8c,0x9d,0x8c,0x76,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb4,0xa4,0x94,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8e,0x9d,0xb1,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c
+ ,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xb5,0xa8,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x8e,0xa3,0xa4,0x8c,0x77,0x73,0x73,0x73,0x76,0x8c,0xa4,0xb0,0x98,0x7f,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xa9,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x09,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8e,0x9c,0xa1,0x98,0x8c,0x7f,0x74,0x6a,0x5c,0x51,0x41,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2f,0x3c,0x46,0x52,0x61,0x6b,0x7b,0x84,0x8e,0x9c,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x36,0x1e,0x00
+ ,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x97,0x97,0x8e,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x7b,0x71,0x66,0x61,0x61,0x65,0x67,0x71,0x7b,0x8e,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06
+ ,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xa8,0x93,0x7f,0x6c,0x63,0x5e,0x5b,0x5e,0x61,0x66,0x67,0x63,0x5c,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xad,0xa4,0x8c,0x74,0x62,0x5a,0x5c,0x66,0x74,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x97,0xac,0xa8,0x93,0x7f,0x6b,0x5c,0x5c,0x68,0x7b,0x8e,0xa4,0xad,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xad,0x98,0x84,0x72,0x66,0x5c,0x5b,0x5c,0x66
+ ,0x71,0x73,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8e,0x84,0x98,0x8c,0x74,0x7f,0x98,0x8e,0x84,0x99,0xa6,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98
+ ,0x7f,0x6c,0x7b,0x8e,0x9e,0x8c,0x79,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x94,0x9d,0x8e,0x8c,0x8c,0x8c,0x94,0xa2,0x94,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x99,0x84,0x74,0x73,0x73,0x73,0x73,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x51,0x3f,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x06,0x0e,0x15,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9c,0xae,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x94,0xa8,0xb3,0x9d,0x8e,0x8c,0x89
+ ,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xa8,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x21,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c
+ ,0x73,0x5b,0x43,0x2a,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x7b,0x8a,0x94,0xa1,0x9d,0x93,0x8a,0x7b,0x71,0x62,0x57,0x4c,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x41,0x51,0x5c,0x66,0x72,0x7f,0x8c,0x98,0xa0
+ ,0x9d,0x93,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xac,0xad,0xa3,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x8d,0x84,0x7b,0x73,0x71,0x67,0x67,0x6b,0x76,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x98,0xaa,0x9d,0x8c,0x7f,0x74,0x6b,0x67,0x6b,0x73,0x7b,0x7f,0x72,0x61,0x4c,0x3a,0x27,0x14,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x71,0x6b
+ ,0x73,0x7b,0x84,0x94,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x07,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9d,0xad,0x9d,0x8c,0x7b,0x73,0x73,0x7b,0x84,0x98,0xab,0xa3,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a
+ ,0x9c,0xac,0xa4,0x94,0x84,0x7b,0x73,0x73,0x73,0x7b,0x84,0x8a,0x7b,0x66,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xab,0x9d,0x99,0x98,0x84,0x71,0x7f,0x98,0x9d,0x99,0xa4,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8a,0x9c,0x93,0x7f,0x8c,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x9e,0x9e,0xa5,0xa9,0x9f,0x9e,0x9e,0x9e,0xa5,0xab,0xa0,0x9e,0x98,0x7f,0x67,0x4f
+ ,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x5b,0x5b,0x5b,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2d
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0xad,0xa6,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0xa8,0xb5,0xbe,0xae,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34
+ ,0x37,0x37,0x3a,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x37,0x36,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c,0x6a,0x74,0x84,0x8e,0x9c,0xa2,0x9c,0x8e,0x84,0x74,0x6b,0x61,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x0a,0x21,0x36
+ ,0x49,0x57,0x62,0x71,0x7b,0x84,0x93,0x9d,0xa1,0x94,0x8a,0x7f,0x72,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x97,0xac,0xbe,0xc2,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0x98
+ ,0x8e,0x8c,0x84,0x7f,0x7f,0x7f,0x8a,0x94,0xa7,0xa4,0x93,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x66,0x7b,0x8c,0x9c,0xa9,0x9d,0x93,0x8a,0x7f,0x7f,0x7f,0x8a,0x8e,0x92,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x06,0x1e,0x37
+ ,0x4f,0x67,0x7f,0x93,0xa8,0xae,0x9c,0x8e,0x84,0x7f,0x8a,0x8e,0x98,0x9f,0xad,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x93,0xa4,0xab,0x9c,0x8e,0x8c,0x8c,0x8e,0x98,0xa4,0xa4,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b
+ ,0x06,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8e,0xa1,0xad,0xa4,0x98,0x8e,0x8c,0x8c,0x8c,0x8e,0x98,0x98,0x84,0x71,0x5c,0x46,0x30,0x19,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xb1,0xad,0x98,0x7f,0x6d,0x7f,0x93,0xa6,0xb0,0xb4
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x6b,0x7f,0x93,0x9c,0x8e,0x94,0xa8,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8e,0x9d,0x9d,0x8e,0x8c
+ ,0x8c,0x8e,0x9d,0x9d,0x8e,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xb3
+ ,0xa2,0x8c,0x73,0x5b,0x45,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x46,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a
+ ,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x9d,0xae,0xb8,0xa4,0x99,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x52,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x4f,0x4f,0x4e,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x49,0x57,0x62,0x71,0x7b,0x8a,0x93,0x9d,0xa1,0x94,0x8a,0x7f,0x72
+ ,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x74,0x84,0x8e,0x98,0xa1,0x9c,0x8e,0x84,0x74,0x6b,0x61,0x52,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xc5,0xcb,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8e,0x98,0xa1,0xa3,0xa2,0x99,0x98,0x98,0x98,0x9d,0xa5,0xa3,0x94,0x84,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x6a,0x7b,0x8c,0x9c,0xa6,0xa6,0x9d,0x98,0x98,0x98,0x9d,0xa0,0x99,0x8a,0x73
+ ,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xac,0xab,0xa3,0x99,0x98,0x9c,0x9a,0x8e,0x8e,0x9d,0xab,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x94,0xa3,0xa8,0xa4,0xa4,0xa4,0xa4
+ ,0xa7,0xa3,0x94,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5c,0x71,0x84,0x8e,0x9c,0xa8,0xa9,0xa4,0xa4,0xa4,0xa4,0xa3,0xa3,0x9c,0x8a,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67,0x7f,0x98,0xa4
+ ,0xa4,0xa4,0x97,0x7f,0x69,0x74,0x8c,0xa1,0xa4,0xa4,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x61,0x74,0x8a,0x9d,0xa4,0xa8,0xb3,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x11,0x28
+ ,0x40,0x57,0x6a,0x73,0x73,0x7f,0x98,0x93,0x7f,0x73,0x73,0x7f,0x98,0x97,0x7f,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x62,0x55,0x5d,0x71,0x84,0x99,0xae,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5e,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x57
+ ,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5e,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x46,0x43,0x43,0x43,0x43,0x43
+ ,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0xb0,0x99,0x84,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xac
+ ,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x6a,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x67,0x67,0x67,0x65,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x36,0x41,0x51
+ ,0x5c,0x6a,0x74,0x7f,0x8c,0x98,0xa1,0x9d,0x92,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x94,0xa1,0xa1,0x94,0x8a,0x7b,0x71,0x62,0x57,0x4c,0x40,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa4,0xb5
+ ,0xbb,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x7b,0x84,0x8e,0x97,0x99,0xa2,0xa4,0xa4,0xa2,0x99,0x97,0x8e,0x84,0x72,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x8a,0x93
+ ,0x98,0x9d,0xa4,0xa4,0x9d,0x98,0x93,0x8a,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x97,0x9d,0xa4,0xa2,0x99,0x93,0x8a,0x7b,0x7f,0x95,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x04,0x17,0x2b,0x40
+ ,0x51,0x62,0x72,0x84,0x8e,0x97,0x9d,0xa4,0xa4,0x9d,0x97,0x8e,0x84,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x3c,0x51,0x62,0x71,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0xa4,0x9d,0x97,0x8e,0x8a,0x7b,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8a,0x7b,0x66,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x58,0x6b,0x7f,0x97,0xad,0xbc,0xbb,0xa4
+ ,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x67,0x7f,0x98,0x8c,0x74,0x62,0x67,0x7f,0x98,0x8e,0x7b,0x65,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa8,0xa8,0x94,0x84,0x72,0x68,0x71,0x7b,0x8e,0xa3,0xae,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x76,0x8c
+ ,0xa4,0xb6,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x76,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2d,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x6a,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xae,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x84,0x99,0xb0,0xa4,0x8e,0x7f,0x7f,0x7f,0x7f,0x7b,0x6a,0x57,0x40,0x28,0x11
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2f,0x3c,0x49,0x57,0x61,0x6b,0x7b,0x84,0x93,0x9d,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0x9c,0x8e,0x84,0x74,0x6a,0x5c,0x51,0x41,0x36,0x2b,0x1e,0x10,0x04,0x00,0x00,0x00
+ ,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa2,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5c,0x66,0x71,0x7b,0x7f,0x84,0x8c,0x8c,0x8c,0x8c,0x84,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7f,0x74,0x6b,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x7f,0x8a,0x8c,0x8c,0x84,0x7f,0x74,0x6d,0x7b,0x7f,0x7f,0x7f,0x7b,0x65,0x4e
+ ,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x71,0x7b,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5c,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8c,0x8a,0x7f
+ ,0x7b,0x73,0x6a,0x5c,0x51,0x40,0x2b,0x15,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x5d,0x6a,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98
+ ,0x7f,0x67,0x54,0x65,0x7b,0x8e,0xa3,0xb8,0xbc,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x14,0x27,0x36,0x44,0x57,0x6b,0x7f,0x98,0x8c,0x73,0x5c,0x67,0x7f,0x98,0x8c,0x73,0x5c,0x48,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xb1,0xa4,0x94,0x84,0x7f,0x84,0x8e,0x9c,0xac,0xa4,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06
+ ,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x94,0xa8,0xb9,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x94,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e
+ ,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x15,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x52
+ ,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x99,0xa4,0xb8,0xae,0x9d
+ ,0x98,0x98,0x98,0x97,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0d,0x1b,0x27,0x36,0x41,0x4c,0x5a,0x66,0x72,0x7f,0x8c,0x94,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x94,0x8a,0x7b,0x71,0x62,0x57,0x49
+ ,0x3c,0x2f,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x8c,0x8c,0x84,0x7b,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x46,0x51,0x5c,0x65,0x67,0x71,0x73,0x73,0x73,0x73,0x71,0x67,0x65,0x5c
+ ,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x38,0x49,0x57,0x61,0x67,0x6b,0x73,0x73,0x73,0x73,0x6b,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x65,0x6b,0x73,0x73,0x73,0x71
+ ,0x67,0x61,0x5c,0x65,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5c,0x65,0x6b,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c
+ ,0x49,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x73,0x6b,0x65,0x5c,0x57,0x49,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x4d,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x50,0x5c,0x71,0x84,0x99,0xb0,0xb9,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x05,0x15,0x2a,0x43,0x5b,0x73,0x8a,0x9b,0x8c,0x73,0x60,0x71,0x84,0x98,0x8c,0x73,0x5b,0x43,0x2d,0x25,0x1b
+ ,0x0c,0x01,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x94,0xa4,0xaf,0xa4,0x99,0x98,0x99,0xa3,0xab,0xa9,0x98
+ ,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa8,0xb3,0xbb,0xb3,0xa8,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb3,0xa8,0xa4,0xa4,0xa4,0xa4
+ ,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x37,0x37,0x37
+ ,0x43,0x5b,0x73,0x8c,0xa4,0xad,0x98,0x7f,0x67,0x4f,0x39,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8c,0xa4,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x8c,0xa4,0xaa,0xaa,0xaa,0xaa,0xae,0xb0,0xb0,0xab,0xaa,0xaa,0xaa,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2b,0x38,0x46,0x52,0x61,0x6b,0x7b,0x84,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x12,0x2a,0x43
+ ,0x5b,0x73,0x89,0x84,0x74,0x6a,0x5c,0x51,0x41,0x36,0x27,0x1b,0x0d,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x71,0x73,0x73,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x31,0x3c,0x46,0x4e
+ ,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4b,0x4f,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4f,0x4b,0x41,0x36,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x05
+ ,0x16,0x27,0x38,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5a,0x51,0x4b,0x46,0x4e,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x46,0x4e,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x27,0x36,0x41,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x4e,0x46,0x40,0x36,0x27,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x40,0x39,0x40,0x43,0x43,0x43,0x43
+ ,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0x98,0x7f,0x67,0x4f,0x51,0x67,0x7f,0x93,0xa2,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x9b,0x8a,0x73,0x61
+ ,0x73,0x8c,0x9d,0x8c,0x73,0x5b,0x43,0x2a,0x13,0x06,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0x98,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x84
+ ,0x93,0x9d,0xa4,0xa9,0xaa,0xaa,0xa8,0xa2,0x94,0x8a,0x7b,0x66,0x52,0x40,0x2b,0x15,0x02,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01
+ ,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x0b,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8d,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x17,0x25,0x31,0x40,0x4c,0x5a,0x66,0x72,0x7b
+ ,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7b,0x71,0x62,0x57,0x49,0x3c,0x2f,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x06,0x10,0x1b,0x26,0x30,0x36,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x36,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x38,0x40,0x43,0x43,0x43,0x43,0x40,0x38,0x34,0x2b,0x21
+ ,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x37,0x40,0x43,0x43,0x43,0x42,0x3c,0x34,0x30,0x36,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x26,0x30,0x37,0x40,0x43,0x43,0x43,0x43
+ ,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14,0x21,0x2b,0x34,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x37,0x30,0x28,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x28,0x23,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x4b,0x61,0x74,0x89,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00
+ ,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x7f,0x6b,0x5e,0x73,0x89,0x8c,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x3d,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x62,0x72,0x7f,0x8a,0x8e,0x97,0x98,0x98,0x93,0x8c,0x84,0x74,0x6a,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73
+ ,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x06,0x06,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f
+ ,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x10,0x1e,0x2b,0x38,0x46,0x52,0x61,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x65,0x5c,0x51,0x41,0x36,0x27,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x43
+ ,0x43,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1c,0x21
+ ,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x1c,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x25,0x1d,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x10,0x19,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x19,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0c,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x41,0x57,0x6a,0x73,0x73,0x73,0x73
+ ,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x71,0x61,0x57,0x6a,0x73,0x73,0x71,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x3a,0x4b,0x61
+ ,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x51,0x61,0x6b,0x73,0x7b,0x7f,0x7f,0x7f,0x7f,0x74,0x71,0x62,0x57,0x49,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73
+ ,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73
+ ,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x31,0x40,0x4b,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4e,0x46,0x3c,0x2f,0x21,0x14,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x07,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x0e,0x06,0x04,0x06,0x06,0x06,0x06,0x06,0x04,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11
+ ,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b
+ ,0x5a,0x51,0x40,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5a,0x51,0x49,0x57,0x5b,0x5b,0x5a,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57
+ ,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x31,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x4c,0x57,0x5c,0x65,0x67,0x67,0x67,0x67,0x61,0x5a,0x51,0x41,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x02
+ ,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15
+ ,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38
+ ,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f
+ ,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x1e,0x2b,0x34,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x36,0x30,0x26,0x1b,0x0d,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x42,0x3c,0x36,0x40,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0c,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x23,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x40,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x43,0x3c
+ ,0x2f,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43
+ ,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c
+ ,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34
+ ,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x0a
+ ,0x15,0x1c,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x25,0x21
+ ,0x28,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x11,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21
+ ,0x28,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2c,0x25,0x1b,0x0d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b
+ ,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x0e,0x0a,0x11,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x01,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11
+ ,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x01,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x06,0x0e,0x12,0x12,0x12
+ ,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x06,0x0a,0x11,0x12,0x12,0x12,0x0e,0x08,0x0e,0x12,0x12,0x12,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x11,0x0a
+ ,0x02,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x05,0x03,0x06,0x0e,0x12,0x12,0x12,0x12,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x06,0x05,0x02,0x03,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x03,0x0a,0x11,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x04,0x00,0x00,0x00,0x02,0x05,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x11,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x28,0x21,0x14,0x05,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x21,0x28,0x2a,0x2a,0x2a,0x25,0x1e,0x25,0x2a,0x2a,0x2a,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x01
+ ,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1c,0x18,0x1d,0x25,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x16,0x0a,0x01,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x16,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x16
+ ,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x28,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00
+ ,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x01,0x0a,0x15,0x1c,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0b,0x15,0x1c,0x1e,0x1e,0x1e,0x19,0x10,0x06,0x0a,0x15,0x1c,0x1e,0x1c,0x15,0x0b,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a
+ ,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x23,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00
+ ,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x36,0x36,0x40,0x43,0x43,0x42,0x3c,0x33,0x3c,0x42,0x43,0x43,0x40
+ ,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x34,0x2e,0x34,0x3c,0x42,0x43
+ ,0x43,0x43,0x40,0x36,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x34,0x2b
+ ,0x2b,0x36,0x40,0x43,0x43,0x43,0x43,0x40,0x36,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04
+ ,0x16,0x25,0x30,0x36,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x40,0x43,0x43,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43
+ ,0x43,0x43,0x43,0x40,0x36,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43
+ ,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x25,0x30,0x36,0x37,0x37,0x36,0x30,0x26,0x1b
+ ,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x34,0x36,0x30,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x2b,0x34,0x37,0x37,0x36,0x30,0x26,0x1b,0x1e,0x2b,0x34,0x37,0x34,0x2b,0x21,0x16,0x0a
+ ,0x01,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43
+ ,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x32,0x40,0x51,0x5a,0x5b,0x5b
+ ,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4e,0x4b,0x57
+ ,0x5b,0x5b,0x5a,0x51,0x49,0x51,0x5a,0x5b,0x5b,0x57,0x4c,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x00,0x00,0x00,0x10,0x25,0x38,0x46
+ ,0x4e,0x4f,0x4f,0x4f,0x4b,0x44,0x4b,0x51,0x5a,0x5b,0x5b,0x5b,0x57,0x4c,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06
+ ,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x41,0x4c,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x4c,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x40,0x4c,0x57,0x5b,0x5b,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00
+ ,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x05,0x16
+ ,0x27,0x38,0x46,0x4e,0x4f,0x4f,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x4b,0x4e,0x46,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x27,0x36,0x41,0x4b,0x4f,0x4f,0x4e,0x46,0x3c
+ ,0x31,0x2f,0x40,0x4b,0x4f,0x4b,0x41,0x36,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b
+ ,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73
+ ,0x73,0x71,0x62,0x51,0x40,0x4c,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x0e
+ ,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x65,0x5e,0x6a,0x73,0x73,0x71,0x66,0x5e,0x66,0x71,0x73,0x73,0x6b,0x61,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61
+ ,0x4b,0x34,0x1c,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x61,0x57,0x61,0x67,0x71,0x73,0x73,0x73,0x6b,0x61,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73
+ ,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x61,0x51,0x57,0x61,0x6b,0x73,0x73,0x73,0x73,0x6b,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x65
+ ,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5a,0x65,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x06,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x61,0x6b,0x73,0x73,0x71
+ ,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x73,0x73,0x73,0x73,0x6a,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x61,0x71,0x73
+ ,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a
+ ,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5a,0x65,0x67,0x67,0x65,0x5c,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x61,0x65,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x16
+ ,0x27,0x38,0x49,0x57,0x61,0x67,0x67,0x65,0x5c,0x51,0x46,0x3f,0x51,0x61,0x67,0x61,0x57,0x4c,0x40,0x2f,0x1b,0x06,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11
+ ,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x87,0x8c,0x8c,0x8c,0x84,0x72,0x61,0x4c,0x57,0x6b,0x7f,0x8c,0x8c,0x8c,0x89,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x8c,0x8c,0x8c,0x89,0x73,0x5c,0x46,0x30,0x3c,0x51,0x67,0x7f,0x8c,0x8c
+ ,0x8c,0x87,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7b,0x6f,0x7b,0x8a,0x8c,0x84,0x7b,0x6d,0x7b,0x84,0x8c,0x8a,0x7f,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x89,0x73,0x5b
+ ,0x43,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x72,0x6a,0x74,0x7f,0x84,0x8c,0x8c,0x8a,0x7f,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x71,0x5f,0x6a,0x74,0x7f,0x8a,0x8c,0x8c,0x8a,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x13,0x25,0x3c,0x51,0x66,0x7b,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x1d,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00
+ ,0x10,0x26,0x3c,0x51,0x62,0x72,0x7f,0x8a,0x8c,0x84,0x7b,0x6a,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x89,0x8c,0x8c,0x8a,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73
+ ,0x89,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x7f,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x51,0x62,0x72,0x7b,0x6a,0x5a,0x49,0x36,0x21
+ ,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x27,0x38,0x49,0x5a,0x6a,0x74,0x7f,0x7f,0x7b,0x71,0x66,0x5a,0x4e,0x5c,0x71,0x7f,0x74,0x6b,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6b,0x7f,0x93,0x9f,0xa2,0x93,0x7f,0x6b,0x5a,0x62,0x74,0x8a,0x9d,0xa1,0x94,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x93,0xa1,0xa1,0x8e
+ ,0x7b,0x65,0x4e,0x37,0x43,0x5a,0x71,0x84,0x99,0xa2,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x97,0x8a,0x7c,0x8c,0x9c,0xa2,0x97,0x84,0x7b,0x8c,0x98,0xa2,0x9d,0x92,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e
+ ,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x92,0x7f,0x7b,0x8a,0x93,0x99,0xa2,0xa4,0x9d,0x93,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a
+ ,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x8c,0x73,0x6a,0x7b,0x8a,0x93,0x9d,0xa4,0xa4,0x99,0x8a,0x73,0x5b
+ ,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x15,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2d,0x42,0x5a,0x71,0x84,0x95,0x8c,0x73,0x5b,0x43,0x2f
+ ,0x34,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x93,0x9d,0xa2,0x98,0x8c,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa2,0xa4,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02
+ ,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0x98,0x7f,0x67,0x67,0x7f,0x98,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xa4,0xa4,0x9b,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa1,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x6a,0x7b,0x8c,0x97,0x97,0x8e,0x84,0x72,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x02,0x15,0x2b,0x40
+ ,0x51,0x62,0x72,0x84,0x8c,0x7b,0x6a,0x57,0x41,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x8a,0x93,0x97,0x8e,0x84,0x7b,0x6b,0x61,0x6a,0x7b,0x8c,0x8a,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f
+ ,0x98,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xaa,0x9d,0x8c,0x7b,0x66,0x71,0x84,0x94,0xa7,0x9d,0x8a,0x74,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00
+ ,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xab,0x97,0x7f,0x6b,0x57,0x40,0x4b,0x61,0x74,0x8c,0xa2,0xa4,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa7,0x94,0x8e,0x9a,0xa3,0xac,0xa3,0x8e,0x84,0x98,0xa3,0xae,0xb0,0x9d
+ ,0x8a,0x73,0x5c,0x46,0x30,0x19,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xaa,0x99,0x84,0x8c,0x9b,0xa0,0xa4,0xa4
+ ,0xae,0xb1,0xa4,0x93,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x9d,0xae,0xba,0xb8,0xad,0x9c,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xa4,0x8e,0x7b,0x7b
+ ,0x8c,0x9c,0xa5,0xa4,0xa4,0xa4,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2d,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43
+ ,0x45,0x5b,0x73,0x8c,0x9d,0x8c,0x73,0x5b,0x45,0x43,0x4b,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa3,0xb3,0xb8,0xac,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x99
+ ,0xad,0xad,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb8,0xb0,0x98,0x7f,0x67,0x67,0x7f,0x97,0xad,0xb7,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0
+ ,0x98,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x97,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8c,0x9c,0xac,0xad,0xa3,0x93,0x7f,0x67
+ ,0x51,0x3c,0x25,0x0e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0x9c,0x8a,0x74,0x62,0x51,0x40,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x02,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x9c,0xa0,0xa2,0x9e,0x98,0x8c,0x7f,0x74,0x7b,0x8c,0x9b,0x93,0x7f,0x6b,0x57,0x40
+ ,0x28,0x11,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98
+ ,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xaa,0x98,0x84,0x71,0x74,0x8c,0xa2,0xa4,0x93
+ ,0x7f,0x6b,0x57,0x41,0x2f,0x1b,0x06,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x98,0xaa,0x9d,0x8a,0x73,0x5c,0x46,0x51,0x67,0x7f,0x93,0xa6,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb3,0xa6,0x9a,0x8e
+ ,0x8e,0x9c,0xa9,0x9d,0x96,0x8e,0x8e,0x9c,0xae,0xa4,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xae,0xa4,0x99,0x98,0x93,0x8c,0x8c,0x8e,0x9c,0xae,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0xb8,0xad,0x9c,0x8c,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xad,0x98,0x84,0x8c,0x9b,0x9d,0x97,0x8e,0x8c,0x8e,0x92,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x46,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02
+ ,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x57,0x5b,0x73,0x8c,0x9e,0x8c,0x73,0x5b,0x57,0x5b,0x61,0x65,0x5a,0x46,0x31,0x1b,0x06,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xbd,0xc5,0xb8,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa1,0x9d,0x99,0xa1,0x93,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8a,0x9d,0xb3,0xb0,0x98,0x7f,0x67,0x65,0x7b,0x8e,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x38,0x21,0x0a,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x97,0xac,0xbe,0xc2,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x90,0xa0,0xa7,0x94,0x84,0x72,0x62,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0x9c,0x8e,0x8c,0x8e,0x9c,0x9c
+ ,0x93,0x8c,0x8e,0x9c,0x9c,0x8a,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f
+ ,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f
+ ,0x93,0xa4,0xa3,0x8e,0x7b,0x7f,0x93,0xa5,0x98,0x84,0x72,0x61,0x4c,0x36,0x21,0x0d,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa4,0xa4,0x8e,0x7b,0x65,0x4e,0x5a,0x71,0x84,0x99,0xa9,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb4,0xa3,0x8e,0x7b,0x7b,0x8e,0xa4,0xa3,0x8e,0x7b,0x7b,0x8e,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xae,0x9c,0x8c,0x7f,0x74,0x73,0x7b,0x8e,0xa3,0xb4,0xa4,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x6e,0x7b,0x8e,0xa4,0xb1,0x9d,0x8c
+ ,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb4,0xa4,0x99,0x9b,0x94,0x8a,0x7f,0x7b,0x73,0x7b,0x7f,0x72,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5e,0x73,0x8c,0xa4,0x98,0x7f
+ ,0x67,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x71,0x73,0x73,0x6b,0x67,0x73,0x8c,0x9e,0x8c,0x73,0x67,0x6b,0x73,0x74,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8a,0x9c,0xac,0xb0,0xb5
+ ,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0x9d,0x8c,0x84,0x99,0x99,0x84,0x71,0x5a,0x43,0x2c,0x16,0x03,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x98,0xb0,0xad,0x97,0x7f,0x67,0x5c,0x73,0x8c
+ ,0xa4,0xb4,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x0a,0x21,0x36,0x49,0x5a,0x65,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61
+ ,0x51,0x3c,0x25,0x0e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xc5,0xcb,0xb3,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa4,0xa4,0x94,0x84,0x72,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x06,0x1e,0x37,0x4f
+ ,0x67,0x7f,0x91,0x9b,0x8c,0x7b,0x73,0x7b,0x8a,0x93,0x9c,0xa0,0x9f,0x9c,0x8c,0x7b,0x6a,0x57,0x41,0x2b,0x16,0x03,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e
+ ,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xa8,0x9c,0x8e,0x8e,0x9d,0x9d,0x8c,0x7b,0x66,0x52,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0xaa,0x97,0x7f,0x6b,0x57,0x61,0x74,0x8c,0xa2,0xa3,0x8e
+ ,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x73,0x8c,0xa4,0x99,0x84,0x71,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b
+ ,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x6b,0x61,0x5e,0x71,0x84,0x99,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f
+ ,0x4f,0x55,0x62,0x74,0x8a,0x9c,0xab,0xa4,0x93,0x7f,0x6b,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xbb,0xb4,0xa4,0x94,0x84,0x74,0x6b,0x65,0x5e,0x65,0x67,0x61,0x51,0x40,0x2b,0x15,0x02,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62
+ ,0x71,0x73,0x73,0x73,0x73,0x76,0x8c,0xa4,0x98,0x7f,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x8c,0x8a,0x7f,0x7f,0x77,0x8c,0x9e,0x8c,0x77,0x7f,0x7f,0x8a,0x8c,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x02
+ ,0x15,0x2b,0x41,0x57,0x6a,0x7b,0x8c,0x97,0x99,0xa4,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0x97,0x7f,0x7f,0x93,0x9f,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x0a,0x21,0x38,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8e,0x7b,0x65,0x5b,0x73,0x8c,0xa4,0xb0,0x99,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4e,0x54,0x55,0x55,0x55,0x55,0x55
+ ,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x51,0x45,0x33,0x1e,0x08,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa4,0xb5,0xbb,0xac,0x97,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x93,0x9d,0xa2,0x93,0x7f,0x6b
+ ,0x57,0x40,0x28,0x11,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x84,0x8d,0x7f,0x6b,0x5e,0x6a,0x74,0x7f,0x8a,0x93,0x8e,0x8a,0x7b,0x6a,0x5a,0x49,0x36,0x21,0x0b,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f
+ ,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xab,0xa4,0xa4,0xa5,0x93,0x7f,0x6b,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xaa
+ ,0x9d,0x8a,0x73,0x5c,0x67,0x7f,0x93,0xa6,0x99,0x84,0x71,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e
+ ,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x4c,0x51,0x67,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67,0x4f,0x37,0x1e
+ ,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x38,0x42,0x51,0x62,0x72,0x84,0x94,0xa7,0xa4,0x94,0x84,0x72,0x61,0x4c,0x38,0x27,0x16,0x05,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb9,0xad,0x98,0x84,0x72,0x62,0x57,0x4e,0x49,0x4e,0x4f,0x4b,0x40,0x2f
+ ,0x1e,0x0a,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x8c,0x8c,0x94,0xa8,0x9d,0x8e,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x82,0x92,0x98,0x98,0x93,0x8c,0x94,0xa2,0x94,0x8c,0x93,0x98,0x98
+ ,0x97,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0b,0x21,0x36,0x49,0x5a,0x6a,0x7b,0x7f,0x84,0x99,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0x9f,0x8e,0x7b,0x74,0x8c,0x9f,0x93,0x7f,0x6b,0x57,0x40,0x28
+ ,0x11,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5c,0x5b,0x73,0x8c,0xa2,0xae,0x98,0x7f,0x67,0x51,0x3c,0x25,0x0e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0xad,0x97,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00,0x00,0x0e
+ ,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x94,0xa2,0xa2,0x98,0x8c,0x7b,0x65,0x4e,0x37,0x21,0x0a,0x00,0x00,0x00,0x0a,0x1e,0x2f
+ ,0x40,0x51,0x62,0x72,0x7f,0x8c,0x9c,0x94,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x66,0x71,0x7b,0x72,0x61,0x4f,0x57,0x61,0x6b,0x74,0x7f,0x7b,0x73,0x6a,0x5a,0x49,0x38,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36
+ ,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x98,0xb0,0xbc,0xb2,0x9d,0x8a,0x74,0x61,0x4c,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8e,0xa3,0xa4,0x8e,0x7b,0x65,0x71,0x84,0x99,0xa6,0x93,0x7f,0x67,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x28,0x3c,0x51,0x62,0x72,0x84,0x94,0xa4,0xa7,0x94,0x84,0x72,0x62,0x51,0x40,0x2b,0x17,0x05,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8e,0x7b
+ ,0x66,0x52,0x41,0x37,0x33,0x36,0x37,0x34,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xa4,0xa4,0xa4,0xa4,0xa8,0xb5,0xae,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x74,0x7f,0x8a
+ ,0x93,0x9c,0xa0,0xa8,0xb1,0xa8,0xa2,0x9c,0x93,0x8a,0x7f,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x03,0x14,0x27,0x38,0x49,0x5a,0x65,0x6e,0x7f,0x98,0xa2,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x03,0x16,0x2c,0x43,0x5a,0x71,0x84,0x98,0x9d,0x8a
+ ,0x73,0x71,0x84,0x99,0x9d,0x8a,0x73,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x93,0xa8,0xa4,0x8c,0x73,0x5b,0x5a,0x71,0x84,0x99,0xaa,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x07,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0xa4,0xa4
+ ,0x8e,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x62,0x72,0x84,0x8c,0x8c,0x84,0x7b,0x6a,0x5a
+ ,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x61,0x6b,0x7b,0x8c,0x84,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x51,0x5c,0x65,0x61,0x51,0x40,0x41,0x4c,0x57,0x61,0x67,0x65,0x5c,0x57,0x49,0x38,0x27,0x16,0x05
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e
+ ,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x99,0xad,0xb0,0xae,0x99,0x84,0x71,0x5c
+ ,0x49,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x71,0x84,0x99,0xa9,0x97,0x7f,0x69,0x74,0x8c,0xa2,0xa2,0x8c,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67
+ ,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x38,0x49,0x5c,0x71,0x84,0x94,0xa4,0xab,0x9c,0x8a,0x74,0x62,0x51,0x40,0x2f,0x23,0x19,0x10,0x04,0x00,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5c,0x46,0x31,0x21,0x1b,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x9d,0xae,0xa4,0x99,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12
+ ,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x61,0x6b,0x74,0x7f,0x8a,0x94,0xa8,0xba,0xb3,0x9d,0x8c,0x7f,0x74,0x6b,0x65,0x5a,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x4c,0x57,0x62,0x74,0x8a,0x9d,0x98,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00
+ ,0x0a,0x21,0x36,0x4c,0x61,0x74,0x8c,0xa1,0x97,0x7f,0x6b,0x67,0x7f,0x93,0xa0,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0xa4,0x9d,0x8a,0x73,0x5b,0x51,0x67,0x7f,0x98,0xa6,0x93,0x7f,0x67,0x4f,0x37,0x1e,0x06,0x00
+ ,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa2,0xa4,0x8c,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x0a,0x1e,0x2f
+ ,0x40,0x51,0x62,0x71,0x73,0x73,0x71,0x66,0x5a,0x49,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x4c,0x5a,0x6a,0x7b,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x04,0x16,0x25,0x31,0x3c,0x46,0x4e,0x4b,0x40,0x2f,0x2b,0x36,0x41
+ ,0x4b,0x4f,0x4e,0x46,0x40,0x36,0x27,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b
+ ,0x7f,0x93,0xa2,0x9d,0x99,0xa4,0xa3,0x8e,0x7b,0x6a,0x5a,0x46,0x31,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x26,0x3c,0x51,0x67,0x7f,0x93,0xa6,0x99,0x84,0x71,0x7f,0x93,0xa6,0x99,0x84,0x71,0x5a,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x74,0x61,0x4b,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x49,0x5a,0x6a,0x7b,0x8e,0xa3,0xab,0x9c,0x8c,0x7b,0x6a,0x57,0x42
+ ,0x38,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x05,0x06,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x8e,0xa4,0x99,0x84
+ ,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x02,0x14,0x27,0x36,0x41,0x4c,0x57,0x61,0x6f,0x7c,0x8e,0xa3,0xa4,0xa6,0x98,0x7f,0x6f,0x62,0x57,0x4e,0x46,0x38,0x27,0x14,0x02,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x61,0x6b,0x74,0x84,0x94,0xa0
+ ,0x8e,0x7b,0x66,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x93,0xa0,0x8e,0x7b,0x65,0x61,0x74,0x8c,0xa1,0x98,0x84,0x71,0x5a,0x43,0x2c,0x16,0x03,0x00,0x00,0x02,0x15,0x2c,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x6b,0x57,0x4f,0x67,0x7f
+ ,0x98,0xa4,0x8c,0x74,0x61,0x4b,0x34,0x1c,0x05,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x99,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa0,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa1,0x8c,0x73
+ ,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x46,0x38,0x27,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x38,0x49,0x5a,0x65,0x61,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x04,0x10
+ ,0x1b,0x26,0x30,0x36,0x34,0x2b,0x1e,0x16,0x21,0x2b,0x34,0x37,0x36,0x30,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x04,0x17,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xa3,0x8e,0x84,0x98,0xa8,0x9c,0x8c,0x7b,0x66,0x52,0x40,0x2b,0x17,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x34,0x4b,0x61,0x74,0x8c,0xa2,0xa2,0x8c,0x74,0x7f,0x98,0xa6,0x93,0x7f,0x67
+ ,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa8,0x93,0x7f,0x67
+ ,0x56,0x5c,0x6b,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x0c,0x1e,0x31,0x46,0x5a,0x6a,0x7b
+ ,0x8c,0x9c,0xa9,0x9c,0x8c,0x7b,0x6a,0x5b,0x51,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61
+ ,0x67,0x67,0x67,0x67,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x6a,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x05,0x14,0x21,0x2d,0x3c,0x4c,0x61,0x74,0x8a,0x9c,0x9c,0x8e,0x94,0x9c,0x8c,0x7b,0x66,0x51,0x3e,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x05
+ ,0x1c,0x34,0x4b,0x61,0x72,0x7f,0x8a,0x94,0xa0,0x94,0x84,0x71,0x5c,0x46,0x31,0x1b,0x06,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0x9d,0x8a,0x73,0x5c,0x5a,0x71,0x84,0x99,0xa2,0x8c,0x74,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b
+ ,0x73,0x8a,0x9d,0x98,0x7f,0x67,0x4f,0x4f,0x67,0x7f,0x93,0x9f,0x8c,0x73,0x5b,0x43,0x2c,0x15,0x02,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x67,0x7f,0x98,0x9d,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x8c,0x8c,0x8c,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x42,0x3c,0x31,0x25,0x16,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x27,0x38,0x46,0x4e,0x4b,0x40,0x2f
+ ,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x10,0x19,0x1e,0x1c,0x15,0x0a,0x03,0x0b,0x15,0x1c,0x1e,0x1e,0x19,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x25,0x38,0x4c,0x61,0x72,0x84,0x98,0xa8,0x98,0x84,0x7b,0x8c,0x9d,0xaa,0x98,0x84,0x72,0x61,0x4c,0x38,0x25,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84
+ ,0x98,0xa5,0x93,0x7f,0x8a,0x9d,0x9d,0x8a,0x74,0x61,0x4b,0x34,0x1d,0x06,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e
+ ,0x37,0x4f,0x67,0x7f,0x97,0xad,0xb0,0x98,0x7f,0x71,0x68,0x71,0x7b,0x8c,0x9d,0xb3,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e
+ ,0x00,0x00,0x06,0x1b,0x2f,0x40,0x52,0x66,0x7b,0x8c,0x9c,0xad,0xa4,0x8e,0x7b,0x6e,0x67,0x67,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x52,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x07,0x1b,0x31,0x46,0x5a,0x6b,0x7f,0x93,0x9b,0x8c,0x7c,0x8a,0x9c,0x98,0x84,0x71
+ ,0x5c,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8f,0x9d,0xa0,0x94,0x84,0x72,0x62,0x51,0x3c,0x26,0x10,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8d,0x98,0x95,0x7f,0x6b,0x57,0x51,0x67,0x7f,0x92,0x98,0x91,0x7f,0x6b,0x57
+ ,0x40,0x28,0x11,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x8c,0x8c,0x7f,0x67,0x4f,0x4b,0x61,0x74,0x89,0x8c,0x89,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x07,0x1e,0x37,0x4f,0x67,0x7f,0x8c,0x8c,0x7f,0x6b,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x0e
+ ,0x25,0x3c,0x51,0x62,0x71,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x05,0x16,0x25,0x30,0x36,0x34,0x2b,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x31,0x46,0x5a,0x6b,0x7f,0x93,0xa4,0x9d,0x8c,0x7b,0x6e,0x7f,0x93,0xa4,0xa4,0x93,0x7f,0x6b,0x5a,0x46,0x31,0x1e,0x0c,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b,0x8e,0xa4,0x99,0x84,0x8e,0xa3,0x97,0x7f,0x6b,0x57,0x41,0x2b,0x15,0x02,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0
+ ,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x8e,0xa4,0xb2,0x9d,0x8e,0x84,0x7f,0x84,0x8e,0x9a,0xa5,0xb5,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x72,0x84,0x98,0xac,0xb8,0xa4,0x8e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73
+ ,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x3a,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x66,0x7b
+ ,0x8c,0x98,0x8c,0x7b,0x6f,0x7b,0x8c,0x9a,0x8e,0x7b,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x74,0x8c,0x97,0x8e,0x84,0x72,0x62,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7b,0x65
+ ,0x4e,0x4b,0x61,0x72,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x71,0x73,0x73,0x71,0x61,0x4b,0x41,0x57,0x6a,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73
+ ,0x71,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x52,0x66,0x7b,0x8c,0x9d,0xa6,0x93,0x7f,0x6b,0x62,0x72,0x84,0x98,0xaa,0x9d
+ ,0x8c,0x7b,0x66,0x52,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x31,0x46,0x5c,0x73,0x8a,0x9d,0xa4,0x99,0x9d,0xa3,0x8e,0x7b,0x65,0x4e,0x37,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67
+ ,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x04,0x19,0x30,0x46,0x5c,0x73,0x8a,0x9d,0xb1,0xae,0xa3,0x99,0x98,0x99,0x9a,0x8e,0x94,0xa8,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67
+ ,0x7f,0x98,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xb0,0xb0,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x94,0xa4,0xb5,0xba,0xae,0x9d,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb6,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x21,0x1e,0x1c,0x15,0x0a,0x01,0x00
+ ,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x84,0x97,0x93,0x7f,0x6b,0x5e,0x6a,0x7b,0x8c,0x98,0x8a,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x02,0x15,0x2c,0x43,0x5a,0x71,0x84,0x7f,0x7b,0x71,0x62,0x51,0x40,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x04
+ ,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x65,0x5a,0x46,0x40,0x51,0x61,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x03,0x16,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x40,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00
+ ,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x72,0x84,0x98,0xa2
+ ,0x9d,0x8a,0x74,0x61,0x54,0x66,0x7b,0x8c,0x9d,0xa2,0x98,0x84,0x72,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x97,0xa4,0xa4,0xa4,0x9d,0x8a,0x73,0x5c,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x12
+ ,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xad,0x98,0x7f,0x67,0x73,0x8c,0xa4,0x98,0x7f,0x67,0x73,0x8c,0xa4,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x11,0x28,0x40,0x57,0x6b,0x7f,0x92,0x9d,0xa8,0xae,0xa9,0xa2,0x98,0x8c,0x7c,0x8a,0x9d,0xa4,0x98,0x7f,0x67
+ ,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x98,0xad,0xa4,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x98,0xad,0xad,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x9f,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4
+ ,0xa4,0x98,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0xa4,0xb0,0xa4,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x05,0x06,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x95,0x7f
+ ,0x67,0x4f,0x37,0x1e,0x09,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x8c,0x84,0x72,0x61,0x4f,0x5a,0x6b,0x7f,0x8d,0x84,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x62,0x71,0x6b,0x65,0x5c,0x51
+ ,0x40,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x42,0x3c,0x2f,0x27,0x36,0x40
+ ,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28
+ ,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x8a,0x8c,0x8c,0x8c,0x7f,0x6b,0x57,0x49,0x5a,0x6b,0x7f,0x8c,0x8c,0x8c,0x8a,0x82,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x21,0x37,0x4e,0x65,0x7b,0x8a,0x8c,0x8c,0x8c,0x8c,0x7f,0x6b,0x57,0x40
+ ,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x95,0x7f,0x67,0x73,0x8c,0x98,0x95,0x7f,0x67,0x73,0x8c,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x00,0x0a,0x21,0x36,0x4c,0x61,0x72,0x7f,0x8a,0x93,0x98,0x97
+ ,0x8e,0x84,0x7b,0x6f,0x7f,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x06,0x1e,0x37,0x4f,0x67,0x7f,0x95,0x98,0x98,0x8c,0x73,0x5b,0x43,0x4f,0x67,0x7f,0x95,0x98,0x98,0x95,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x89,0x8c,0x8c
+ ,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x7f,0x67,0x4f,0x37,0x1e,0x00,0x00,0x12,0x2a,0x43,0x5b,0x73,0x8c,0x98,0x98,0x98,0x8c,0x73,0x5b,0x43,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x6b,0x7b,0x72,0x62,0x51,0x41,0x4c,0x61,0x72,0x7b,0x71,0x62,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00
+ ,0x06,0x1b,0x2f,0x40,0x51,0x5a,0x57,0x4e,0x46,0x3c,0x2f,0x1e,0x0d,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x36,0x30,0x25,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b
+ ,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1c,0x34,0x4b,0x61,0x71,0x73,0x73,0x73,0x73,0x71,0x61,0x4c,0x3c,0x4c,0x61,0x71,0x73,0x73,0x73,0x73,0x73,0x6a,0x57,0x40,0x28,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x19,0x30,0x46,0x5a
+ ,0x6a,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4c,0x36,0x21,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x71,0x7f,0x7f,0x7f,0x7b,0x65,0x71,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e,0x00,0x00,0x00,0x03
+ ,0x16,0x2b,0x40,0x51,0x61,0x6b,0x74,0x7f,0x7f,0x7f,0x7b,0x71,0x66,0x62,0x71,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00,0x06,0x1e,0x36,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x4e,0x65,0x7b,0x7f,0x7f,0x7f,0x7f,0x7b,0x65,0x4e,0x36,0x1e
+ ,0x00,0x00,0x11,0x28,0x40,0x57,0x6a,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x71,0x61,0x4b,0x34,0x1c,0x00,0x00,0x12,0x2a,0x42,0x5a,0x71,0x7f,0x7f,0x7f,0x7f,0x7f,0x71,0x5a,0x42,0x2a,0x12,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4c,0x5a,0x65,0x61,0x51,0x40,0x32,0x40,0x51,0x61,0x65,0x5c
+ ,0x51,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2f,0x3c,0x42,0x40,0x37,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1c,0x15
+ ,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x02,0x0a,0x11,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0x2b,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x31,0x40,0x51,0x5a,0x5b,0x5b,0x5b,0x5b,0x5b,0x57,0x49,0x36,0x21,0x0a,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x25,0x38,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x16,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x65,0x5a,0x61,0x67,0x67,0x67,0x65,0x5a,0x61,0x67,0x67,0x67
+ ,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x40,0x4c,0x57,0x61,0x67,0x67,0x67,0x65,0x5c,0x51,0x51,0x5a,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x00,0x00,0x04,0x19,0x30,0x46,0x5a,0x65,0x67,0x67,0x67,0x67,0x61,0x51,0x3c,0x46,0x5a
+ ,0x65,0x67,0x67,0x67,0x67,0x65,0x5a,0x46,0x30,0x19,0x00,0x00,0x0a,0x21,0x36,0x49,0x57,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5a,0x51,0x40,0x2b,0x15,0x00,0x00,0x0e,0x25,0x3c,0x51,0x61,0x67,0x67,0x67,0x67,0x67,0x61
+ ,0x51,0x3c,0x25,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x38,0x46
+ ,0x4e,0x4b,0x40,0x2f,0x23,0x2f,0x40,0x4b,0x4e,0x46,0x3c,0x2f,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x28,0x21,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x06,0x06,0x06,0x06,0x06,0x04
+ ,0x00,0x00,0x02,0x05,0x06,0x06,0x06,0x06,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x1e,0x2f,0x3c,0x42,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x23,0x2f,0x3c,0x42,0x43,0x43
+ ,0x43,0x43,0x43,0x40,0x36,0x27,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x16,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4e,0x46
+ ,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x4b,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x00,0x00,0x01,0x0d,0x1e,0x2b,0x36,0x41,0x4b,0x4f,0x4f,0x4f,0x4e,0x46,0x3c,0x3c,0x42,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x00,0x10,0x25,0x38,0x46
+ ,0x4e,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x38,0x46,0x4e,0x4f,0x4f,0x4f,0x4f,0x4e,0x46,0x38,0x25,0x10,0x00,0x00,0x02,0x14,0x27,0x36,0x40,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x3c,0x2f,0x1e,0x0a,0x00,0x00,0x06
+ ,0x1b,0x2f,0x40,0x4b,0x4f,0x4f,0x4f,0x4f,0x4f,0x4b,0x40,0x2f,0x1b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x17,0x25,0x30,0x36,0x34,0x2b,0x1e,0x11,0x1e,0x2b,0x34,0x36,0x30,0x26,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x11,0x0a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0c,0x1b,0x25,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x25,0x1b,0x11,0x1b,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x28,0x21,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x36,0x30,0x34,0x37,0x37,0x37,0x36,0x30,0x34,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x16,0x21,0x2b,0x34,0x37,0x37,0x37,0x36,0x30,0x26,0x25,0x2a,0x2a,0x2a,0x2a,0x2a,0x25
+ ,0x1b,0x0c,0x01,0x00,0x00,0x00,0x04,0x16,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x25,0x30,0x36,0x37,0x37,0x37,0x37,0x36,0x30,0x25,0x16,0x04,0x00,0x00,0x00,0x05,0x14,0x21,0x28,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a
+ ,0x2a,0x2a,0x2a,0x25,0x1b,0x0c,0x01,0x00,0x00,0x00,0x0c,0x1e,0x2b,0x34,0x37,0x37,0x37,0x37,0x37,0x34,0x2b,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e
+ ,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1c,0x15,0x0a,0x02,0x0a,0x15,0x1c,0x1e,0x19,0x10,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x01,0x06,0x0e,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x0a,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x1c,0x1e,0x1e,0x1e,0x1e,0x19,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0b,0x15,0x1c,0x1e,0x1e,0x1e
+ ,0x1e,0x19,0x10,0x0e,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x10,0x19,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x19,0x10,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x0a,0x11,0x12,0x12,0x12
+ ,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x01,0x0a,0x15,0x1c,0x1e,0x1e,0x1e,0x1e,0x1e,0x1c,0x15,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ };
+
+ const HudFont g_hudFont = { 32, 510, 172, 5, 24, 95, g_hudFontGlyphs, g_hudFontImage };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.h
new file mode 100644
index 00000000..d9530b3f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_font.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <cstdint>
+
+namespace dxvk::hud {
+
+ struct HudGlyph {
+ uint32_t codePoint;
+ int32_t x;
+ int32_t y;
+ int32_t w;
+ int32_t h;
+ int32_t originX;
+ int32_t originY;
+ };
+
+ struct HudFont {
+ int32_t size;
+ uint32_t width;
+ uint32_t height;
+ uint32_t falloff;
+ uint32_t advance;
+ uint32_t charCount;
+
+ const HudGlyph* glyphs;
+ const uint8_t* texture;
+ };
+
+ extern const HudFont g_hudFont;
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.cpp
new file mode 100644
index 00000000..ec3de389
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.cpp
@@ -0,0 +1,605 @@
+#include "dxvk_hud_item.h"
+
+#include <iomanip>
+#include <version.h>
+
+namespace dxvk::hud {
+
+ HudItem::~HudItem() {
+
+ }
+
+
+ void HudItem::update(dxvk::high_resolution_clock::time_point time) {
+ // Do nothing by default. Some items won't need this.
+ }
+
+
+ HudItemSet::HudItemSet(const Rc<DxvkDevice>& device) {
+ std::string configStr = env::getEnvVar("DXVK_HUD");
+
+ if (configStr.empty())
+ configStr = device->config().hud;
+
+ std::string::size_type pos = 0;
+ std::string::size_type end = 0;
+ std::string::size_type mid = 0;
+
+ while (pos < configStr.size()) {
+ end = configStr.find(',', pos);
+ mid = configStr.find('=', pos);
+
+ if (end == std::string::npos)
+ end = configStr.size();
+
+ if (mid != std::string::npos && mid < end) {
+ m_options.insert({
+ configStr.substr(pos, mid - pos),
+ configStr.substr(mid + 1, end - mid - 1) });
+ } else {
+ m_enabled.insert(configStr.substr(pos, end - pos));
+ }
+
+ pos = end + 1;
+ }
+
+ if (m_enabled.find("full") != m_enabled.end())
+ m_enableFull = true;
+
+ if (m_enabled.find("1") != m_enabled.end()) {
+ m_enabled.insert("devinfo");
+ m_enabled.insert("fps");
+ }
+ }
+
+
+ HudItemSet::~HudItemSet() {
+
+ }
+
+
+ void HudItemSet::update() {
+ auto time = dxvk::high_resolution_clock::now();
+
+ for (const auto& item : m_items)
+ item->update(time);
+ }
+
+
+ void HudItemSet::render(HudRenderer& renderer) {
+ HudPos position = { 8.0f, 8.0f };
+
+ for (const auto& item : m_items)
+ position = item->render(renderer, position);
+ }
+
+
+ void HudItemSet::parseOption(const std::string& str, float& value) {
+ try {
+ value = std::stof(str);
+ } catch (const std::invalid_argument&) {
+ return;
+ }
+ }
+
+
+ HudPos HudVersionItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ "DXVK " DXVK_VERSION);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudClientApiItem::HudClientApiItem(std::string api)
+ : m_api(api) {
+
+ }
+
+
+ HudClientApiItem::~HudClientApiItem() {
+
+ }
+
+
+ HudPos HudClientApiItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_api);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudDeviceInfoItem::HudDeviceInfoItem(const Rc<DxvkDevice>& device) {
+ VkPhysicalDeviceProperties props = device->adapter()->deviceProperties();
+
+ m_deviceName = props.deviceName;
+ m_driverVer = str::format("Driver: ",
+ VK_VERSION_MAJOR(props.driverVersion), ".",
+ VK_VERSION_MINOR(props.driverVersion), ".",
+ VK_VERSION_PATCH(props.driverVersion));
+ m_vulkanVer = str::format("Vulkan: ",
+ VK_VERSION_MAJOR(props.apiVersion), ".",
+ VK_VERSION_MINOR(props.apiVersion), ".",
+ VK_VERSION_PATCH(props.apiVersion));
+ }
+
+
+ HudDeviceInfoItem::~HudDeviceInfoItem() {
+
+ }
+
+
+ HudPos HudDeviceInfoItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_deviceName);
+
+ position.y += 24.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_driverVer);
+
+ position.y += 20.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_vulkanVer);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudFpsItem::HudFpsItem() { }
+ HudFpsItem::~HudFpsItem() { }
+
+
+ void HudFpsItem::update(dxvk::high_resolution_clock::time_point time) {
+ m_frameCount += 1;
+
+ auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
+
+ if (elapsed.count() >= UpdateInterval) {
+ int64_t fps = (10'000'000ll * m_frameCount) / elapsed.count();
+
+ m_frameRate = str::format(fps / 10, ".", fps % 10);
+ m_frameCount = 0;
+ m_lastUpdate = time;
+ }
+ }
+
+
+ HudPos HudFpsItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 0.25f, 0.25f, 1.0f },
+ "FPS:");
+
+ renderer.drawText(16.0f,
+ { position.x + 60.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_frameRate);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudFrameTimeItem::HudFrameTimeItem() { }
+ HudFrameTimeItem::~HudFrameTimeItem() { }
+
+
+ void HudFrameTimeItem::update(dxvk::high_resolution_clock::time_point time) {
+ auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
+
+ m_dataPoints[m_dataPointId] = float(elapsed.count());
+ m_dataPointId = (m_dataPointId + 1) % NumDataPoints;
+
+ m_lastUpdate = time;
+ }
+
+
+ HudPos HudFrameTimeItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ std::array<HudLineVertex, NumDataPoints * 2> vData;
+ position.y += 40.0f;
+
+ // 60 FPS = optimal, 10 FPS = worst
+ const float targetUs = 16'666.6f;
+ const float minUs = 5'000.0f;
+ const float maxUs = 100'000.0f;
+
+ // Ten times the maximum/minimum number
+ // of milliseconds for a single frame
+ uint32_t minMs = 0xFFFFFFFFu;
+ uint32_t maxMs = 0x00000000u;
+
+ // Paint the time points
+ for (uint32_t i = 0; i < NumDataPoints; i++) {
+ float us = m_dataPoints[(m_dataPointId + i) % NumDataPoints];
+
+ minMs = std::min(minMs, uint32_t(us / 100.0f));
+ maxMs = std::max(maxMs, uint32_t(us / 100.0f));
+
+ float r = std::min(std::max(-1.0f + us / targetUs, 0.0f), 1.0f);
+ float g = std::min(std::max( 3.0f - us / targetUs, 0.0f), 1.0f);
+ float l = std::sqrt(r * r + g * g);
+
+ HudNormColor color = {
+ uint8_t(255.0f * (r / l)),
+ uint8_t(255.0f * (g / l)),
+ uint8_t(0), uint8_t(255) };
+
+ float x = position.x + float(i);
+ float y = position.y;
+
+ float hVal = std::log2(std::max((us - minUs) / targetUs + 1.0f, 1.0f))
+ / std::log2((maxUs - minUs) / targetUs);
+ float h = std::min(std::max(40.0f * hVal, 2.0f), 40.0f);
+
+ vData[2 * i + 0] = HudLineVertex { { x, y }, color };
+ vData[2 * i + 1] = HudLineVertex { { x, y - h }, color };
+ }
+
+ renderer.drawLines(vData.size(), vData.data());
+
+ // Paint min/max frame times in the entire window
+ position.y += 18.0f;
+
+ renderer.drawText(12.0f,
+ { position.x, position.y },
+ { 1.0f, 0.25f, 0.25f, 1.0f },
+ "min:");
+
+ renderer.drawText(12.0f,
+ { position.x + 45.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(minMs / 10, ".", minMs % 10));
+
+ renderer.drawText(12.0f,
+ { position.x + 150.0f, position.y },
+ { 1.0f, 0.25f, 0.25f, 1.0f },
+ "max:");
+
+ renderer.drawText(12.0f,
+ { position.x + 195.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(maxMs / 10, ".", maxMs % 10));
+
+ position.y += 4.0f;
+ return position;
+ }
+
+
+ HudSubmissionStatsItem::HudSubmissionStatsItem(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ HudSubmissionStatsItem::~HudSubmissionStatsItem() {
+
+ }
+
+
+ void HudSubmissionStatsItem::update(dxvk::high_resolution_clock::time_point time) {
+ DxvkStatCounters counters = m_device->getStatCounters();
+
+ uint32_t currCounter = counters.getCtr(DxvkStatCounter::QueueSubmitCount);
+ m_diffCounter = std::max(m_diffCounter, currCounter - m_prevCounter);
+ m_prevCounter = currCounter;
+
+ auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
+
+ if (elapsed.count() >= UpdateInterval) {
+ m_showCounter = m_diffCounter;
+ m_diffCounter = 0;
+
+ m_lastUpdate = time;
+ }
+ }
+
+
+ HudPos HudSubmissionStatsItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 0.5f, 0.25f, 1.0f },
+ "Queue submissions: ");
+
+ renderer.drawText(16.0f,
+ { position.x + 228.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_showCounter));
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudDrawCallStatsItem::HudDrawCallStatsItem(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ HudDrawCallStatsItem::~HudDrawCallStatsItem() {
+
+ }
+
+
+ void HudDrawCallStatsItem::update(dxvk::high_resolution_clock::time_point time) {
+ auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate);
+
+ DxvkStatCounters counters = m_device->getStatCounters();
+ auto diffCounters = counters.diff(m_prevCounters);
+
+ if (elapsed.count() >= UpdateInterval) {
+ m_gpCount = diffCounters.getCtr(DxvkStatCounter::CmdDrawCalls);
+ m_cpCount = diffCounters.getCtr(DxvkStatCounter::CmdDispatchCalls);
+ m_rpCount = diffCounters.getCtr(DxvkStatCounter::CmdRenderPassCount);
+
+ m_lastUpdate = time;
+ }
+
+ m_prevCounters = counters;
+ }
+
+
+ HudPos HudDrawCallStatsItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 0.25f, 0.5f, 1.0f, 1.0f },
+ "Draw calls:");
+
+ renderer.drawText(16.0f,
+ { position.x + 192.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_gpCount));
+
+ position.y += 20.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 0.25f, 0.5f, 1.0f, 1.0f },
+ "Dispatch calls:");
+
+ renderer.drawText(16.0f,
+ { position.x + 192.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_cpCount));
+
+ position.y += 20.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 0.25f, 0.5f, 1.0f, 1.0f },
+ "Render passes:");
+
+ renderer.drawText(16.0f,
+ { position.x + 192.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_rpCount));
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudPipelineStatsItem::HudPipelineStatsItem(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ HudPipelineStatsItem::~HudPipelineStatsItem() {
+
+ }
+
+
+ void HudPipelineStatsItem::update(dxvk::high_resolution_clock::time_point time) {
+ DxvkStatCounters counters = m_device->getStatCounters();
+
+ m_graphicsPipelines = counters.getCtr(DxvkStatCounter::PipeCountGraphics);
+ m_computePipelines = counters.getCtr(DxvkStatCounter::PipeCountCompute);
+ }
+
+
+ HudPos HudPipelineStatsItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 0.25f, 1.0f, 1.0f },
+ "Graphics pipelines:");
+
+ renderer.drawText(16.0f,
+ { position.x + 240.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_graphicsPipelines));
+
+ position.y += 20.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 0.25f, 1.0f, 1.0f },
+ "Compute pipelines:");
+
+ renderer.drawText(16.0f,
+ { position.x + 240.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ str::format(m_computePipelines));
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudMemoryStatsItem::HudMemoryStatsItem(const Rc<DxvkDevice>& device)
+ : m_device(device), m_memory(device->adapter()->memoryProperties()) {
+
+ }
+
+
+ HudMemoryStatsItem::~HudMemoryStatsItem() {
+
+ }
+
+
+ void HudMemoryStatsItem::update(dxvk::high_resolution_clock::time_point time) {
+ for (uint32_t i = 0; i < m_memory.memoryHeapCount; i++)
+ m_heaps[i] = m_device->getMemoryStats(i);
+ }
+
+
+ HudPos HudMemoryStatsItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ for (uint32_t i = 0; i < m_memory.memoryHeapCount; i++) {
+ bool isDeviceLocal = m_memory.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+
+ uint64_t memUsedMib = m_heaps[i].memoryUsed >> 20;
+ uint64_t percentage = (100 * m_heaps[i].memoryUsed) / m_memory.memoryHeaps[i].size;
+
+ std::string label = str::format(isDeviceLocal ? "Vidmem" : "Sysmem", " heap ", i, ":");
+ std::string text = str::format(std::setfill(' '), std::setw(5), memUsedMib, " MB (", percentage, "%)");
+
+ position.y += 16.0f;
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 1.0f, 1.0f, 0.25f, 1.0f },
+ label);
+
+ renderer.drawText(16.0f,
+ { position.x + 168.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ text);
+ position.y += 4.0f;
+ }
+
+ position.y += 4.0f;
+ return position;
+ }
+
+
+ HudGpuLoadItem::HudGpuLoadItem(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ HudGpuLoadItem::~HudGpuLoadItem() {
+
+ }
+
+
+ void HudGpuLoadItem::update(dxvk::high_resolution_clock::time_point time) {
+ uint64_t ticks = std::chrono::duration_cast<std::chrono::microseconds>(time - m_lastUpdate).count();
+
+ if (ticks >= UpdateInterval) {
+ DxvkStatCounters counters = m_device->getStatCounters();
+ uint64_t currGpuIdleTicks = counters.getCtr(DxvkStatCounter::GpuIdleTicks);
+
+ m_diffGpuIdleTicks = currGpuIdleTicks - m_prevGpuIdleTicks;
+ m_prevGpuIdleTicks = currGpuIdleTicks;
+
+ uint64_t busyTicks = ticks > m_diffGpuIdleTicks
+ ? uint64_t(ticks - m_diffGpuIdleTicks)
+ : uint64_t(0);
+
+ m_gpuLoadString = str::format((100 * busyTicks) / ticks, "%");
+ m_lastUpdate = time;
+ }
+ }
+
+
+ HudPos HudGpuLoadItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ position.y += 16.0f;
+
+ renderer.drawText(16.0f,
+ { position.x, position.y },
+ { 0.25f, 0.5f, 0.25f, 1.0f },
+ "GPU:");
+
+ renderer.drawText(16.0f,
+ { position.x + 60.0f, position.y },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ m_gpuLoadString);
+
+ position.y += 8.0f;
+ return position;
+ }
+
+
+ HudCompilerActivityItem::HudCompilerActivityItem(const Rc<DxvkDevice>& device)
+ : m_device(device) {
+
+ }
+
+
+ HudCompilerActivityItem::~HudCompilerActivityItem() {
+
+ }
+
+
+ void HudCompilerActivityItem::update(dxvk::high_resolution_clock::time_point time) {
+ DxvkStatCounters counters = m_device->getStatCounters();
+ bool doShow = counters.getCtr(DxvkStatCounter::PipeCompilerBusy);
+
+ if (!doShow) {
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(time - m_timeShown);
+ doShow = elapsed.count() <= MinShowDuration;
+ }
+
+ if (doShow && !m_show)
+ m_timeShown = time;
+
+ m_show = doShow;
+ }
+
+
+ HudPos HudCompilerActivityItem::render(
+ HudRenderer& renderer,
+ HudPos position) {
+ if (m_show) {
+ renderer.drawText(16.0f,
+ { position.x, renderer.surfaceSize().height / renderer.scale() - 20.0f },
+ { 1.0f, 1.0f, 1.0f, 1.0f },
+ "Compiling shaders...");
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.h
new file mode 100644
index 00000000..84fe5ccd
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_item.h
@@ -0,0 +1,417 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "../../util/util_time.h"
+
+#include "dxvk_hud_renderer.h"
+
+namespace dxvk::hud {
+
+ /**
+ * \brief HUD item
+ *
+ * A single named item in the HUD that
+ * can be enabled by the user.
+ */
+ class HudItem : public RcObject {
+
+ public:
+
+ virtual ~HudItem();
+
+ /**
+ * \brief Updates the HUD item
+ * \param [in] time Current time
+ */
+ virtual void update(
+ dxvk::high_resolution_clock::time_point time);
+
+ /**
+ * \brief Renders the HUD
+ *
+ * \param [in] renderer HUD renderer
+ * \param [in] position Base offset
+ * \returns Base offset for next item
+ */
+ virtual HudPos render(
+ HudRenderer& renderer,
+ HudPos position) = 0;
+
+ };
+
+
+ /**
+ * \brief HUD item set
+ *
+ * Manages HUD items.
+ */
+ class HudItemSet {
+
+ public:
+
+ HudItemSet(const Rc<DxvkDevice>& device);
+
+ ~HudItemSet();
+
+ /**
+ * \brief Updates the HUD
+ * Updates all enabled HUD items.
+ */
+ void update();
+
+ /**
+ * \brief Renders the HUD
+ *
+ * \param [in] renderer HUD renderer
+ * \returns Base offset for next item
+ */
+ void render(
+ HudRenderer& renderer);
+
+ /**
+ * \brief Creates a HUD item if enabled
+ *
+ * \tparam T The HUD item type
+ * \param [in] name HUD item name
+ * \param [in] at Position at which to insert the item
+ * \param [in] args Constructor arguments
+ */
+ template<typename T, typename... Args>
+ void add(const char* name, int32_t at, Args... args) {
+ bool enable = m_enableFull;
+
+ if (!enable) {
+ auto entry = m_enabled.find(name);
+ enable = entry != m_enabled.end();
+ }
+
+ if (at < 0 || at > int32_t(m_items.size()))
+ at = m_items.size();
+
+ if (enable) {
+ m_items.insert(m_items.begin() + at,
+ new T(std::forward<Args>(args)...));
+ }
+ }
+
+ template<typename T>
+ T getOption(const char *option, T fallback) {
+ auto entry = m_options.find(option);
+ if (entry == m_options.end())
+ return fallback;
+
+ T value = fallback;
+ parseOption(entry->second, value);
+ return value;
+ }
+
+ private:
+
+ bool m_enableFull = false;
+ std::unordered_set<std::string> m_enabled;
+ std::unordered_map<std::string, std::string> m_options;
+ std::vector<Rc<HudItem>> m_items;
+
+ static void parseOption(const std::string& str, float& value);
+
+ };
+
+
+ /**
+ * \brief HUD item to display DXVK version
+ */
+ class HudVersionItem : public HudItem {
+
+ public:
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ };
+
+
+ /**
+ * \brief HUD item to display the client API
+ */
+ class HudClientApiItem : public HudItem {
+
+ public:
+
+ HudClientApiItem(std::string api);
+
+ ~HudClientApiItem();
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ std::string m_api;
+
+ };
+
+
+ /**
+ * \brief HUD item to display device info
+ */
+ class HudDeviceInfoItem : public HudItem {
+
+ public:
+
+ HudDeviceInfoItem(const Rc<DxvkDevice>& device);
+
+ ~HudDeviceInfoItem();
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ std::string m_deviceName;
+ std::string m_driverVer;
+ std::string m_vulkanVer;
+
+ };
+
+
+ /**
+ * \brief HUD item to display the frame rate
+ */
+ class HudFpsItem : public HudItem {
+ constexpr static int64_t UpdateInterval = 500'000;
+ public:
+
+ HudFpsItem();
+
+ ~HudFpsItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ uint32_t m_frameCount = 0;
+ dxvk::high_resolution_clock::time_point m_lastUpdate
+ = dxvk::high_resolution_clock::now();
+
+ std::string m_frameRate;
+
+ };
+
+
+ /**
+ * \brief HUD item to display the frame rate
+ */
+ class HudFrameTimeItem : public HudItem {
+ constexpr static size_t NumDataPoints = 300;
+ public:
+
+ HudFrameTimeItem();
+
+ ~HudFrameTimeItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ dxvk::high_resolution_clock::time_point m_lastUpdate
+ = dxvk::high_resolution_clock::now();
+
+ std::array<float, NumDataPoints> m_dataPoints = {};
+ uint32_t m_dataPointId = 0;
+
+ };
+
+
+ /**
+ * \brief HUD item to display queue submissions
+ */
+ class HudSubmissionStatsItem : public HudItem {
+ constexpr static int64_t UpdateInterval = 500'000;
+ public:
+
+ HudSubmissionStatsItem(const Rc<DxvkDevice>& device);
+
+ ~HudSubmissionStatsItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+
+ uint64_t m_prevCounter = 0;
+ uint64_t m_diffCounter = 0;
+ uint64_t m_showCounter = 0;
+
+ dxvk::high_resolution_clock::time_point m_lastUpdate
+ = dxvk::high_resolution_clock::now();
+
+ };
+
+
+ /**
+ * \brief HUD item to display draw call counts
+ */
+ class HudDrawCallStatsItem : public HudItem {
+ constexpr static int64_t UpdateInterval = 500'000;
+ public:
+
+ HudDrawCallStatsItem(const Rc<DxvkDevice>& device);
+
+ ~HudDrawCallStatsItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+
+ DxvkStatCounters m_prevCounters;
+
+ uint64_t m_gpCount = 0;
+ uint64_t m_cpCount = 0;
+ uint64_t m_rpCount = 0;
+
+ dxvk::high_resolution_clock::time_point m_lastUpdate
+ = dxvk::high_resolution_clock::now();
+
+ };
+
+
+ /**
+ * \brief HUD item to display pipeline counts
+ */
+ class HudPipelineStatsItem : public HudItem {
+
+ public:
+
+ HudPipelineStatsItem(const Rc<DxvkDevice>& device);
+
+ ~HudPipelineStatsItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+
+ uint64_t m_graphicsPipelines = 0;
+ uint64_t m_computePipelines = 0;
+
+ };
+
+
+ /**
+ * \brief HUD item to display memory usage
+ */
+ class HudMemoryStatsItem : public HudItem {
+
+ public:
+
+ HudMemoryStatsItem(const Rc<DxvkDevice>& device);
+
+ ~HudMemoryStatsItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+ VkPhysicalDeviceMemoryProperties m_memory;
+ DxvkMemoryStats m_heaps[VK_MAX_MEMORY_HEAPS];
+
+ };
+
+
+ /**
+ * \brief HUD item to display GPU load
+ */
+ class HudGpuLoadItem : public HudItem {
+ constexpr static int64_t UpdateInterval = 500'000;
+ public:
+
+ HudGpuLoadItem(const Rc<DxvkDevice>& device);
+
+ ~HudGpuLoadItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+
+ uint64_t m_prevGpuIdleTicks = 0;
+ uint64_t m_diffGpuIdleTicks = 0;
+
+ std::string m_gpuLoadString;
+
+ dxvk::high_resolution_clock::time_point m_lastUpdate
+ = dxvk::high_resolution_clock::now();
+
+ };
+
+
+ /**
+ * \brief HUD item to display pipeline compiler activity
+ */
+ class HudCompilerActivityItem : public HudItem {
+ constexpr static int64_t MinShowDuration = 1500;
+ public:
+
+ HudCompilerActivityItem(const Rc<DxvkDevice>& device);
+
+ ~HudCompilerActivityItem();
+
+ void update(dxvk::high_resolution_clock::time_point time);
+
+ HudPos render(
+ HudRenderer& renderer,
+ HudPos position);
+
+ private:
+
+ Rc<DxvkDevice> m_device;
+
+ bool m_show = false;
+
+ dxvk::high_resolution_clock::time_point m_timeShown
+ = dxvk::high_resolution_clock::now();
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.cpp
new file mode 100644
index 00000000..1de3607b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.cpp
@@ -0,0 +1,365 @@
+#include "dxvk_hud_renderer.h"
+
+#include <hud_line_frag.h>
+#include <hud_line_vert.h>
+
+#include <hud_text_frag.h>
+#include <hud_text_vert.h>
+
+namespace dxvk::hud {
+
+ HudRenderer::HudRenderer(const Rc<DxvkDevice>& device)
+ : m_mode (Mode::RenderNone),
+ m_scale (1.0f),
+ m_surfaceSize { 0, 0 },
+ m_textShaders (createTextShaders(device)),
+ m_lineShaders (createLineShaders(device)),
+ m_fontImage (createFontImage(device)),
+ m_fontView (createFontView(device)),
+ m_fontSampler (createFontSampler(device)),
+ m_vertexBuffer (createVertexBuffer(device)) {
+ this->initFontTexture(device);
+ this->initCharMap();
+ }
+
+
+ HudRenderer::~HudRenderer() {
+
+ }
+
+
+ void HudRenderer::beginFrame(const Rc<DxvkContext>& context, VkExtent2D surfaceSize, float scale) {
+ context->bindResourceSampler(0, m_fontSampler);
+ context->bindResourceView (0, m_fontView, nullptr);
+
+ m_mode = Mode::RenderNone;
+ m_scale = scale;
+ m_surfaceSize = surfaceSize;
+ m_context = context;
+
+ allocVertexBufferSlice();
+ }
+
+
+ void HudRenderer::drawText(
+ float size,
+ HudPos pos,
+ HudColor color,
+ const std::string& text) {
+ beginTextRendering();
+
+ const float xscale = m_scale / std::max(float(m_surfaceSize.width), 1.0f);
+ const float yscale = m_scale / std::max(float(m_surfaceSize.height), 1.0f);
+
+ uint32_t vertexCount = 6 * text.size();
+
+ if (m_currTextVertex + vertexCount > MaxTextVertexCount
+ || m_currTextInstance + 1 > MaxTextInstanceCount)
+ allocVertexBufferSlice();
+
+ m_context->draw(vertexCount, 1, m_currTextVertex, m_currTextInstance);
+
+ const float sizeFactor = size / float(g_hudFont.size);
+
+ for (size_t i = 0; i < text.size(); i++) {
+ const HudGlyph& glyph = g_hudFont.glyphs[
+ m_charMap[uint8_t(text[i])]];
+
+ HudPos size = {
+ sizeFactor * float(glyph.w),
+ sizeFactor * float(glyph.h) };
+
+ HudPos origin = {
+ pos.x - sizeFactor * float(glyph.originX),
+ pos.y - sizeFactor * float(glyph.originY) };
+
+ HudPos posTl = { xscale * (origin.x), yscale * (origin.y) };
+ HudPos posBr = { xscale * (origin.x + size.x), yscale * (origin.y + size.y) };
+
+ HudTexCoord texTl = { uint32_t(glyph.x), uint32_t(glyph.y) };
+ HudTexCoord texBr = { uint32_t(glyph.x + glyph.w), uint32_t(glyph.y + glyph.h) };
+
+ uint32_t idx = 6 * i + m_currTextVertex;
+
+ m_vertexData->textVertices[idx + 0].position = { posTl.x, posTl.y };
+ m_vertexData->textVertices[idx + 0].texcoord = { texTl.u, texTl.v };
+
+ m_vertexData->textVertices[idx + 1].position = { posBr.x, posTl.y };
+ m_vertexData->textVertices[idx + 1].texcoord = { texBr.u, texTl.v };
+
+ m_vertexData->textVertices[idx + 2].position = { posTl.x, posBr.y };
+ m_vertexData->textVertices[idx + 2].texcoord = { texTl.u, texBr.v };
+
+ m_vertexData->textVertices[idx + 3].position = { posBr.x, posBr.y };
+ m_vertexData->textVertices[idx + 3].texcoord = { texBr.u, texBr.v };
+
+ m_vertexData->textVertices[idx + 4].position = { posTl.x, posBr.y };
+ m_vertexData->textVertices[idx + 4].texcoord = { texTl.u, texBr.v };
+
+ m_vertexData->textVertices[idx + 5].position = { posBr.x, posTl.y };
+ m_vertexData->textVertices[idx + 5].texcoord = { texBr.u, texTl.v };
+
+ pos.x += sizeFactor * static_cast<float>(g_hudFont.advance);
+ }
+
+ m_vertexData->textColors[m_currTextInstance] = color;
+
+ m_currTextVertex += vertexCount;
+ m_currTextInstance += 1;
+ }
+
+
+ void HudRenderer::drawLines(
+ size_t vertexCount,
+ const HudLineVertex* vertexData) {
+ beginLineRendering();
+
+ const float xscale = m_scale / std::max(float(m_surfaceSize.width), 1.0f);
+ const float yscale = m_scale / std::max(float(m_surfaceSize.height), 1.0f);
+
+ if (m_currLineVertex + vertexCount > MaxLineVertexCount)
+ allocVertexBufferSlice();
+
+ m_context->draw(vertexCount, 1, m_currLineVertex, 0);
+
+ for (size_t i = 0; i < vertexCount; i++) {
+ uint32_t idx = m_currLineVertex + i;
+
+ m_vertexData->lineVertices[idx].position = {
+ xscale * vertexData[i].position.x,
+ yscale * vertexData[i].position.y };
+ m_vertexData->lineVertices[idx].color = vertexData[i].color;
+ }
+
+ m_currLineVertex += vertexCount;
+ }
+
+
+ void HudRenderer::allocVertexBufferSlice() {
+ auto vertexSlice = m_vertexBuffer->allocSlice();
+ m_context->invalidateBuffer(m_vertexBuffer, vertexSlice);
+
+ m_currTextVertex = 0;
+ m_currTextInstance = 0;
+ m_currLineVertex = 0;
+
+ m_vertexData = reinterpret_cast<VertexBufferData*>(vertexSlice.mapPtr);
+ }
+
+
+ void HudRenderer::beginTextRendering() {
+ if (m_mode != Mode::RenderText) {
+ m_mode = Mode::RenderText;
+
+ m_context->bindVertexBuffer(0, DxvkBufferSlice(m_vertexBuffer, offsetof(VertexBufferData, textVertices), sizeof(HudTextVertex) * MaxTextVertexCount), sizeof(HudTextVertex));
+ m_context->bindVertexBuffer(1, DxvkBufferSlice(m_vertexBuffer, offsetof(VertexBufferData, textColors), sizeof(HudColor) * MaxTextInstanceCount), sizeof(HudColor));
+
+ m_context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_textShaders.vert);
+ m_context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_textShaders.frag);
+
+ static const DxvkInputAssemblyState iaState = {
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ VK_FALSE, 0 };
+
+ static const std::array<DxvkVertexAttribute, 3> ilAttributes = {{
+ { 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudTextVertex, position) },
+ { 1, 0, VK_FORMAT_R32G32_UINT, offsetof(HudTextVertex, texcoord) },
+ { 2, 1, VK_FORMAT_R32G32B32A32_SFLOAT, 0 },
+ }};
+
+ static const std::array<DxvkVertexBinding, 2> ilBindings = {{
+ { 0, 0, VK_VERTEX_INPUT_RATE_VERTEX },
+ { 1, 1, VK_VERTEX_INPUT_RATE_INSTANCE },
+ }};
+
+ m_context->setInputAssemblyState(iaState);
+ m_context->setInputLayout(
+ ilAttributes.size(),
+ ilAttributes.data(),
+ ilBindings.size(),
+ ilBindings.data());
+ }
+ }
+
+
+ void HudRenderer::beginLineRendering() {
+ if (m_mode != Mode::RenderLines) {
+ m_mode = Mode::RenderLines;
+
+ m_context->bindVertexBuffer(0, DxvkBufferSlice(m_vertexBuffer, offsetof(VertexBufferData, lineVertices), sizeof(HudLineVertex) * MaxLineVertexCount), sizeof(HudLineVertex));
+
+ m_context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_lineShaders.vert);
+ m_context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_lineShaders.frag);
+
+ static const DxvkInputAssemblyState iaState = {
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ VK_FALSE, 0 };
+
+ static const std::array<DxvkVertexAttribute, 2> ilAttributes = {{
+ { 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudLineVertex, position) },
+ { 1, 0, VK_FORMAT_R8G8B8A8_UNORM, offsetof(HudLineVertex, color) },
+ }};
+
+ static const std::array<DxvkVertexBinding, 1> ilBindings = {{
+ { 0, 0, VK_VERTEX_INPUT_RATE_VERTEX },
+ }};
+
+ m_context->setInputAssemblyState(iaState);
+ m_context->setInputLayout(
+ ilAttributes.size(),
+ ilAttributes.data(),
+ ilBindings.size(),
+ ilBindings.data());
+ }
+ }
+
+
+ HudRenderer::ShaderPair HudRenderer::createTextShaders(const Rc<DxvkDevice>& device) {
+ ShaderPair result;
+
+ const SpirvCodeBuffer vsCode(hud_text_vert);
+ const SpirvCodeBuffer fsCode(hud_text_frag);
+
+ // Two shader resources: Font texture and sampler
+ const std::array<DxvkResourceSlot, 1> fsResources = {{
+ { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D },
+ }};
+
+ result.vert = device->createShader(
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0, nullptr, { 0x7, 0x3 }, vsCode);
+
+ result.frag = device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ fsResources.size(),
+ fsResources.data(),
+ { 0x3, 0x1 },
+ fsCode);
+
+ return result;
+ }
+
+
+ HudRenderer::ShaderPair HudRenderer::createLineShaders(const Rc<DxvkDevice>& device) {
+ ShaderPair result;
+
+ const SpirvCodeBuffer vsCode(hud_line_vert);
+ const SpirvCodeBuffer fsCode(hud_line_frag);
+
+ result.vert = device->createShader(
+ VK_SHADER_STAGE_VERTEX_BIT,
+ 0, nullptr, { 0x3, 0x1 }, vsCode);
+
+ result.frag = device->createShader(
+ VK_SHADER_STAGE_FRAGMENT_BIT,
+ 0, nullptr, { 0x1, 0x1 }, fsCode);
+
+ return result;
+ }
+
+
+ Rc<DxvkImage> HudRenderer::createFontImage(const Rc<DxvkDevice>& device) {
+ DxvkImageCreateInfo info;
+ info.type = VK_IMAGE_TYPE_2D;
+ info.format = VK_FORMAT_R8_UNORM;
+ info.flags = 0;
+ info.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ info.extent = { g_hudFont.width, g_hudFont.height, 1 };
+ info.numLayers = 1;
+ info.mipLevels = 1;
+ info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT;
+ info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
+ | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ info.access = VK_ACCESS_TRANSFER_WRITE_BIT
+ | VK_ACCESS_SHADER_READ_BIT;
+ info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ return device->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ }
+
+
+ Rc<DxvkImageView> HudRenderer::createFontView(const Rc<DxvkDevice>& device) {
+ DxvkImageViewCreateInfo info;
+ info.type = VK_IMAGE_VIEW_TYPE_2D;
+ info.format = m_fontImage->info().format;
+ info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
+ info.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ info.minLevel = 0;
+ info.numLevels = 1;
+ info.minLayer = 0;
+ info.numLayers = 1;
+
+ return device->createImageView(m_fontImage, info);
+ }
+
+
+ Rc<DxvkSampler> HudRenderer::createFontSampler(const Rc<DxvkDevice>& device) {
+ DxvkSamplerCreateInfo info;
+ info.magFilter = VK_FILTER_LINEAR;
+ info.minFilter = VK_FILTER_LINEAR;
+ info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ info.mipmapLodBias = 0.0f;
+ info.mipmapLodMin = 0.0f;
+ info.mipmapLodMax = 0.0f;
+ info.useAnisotropy = VK_FALSE;
+ info.maxAnisotropy = 1.0f;
+ info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+ info.compareToDepth = VK_FALSE;
+ info.compareOp = VK_COMPARE_OP_NEVER;
+ info.borderColor = VkClearColorValue();
+ info.usePixelCoord = VK_TRUE;
+
+ return device->createSampler(info);
+ }
+
+
+ Rc<DxvkBuffer> HudRenderer::createVertexBuffer(const Rc<DxvkDevice>& device) {
+ DxvkBufferCreateInfo info;
+ info.size = sizeof(VertexBufferData);
+ info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
+
+ return device->createBuffer(info,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+ }
+
+
+ void HudRenderer::initFontTexture(
+ const Rc<DxvkDevice>& device) {
+ Rc<DxvkContext> context = device->createContext();
+
+ context->beginRecording(
+ device->createCommandList());
+
+ context->uploadImage(m_fontImage,
+ VkImageSubresourceLayers {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, 0, 1 },
+ g_hudFont.texture,
+ g_hudFont.width,
+ g_hudFont.width * g_hudFont.height);
+
+ device->submitCommandList(
+ context->endRecording(),
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE);
+
+ context->trimStagingBuffers();
+ }
+
+
+ void HudRenderer::initCharMap() {
+ std::fill(m_charMap.begin(), m_charMap.end(), 0);
+
+ for (uint32_t i = 0; i < g_hudFont.charCount; i++)
+ m_charMap.at(g_hudFont.glyphs[i].codePoint) = i;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.h b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.h
new file mode 100644
index 00000000..c5b8e1da
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/dxvk_hud_renderer.h
@@ -0,0 +1,182 @@
+#pragma once
+
+#include "../dxvk_device.h"
+
+#include "dxvk_hud_font.h"
+
+namespace dxvk::hud {
+
+ /**
+ * \brief HUD coordinates
+ *
+ * Coordinates relative to the top-left
+ * corner of the swap image, in pixels.
+ */
+ struct HudPos {
+ float x;
+ float y;
+ };
+
+ /**
+ * \brief Texture coordinates
+ *
+ * Absolute texture coordinates that are used
+ * to pick letters in the font texture.
+ */
+ struct HudTexCoord {
+ uint32_t u;
+ uint32_t v;
+ };
+
+ /**
+ * \brief Color
+ *
+ * SRGB color with alpha channel. The text
+ * will use this color for the most part.
+ */
+ struct HudColor {
+ float r;
+ float g;
+ float b;
+ float a;
+ };
+
+ /**
+ * \brief Normalized color
+ * SRGB color with alpha channel.
+ */
+ struct HudNormColor {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+ };
+
+ /**
+ * \brief Text vertex and texture coordinates
+ */
+ struct HudTextVertex {
+ HudPos position;
+ HudTexCoord texcoord;
+ };
+
+ /**
+ * \brief Line vertex and color
+ */
+ struct HudLineVertex {
+ HudPos position;
+ HudNormColor color;
+ };
+
+ /**
+ * \brief Text renderer for the HUD
+ *
+ * Can be used by the presentation backend to
+ * display performance and driver information.
+ */
+ class HudRenderer {
+ constexpr static uint32_t MaxTextVertexCount = 512 * 6;
+ constexpr static uint32_t MaxTextInstanceCount = 64;
+ constexpr static uint32_t MaxLineVertexCount = 1024;
+
+ struct VertexBufferData {
+ HudColor textColors[MaxTextInstanceCount];
+ HudTextVertex textVertices[MaxTextVertexCount];
+ HudLineVertex lineVertices[MaxLineVertexCount];
+ };
+ public:
+
+ HudRenderer(
+ const Rc<DxvkDevice>& device);
+
+ ~HudRenderer();
+
+ void beginFrame(
+ const Rc<DxvkContext>& context,
+ VkExtent2D surfaceSize,
+ float scale);
+
+ void drawText(
+ float size,
+ HudPos pos,
+ HudColor color,
+ const std::string& text);
+
+ void drawLines(
+ size_t vertexCount,
+ const HudLineVertex* vertexData);
+
+ VkExtent2D surfaceSize() const {
+ return m_surfaceSize;
+ }
+
+ float scale() const {
+ return m_scale;
+ }
+
+ private:
+
+ enum class Mode {
+ RenderNone,
+ RenderText,
+ RenderLines,
+ };
+
+ struct ShaderPair {
+ Rc<DxvkShader> vert;
+ Rc<DxvkShader> frag;
+ };
+
+ std::array<uint8_t, 256> m_charMap;
+
+ Mode m_mode;
+ float m_scale;
+ VkExtent2D m_surfaceSize;
+ Rc<DxvkContext> m_context;
+
+ ShaderPair m_textShaders;
+ ShaderPair m_lineShaders;
+
+ Rc<DxvkImage> m_fontImage;
+ Rc<DxvkImageView> m_fontView;
+ Rc<DxvkSampler> m_fontSampler;
+
+ Rc<DxvkBuffer> m_vertexBuffer;
+ VertexBufferData* m_vertexData = nullptr;
+
+ uint32_t m_currTextVertex = 0;
+ uint32_t m_currTextInstance = 0;
+ uint32_t m_currLineVertex = 0;
+
+ void allocVertexBufferSlice();
+
+ void beginTextRendering();
+
+ void beginLineRendering();
+
+ ShaderPair createTextShaders(
+ const Rc<DxvkDevice>& device);
+
+ ShaderPair createLineShaders(
+ const Rc<DxvkDevice>& device);
+
+ Rc<DxvkImage> createFontImage(
+ const Rc<DxvkDevice>& device);
+
+ Rc<DxvkImageView> createFontView(
+ const Rc<DxvkDevice>& device);
+
+ Rc<DxvkSampler> createFontSampler(
+ const Rc<DxvkDevice>& device);
+
+ Rc<DxvkBuffer> createVertexBuffer(
+ const Rc<DxvkDevice>& device);
+
+ void initFontTexture(
+ const Rc<DxvkDevice>& device);
+
+ void initCharMap();
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_frag.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_frag.frag
new file mode 100644
index 00000000..73c34865
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_frag.frag
@@ -0,0 +1,23 @@
+#version 450
+
+layout(constant_id = 1225) const bool srgbSwapchain = false;
+
+layout(location = 0) in vec4 v_color;
+layout(location = 0) out vec4 o_color;
+
+vec3 linearToSrgb(vec3 color) {
+ bvec3 isLo = lessThanEqual(color, vec3(0.0031308f));
+
+ vec3 loPart = color * 12.92f;
+ vec3 hiPart = pow(color, vec3(5.0f / 12.0f)) * 1.055f - 0.055f;
+ return mix(hiPart, loPart, isLo);
+}
+
+void main() {
+ o_color = vec4(
+ v_color.rgb * v_color.a,
+ v_color.a);
+
+ if (!srgbSwapchain)
+ o_color.rgb = linearToSrgb(o_color.rgb);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_vert.vert b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_vert.vert
new file mode 100644
index 00000000..6154baf3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_line_vert.vert
@@ -0,0 +1,13 @@
+#version 450
+
+layout(location = 0) in vec2 v_position;
+layout(location = 1) in vec4 v_color;
+
+layout(location = 0) out vec4 o_color;
+
+void main() {
+ o_color = v_color;
+
+ vec2 pos = 2.0f * v_position - 1.0f;
+ gl_Position = vec4(pos, 0.0f, 1.0f);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_frag.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_frag.frag
new file mode 100644
index 00000000..e6f91bf6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_frag.frag
@@ -0,0 +1,38 @@
+#version 450
+
+layout(constant_id = 1225) const bool srgbSwapchain = false;
+
+layout(set = 0, binding = 0) uniform sampler2D s_font;
+
+layout(location = 0) in vec2 v_texcoord;
+layout(location = 1) in vec4 v_color;
+
+layout(location = 0) out vec4 o_color;
+
+vec3 linearToSrgb(vec3 color) {
+ bvec3 isLo = lessThanEqual(color, vec3(0.0031308f));
+
+ vec3 loPart = color * 12.92f;
+ vec3 hiPart = pow(color, vec3(5.0f / 12.0f)) * 1.055f - 0.055f;
+ return mix(hiPart, loPart, isLo);
+}
+
+float sampleAlpha(float alpha_bias, float dist_range) {
+ float value = textureLod(s_font, v_texcoord, 0).r + alpha_bias - 0.5f;
+ float dist = value * dot(vec2(dist_range, dist_range), 1.0f / fwidth(v_texcoord.xy));
+ return clamp(dist + 0.5f, 0.0f, 1.0f);
+}
+
+void main() {
+ float r_alpha_center = sampleAlpha(0.0f, 5.0f);
+ float r_alpha_shadow = sampleAlpha(0.3f, 5.0f);
+
+ vec4 r_center = vec4(v_color.rgb, v_color.a * r_alpha_center);
+ vec4 r_shadow = vec4(0.0f, 0.0f, 0.0f, r_alpha_shadow);
+
+ o_color = mix(r_shadow, r_center, r_alpha_center);
+ o_color.rgb *= o_color.a;
+
+ if (!srgbSwapchain)
+ o_color.rgb = linearToSrgb(o_color.rgb);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_vert.vert b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_vert.vert
new file mode 100644
index 00000000..7b866704
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/hud/shaders/hud_text_vert.vert
@@ -0,0 +1,16 @@
+#version 450
+
+layout(location = 0) in vec2 v_position;
+layout(location = 1) in uvec2 v_texcoord;
+layout(location = 2) in vec4 v_color;
+
+layout(location = 0) out vec2 o_texcoord;
+layout(location = 1) out vec4 o_color;
+
+void main() {
+ o_texcoord = vec2(v_texcoord);
+ o_color = v_color;
+
+ vec2 pos = 2.0f * v_position - 1.0f;
+ gl_Position = vec4(pos, 0.0f, 1.0f);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/meson.build b/src/libs/dxvk-native-1.9.2a/src/dxvk/meson.build
new file mode 100644
index 00000000..71359110
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/meson.build
@@ -0,0 +1,143 @@
+dxvk_shaders = files([
+ 'shaders/dxvk_blit_frag_1d.frag',
+ 'shaders/dxvk_blit_frag_2d.frag',
+ 'shaders/dxvk_blit_frag_3d.frag',
+
+ 'shaders/dxvk_clear_buffer_u.comp',
+ 'shaders/dxvk_clear_buffer_f.comp',
+ 'shaders/dxvk_clear_image1d_u.comp',
+ 'shaders/dxvk_clear_image1d_f.comp',
+ 'shaders/dxvk_clear_image1darr_u.comp',
+ 'shaders/dxvk_clear_image1darr_f.comp',
+ 'shaders/dxvk_clear_image2d_u.comp',
+ 'shaders/dxvk_clear_image2d_f.comp',
+ 'shaders/dxvk_clear_image2darr_u.comp',
+ 'shaders/dxvk_clear_image2darr_f.comp',
+ 'shaders/dxvk_clear_image3d_u.comp',
+ 'shaders/dxvk_clear_image3d_f.comp',
+
+ 'shaders/dxvk_copy_buffer_image.comp',
+ 'shaders/dxvk_copy_color_1d.frag',
+ 'shaders/dxvk_copy_color_2d.frag',
+ 'shaders/dxvk_copy_color_ms.frag',
+ 'shaders/dxvk_copy_depth_1d.frag',
+ 'shaders/dxvk_copy_depth_2d.frag',
+ 'shaders/dxvk_copy_depth_ms.frag',
+ 'shaders/dxvk_copy_depth_stencil_1d.frag',
+ 'shaders/dxvk_copy_depth_stencil_2d.frag',
+ 'shaders/dxvk_copy_depth_stencil_ms.frag',
+
+ 'shaders/dxvk_fullscreen_geom.geom',
+ 'shaders/dxvk_fullscreen_vert.vert',
+ 'shaders/dxvk_fullscreen_layer_vert.vert',
+
+ 'shaders/dxvk_pack_d24s8.comp',
+ 'shaders/dxvk_pack_d32s8.comp',
+
+ 'shaders/dxvk_present_frag.frag',
+ 'shaders/dxvk_present_frag_blit.frag',
+ 'shaders/dxvk_present_frag_ms.frag',
+ 'shaders/dxvk_present_frag_ms_amd.frag',
+ 'shaders/dxvk_present_vert.vert',
+
+ 'shaders/dxvk_resolve_frag_d.frag',
+ 'shaders/dxvk_resolve_frag_ds.frag',
+ 'shaders/dxvk_resolve_frag_f.frag',
+ 'shaders/dxvk_resolve_frag_f_amd.frag',
+ 'shaders/dxvk_resolve_frag_i.frag',
+ 'shaders/dxvk_resolve_frag_u.frag',
+
+ 'shaders/dxvk_unpack_d24s8_as_d32s8.comp',
+ 'shaders/dxvk_unpack_d24s8.comp',
+ 'shaders/dxvk_unpack_d32s8.comp',
+
+ 'hud/shaders/hud_line_frag.frag',
+ 'hud/shaders/hud_line_vert.vert',
+
+ 'hud/shaders/hud_text_frag.frag',
+ 'hud/shaders/hud_text_vert.vert',
+])
+
+dxvk_src = [
+ 'dxvk_adapter.cpp',
+ 'dxvk_barrier.cpp',
+ 'dxvk_buffer.cpp',
+ 'dxvk_cmdlist.cpp',
+ 'dxvk_compute.cpp',
+ 'dxvk_context.cpp',
+ 'dxvk_cs.cpp',
+ 'dxvk_data.cpp',
+ 'dxvk_descriptor.cpp',
+ 'dxvk_device.cpp',
+ 'dxvk_device_filter.cpp',
+ 'dxvk_extensions.cpp',
+ 'dxvk_format.cpp',
+ 'dxvk_framebuffer.cpp',
+ 'dxvk_gpu_event.cpp',
+ 'dxvk_gpu_query.cpp',
+ 'dxvk_graphics.cpp',
+ 'dxvk_image.cpp',
+ 'dxvk_instance.cpp',
+ 'dxvk_lifetime.cpp',
+ 'dxvk_main.cpp',
+ 'dxvk_memory.cpp',
+ 'dxvk_meta_blit.cpp',
+ 'dxvk_meta_clear.cpp',
+ 'dxvk_meta_copy.cpp',
+ 'dxvk_meta_mipgen.cpp',
+ 'dxvk_meta_pack.cpp',
+ 'dxvk_meta_resolve.cpp',
+ 'dxvk_options.cpp',
+ 'dxvk_pipecache.cpp',
+ 'dxvk_pipelayout.cpp',
+ 'dxvk_pipemanager.cpp',
+ 'dxvk_queue.cpp',
+ 'dxvk_renderpass.cpp',
+ 'dxvk_resource.cpp',
+ 'dxvk_sampler.cpp',
+ 'dxvk_shader.cpp',
+ 'dxvk_shader_key.cpp',
+ 'dxvk_signal.cpp',
+ 'dxvk_spec_const.cpp',
+ 'dxvk_staging.cpp',
+ 'dxvk_state_cache.cpp',
+ 'dxvk_stats.cpp',
+ 'dxvk_swapchain_blitter.cpp',
+ 'dxvk_unbound.cpp',
+ 'dxvk_util.cpp',
+
+ 'hud/dxvk_hud.cpp',
+ 'hud/dxvk_hud_font.cpp',
+ 'hud/dxvk_hud_item.cpp',
+ 'hud/dxvk_hud_renderer.cpp',
+]
+
+dxvk_src_win32 = [
+ 'dxvk_openvr.cpp',
+ 'dxvk_openxr.cpp',
+ 'platform/dxvk_win32_exts.cpp'
+]
+
+dxvk_src_sdl2 = [
+ 'platform/dxvk_sdl2_exts.cpp'
+]
+
+if dxvk_wsi == 'win32'
+ dxvk_src += dxvk_src_win32
+elif dxvk_wsi == 'sdl2'
+ dxvk_src += dxvk_src_sdl2
+else
+ error('Unknown platform for dxvk')
+endif
+
+thread_dep = dependency('threads')
+
+dxvk_lib = static_library('dxvk', dxvk_src, glsl_generator.process(dxvk_shaders), dxvk_version,
+ link_with : [ util_lib, spirv_lib ],
+ dependencies : [ thread_dep, vkcommon_dep ] + dxvk_extradep,
+ include_directories : [ dxvk_include_path ],
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+dxvk_dep = declare_dependency(
+ link_with : [ dxvk_lib ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_headless_exts.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_headless_exts.cpp
new file mode 100644
index 00000000..304f51f5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_headless_exts.cpp
@@ -0,0 +1,32 @@
+#include "../dxvk_platform_exts.h"
+
+namespace dxvk {
+
+ DxvkPlatformExts DxvkPlatformExts::s_instance;
+
+ std::string_view DxvkPlatformExts::getName() {
+ return "Headless WSI";
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
+ return DxvkNameSet();
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getDeviceExtensions(
+ uint32_t adapterId) {
+ return DxvkNameSet();
+ }
+
+
+ void DxvkPlatformExts::initInstanceExtensions() {
+ }
+
+
+ void DxvkPlatformExts::initDeviceExtensions(
+ const DxvkInstance* instance) {
+
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_sdl2_exts.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_sdl2_exts.cpp
new file mode 100644
index 00000000..09de7843
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_sdl2_exts.cpp
@@ -0,0 +1,60 @@
+#include "../dxvk_platform_exts.h"
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+
+namespace dxvk {
+
+ DxvkPlatformExts DxvkPlatformExts::s_instance;
+
+ std::string_view DxvkPlatformExts::getName() {
+ return "SDL2 WSI";
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
+ SDL_Window* window = SDL_CreateWindow(
+ "Dummy Window",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ 1, 1,
+ SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
+
+ if (window == nullptr)
+ throw DxvkError(str::format("SDL2 WSI: Failed to create dummy window. ", SDL_GetError()));
+
+ uint32_t extensionCount = 0;
+ if (!SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr))
+ throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", SDL_GetError()));
+
+ auto extensionNames = std::vector<const char *>(extensionCount);
+ if (!SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensionNames.data()))
+ throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError()));
+
+ DxvkNameSet names;
+ for (const char* name : extensionNames)
+ names.add(name);
+
+ SDL_DestroyWindow(window);
+
+ return names;
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getDeviceExtensions(
+ uint32_t adapterId) {
+ return DxvkNameSet();
+ }
+
+
+ void DxvkPlatformExts::initInstanceExtensions() {
+
+ }
+
+
+ void DxvkPlatformExts::initDeviceExtensions(
+ const DxvkInstance* instance) {
+
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_win32_exts.cpp b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_win32_exts.cpp
new file mode 100644
index 00000000..25c81cc5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/platform/dxvk_win32_exts.cpp
@@ -0,0 +1,36 @@
+#include "../dxvk_platform_exts.h"
+
+namespace dxvk {
+
+ DxvkPlatformExts DxvkPlatformExts::s_instance;
+
+ std::string_view DxvkPlatformExts::getName() {
+ return "Win32 WSI";
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
+ DxvkNameSet names;
+ names.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+
+ return names;
+ }
+
+
+ DxvkNameSet DxvkPlatformExts::getDeviceExtensions(
+ uint32_t adapterId) {
+ return DxvkNameSet();
+ }
+
+
+ void DxvkPlatformExts::initInstanceExtensions() {
+
+ }
+
+
+ void DxvkPlatformExts::initDeviceExtensions(
+ const DxvkInstance* instance) {
+
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_1d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_1d.frag
new file mode 100644
index 00000000..2311c57c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_1d.frag
@@ -0,0 +1,19 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler1DArray s_texture;
+
+layout(location = 0) in vec2 i_pos;
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform push_block {
+ vec3 p_src_coord0;
+ vec3 p_src_coord1;
+ uint p_layer_count;
+};
+
+void main() {
+ float coord = mix(p_src_coord0.x, p_src_coord1.x, i_pos.x);
+ o_color = texture(s_texture, vec2(coord, gl_Layer));
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_2d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_2d.frag
new file mode 100644
index 00000000..b177c5ee
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_2d.frag
@@ -0,0 +1,19 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler2DArray s_texture;
+
+layout(location = 0) in vec2 i_pos;
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform push_block {
+ vec3 p_src_coord0;
+ vec3 p_src_coord1;
+ uint p_layer_count;
+};
+
+void main() {
+ vec2 coord = mix(p_src_coord0.xy, p_src_coord1.xy, i_pos);
+ o_color = texture(s_texture, vec3(coord, gl_Layer));
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_3d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_3d.frag
new file mode 100644
index 00000000..856855c6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_blit_frag_3d.frag
@@ -0,0 +1,20 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler3D s_texture;
+
+layout(location = 0) in vec2 i_pos;
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform push_block {
+ vec3 p_src_coord0;
+ vec3 p_src_coord1;
+ uint p_layer_count;
+};
+
+void main() {
+ vec3 coord = mix(p_src_coord0, p_src_coord1,
+ vec3(i_pos, (float(gl_Layer) + 0.5f) / float(p_layer_count)));
+ o_color = texture(s_texture, coord);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_f.comp
new file mode 100644
index 00000000..d682cb40
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 128,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform imageBuffer dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ int thread_id = int(gl_GlobalInvocationID.x);
+
+ if (thread_id < u_info.dst_extent.x) {
+ imageStore(dst,
+ u_info.dst_offset.x + thread_id,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_u.comp
new file mode 100644
index 00000000..97c1d0b0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_buffer_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 128,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform uimageBuffer dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ int thread_id = int(gl_GlobalInvocationID.x);
+
+ if (thread_id < u_info.dst_extent.x) {
+ imageStore(dst,
+ u_info.dst_offset.x + thread_id,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_f.comp
new file mode 100644
index 00000000..4170dd23
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image1D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (thread_id.x < u_info.dst_extent.x) {
+ imageStore(dst,
+ u_info.dst_offset.x + thread_id.x,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_u.comp
new file mode 100644
index 00000000..43b62833
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1d_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform uimage1D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (thread_id.x < u_info.dst_extent.x) {
+ imageStore(dst,
+ u_info.dst_offset.x + thread_id.x,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_f.comp
new file mode 100644
index 00000000..ae5749a2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image1DArray dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (thread_id.x < u_info.dst_extent.x) {
+ imageStore(dst,
+ ivec2(u_info.dst_offset.x + thread_id.x, thread_id.y),
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_u.comp
new file mode 100644
index 00000000..24dcdf87
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image1darr_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform uimage1DArray dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (thread_id.x < u_info.dst_extent.x) {
+ imageStore(dst,
+ ivec2(u_info.dst_offset.x + thread_id.x, thread_id.y),
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_f.comp
new file mode 100644
index 00000000..5a5e63f7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.dst_extent.xy))) {
+ imageStore(dst,
+ u_info.dst_offset.xy + thread_id.xy,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_u.comp
new file mode 100644
index 00000000..32eecabc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2d_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform uimage2D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.dst_extent.xy))) {
+ imageStore(dst,
+ u_info.dst_offset.xy + thread_id.xy,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_f.comp
new file mode 100644
index 00000000..4eec19cc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform image2DArray dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.dst_extent.xy))) {
+ imageStore(dst,
+ ivec3(u_info.dst_offset.xy + thread_id.xy, thread_id.z),
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_u.comp
new file mode 100644
index 00000000..c8babb78
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image2darr_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0)
+writeonly uniform uimage2DArray dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xy, u_info.dst_extent.xy))) {
+ imageStore(dst,
+ ivec3(u_info.dst_offset.xy + thread_id.xy, thread_id.z),
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_f.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_f.comp
new file mode 100644
index 00000000..2b38fb4f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_f.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 4,
+ local_size_y = 4,
+ local_size_z = 4) in;
+
+layout(binding = 0)
+writeonly uniform image3D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ vec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xyz, u_info.dst_extent.xyz))) {
+ imageStore(dst,
+ u_info.dst_offset.xyz + thread_id.xyz,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_u.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_u.comp
new file mode 100644
index 00000000..06db19a9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_clear_image3d_u.comp
@@ -0,0 +1,26 @@
+#version 450
+
+layout(
+ local_size_x = 4,
+ local_size_y = 4,
+ local_size_z = 4) in;
+
+layout(binding = 0)
+writeonly uniform uimage3D dst;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec4 clear_value;
+ ivec4 dst_offset;
+ ivec4 dst_extent;
+} u_info;
+
+void main() {
+ ivec3 thread_id = ivec3(gl_GlobalInvocationID);
+
+ if (all(lessThan(thread_id.xyz, u_info.dst_extent.xyz))) {
+ imageStore(dst,
+ u_info.dst_offset.xyz + thread_id.xyz,
+ u_info.clear_value);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_buffer_image.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_buffer_image.comp
new file mode 100644
index 00000000..7407285e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_buffer_image.comp
@@ -0,0 +1,30 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0) writeonly uniform uimageBuffer u_dst;
+layout(binding = 1) uniform usamplerBuffer u_src;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec3 dst_offset;
+ uvec3 src_offset;
+ uvec3 extent;
+ uvec2 dst_size;
+ uvec2 src_size;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID, u_info.extent))) {
+ uvec3 dst_coord = u_info.dst_offset + gl_GlobalInvocationID;
+ uvec3 src_coord = u_info.src_offset + gl_GlobalInvocationID;
+
+ uint dst_index = dst_coord.x + u_info.dst_size.x * (dst_coord.y + u_info.dst_size.y * dst_coord.z);
+ uint src_index = src_coord.x + u_info.src_size.x * (src_coord.y + u_info.src_size.y * src_coord.z);
+
+ imageStore(u_dst, int(dst_index), texelFetch(u_src, int(src_index)));
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_1d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_1d.frag
new file mode 100644
index 00000000..76e83dac
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_1d.frag
@@ -0,0 +1,16 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler1DArray s_image;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ o_color = texelFetch(s_image,
+ ivec2(gl_FragCoord.x + u_info.offset.x, gl_Layer), 0);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_2d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_2d.frag
new file mode 100644
index 00000000..db76c248
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_2d.frag
@@ -0,0 +1,16 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler2DArray s_image;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ o_color = texelFetch(s_image,
+ ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer), 0);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_ms.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_ms.frag
new file mode 100644
index 00000000..61b81241
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_color_ms.frag
@@ -0,0 +1,17 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler2DMSArray s_image;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ o_color = texelFetch(s_image,
+ ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer),
+ gl_SampleID);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_1d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_1d.frag
new file mode 100644
index 00000000..7150db10
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_1d.frag
@@ -0,0 +1,14 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler1DArray s_image;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ gl_FragDepth = texelFetch(s_image,
+ ivec2(gl_FragCoord.x + u_info.offset.x, gl_Layer), 0).r;
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_2d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_2d.frag
new file mode 100644
index 00000000..a5eaf4e9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_2d.frag
@@ -0,0 +1,14 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler2DArray s_image;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ gl_FragDepth = texelFetch(s_image,
+ ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer), 0).r;
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_ms.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_ms.frag
new file mode 100644
index 00000000..4264c038
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_ms.frag
@@ -0,0 +1,15 @@
+#version 450
+
+layout(set = 0, binding = 0)
+uniform sampler2DMSArray s_image;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ gl_FragDepth = texelFetch(s_image,
+ ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer),
+ gl_SampleID).r;
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_1d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_1d.frag
new file mode 100644
index 00000000..e017145d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_1d.frag
@@ -0,0 +1,20 @@
+#version 450
+
+#extension GL_ARB_shader_stencil_export : enable
+
+layout(set = 0, binding = 0)
+uniform sampler1DArray s_depth;
+
+layout(set = 0, binding = 1)
+uniform usampler1DArray s_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.x + u_info.offset.x, gl_Layer);
+ gl_FragDepth = texelFetch(s_depth, coord, 0).r;
+ gl_FragStencilRefARB = int(texelFetch(s_stencil, coord, 0).r);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_2d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_2d.frag
new file mode 100644
index 00000000..29e7d6b0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_2d.frag
@@ -0,0 +1,20 @@
+#version 450
+
+#extension GL_ARB_shader_stencil_export : enable
+
+layout(set = 0, binding = 0)
+uniform sampler2DArray s_depth;
+
+layout(set = 0, binding = 1)
+uniform usampler2DArray s_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset.xy, gl_Layer);
+ gl_FragDepth = texelFetch(s_depth, coord, 0).r;
+ gl_FragStencilRefARB = int(texelFetch(s_stencil, coord, 0).r);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_ms.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_ms.frag
new file mode 100644
index 00000000..dfb5f005
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_copy_depth_stencil_ms.frag
@@ -0,0 +1,20 @@
+#version 450
+
+#extension GL_ARB_shader_stencil_export : enable
+
+layout(set = 0, binding = 0)
+uniform sampler2DMSArray s_depth;
+
+layout(set = 0, binding = 1)
+uniform usampler2DMSArray s_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset.xy, gl_Layer);
+ gl_FragDepth = texelFetch(s_depth, coord, gl_SampleID).r;
+ gl_FragStencilRefARB = int(texelFetch(s_stencil, coord, gl_SampleID).r);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_geom.geom b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_geom.geom
new file mode 100644
index 00000000..c9fae0cc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_geom.geom
@@ -0,0 +1,19 @@
+#version 450
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices = 3) out;
+
+layout(location = 0) in int i_instance[3];
+layout(location = 1) in vec2 i_texcoord[3];
+layout(location = 0) out vec2 o_texcoord;
+
+void main() {
+ for (int i = 0; i < 3; i++) {
+ o_texcoord = i_texcoord[i];
+ gl_Layer = i_instance[i];
+ gl_Position = gl_in[i].gl_Position;
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_layer_vert.vert b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_layer_vert.vert
new file mode 100644
index 00000000..ee33749b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_layer_vert.vert
@@ -0,0 +1,15 @@
+#version 450
+
+#extension GL_ARB_shader_viewport_layer_array : enable
+
+layout(location = 0) out vec2 o_texcoord;
+
+void main() {
+ vec2 coord = vec2(
+ float(gl_VertexIndex & 2),
+ float(gl_VertexIndex & 1) * 2.0f);
+
+ o_texcoord = coord;
+ gl_Layer = gl_InstanceIndex;
+ gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_vert.vert b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_vert.vert
new file mode 100644
index 00000000..cf1856d0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_fullscreen_vert.vert
@@ -0,0 +1,14 @@
+#version 450
+
+layout(location = 0) out int o_instance;
+layout(location = 1) out vec2 o_texcoord;
+
+void main() {
+ vec2 coord = vec2(
+ float(gl_VertexIndex & 2),
+ float(gl_VertexIndex & 1) * 2.0f);
+
+ o_instance = gl_InstanceIndex;
+ o_texcoord = coord;
+ gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d24s8.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d24s8.comp
new file mode 100644
index 00000000..c32fae58
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d24s8.comp
@@ -0,0 +1,41 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+layout(binding = 0, std430)
+writeonly buffer s_buffer_t {
+ uint data[];
+} s_buffer;
+
+layout(binding = 1) uniform sampler2DArray u_depth;
+layout(binding = 2) uniform usampler2DArray u_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 src_offset;
+ uvec2 src_extent;
+ uvec2 dst_offset;
+ uvec2 dst_extent;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID.xy, u_info.src_extent))) {
+ uvec3 src_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.src_offset,
+ gl_GlobalInvocationID.z);
+
+ uvec3 dst_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.dst_offset,
+ gl_GlobalInvocationID.z);
+
+ uint dst_index = dst_coord.x + u_info.dst_extent.x * (dst_coord.y + u_info.dst_extent.y * dst_coord.z);
+
+ float depth = texelFetch(u_depth, ivec3(src_coord), 0).r;
+ uint stencil = texelFetch(u_stencil, ivec3(src_coord), 0).r;
+
+ s_buffer.data[dst_index] = uint(mix(0.0f, float((1 << 24) - 1), depth)) | (stencil << 24);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d32s8.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d32s8.comp
new file mode 100644
index 00000000..a0332f02
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_pack_d32s8.comp
@@ -0,0 +1,44 @@
+#version 450
+
+layout(
+ local_size_x = 8,
+ local_size_y = 8,
+ local_size_z = 1) in;
+
+struct d32s8_t {
+ float d32;
+ uint s8;
+};
+
+layout(binding = 0, std430)
+writeonly buffer s_buffer_t {
+ d32s8_t data[];
+} s_buffer;
+
+layout(binding = 1) uniform sampler2DArray u_depth;
+layout(binding = 2) uniform usampler2DArray u_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 src_offset;
+ uvec2 src_extent;
+ uvec2 dst_offset;
+ uvec2 dst_extent;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID.xy, u_info.src_extent))) {
+ uvec3 src_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.src_offset,
+ gl_GlobalInvocationID.z);
+
+ uvec3 dst_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.dst_offset,
+ gl_GlobalInvocationID.z);
+
+ uint dst_index = dst_coord.x + u_info.dst_extent.x * (dst_coord.y + u_info.dst_extent.y * dst_coord.z);
+
+ s_buffer.data[dst_index].d32 = texelFetch(u_depth, ivec3(src_coord), 0).r;
+ s_buffer.data[dst_index].s8 = texelFetch(u_stencil, ivec3(src_coord), 0).r;
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag.frag
new file mode 100644
index 00000000..7498a407
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag.frag
@@ -0,0 +1,27 @@
+#version 450
+
+layout(constant_id = 1) const bool s_gamma_bound = true;
+
+layout(binding = 0) uniform sampler2D s_image;
+layout(binding = 1) uniform sampler1D s_gamma;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform present_info_t {
+ ivec2 src_offset;
+ ivec2 dst_offset;
+};
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
+ o_color = texelFetch(s_image, coord, 0);
+
+ if (s_gamma_bound) {
+ o_color = vec4(
+ texture(s_gamma, o_color.r).r,
+ texture(s_gamma, o_color.g).g,
+ texture(s_gamma, o_color.b).b,
+ o_color.a);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_blit.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_blit.frag
new file mode 100644
index 00000000..c5b66069
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_blit.frag
@@ -0,0 +1,28 @@
+#version 450
+
+layout(constant_id = 1) const bool s_gamma_bound = true;
+
+layout(binding = 0) uniform sampler2D s_image;
+layout(binding = 1) uniform sampler1D s_gamma;
+
+layout(location = 0) in vec2 i_coord;
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform present_info_t {
+ ivec2 src_offset;
+ uvec2 src_extent;
+};
+
+void main() {
+ vec2 coord = vec2(src_offset) + vec2(src_extent) * i_coord;
+ o_color = textureLod(s_image, coord, 0.0f);
+
+ if (s_gamma_bound) {
+ o_color = vec4(
+ texture(s_gamma, o_color.r).r,
+ texture(s_gamma, o_color.g).g,
+ texture(s_gamma, o_color.b).b,
+ o_color.a);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms.frag
new file mode 100644
index 00000000..9dd751ec
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms.frag
@@ -0,0 +1,33 @@
+#version 450
+
+layout(constant_id = 1) const bool s_gamma_bound = true;
+layout(constant_id = 1225) const uint c_samples = 0;
+
+layout(binding = 0) uniform sampler2DMS s_image;
+layout(binding = 1) uniform sampler1D s_gamma;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform present_info_t {
+ ivec2 src_offset;
+ ivec2 dst_offset;
+};
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
+ o_color = texelFetch(s_image, coord, 0);
+
+ for (uint i = 1; i < c_samples; i++)
+ o_color += texelFetch(s_image, coord, int(i));
+
+ o_color /= float(c_samples);
+
+ if (s_gamma_bound) {
+ o_color = vec4(
+ texture(s_gamma, o_color.r).r,
+ texture(s_gamma, o_color.g).g,
+ texture(s_gamma, o_color.b).b,
+ o_color.a);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms_amd.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms_amd.frag
new file mode 100644
index 00000000..c234591f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_frag_ms_amd.frag
@@ -0,0 +1,52 @@
+#version 450
+
+#extension GL_AMD_shader_fragment_mask: enable
+
+layout(constant_id = 1) const bool s_gamma_bound = true;
+layout(constant_id = 1225) const uint c_samples = 0;
+
+layout(binding = 0) uniform sampler2DMS s_image;
+layout(binding = 1) uniform sampler1D s_gamma;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform present_info_t {
+ ivec2 src_offset;
+ ivec2 dst_offset;
+};
+
+void main() {
+ ivec2 coord = ivec2(gl_FragCoord.xy) + src_offset - dst_offset;
+
+ // check dxvk_resolve_frag_f_amd.frag for documentation
+ uint fragMask = fragmentMaskFetchAMD(s_image, coord);
+ uint fragCount = 0u;
+
+ for (int i = 0; i < 4 * c_samples; i += 4) {
+ uint fragIndex = bitfieldExtract(fragMask, i, 4);
+ fragCount += 1u << (fragIndex << 2);
+ }
+
+ o_color = vec4(0.0f);
+
+ while (fragCount != 0) {
+ int fragIndex = findLSB(fragCount) >> 2;
+ int fragShift = fragIndex << 2;
+
+ o_color += fragmentFetchAMD(s_image, coord, fragIndex)
+ * float(bitfieldExtract(fragCount, fragShift, 4));
+
+ fragCount = bitfieldInsert(fragCount, 0, fragShift, 4);
+ }
+
+ o_color /= float(c_samples);
+
+ if (s_gamma_bound) {
+ o_color = vec4(
+ texture(s_gamma, o_color.r).r,
+ texture(s_gamma, o_color.g).g,
+ texture(s_gamma, o_color.b).b,
+ o_color.a);
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_vert.vert b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_vert.vert
new file mode 100644
index 00000000..753a16f8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_present_vert.vert
@@ -0,0 +1,12 @@
+#version 450
+
+layout(location = 0) out vec2 o_coord;
+
+void main() {
+ vec2 coord = vec2(
+ float(gl_VertexIndex & 2),
+ float(gl_VertexIndex & 1) * 2.0f);
+
+ o_coord = coord;
+ gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_d.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_d.frag
new file mode 100644
index 00000000..0b726c97
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_d.frag
@@ -0,0 +1,54 @@
+#version 450
+
+#define VK_RESOLVE_MODE_NONE_KHR (0)
+#define VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR (1 << 0)
+#define VK_RESOLVE_MODE_AVERAGE_BIT_KHR (1 << 1)
+#define VK_RESOLVE_MODE_MIN_BIT_KHR (1 << 2)
+#define VK_RESOLVE_MODE_MAX_BIT_KHR (1 << 3)
+
+layout(constant_id = 0) const int c_samples = 1;
+layout(constant_id = 1) const int c_mode_d = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;
+
+layout(binding = 0) uniform sampler2DMSArray s_depth;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+float resolve_depth(ivec3 coord) {
+ float depth = 0.0f;
+
+ switch (c_mode_d) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ break;
+
+ case VK_RESOLVE_MODE_AVERAGE_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth += texelFetch(s_depth, coord, i).r;
+ depth /= float(c_samples);
+ break;
+
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth = min(depth, texelFetch(s_depth, coord, i).r);
+ break;
+
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth = max(depth, texelFetch(s_depth, coord, i).r);
+ break;
+ }
+
+ return depth;
+}
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+
+ gl_FragDepth = resolve_depth(coord);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag
new file mode 100644
index 00000000..734fe0fb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_ds.frag
@@ -0,0 +1,83 @@
+#version 450
+
+#extension GL_ARB_shader_stencil_export : enable
+
+#define VK_RESOLVE_MODE_NONE_KHR (0)
+#define VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR (1 << 0)
+#define VK_RESOLVE_MODE_AVERAGE_BIT_KHR (1 << 1)
+#define VK_RESOLVE_MODE_MIN_BIT_KHR (1 << 2)
+#define VK_RESOLVE_MODE_MAX_BIT_KHR (1 << 3)
+
+layout(constant_id = 0) const int c_samples = 1;
+layout(constant_id = 1) const int c_mode_d = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;
+layout(constant_id = 2) const int c_mode_s = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR;
+
+layout(binding = 0) uniform sampler2DMSArray s_depth;
+layout(binding = 1) uniform usampler2DMSArray s_stencil;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+float resolve_depth(ivec3 coord) {
+ float depth = 0.0f;
+
+ switch (c_mode_d) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ break;
+
+ case VK_RESOLVE_MODE_AVERAGE_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth += texelFetch(s_depth, coord, i).r;
+ depth /= float(c_samples);
+ break;
+
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth = min(depth, texelFetch(s_depth, coord, i).r);
+ break;
+
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ depth = texelFetch(s_depth, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ depth = max(depth, texelFetch(s_depth, coord, i).r);
+ break;
+ }
+
+ return depth;
+}
+
+int resolve_stencil(ivec3 coord) {
+ uint stencil = 0u;
+
+ switch (c_mode_s) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR:
+ stencil = texelFetch(s_stencil, coord, 0).r;
+ break;
+
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ stencil = texelFetch(s_stencil, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ stencil = min(stencil, texelFetch(s_stencil, coord, i).r);
+ break;
+
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ stencil = texelFetch(s_stencil, coord, 0).r;
+ for (int i = 1; i < c_samples; i++)
+ stencil = max(stencil, texelFetch(s_stencil, coord, i).r);
+ break;
+ }
+
+ return int(stencil);
+}
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+
+ gl_FragDepth = resolve_depth(coord);
+ gl_FragStencilRefARB = resolve_stencil(coord);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f.frag
new file mode 100644
index 00000000..645a2f9b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f.frag
@@ -0,0 +1,20 @@
+#version 450
+
+layout(constant_id = 0) const int c_samples = 1;
+
+layout(binding = 0) uniform sampler2DMSArray s_image;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+ vec4 color = vec4(0.0f);
+ for (int i = 0; i < c_samples; i++)
+ color += texelFetch(s_image, coord, i);
+ o_color = color / float(c_samples);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag
new file mode 100644
index 00000000..a9cf9ee4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag
@@ -0,0 +1,47 @@
+#version 450
+
+#extension GL_AMD_shader_fragment_mask: enable
+
+layout(constant_id = 0) const int c_samples = 1;
+
+layout(set = 0, binding = 0)
+uniform sampler2DMSArray s_image;
+
+layout(location = 0) out vec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+
+ // get a four-bit fragment index for each sample
+ uint fragMask = fragmentMaskFetchAMD(s_image, coord);
+
+ // count number of occurences of each fragment
+ // index in one four-bit counter for each sample
+ uint fragCount = 0u;
+
+ for (int i = 0; i < 4 * c_samples; i += 4) {
+ uint fragIndex = bitfieldExtract(fragMask, i, 4);
+ fragCount += 1u << (fragIndex << 2);
+ }
+
+ // perform necessary texture lookups to compute
+ // final fragment color
+ o_color = vec4(0.0f);
+
+ while (fragCount != 0) {
+ int fragIndex = findLSB(fragCount) >> 2;
+ int fragShift = fragIndex << 2;
+
+ o_color += fragmentFetchAMD(s_image, coord, fragIndex)
+ * float(bitfieldExtract(fragCount, fragShift, 4));
+
+ fragCount = bitfieldInsert(fragCount, 0, fragShift, 4);
+ }
+
+ o_color /= float(c_samples);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_i.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_i.frag
new file mode 100644
index 00000000..021980d6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_i.frag
@@ -0,0 +1,15 @@
+#version 450
+
+layout(binding = 0) uniform isampler2DMSArray s_image;
+
+layout(location = 0) out ivec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+ o_color = texelFetch(s_image, coord, 0);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_u.frag b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_u.frag
new file mode 100644
index 00000000..3d3cfdf3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_resolve_frag_u.frag
@@ -0,0 +1,15 @@
+#version 450
+
+layout(binding = 0) uniform usampler2DMSArray s_image;
+
+layout(location = 0) out uvec4 o_color;
+
+layout(push_constant)
+uniform u_info_t {
+ ivec2 offset;
+} u_info;
+
+void main() {
+ ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
+ o_color = texelFetch(s_image, coord, 0);
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8.comp
new file mode 100644
index 00000000..6b7a8557
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8.comp
@@ -0,0 +1,41 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0, r32ui) writeonly uniform uimageBuffer u_depth;
+layout(binding = 1, r8ui) writeonly uniform uimageBuffer u_stencil;
+
+layout(binding = 2)
+readonly buffer s_buffer_t {
+ uint data[];
+} s_buffer;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 src_offset;
+ uvec2 src_extent;
+ uvec2 dst_offset;
+ uvec2 dst_extent;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID.xy, u_info.dst_extent))) {
+ uvec3 src_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.src_offset,
+ gl_GlobalInvocationID.z);
+
+ uvec3 dst_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.dst_offset,
+ gl_GlobalInvocationID.z);
+
+ uint src_index = src_coord.x + u_info.src_extent.x * (src_coord.y + u_info.src_extent.y * src_coord.z);
+ uint dst_index = dst_coord.x + u_info.dst_extent.x * (dst_coord.y + u_info.dst_extent.y * dst_coord.z);
+
+ uint src_data = s_buffer.data[src_index];
+ imageStore(u_depth, int(dst_index), uvec4(src_data & 0xFFFFFF));
+ imageStore(u_stencil, int(dst_index), uvec4(src_data >> 24));
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8_as_d32s8.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8_as_d32s8.comp
new file mode 100644
index 00000000..4c87fbba
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d24s8_as_d32s8.comp
@@ -0,0 +1,41 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+layout(binding = 0, r32f) writeonly uniform imageBuffer u_depth;
+layout(binding = 1, r8ui) writeonly uniform uimageBuffer u_stencil;
+
+layout(binding = 2)
+readonly buffer s_buffer_t {
+ uint data[];
+} s_buffer;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 src_offset;
+ uvec2 src_extent;
+ uvec2 dst_offset;
+ uvec2 dst_extent;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID.xy, u_info.dst_extent))) {
+ uvec3 src_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.src_offset,
+ gl_GlobalInvocationID.z);
+
+ uvec3 dst_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.dst_offset,
+ gl_GlobalInvocationID.z);
+
+ uint src_index = src_coord.x + u_info.src_extent.x * (src_coord.y + u_info.src_extent.y * src_coord.z);
+ uint dst_index = dst_coord.x + u_info.dst_extent.x * (dst_coord.y + u_info.dst_extent.y * dst_coord.z);
+
+ uint src_data = s_buffer.data[src_index];
+ imageStore(u_depth, int(dst_index), vec4(float(src_data & 0xFFFFFF) / float(0xFFFFFF)));
+ imageStore(u_stencil, int(dst_index), uvec4(src_data >> 24));
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d32s8.comp b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d32s8.comp
new file mode 100644
index 00000000..dd114746
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/dxvk/shaders/dxvk_unpack_d32s8.comp
@@ -0,0 +1,46 @@
+#version 450
+
+layout(
+ local_size_x = 64,
+ local_size_y = 1,
+ local_size_z = 1) in;
+
+struct d32s8_t {
+ float d32;
+ uint s8;
+};
+
+layout(binding = 0, r32f) writeonly uniform imageBuffer u_depth;
+layout(binding = 1, r8ui) writeonly uniform uimageBuffer u_stencil;
+
+layout(binding = 2)
+readonly buffer s_buffer_t {
+ d32s8_t data[];
+} s_buffer;
+
+layout(push_constant)
+uniform u_info_t {
+ uvec2 src_offset;
+ uvec2 src_extent;
+ uvec2 dst_offset;
+ uvec2 dst_extent;
+} u_info;
+
+void main() {
+ if (all(lessThan(gl_GlobalInvocationID.xy, u_info.dst_extent))) {
+ uvec3 src_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.src_offset,
+ gl_GlobalInvocationID.z);
+
+ uvec3 dst_coord = uvec3(
+ gl_GlobalInvocationID.xy + u_info.dst_offset,
+ gl_GlobalInvocationID.z);
+
+ uint src_index = src_coord.x + u_info.src_extent.x * (src_coord.y + u_info.src_extent.y * src_coord.z);
+ uint dst_index = dst_coord.x + u_info.dst_extent.x * (dst_coord.y + u_info.dst_extent.y * dst_coord.z);
+
+ d32s8_t src_data = s_buffer.data[src_index];
+ imageStore(u_depth, int(dst_index), vec4(src_data.d32));
+ imageStore(u_stencil, int(dst_index), uvec4(src_data.s8));
+ }
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/meson.build b/src/libs/dxvk-native-1.9.2a/src/meson.build
new file mode 100644
index 00000000..895eae2a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/meson.build
@@ -0,0 +1,48 @@
+subdir('util')
+subdir('spirv')
+subdir('wsi')
+subdir('vulkan')
+subdir('dxvk')
+
+enable_dxgi = get_option('enable_dxgi')
+enable_d3d9 = get_option('enable_d3d9')
+enable_d3d10 = get_option('enable_d3d10')
+enable_d3d11 = get_option('enable_d3d11')
+enable_tests = get_option('enable_tests')
+
+if enable_d3d10 and dxvk_native
+ warning('Ignoring D3D10... Not supported for DXVK native.')
+ enable_d3d10 = false
+endif
+
+if enable_dxgi
+ if not enable_d3d11
+ error('D3D11 is required for DXGI.')
+ endif
+ subdir('dxgi')
+endif
+
+if enable_d3d10 or enable_d3d11 or enable_tests
+ subdir('dxbc')
+endif
+
+if enable_d3d11
+ subdir('d3d11')
+endif
+
+if enable_d3d10
+ if not enable_d3d11
+ error('D3D11 is required for D3D10.')
+ endif
+ subdir('d3d10')
+endif
+
+if enable_d3d9
+ subdir('dxso')
+ subdir('d3d9')
+endif
+
+# Nothing selected
+if not enable_d3d9 and not enable_d3d10 and not enable_d3d11 and not enable_tests
+ warning('Nothing selected to be built. Are you missing a frontend or tests?')
+endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/meson.build b/src/libs/dxvk-native-1.9.2a/src/spirv/meson.build
new file mode 100644
index 00000000..7c180f98
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/meson.build
@@ -0,0 +1,9 @@
+spirv_src = files([
+ 'spirv_code_buffer.cpp',
+ 'spirv_compression.cpp',
+ 'spirv_module.cpp',
+])
+
+spirv_lib = static_library('spirv', spirv_src,
+ include_directories : [ dxvk_include_path ],
+ override_options : ['cpp_std='+dxvk_cpp_std])
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.cpp b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.cpp
new file mode 100644
index 00000000..74d8dd97
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.cpp
@@ -0,0 +1,154 @@
+#include <array>
+#include <cstring>
+
+#include "spirv_code_buffer.h"
+
+namespace dxvk {
+
+ SpirvCodeBuffer:: SpirvCodeBuffer() { }
+ SpirvCodeBuffer::~SpirvCodeBuffer() { }
+
+
+ SpirvCodeBuffer::SpirvCodeBuffer(uint32_t size)
+ : m_ptr(size) {
+ m_code.resize(size);
+ }
+
+
+ SpirvCodeBuffer::SpirvCodeBuffer(uint32_t size, const uint32_t* data)
+ : m_ptr(size) {
+ m_code.resize(size);
+ std::memcpy(m_code.data(), data, size * sizeof(uint32_t));
+ }
+
+
+ SpirvCodeBuffer::SpirvCodeBuffer(std::istream& stream) {
+ stream.ignore(std::numeric_limits<std::streamsize>::max());
+ std::streamsize length = stream.gcount();
+ stream.clear();
+ stream.seekg(0, std::ios_base::beg);
+
+ std::vector<char> buffer(length);
+ stream.read(buffer.data(), length);
+ buffer.resize(stream.gcount());
+
+ m_code.resize(buffer.size() / sizeof(uint32_t));
+ std::memcpy(reinterpret_cast<char*>(m_code.data()),
+ buffer.data(), m_code.size() * sizeof(uint32_t));
+
+ m_ptr = m_code.size();
+ }
+
+
+ uint32_t SpirvCodeBuffer::allocId() {
+ constexpr size_t BoundIdsOffset = 3;
+
+ if (m_code.size() <= BoundIdsOffset)
+ return 0;
+
+ return m_code[BoundIdsOffset]++;
+ }
+
+
+ void SpirvCodeBuffer::append(const SpirvCodeBuffer& other) {
+ if (other.size() != 0) {
+ const size_t size = m_code.size();
+ m_code.resize(size + other.m_code.size());
+
+ uint32_t* dst = this->m_code.data();
+ const uint32_t* src = other.m_code.data();
+
+ std::memcpy(dst + size, src, other.size());
+ m_ptr += other.m_code.size();
+ }
+ }
+
+
+ void SpirvCodeBuffer::putWord(uint32_t word) {
+ m_code.insert(m_code.begin() + m_ptr, word);
+ m_ptr += 1;
+ }
+
+
+ void SpirvCodeBuffer::putIns(spv::Op opCode, uint16_t wordCount) {
+ this->putWord(
+ (static_cast<uint32_t>(opCode) << 0)
+ | (static_cast<uint32_t>(wordCount) << 16));
+ }
+
+
+ void SpirvCodeBuffer::putInt32(uint32_t word) {
+ this->putWord(word);
+ }
+
+
+ void SpirvCodeBuffer::putInt64(uint64_t value) {
+ this->putWord(value >> 0);
+ this->putWord(value >> 32);
+ }
+
+
+ void SpirvCodeBuffer::putFloat32(float value) {
+ uint32_t tmp;
+ static_assert(sizeof(tmp) == sizeof(value));
+ std::memcpy(&tmp, &value, sizeof(value));
+ this->putInt32(tmp);
+ }
+
+
+ void SpirvCodeBuffer::putFloat64(double value) {
+ uint64_t tmp;
+ static_assert(sizeof(tmp) == sizeof(value));
+ std::memcpy(&tmp, &value, sizeof(value));
+ this->putInt64(tmp);
+ }
+
+
+ void SpirvCodeBuffer::putStr(const char* str) {
+ uint32_t word = 0;
+ uint32_t nbit = 0;
+
+ for (uint32_t i = 0; str[i] != '\0'; str++) {
+ word |= (static_cast<uint32_t>(str[i]) & 0xFF) << nbit;
+
+ if ((nbit += 8) == 32) {
+ this->putWord(word);
+ word = 0;
+ nbit = 0;
+ }
+ }
+
+ // Commit current word
+ this->putWord(word);
+ }
+
+
+ void SpirvCodeBuffer::putHeader(uint32_t version, uint32_t boundIds) {
+ this->putWord(spv::MagicNumber);
+ this->putWord(version);
+ this->putWord(0); // Generator
+ this->putWord(boundIds);
+ this->putWord(0); // Schema
+ }
+
+
+ void SpirvCodeBuffer::erase(size_t size) {
+ m_code.erase(
+ m_code.begin() + m_ptr,
+ m_code.begin() + m_ptr + size);
+ }
+
+
+ uint32_t SpirvCodeBuffer::strLen(const char* str) {
+ // Null-termination plus padding
+ return (std::strlen(str) + 4) / 4;
+ }
+
+
+ void SpirvCodeBuffer::store(std::ostream& stream) const {
+ stream.write(
+ reinterpret_cast<const char*>(m_code.data()),
+ sizeof(uint32_t) * m_code.size());
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.h b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.h
new file mode 100644
index 00000000..a06b594c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_code_buffer.h
@@ -0,0 +1,223 @@
+#pragma once
+
+#include <spirv/spirv.hpp>
+
+#include <iostream>
+#include <vector>
+
+#include "spirv_instruction.h"
+
+namespace dxvk {
+
+ /**
+ * \brief SPIR-V code buffer
+ *
+ * Helper class for generating SPIR-V shaders.
+ * Stores arbitrary SPIR-V instructions in a
+ * format that can be read by Vulkan drivers.
+ */
+ class SpirvCodeBuffer {
+
+ public:
+
+ SpirvCodeBuffer();
+ explicit SpirvCodeBuffer(uint32_t size);
+ SpirvCodeBuffer(uint32_t size, const uint32_t* data);
+ SpirvCodeBuffer(std::istream& stream);
+
+ template<size_t N>
+ SpirvCodeBuffer(const uint32_t (&data)[N])
+ : SpirvCodeBuffer(N, data) { }
+
+ ~SpirvCodeBuffer();
+
+ /**
+ * \brief Code data
+ * \returns Code data
+ */
+ const uint32_t* data() const { return m_code.data(); }
+ uint32_t* data() { return m_code.data(); }
+
+ /**
+ * \brief Code size, in dwords
+ * \returns Code size, in dwords
+ */
+ uint32_t dwords() const {
+ return m_code.size();
+ }
+
+ /**
+ * \brief Code size, in bytes
+ * \returns Code size, in bytes
+ */
+ size_t size() const {
+ return m_code.size() * sizeof(uint32_t);
+ }
+
+ /**
+ * \brief Begin instruction iterator
+ *
+ * Points to the first instruction in the instruction
+ * block. The header, if any, will be skipped over.
+ * \returns Instruction iterator
+ */
+ SpirvInstructionIterator begin() {
+ return SpirvInstructionIterator(
+ m_code.data(), 0, m_code.size());
+ }
+
+ /**
+ * \brief End instruction iterator
+ *
+ * Points to the end of the instruction block.
+ * \returns Instruction iterator
+ */
+ SpirvInstructionIterator end() {
+ return SpirvInstructionIterator(nullptr, 0, 0);
+ }
+
+ /**
+ * \brief Allocates a new ID
+ *
+ * Returns a new valid ID and increments the
+ * maximum ID count stored in the header.
+ * \returns The new SPIR-V ID
+ */
+ uint32_t allocId();
+
+ /**
+ * \brief Merges two code buffers
+ *
+ * This is useful to generate declarations or
+ * the SPIR-V header at the same time as the
+ * code when doing so in advance is impossible.
+ * \param [in] other Code buffer to append
+ */
+ void append(const SpirvCodeBuffer& other);
+
+ /**
+ * \brief Appends an 32-bit word to the buffer
+ * \param [in] word The word to append
+ */
+ void putWord(uint32_t word);
+
+ /**
+ * \brief Appends an instruction word to the buffer
+ *
+ * Adds a single word containing both the word count
+ * and the op code number for a single instruction.
+ * \param [in] opCode Operand code
+ * \param [in] wordCount Number of words
+ */
+ void putIns(spv::Op opCode, uint16_t wordCount);
+
+ /**
+ * \brief Appends a 32-bit integer to the buffer
+ * \param [in] value The number to add
+ */
+ void putInt32(uint32_t word);
+
+ /**
+ * \brief Appends a 64-bit integer to the buffer
+ *
+ * A 64-bit integer will take up two 32-bit words.
+ * \param [in] value 64-bit value to add
+ */
+ void putInt64(uint64_t value);
+
+ /**
+ * \brief Appends a 32-bit float to the buffer
+ * \param [in] value The number to add
+ */
+ void putFloat32(float value);
+
+ /**
+ * \brief Appends a 64-bit float to the buffer
+ * \param [in] value The number to add
+ */
+ void putFloat64(double value);
+
+ /**
+ * \brief Appends a literal string to the buffer
+ * \param [in] str String to append to the buffer
+ */
+ void putStr(const char* str);
+
+ /**
+ * \brief Adds the header to the buffer
+ *
+ * \param [in] version SPIR-V version
+ * \param [in] boundIds Number of bound IDs
+ */
+ void putHeader(uint32_t version, uint32_t boundIds);
+
+ /**
+ * \brief Erases given number of dwords
+ *
+ * Removes data from the code buffer, starting
+ * at the current insertion offset.
+ * \param [in] size Number of words to remove
+ */
+ void erase(size_t size);
+
+ /**
+ * \brief Computes length of a literal string
+ *
+ * \param [in] str The string to check
+ * \returns Number of words consumed by a string
+ */
+ uint32_t strLen(const char* str);
+
+ /**
+ * \brief Stores the SPIR-V module to a stream
+ *
+ * The ability to save modules to a file
+ * exists mostly for debugging purposes.
+ * \param [in] stream Output stream
+ */
+ void store(std::ostream& stream) const;
+
+ /**
+ * \brief Retrieves current insertion pointer
+ *
+ * Sometimes it may be necessay to insert code into the
+ * middle of the stream rather than appending it. This
+ * retrieves the current function pointer. Note that the
+ * pointer will become invalid if any code is inserted
+ * before the current pointer location.
+ * \returns Current instruction pointr
+ */
+ size_t getInsertionPtr() const {
+ return m_ptr;
+ }
+
+ /**
+ * \brief Sets insertion pointer to a specific value
+ *
+ * Sets the insertion pointer to a value that was
+ * previously retrieved by \ref getInsertionPtr.
+ * \returns Current instruction pointr
+ */
+ void beginInsertion(size_t ptr) {
+ m_ptr = ptr;
+ }
+
+ /**
+ * \brief Sets insertion pointer to the end
+ *
+ * After this call, new instructions will be
+ * appended to the stream. In other words,
+ * this will restore default behaviour.
+ */
+ void endInsertion() {
+ m_ptr = m_code.size();
+ }
+
+ private:
+
+ std::vector<uint32_t> m_code;
+ size_t m_ptr = 0;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.cpp b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.cpp
new file mode 100644
index 00000000..6c3f6875
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.cpp
@@ -0,0 +1,110 @@
+#include "spirv_compression.h"
+
+namespace dxvk {
+
+ SpirvCompressedBuffer::SpirvCompressedBuffer()
+ : m_size(0) {
+
+ }
+
+
+ SpirvCompressedBuffer::SpirvCompressedBuffer(
+ const SpirvCodeBuffer& code)
+ : m_size(code.dwords()) {
+ const uint32_t* data = code.data();
+
+ // The compression works by eliminating leading null bytes
+ // from DWORDs, exploiting that SPIR-V IDs are consecutive
+ // integers that usually fall into the 16-bit range. For
+ // each DWORD, a two-bit integer is stored which indicates
+ // the number of bytes it takes in the compressed buffer.
+ // This way, it can achieve a compression ratio of ~50%.
+ m_mask.reserve((m_size + NumMaskWords - 1) / NumMaskWords);
+ m_code.reserve((m_size + 1) / 2);
+
+ uint64_t dstWord = 0;
+ uint32_t dstShift = 0;
+
+ for (uint32_t i = 0; i < m_size; i += NumMaskWords) {
+ uint64_t byteCounts = 0;
+
+ for (uint32_t w = 0; w < NumMaskWords && i + w < m_size; w++) {
+ uint64_t word = data[i + w];
+ uint64_t bytes = 0;
+
+ if (word < (1 << 8)) bytes = 0;
+ else if (word < (1 << 16)) bytes = 1;
+ else if (word < (1 << 24)) bytes = 2;
+ else bytes = 3;
+
+ byteCounts |= bytes << (2 * w);
+
+ uint32_t bits = 8 * bytes + 8;
+ uint32_t rem = bit::pack(dstWord, dstShift, word, bits);
+
+ if (unlikely(rem != 0)) {
+ m_code.push_back(dstWord);
+
+ dstWord = 0;
+ dstShift = 0;
+
+ bit::pack(dstWord, dstShift, word >> (bits - rem), rem);
+ }
+ }
+
+ m_mask.push_back(byteCounts);
+ }
+
+ if (dstShift)
+ m_code.push_back(dstWord);
+
+ m_mask.shrink_to_fit();
+ m_code.shrink_to_fit();
+ }
+
+
+ SpirvCompressedBuffer::~SpirvCompressedBuffer() {
+
+ }
+
+
+ SpirvCodeBuffer SpirvCompressedBuffer::decompress() const {
+ SpirvCodeBuffer code(m_size);
+ uint32_t* data = code.data();
+
+ if (m_size == 0)
+ return code;
+
+ uint32_t maskIdx = 0;
+ uint32_t codeIdx = 0;
+
+ uint64_t srcWord = m_code[codeIdx++];
+ uint32_t srcShift = 0;
+
+ for (uint32_t i = 0; i < m_size; i += NumMaskWords) {
+ uint64_t srcMask = m_mask[maskIdx++];
+
+ for (uint32_t w = 0; w < NumMaskWords && i + w < m_size; w++) {
+ uint32_t bits = 8 * ((srcMask & 3) + 1);
+
+ uint64_t word = 0;
+ uint32_t rem = bit::unpack(word, srcWord, srcShift, bits);
+
+ if (unlikely(rem != 0)) {
+ srcWord = m_code[codeIdx++];
+ srcShift = 0;
+
+ uint64_t tmp = 0;
+ bit::unpack(tmp, srcWord, srcShift, rem);
+ word |= tmp << (bits - rem);
+ }
+
+ data[i + w] = word;
+ srcMask >>= 2;
+ }
+ }
+
+ return code;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.h b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.h
new file mode 100644
index 00000000..7a1276c8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_compression.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <vector>
+
+#include "spirv_code_buffer.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Compressed SPIR-V code buffer
+ *
+ * Implements a fast in-memory compression
+ * to keep memory footprint low.
+ */
+ class SpirvCompressedBuffer {
+ constexpr static uint32_t NumMaskWords = 32;
+ public:
+
+ SpirvCompressedBuffer();
+
+ SpirvCompressedBuffer(
+ const SpirvCodeBuffer& code);
+
+ ~SpirvCompressedBuffer();
+
+ SpirvCodeBuffer decompress() const;
+
+ private:
+
+ uint32_t m_size;
+ std::vector<uint64_t> m_mask;
+ std::vector<uint64_t> m_code;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_include.h b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_include.h
new file mode 100644
index 00000000..fca94181
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_include.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "../util/log/log.h"
+#include "../util/log/log_debug.h"
+
+#include "../util/util_error.h"
+#include "../util/util_flags.h"
+#include "../util/util_likely.h"
+#include "../util/util_string.h"
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_instruction.h b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_instruction.h
new file mode 100644
index 00000000..061d5ab7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_instruction.h
@@ -0,0 +1,155 @@
+#pragma once
+
+#include <spirv/spirv.hpp>
+#include <spirv/GLSL.std.450.hpp>
+
+#include "spirv_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief SPIR-V instruction
+ *
+ * Helps parsing a single instruction, providing
+ * access to the op code, instruction length and
+ * instruction arguments.
+ */
+ class SpirvInstruction {
+
+ public:
+
+ SpirvInstruction() { }
+ SpirvInstruction(uint32_t* code, uint32_t offset, uint32_t length)
+ : m_code(code), m_offset(offset), m_length(length) { }
+
+ /**
+ * \brief SPIR-V Op code
+ * \returns The op code
+ */
+ spv::Op opCode() const {
+ return static_cast<spv::Op>(
+ this->arg(0) & spv::OpCodeMask);
+ }
+
+ /**
+ * \brief Instruction length
+ * \returns Number of DWORDs
+ */
+ uint32_t length() const {
+ return this->arg(0) >> spv::WordCountShift;
+ }
+
+ /**
+ * \brief Instruction offset
+ * \returns Offset in DWORDs
+ */
+ uint32_t offset() const {
+ return m_offset;
+ }
+
+ /**
+ * \brief Argument value
+ *
+ * Retrieves an argument DWORD. Note that some instructions
+ * take 64-bit arguments which require more than one DWORD.
+ * Arguments start at index 1. Calling this method with an
+ * argument ID of 0 will return the opcode token.
+ * \param [in] idx Argument index, starting at 1
+ * \returns The argument value
+ */
+ uint32_t arg(uint32_t idx) const {
+ const uint32_t index = m_offset + idx;
+ return index < m_length ? m_code[index] : 0;
+ }
+
+ /**
+ * \brief Argument string
+ *
+ * Retrieves a pointer to a UTF-8-encoded string.
+ * \param [in] idx Argument index, starting at 1
+ * \returns Pointer to the literal string
+ */
+ const char* chr(uint32_t idx) const {
+ const uint32_t index = m_offset + idx;
+ return index < m_length ? reinterpret_cast<const char*>(&m_code[index]) : nullptr;
+ }
+
+ /**
+ * \brief Changes the value of an argument
+ *
+ * \param [in] idx Argument index, starting at 1
+ * \param [in] word New argument word
+ */
+ void setArg(uint32_t idx, uint32_t word) const {
+ if (m_offset + idx < m_length)
+ m_code[m_offset + idx] = word;
+ }
+
+ private:
+
+ uint32_t* m_code = nullptr;
+ uint32_t m_offset = 0;
+ uint32_t m_length = 0;
+
+ };
+
+
+ /**
+ * \brief SPIR-V instruction iterator
+ *
+ * Convenient iterator that can be used
+ * to process raw SPIR-V shader code.
+ */
+ class SpirvInstructionIterator {
+
+ public:
+
+ SpirvInstructionIterator() { }
+ SpirvInstructionIterator(uint32_t* code, uint32_t offset, uint32_t length)
+ : m_code (length != 0 ? code : nullptr),
+ m_offset(length != 0 ? offset : 0),
+ m_length(length) {
+ if ((length >= 5) && (m_code[0] == spv::MagicNumber))
+ this->advance(5);
+ }
+
+ SpirvInstructionIterator& operator ++ () {
+ this->advance(SpirvInstruction(m_code, m_offset, m_length).length());
+ return *this;
+ }
+
+ SpirvInstruction operator * () const {
+ return SpirvInstruction(m_code, m_offset, m_length);
+ }
+
+ bool operator == (const SpirvInstructionIterator& other) const {
+ return this->m_code == other.m_code
+ && this->m_offset == other.m_offset
+ && this->m_length == other.m_length;
+ }
+
+ bool operator != (const SpirvInstructionIterator& other) const {
+ return this->m_code != other.m_code
+ || this->m_offset != other.m_offset
+ || this->m_length != other.m_length;
+ }
+
+ private:
+
+ uint32_t* m_code = nullptr;
+ uint32_t m_offset = 0;
+ uint32_t m_length = 0;
+
+ void advance(uint32_t n) {
+ if (m_offset + n < m_length) {
+ m_offset += n;
+ } else {
+ m_code = nullptr;
+ m_offset = 0;
+ m_length = 0;
+ }
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.cpp b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.cpp
new file mode 100644
index 00000000..7811bae9
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.cpp
@@ -0,0 +1,3741 @@
+#include <cstring>
+
+#include "spirv_module.h"
+
+namespace dxvk {
+
+ SpirvModule::SpirvModule(uint32_t version)
+ : m_version(version) {
+ this->instImportGlsl450();
+ }
+
+
+ SpirvModule::~SpirvModule() {
+
+ }
+
+
+ SpirvCodeBuffer SpirvModule::compile() const {
+ SpirvCodeBuffer result;
+ result.putHeader(m_version, m_id);
+ result.append(m_capabilities);
+ result.append(m_extensions);
+ result.append(m_instExt);
+ result.append(m_memoryModel);
+ result.append(m_entryPoints);
+ result.append(m_execModeInfo);
+ result.append(m_debugNames);
+ result.append(m_annotations);
+ result.append(m_typeConstDefs);
+ result.append(m_variables);
+ result.append(m_code);
+ return result;
+ }
+
+
+ uint32_t SpirvModule::allocateId() {
+ return m_id++;
+ }
+
+
+ bool SpirvModule::hasCapability(
+ spv::Capability capability) {
+ for (auto ins : m_capabilities) {
+ if (ins.opCode() == spv::OpCapability && ins.arg(1) == capability)
+ return true;
+ }
+
+ return false;
+ }
+
+ void SpirvModule::enableCapability(
+ spv::Capability capability) {
+ // Scan the generated instructions to check
+ // whether we already enabled the capability.
+ if (!hasCapability(capability)) {
+ m_capabilities.putIns (spv::OpCapability, 2);
+ m_capabilities.putWord(capability);
+ }
+ }
+
+
+ void SpirvModule::enableExtension(
+ const char* extensionName) {
+ m_extensions.putIns (spv::OpExtension, 1 + m_extensions.strLen(extensionName));
+ m_extensions.putStr (extensionName);
+ }
+
+
+ void SpirvModule::addEntryPoint(
+ uint32_t entryPointId,
+ spv::ExecutionModel executionModel,
+ const char* name,
+ uint32_t interfaceCount,
+ const uint32_t* interfaceIds) {
+ m_entryPoints.putIns (spv::OpEntryPoint, 3 + m_entryPoints.strLen(name) + interfaceCount);
+ m_entryPoints.putWord (executionModel);
+ m_entryPoints.putWord (entryPointId);
+ m_entryPoints.putStr (name);
+
+ for (uint32_t i = 0; i < interfaceCount; i++)
+ m_entryPoints.putWord(interfaceIds[i]);
+ }
+
+
+ void SpirvModule::setMemoryModel(
+ spv::AddressingModel addressModel,
+ spv::MemoryModel memoryModel) {
+ m_memoryModel.putIns (spv::OpMemoryModel, 3);
+ m_memoryModel.putWord (addressModel);
+ m_memoryModel.putWord (memoryModel);
+ }
+
+
+ void SpirvModule::setExecutionMode(
+ uint32_t entryPointId,
+ spv::ExecutionMode executionMode) {
+ m_execModeInfo.putIns (spv::OpExecutionMode, 3);
+ m_execModeInfo.putWord(entryPointId);
+ m_execModeInfo.putWord(executionMode);
+ }
+
+
+ void SpirvModule::setExecutionMode(
+ uint32_t entryPointId,
+ spv::ExecutionMode executionMode,
+ uint32_t argCount,
+ const uint32_t* args) {
+ m_execModeInfo.putIns (spv::OpExecutionMode, 3 + argCount);
+ m_execModeInfo.putWord(entryPointId);
+ m_execModeInfo.putWord(executionMode);
+
+ for (uint32_t i = 0; i < argCount; i++)
+ m_execModeInfo.putWord(args[i]);
+ }
+
+
+ void SpirvModule::setInvocations(
+ uint32_t entryPointId,
+ uint32_t invocations) {
+ m_execModeInfo.putIns (spv::OpExecutionMode, 4);
+ m_execModeInfo.putWord (entryPointId);
+ m_execModeInfo.putWord (spv::ExecutionModeInvocations);
+ m_execModeInfo.putInt32(invocations);
+ }
+
+
+ void SpirvModule::setLocalSize(
+ uint32_t entryPointId,
+ uint32_t x,
+ uint32_t y,
+ uint32_t z) {
+ m_execModeInfo.putIns (spv::OpExecutionMode, 6);
+ m_execModeInfo.putWord (entryPointId);
+ m_execModeInfo.putWord (spv::ExecutionModeLocalSize);
+ m_execModeInfo.putInt32(x);
+ m_execModeInfo.putInt32(y);
+ m_execModeInfo.putInt32(z);
+ }
+
+
+ void SpirvModule::setOutputVertices(
+ uint32_t entryPointId,
+ uint32_t vertexCount) {
+ m_execModeInfo.putIns (spv::OpExecutionMode, 4);
+ m_execModeInfo.putWord(entryPointId);
+ m_execModeInfo.putWord(spv::ExecutionModeOutputVertices);
+ m_execModeInfo.putWord(vertexCount);
+ }
+
+
+ uint32_t SpirvModule::addDebugString(
+ const char* string) {
+ uint32_t resultId = this->allocateId();
+
+ m_debugNames.putIns (spv::OpString,
+ 2 + m_debugNames.strLen(string));
+ m_debugNames.putWord(resultId);
+ m_debugNames.putStr (string);
+ return resultId;
+ }
+
+
+ void SpirvModule::setDebugSource(
+ spv::SourceLanguage language,
+ uint32_t version,
+ uint32_t file,
+ const char* source) {
+ uint32_t strLen = source != nullptr
+ ? m_debugNames.strLen(source) : 0;
+
+ m_debugNames.putIns (spv::OpSource, 4 + strLen);
+ m_debugNames.putWord(language);
+ m_debugNames.putWord(version);
+ m_debugNames.putWord(file);
+
+ if (source != nullptr)
+ m_debugNames.putStr(source);
+ }
+
+ void SpirvModule::setDebugName(
+ uint32_t expressionId,
+ const char* debugName) {
+ m_debugNames.putIns (spv::OpName, 2 + m_debugNames.strLen(debugName));
+ m_debugNames.putWord(expressionId);
+ m_debugNames.putStr (debugName);
+ }
+
+
+ void SpirvModule::setDebugMemberName(
+ uint32_t structId,
+ uint32_t memberId,
+ const char* debugName) {
+ m_debugNames.putIns (spv::OpMemberName, 3 + m_debugNames.strLen(debugName));
+ m_debugNames.putWord(structId);
+ m_debugNames.putWord(memberId);
+ m_debugNames.putStr (debugName);
+ }
+
+
+ uint32_t SpirvModule::constBool(
+ bool v) {
+ return this->defConst(v
+ ? spv::OpConstantTrue
+ : spv::OpConstantFalse,
+ this->defBoolType(),
+ 0, nullptr);
+ }
+
+
+ uint32_t SpirvModule::consti32(
+ int32_t v) {
+ std::array<uint32_t, 1> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defIntType(32, 1),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::consti64(
+ int64_t v) {
+ std::array<uint32_t, 2> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defIntType(64, 1),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::constu32(
+ uint32_t v) {
+ std::array<uint32_t, 1> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defIntType(32, 0),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::constu64(
+ uint64_t v) {
+ std::array<uint32_t, 2> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defIntType(64, 0),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::constf32(
+ float v) {
+ std::array<uint32_t, 1> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defFloatType(32),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::constf64(
+ double v) {
+ std::array<uint32_t, 2> data;
+ std::memcpy(data.data(), &v, sizeof(v));
+
+ return this->defConst(
+ spv::OpConstant,
+ this->defFloatType(64),
+ data.size(),
+ data.data());
+ }
+
+
+ uint32_t SpirvModule::constvec4i32(
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ int32_t w) {
+ std::array<uint32_t, 4> args = {{
+ this->consti32(x), this->consti32(y),
+ this->consti32(z), this->consti32(w),
+ }};
+
+ uint32_t scalarTypeId = this->defIntType(32, 1);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constvec4b32(
+ bool x,
+ bool y,
+ bool z,
+ bool w) {
+ std::array<uint32_t, 4> args = {{
+ this->constBool(x), this->constBool(y),
+ this->constBool(z), this->constBool(w),
+ }};
+
+ uint32_t scalarTypeId = this->defBoolType();
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constvec4u32(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z,
+ uint32_t w) {
+ std::array<uint32_t, 4> args = {{
+ this->constu32(x), this->constu32(y),
+ this->constu32(z), this->constu32(w),
+ }};
+
+ uint32_t scalarTypeId = this->defIntType(32, 0);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constvec2f32(
+ float x,
+ float y) {
+ std::array<uint32_t, 2> args = {{
+ this->constf32(x), this->constf32(y),
+ }};
+
+ uint32_t scalarTypeId = this->defFloatType(32);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 2);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constvec3f32(
+ float x,
+ float y,
+ float z) {
+ std::array<uint32_t, 3> args = {{
+ this->constf32(x), this->constf32(y),
+ this->constf32(z),
+ }};
+
+ uint32_t scalarTypeId = this->defFloatType(32);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 3);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constvec4f32(
+ float x,
+ float y,
+ float z,
+ float w) {
+ std::array<uint32_t, 4> args = {{
+ this->constf32(x), this->constf32(y),
+ this->constf32(z), this->constf32(w),
+ }};
+
+ uint32_t scalarTypeId = this->defFloatType(32);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4);
+
+ return this->constComposite(vectorTypeId, args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::constfReplicant(
+ float replicant,
+ uint32_t count) {
+ uint32_t value = this->constf32(replicant);
+
+ std::array<uint32_t, 4> args = { value, value, value, value };
+
+ // Can't make a scalar composite.
+ if (count == 1)
+ return args[0];
+
+ uint32_t scalarTypeId = this->defFloatType(32);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, count);
+
+ return this->constComposite(vectorTypeId, count, args.data());
+ }
+
+
+ uint32_t SpirvModule::constbReplicant(
+ bool replicant,
+ uint32_t count) {
+ uint32_t value = this->constBool(replicant);
+
+ std::array<uint32_t, 4> args = { value, value, value, value };
+
+ // Can't make a scalar composite.
+ if (count == 1)
+ return args[0];
+
+ uint32_t scalarTypeId = this->defBoolType();
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, count);
+
+ return this->constComposite(vectorTypeId, count, args.data());
+ }
+
+
+ uint32_t SpirvModule::constiReplicant(
+ int32_t replicant,
+ uint32_t count) {
+ uint32_t value = this->consti32(replicant);
+
+ std::array<uint32_t, 4> args = { value, value, value, value };
+
+ // Can't make a scalar composite.
+ if (count == 1)
+ return args[0];
+
+ uint32_t scalarTypeId = this->defIntType(32, 1);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, count);
+
+ return this->constComposite(vectorTypeId, count, args.data());
+ }
+
+
+ uint32_t SpirvModule::constuReplicant(
+ int32_t replicant,
+ uint32_t count) {
+ uint32_t value = this->constu32(replicant);
+
+ std::array<uint32_t, 4> args = { value, value, value, value };
+
+ // Can't make a scalar composite.
+ if (count == 1)
+ return args[0];
+
+ uint32_t scalarTypeId = this->defIntType(32, 0);
+ uint32_t vectorTypeId = this->defVectorType(scalarTypeId, count);
+
+ return this->constComposite(vectorTypeId, count, args.data());
+ }
+
+
+ uint32_t SpirvModule::constComposite(
+ uint32_t typeId,
+ uint32_t constCount,
+ const uint32_t* constIds) {
+ return this->defConst(
+ spv::OpConstantComposite,
+ typeId, constCount, constIds);
+ }
+
+
+ uint32_t SpirvModule::constUndef(
+ uint32_t typeId) {
+ return this->defConst(spv::OpUndef,
+ typeId, 0, nullptr);
+ }
+
+
+ uint32_t SpirvModule::lateConst32(
+ uint32_t typeId) {
+ uint32_t resultId = this->allocateId();
+ m_lateConsts.insert(resultId);
+
+ m_typeConstDefs.putIns (spv::OpConstant, 4);
+ m_typeConstDefs.putWord(typeId);
+ m_typeConstDefs.putWord(resultId);
+ m_typeConstDefs.putWord(0);
+ return resultId;
+ }
+
+
+ void SpirvModule::setLateConst(
+ uint32_t constId,
+ const uint32_t* argIds) {
+ for (auto ins : m_typeConstDefs) {
+ if (ins.opCode() != spv::OpConstant
+ && ins.opCode() != spv::OpConstantComposite)
+ continue;
+
+ if (ins.arg(2) != constId)
+ continue;
+
+ for (uint32_t i = 3; i < ins.length(); i++)
+ ins.setArg(i, argIds[i - 3]);
+
+ return;
+ }
+ }
+
+
+ uint32_t SpirvModule::specConstBool(
+ bool v) {
+ uint32_t typeId = this->defBoolType();
+ uint32_t resultId = this->allocateId();
+
+ const spv::Op op = v
+ ? spv::OpSpecConstantTrue
+ : spv::OpSpecConstantFalse;
+
+ m_typeConstDefs.putIns (op, 3);
+ m_typeConstDefs.putWord (typeId);
+ m_typeConstDefs.putWord (resultId);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::specConst32(
+ uint32_t typeId,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_typeConstDefs.putIns (spv::OpSpecConstant, 4);
+ m_typeConstDefs.putWord (typeId);
+ m_typeConstDefs.putWord (resultId);
+ m_typeConstDefs.putWord (value);
+ return resultId;
+ }
+
+
+ void SpirvModule::decorate(
+ uint32_t object,
+ spv::Decoration decoration) {
+ m_annotations.putIns (spv::OpDecorate, 3);
+ m_annotations.putWord (object);
+ m_annotations.putWord (decoration);
+ }
+
+
+ void SpirvModule::decorateArrayStride(
+ uint32_t object,
+ uint32_t stride) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationArrayStride);
+ m_annotations.putInt32(stride);
+ }
+
+
+ void SpirvModule::decorateBinding(
+ uint32_t object,
+ uint32_t binding) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationBinding);
+ m_annotations.putInt32(binding);
+ }
+
+
+ void SpirvModule::decorateBlock(uint32_t object) {
+ m_annotations.putIns (spv::OpDecorate, 3);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationBlock);
+ }
+
+
+ void SpirvModule::decorateBuiltIn(
+ uint32_t object,
+ spv::BuiltIn builtIn) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationBuiltIn);
+ m_annotations.putWord (builtIn);
+ }
+
+
+ void SpirvModule::decorateComponent(
+ uint32_t object,
+ uint32_t location) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationComponent);
+ m_annotations.putInt32(location);
+ }
+
+
+ void SpirvModule::decorateDescriptorSet(
+ uint32_t object,
+ uint32_t set) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationDescriptorSet);
+ m_annotations.putInt32(set);
+ }
+
+
+ void SpirvModule::decorateIndex(
+ uint32_t object,
+ uint32_t index) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationIndex);
+ m_annotations.putInt32(index);
+ }
+
+
+ void SpirvModule::decorateLocation(
+ uint32_t object,
+ uint32_t location) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationLocation);
+ m_annotations.putInt32(location);
+ }
+
+
+ void SpirvModule::decorateSpecId(
+ uint32_t object,
+ uint32_t specId) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationSpecId);
+ m_annotations.putInt32(specId);
+ }
+
+
+ void SpirvModule::decorateXfb(
+ uint32_t object,
+ uint32_t streamId,
+ uint32_t bufferId,
+ uint32_t offset,
+ uint32_t stride) {
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationStream);
+ m_annotations.putInt32(streamId);
+
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationXfbBuffer);
+ m_annotations.putInt32(bufferId);
+
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationXfbStride);
+ m_annotations.putInt32(stride);
+
+ m_annotations.putIns (spv::OpDecorate, 4);
+ m_annotations.putWord (object);
+ m_annotations.putWord (spv::DecorationOffset);
+ m_annotations.putInt32(offset);
+ }
+
+
+ void SpirvModule::memberDecorateBuiltIn(
+ uint32_t structId,
+ uint32_t memberId,
+ spv::BuiltIn builtIn) {
+ m_annotations.putIns (spv::OpMemberDecorate, 5);
+ m_annotations.putWord (structId);
+ m_annotations.putWord (memberId);
+ m_annotations.putWord (spv::DecorationBuiltIn);
+ m_annotations.putWord (builtIn);
+ }
+
+
+ void SpirvModule::memberDecorate(
+ uint32_t structId,
+ uint32_t memberId,
+ spv::Decoration decoration) {
+ m_annotations.putIns (spv::OpMemberDecorate, 4);
+ m_annotations.putWord (structId);
+ m_annotations.putWord (memberId);
+ m_annotations.putWord (decoration);
+ }
+
+
+ void SpirvModule::memberDecorateMatrixStride(
+ uint32_t structId,
+ uint32_t memberId,
+ uint32_t stride) {
+ m_annotations.putIns (spv::OpMemberDecorate, 5);
+ m_annotations.putWord (structId);
+ m_annotations.putWord (memberId);
+ m_annotations.putWord (spv::DecorationMatrixStride);
+ m_annotations.putWord (stride);
+ }
+
+
+ void SpirvModule::memberDecorateOffset(
+ uint32_t structId,
+ uint32_t memberId,
+ uint32_t offset) {
+ m_annotations.putIns (spv::OpMemberDecorate, 5);
+ m_annotations.putWord (structId);
+ m_annotations.putWord (memberId);
+ m_annotations.putWord (spv::DecorationOffset);
+ m_annotations.putWord (offset);
+ }
+
+
+ uint32_t SpirvModule::defVoidType() {
+ return this->defType(spv::OpTypeVoid, 0, nullptr);
+ }
+
+
+ uint32_t SpirvModule::defBoolType() {
+ return this->defType(spv::OpTypeBool, 0, nullptr);
+ }
+
+
+ uint32_t SpirvModule::defIntType(
+ uint32_t width,
+ uint32_t isSigned) {
+ std::array<uint32_t, 2> args = {{ width, isSigned }};
+ return this->defType(spv::OpTypeInt,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defFloatType(
+ uint32_t width) {
+ std::array<uint32_t, 1> args = {{ width }};
+ return this->defType(spv::OpTypeFloat,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defVectorType(
+ uint32_t elementType,
+ uint32_t elementCount) {
+ std::array<uint32_t, 2> args =
+ {{ elementType, elementCount }};
+
+ return this->defType(spv::OpTypeVector,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defMatrixType(
+ uint32_t columnType,
+ uint32_t columnCount) {
+ std::array<uint32_t, 2> args =
+ {{ columnType, columnCount }};
+
+ return this->defType(spv::OpTypeMatrix,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defArrayType(
+ uint32_t typeId,
+ uint32_t length) {
+ std::array<uint32_t, 2> args = {{ typeId, length }};
+
+ return this->defType(spv::OpTypeArray,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defArrayTypeUnique(
+ uint32_t typeId,
+ uint32_t length) {
+ uint32_t resultId = this->allocateId();
+
+ m_typeConstDefs.putIns (spv::OpTypeArray, 4);
+ m_typeConstDefs.putWord(resultId);
+ m_typeConstDefs.putWord(typeId);
+ m_typeConstDefs.putWord(length);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::defRuntimeArrayType(
+ uint32_t typeId) {
+ std::array<uint32_t, 1> args = { typeId };
+
+ return this->defType(spv::OpTypeRuntimeArray,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defRuntimeArrayTypeUnique(
+ uint32_t typeId) {
+ uint32_t resultId = this->allocateId();
+
+ m_typeConstDefs.putIns (spv::OpTypeRuntimeArray, 3);
+ m_typeConstDefs.putWord(resultId);
+ m_typeConstDefs.putWord(typeId);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::defFunctionType(
+ uint32_t returnType,
+ uint32_t argCount,
+ const uint32_t* argTypes) {
+ std::vector<uint32_t> args;
+ args.push_back(returnType);
+
+ for (uint32_t i = 0; i < argCount; i++)
+ args.push_back(argTypes[i]);
+
+ return this->defType(spv::OpTypeFunction,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defStructType(
+ uint32_t memberCount,
+ const uint32_t* memberTypes) {
+ return this->defType(spv::OpTypeStruct,
+ memberCount, memberTypes);
+ }
+
+
+ uint32_t SpirvModule::defStructTypeUnique(
+ uint32_t memberCount,
+ const uint32_t* memberTypes) {
+ uint32_t resultId = this->allocateId();
+
+ m_typeConstDefs.putIns (spv::OpTypeStruct, 2 + memberCount);
+ m_typeConstDefs.putWord(resultId);
+
+ for (uint32_t i = 0; i < memberCount; i++)
+ m_typeConstDefs.putWord(memberTypes[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::defPointerType(
+ uint32_t variableType,
+ spv::StorageClass storageClass) {
+ std::array<uint32_t, 2> args = {{
+ static_cast<uint32_t>(storageClass),
+ variableType,
+ }};
+
+ return this->defType(spv::OpTypePointer,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defSamplerType() {
+ return this->defType(spv::OpTypeSampler, 0, nullptr);
+ }
+
+
+ uint32_t SpirvModule::defImageType(
+ uint32_t sampledType,
+ spv::Dim dimensionality,
+ uint32_t depth,
+ uint32_t arrayed,
+ uint32_t multisample,
+ uint32_t sampled,
+ spv::ImageFormat format) {
+ std::array<uint32_t, 7> args = {{
+ sampledType,
+ static_cast<uint32_t>(dimensionality),
+ depth, arrayed,
+ multisample,
+ sampled,
+ static_cast<uint32_t>(format)
+ }};
+
+ return this->defType(spv::OpTypeImage,
+ args.size(), args.data());
+ }
+
+
+ uint32_t SpirvModule::defSampledImageType(
+ uint32_t imageType) {
+ return this->defType(spv::OpTypeSampledImage, 1, &imageType);
+ }
+
+
+ uint32_t SpirvModule::newVar(
+ uint32_t pointerType,
+ spv::StorageClass storageClass) {
+ uint32_t resultId = this->allocateId();
+
+ auto& code = storageClass != spv::StorageClassFunction
+ ? m_variables : m_code;
+
+ code.putIns (spv::OpVariable, 4);
+ code.putWord (pointerType);
+ code.putWord (resultId);
+ code.putWord (storageClass);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::newVarInit(
+ uint32_t pointerType,
+ spv::StorageClass storageClass,
+ uint32_t initialValue) {
+ uint32_t resultId = this->allocateId();
+
+ auto& code = storageClass != spv::StorageClassFunction
+ ? m_variables : m_code;
+
+ code.putIns (spv::OpVariable, 5);
+ code.putWord (pointerType);
+ code.putWord (resultId);
+ code.putWord (storageClass);
+ code.putWord (initialValue);
+ return resultId;
+ }
+
+
+ void SpirvModule::functionBegin(
+ uint32_t returnType,
+ uint32_t functionId,
+ uint32_t functionType,
+ spv::FunctionControlMask functionControl) {
+ m_code.putIns (spv::OpFunction, 5);
+ m_code.putWord(returnType);
+ m_code.putWord(functionId);
+ m_code.putWord(functionControl);
+ m_code.putWord(functionType);
+ }
+
+
+ uint32_t SpirvModule::functionParameter(
+ uint32_t parameterType) {
+ uint32_t parameterId = this->allocateId();
+
+ m_code.putIns (spv::OpFunctionParameter, 3);
+ m_code.putWord(parameterType);
+ m_code.putWord(parameterId);
+ return parameterId;
+ }
+
+
+ void SpirvModule::functionEnd() {
+ m_code.putIns (spv::OpFunctionEnd, 1);
+ }
+
+
+ uint32_t SpirvModule::opAccessChain(
+ uint32_t resultType,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAccessChain, 4 + indexCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(composite);
+
+ for (uint32_t i = 0; i < indexCount; i++)
+ m_code.putInt32(indexArray[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opArrayLength(
+ uint32_t resultType,
+ uint32_t structure,
+ uint32_t memberId) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpArrayLength, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(structure);
+ m_code.putWord(memberId);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAny(
+ uint32_t resultType,
+ uint32_t vector) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAny, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAll(
+ uint32_t resultType,
+ uint32_t vector) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAll, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicLoad(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicLoad, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ return resultId;
+ }
+
+
+ void SpirvModule::opAtomicStore(
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ m_code.putIns (spv::OpAtomicStore, 5);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ }
+
+
+ uint32_t SpirvModule::opAtomicExchange(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicExchange, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicCompareExchange(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t equal,
+ uint32_t unequal,
+ uint32_t value,
+ uint32_t comparator) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicCompareExchange, 9);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(equal);
+ m_code.putWord(unequal);
+ m_code.putWord(value);
+ m_code.putWord(comparator);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicIIncrement(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicIIncrement, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicIDecrement(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicIDecrement, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicIAdd(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicIAdd, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicISub(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicISub, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicSMin(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicSMin, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicSMax(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicSMax, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicUMin(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicUMin, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicUMax(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicUMax, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicAnd(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicAnd, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicOr(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicOr, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opAtomicXor(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpAtomicXor, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(pointer);
+ m_code.putWord(scope);
+ m_code.putWord(semantics);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitcast(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitcast, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitCount(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitCount, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitReverse(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitReverse, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFindILsb(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FindILsb);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFindUMsb(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FindUMsb);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFindSMsb(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FindSMsb);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitFieldInsert(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t insert,
+ uint32_t offset,
+ uint32_t count) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitFieldInsert, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(insert);
+ m_code.putWord(offset);
+ m_code.putWord(count);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitFieldSExtract(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t offset,
+ uint32_t count) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitFieldSExtract, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(offset);
+ m_code.putWord(count);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitFieldUExtract(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t offset,
+ uint32_t count) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitFieldUExtract, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(offset);
+ m_code.putWord(count);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitwiseAnd(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitwiseAnd, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitwiseOr(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitwiseOr, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opBitwiseXor(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpBitwiseXor, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opNot(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpNot, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opShiftLeftLogical(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpShiftLeftLogical, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(shift);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opShiftRightArithmetic(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpShiftRightArithmetic, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(shift);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opShiftRightLogical(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpShiftRightLogical, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(base);
+ m_code.putWord(shift);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opConvertFtoS(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpConvertFToS, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opConvertFtoU(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpConvertFToU, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opConvertStoF(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpConvertSToF, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opConvertUtoF(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpConvertUToF, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCompositeConstruct(
+ uint32_t resultType,
+ uint32_t valueCount,
+ const uint32_t* valueArray) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpCompositeConstruct, 3 + valueCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+
+ for (uint32_t i = 0; i < valueCount; i++)
+ m_code.putWord(valueArray[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCompositeExtract(
+ uint32_t resultType,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpCompositeExtract, 4 + indexCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(composite);
+
+ for (uint32_t i = 0; i < indexCount; i++)
+ m_code.putInt32(indexArray[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCompositeInsert(
+ uint32_t resultType,
+ uint32_t object,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpCompositeInsert, 5 + indexCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(object);
+ m_code.putWord(composite);
+
+ for (uint32_t i = 0; i < indexCount; i++)
+ m_code.putInt32(indexArray[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdx(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdx, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdy(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdy, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdxCoarse(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdxCoarse, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdyCoarse(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdyCoarse, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdxFine(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdxFine, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDpdyFine(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDPdyFine, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opVectorExtractDynamic(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t index) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpVectorExtractDynamic, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector);
+ m_code.putWord(index);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opVectorShuffle(
+ uint32_t resultType,
+ uint32_t vectorLeft,
+ uint32_t vectorRight,
+ uint32_t indexCount,
+ const uint32_t* indexArray) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpVectorShuffle, 5 + indexCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vectorLeft);
+ m_code.putWord(vectorRight);
+
+ for (uint32_t i = 0; i < indexCount; i++)
+ m_code.putInt32(indexArray[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSNegate(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSNegate, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFNegate(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFNegate, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSAbs(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450SAbs);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFAbs(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FAbs);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFSign(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FSign);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFMix(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t y,
+ uint32_t a) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 8);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FMix);
+ m_code.putWord(x);
+ m_code.putWord(y);
+ m_code.putWord(a);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCross(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t y) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Cross);
+ m_code.putWord(x);
+ m_code.putWord(y);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opIAdd(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpIAdd, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opISub(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpISub, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFAdd(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFAdd, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFSub(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFSub, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSDiv, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpUDiv, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSRem(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSRem, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUMod(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpUMod, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFDiv, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opIMul(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpIMul, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFMul(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFMul, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opVectorTimesScalar(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t scalar) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpVectorTimesScalar, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector);
+ m_code.putWord(scalar);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opMatrixTimesMatrix(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpMatrixTimesMatrix, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opMatrixTimesVector(
+ uint32_t resultType,
+ uint32_t matrix,
+ uint32_t vector) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpMatrixTimesVector, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(matrix);
+ m_code.putWord(vector);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opVectorTimesMatrix(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t matrix) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpVectorTimesMatrix, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector);
+ m_code.putWord(matrix);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opTranspose(
+ uint32_t resultType,
+ uint32_t matrix) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpTranspose, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(matrix);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opInverse(
+ uint32_t resultType,
+ uint32_t matrix) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450MatrixInverse);
+ m_code.putWord(matrix);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFFma(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b,
+ uint32_t c) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 8);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Fma);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ m_code.putWord(c);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FMax);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FMin);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opNMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450NMax);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opNMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450NMin);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450SMax);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450SMin);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450UMax);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450UMin);
+ m_code.putWord(a);
+ m_code.putWord(b);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFClamp(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t minVal,
+ uint32_t maxVal) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 8);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450FClamp);
+ m_code.putWord(x);
+ m_code.putWord(minVal);
+ m_code.putWord(maxVal);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opNClamp(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t minVal,
+ uint32_t maxVal) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 8);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450NClamp);
+ m_code.putWord(x);
+ m_code.putWord(minVal);
+ m_code.putWord(maxVal);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opIEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpIEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opINotEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpINotEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSLessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSLessThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSLessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSLessThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSGreaterThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSGreaterThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opULessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpULessThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opULessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpULessThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpUGreaterThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpUGreaterThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdNotEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdNotEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdLessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdLessThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdLessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdLessThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdGreaterThan, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFOrdGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFOrdGreaterThanEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLogicalEqual(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLogicalEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLogicalNotEqual(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLogicalNotEqual, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLogicalAnd(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLogicalAnd, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLogicalOr(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLogicalOr, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLogicalNot(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLogicalNot, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opDot(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpDot, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(vector1);
+ m_code.putWord(vector2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSin(
+ uint32_t resultType,
+ uint32_t vector) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Sin);
+ m_code.putWord(vector);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCos(
+ uint32_t resultType,
+ uint32_t vector) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Cos);
+ m_code.putWord(vector);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSqrt(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Sqrt);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opInverseSqrt(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450InverseSqrt);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opNormalize(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Normalize);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opReflect(
+ uint32_t resultType,
+ uint32_t incident,
+ uint32_t normal) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Reflect);
+ m_code.putWord(incident);
+ m_code.putWord(normal);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLength(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Length);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opExp2(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Exp2);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opExp(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Exp);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opLog2(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Log2);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+ uint32_t SpirvModule::opPow(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t exponent) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Pow);
+ m_code.putWord(base);
+ m_code.putWord(exponent);
+ return resultId;
+ }
+
+ uint32_t SpirvModule::opFract(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Fract);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opCeil(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Ceil);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFloor(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Floor);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opRound(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Round);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opRoundEven(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450RoundEven);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opTrunc(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450Trunc);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFConvert(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFConvert, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opPackHalf2x16(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450PackHalf2x16);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opUnpackHalf2x16(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450UnpackHalf2x16);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opSelect(
+ uint32_t resultType,
+ uint32_t condition,
+ uint32_t operand1,
+ uint32_t operand2) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSelect, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(condition);
+ m_code.putWord(operand1);
+ m_code.putWord(operand2);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opIsNan(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpIsNan, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opIsInf(
+ uint32_t resultType,
+ uint32_t operand) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpIsInf, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(operand);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opFunctionCall(
+ uint32_t resultType,
+ uint32_t functionId,
+ uint32_t argCount,
+ const uint32_t* argIds) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpFunctionCall, 4 + argCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(functionId);
+
+ for (uint32_t i = 0; i < argCount; i++)
+ m_code.putWord(argIds[i]);
+ return resultId;
+ }
+
+
+ void SpirvModule::opLabel(uint32_t labelId) {
+ m_code.putIns (spv::OpLabel, 2);
+ m_code.putWord(labelId);
+ }
+
+
+ uint32_t SpirvModule::opLoad(
+ uint32_t typeId,
+ uint32_t pointerId) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpLoad, 4);
+ m_code.putWord(typeId);
+ m_code.putWord(resultId);
+ m_code.putWord(pointerId);
+ return resultId;
+ }
+
+
+ void SpirvModule::opStore(
+ uint32_t pointerId,
+ uint32_t valueId) {
+ m_code.putIns (spv::OpStore, 3);
+ m_code.putWord(pointerId);
+ m_code.putWord(valueId);
+ }
+
+
+ uint32_t SpirvModule::opInterpolateAtCentroid(
+ uint32_t resultType,
+ uint32_t interpolant) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450InterpolateAtCentroid);
+ m_code.putWord(interpolant);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opInterpolateAtSample(
+ uint32_t resultType,
+ uint32_t interpolant,
+ uint32_t sample) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450InterpolateAtSample);
+ m_code.putWord(interpolant);
+ m_code.putWord(sample);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opInterpolateAtOffset(
+ uint32_t resultType,
+ uint32_t interpolant,
+ uint32_t offset) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpExtInst, 7);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(m_instExtGlsl450);
+ m_code.putWord(spv::GLSLstd450InterpolateAtOffset);
+ m_code.putWord(interpolant);
+ m_code.putWord(offset);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImage(
+ uint32_t resultType,
+ uint32_t sampledImage) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImage, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageRead(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageRead,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ void SpirvModule::opImageWrite(
+ uint32_t image,
+ uint32_t coordinates,
+ uint32_t texel,
+ const SpirvImageOperands& operands) {
+ m_code.putIns (spv::OpImageWrite,
+ 4 + getImageOperandWordCount(operands));
+ m_code.putWord(image);
+ m_code.putWord(coordinates);
+ m_code.putWord(texel);
+
+ putImageOperands(operands);
+ }
+
+
+ uint32_t SpirvModule::opSampledImage(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t sampler) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpSampledImage, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ m_code.putWord(sampler);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageTexelPointer(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ uint32_t sample) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageTexelPointer, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ m_code.putWord(coordinates);
+ m_code.putWord(sample);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageQuerySizeLod(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t lod) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageQuerySizeLod, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ m_code.putWord(lod);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageQuerySize(
+ uint32_t resultType,
+ uint32_t image) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageQuerySize, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageQueryLevels(
+ uint32_t resultType,
+ uint32_t image) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageQueryLevels, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageQueryLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageQueryLod, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageQuerySamples(
+ uint32_t resultType,
+ uint32_t image) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpImageQuerySamples, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageFetch(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageFetch,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(image);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageGather(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t component,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageGather,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(component);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageDrefGather(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageDrefGather,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(reference);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleImplicitLod,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleExplicitLod,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleProjImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleProjImplicitLod,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleProjExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleProjExplicitLod,
+ 5 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleDrefImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleDrefImplicitLod,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(reference);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleDrefExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleDrefExplicitLod,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(reference);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleProjDrefImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleProjDrefImplicitLod,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(reference);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opImageSampleProjDrefExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpImageSampleProjDrefExplicitLod,
+ 6 + getImageOperandWordCount(operands));
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(sampledImage);
+ m_code.putWord(coordinates);
+ m_code.putWord(reference);
+
+ putImageOperands(operands);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opGroupNonUniformBallot(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t predicate) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpGroupNonUniformBallot, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(execution);
+ m_code.putWord(predicate);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opGroupNonUniformBallotBitCount(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t operation,
+ uint32_t ballot) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpGroupNonUniformBallotBitCount, 6);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(execution);
+ m_code.putWord(operation);
+ m_code.putWord(ballot);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opGroupNonUniformElect(
+ uint32_t resultType,
+ uint32_t execution) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpGroupNonUniformElect, 4);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(execution);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::opGroupNonUniformBroadcastFirst(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t value) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns(spv::OpGroupNonUniformBroadcastFirst, 5);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+ m_code.putWord(execution);
+ m_code.putWord(value);
+ return resultId;
+ }
+
+
+ void SpirvModule::opControlBarrier(
+ uint32_t execution,
+ uint32_t memory,
+ uint32_t semantics) {
+ m_code.putIns (spv::OpControlBarrier, 4);
+ m_code.putWord(execution);
+ m_code.putWord(memory);
+ m_code.putWord(semantics);
+ }
+
+
+ void SpirvModule::opMemoryBarrier(
+ uint32_t memory,
+ uint32_t semantics) {
+ m_code.putIns (spv::OpMemoryBarrier, 3);
+ m_code.putWord(memory);
+ m_code.putWord(semantics);
+ }
+
+
+ void SpirvModule::opLoopMerge(
+ uint32_t mergeBlock,
+ uint32_t continueTarget,
+ uint32_t loopControl) {
+ m_code.putIns (spv::OpLoopMerge, 4);
+ m_code.putWord(mergeBlock);
+ m_code.putWord(continueTarget);
+ m_code.putWord(loopControl);
+ }
+
+
+ void SpirvModule::opSelectionMerge(
+ uint32_t mergeBlock,
+ uint32_t selectionControl) {
+ m_code.putIns (spv::OpSelectionMerge, 3);
+ m_code.putWord(mergeBlock);
+ m_code.putWord(selectionControl);
+ }
+
+
+ void SpirvModule::opBranch(
+ uint32_t label) {
+ m_code.putIns (spv::OpBranch, 2);
+ m_code.putWord(label);
+ }
+
+
+ void SpirvModule::opBranchConditional(
+ uint32_t condition,
+ uint32_t trueLabel,
+ uint32_t falseLabel) {
+ m_code.putIns (spv::OpBranchConditional, 4);
+ m_code.putWord(condition);
+ m_code.putWord(trueLabel);
+ m_code.putWord(falseLabel);
+ }
+
+
+ void SpirvModule::opSwitch(
+ uint32_t selector,
+ uint32_t jumpDefault,
+ uint32_t caseCount,
+ const SpirvSwitchCaseLabel* caseLabels) {
+ m_code.putIns (spv::OpSwitch, 3 + 2 * caseCount);
+ m_code.putWord(selector);
+ m_code.putWord(jumpDefault);
+
+ for (uint32_t i = 0; i < caseCount; i++) {
+ m_code.putWord(caseLabels[i].literal);
+ m_code.putWord(caseLabels[i].labelId);
+ }
+ }
+
+
+ uint32_t SpirvModule::opPhi(
+ uint32_t resultType,
+ uint32_t sourceCount,
+ const SpirvPhiLabel* sourceLabels) {
+ uint32_t resultId = this->allocateId();
+
+ m_code.putIns (spv::OpPhi, 3 + 2 * sourceCount);
+ m_code.putWord(resultType);
+ m_code.putWord(resultId);
+
+ for (uint32_t i = 0; i < sourceCount; i++) {
+ m_code.putWord(sourceLabels[i].varId);
+ m_code.putWord(sourceLabels[i].labelId);
+ }
+
+ return resultId;
+ }
+
+
+ void SpirvModule::opReturn() {
+ m_code.putIns (spv::OpReturn, 1);
+ }
+
+
+ void SpirvModule::opKill() {
+ m_code.putIns (spv::OpKill, 1);
+ }
+
+
+ void SpirvModule::opDemoteToHelperInvocation() {
+ m_code.putIns (spv::OpDemoteToHelperInvocationEXT, 1);
+ }
+
+
+ void SpirvModule::opEmitVertex(
+ uint32_t streamId) {
+ if (streamId == 0) {
+ m_code.putIns (spv::OpEmitVertex, 1);
+ } else {
+ m_code.putIns (spv::OpEmitStreamVertex, 2);
+ m_code.putWord(streamId);
+ }
+ }
+
+
+ void SpirvModule::opEndPrimitive(
+ uint32_t streamId) {
+ if (streamId == 0) {
+ m_code.putIns (spv::OpEndPrimitive, 1);
+ } else {
+ m_code.putIns (spv::OpEndStreamPrimitive, 2);
+ m_code.putWord(streamId);
+ }
+ }
+
+
+ uint32_t SpirvModule::defType(
+ spv::Op op,
+ uint32_t argCount,
+ const uint32_t* argIds) {
+ // Since the type info is stored in the code buffer,
+ // we can use the code buffer to look up type IDs as
+ // well. Result IDs are always stored as argument 1.
+ for (auto ins : m_typeConstDefs) {
+ bool match = ins.opCode() == op
+ && ins.length() == 2 + argCount;
+
+ for (uint32_t i = 0; i < argCount && match; i++)
+ match &= ins.arg(2 + i) == argIds[i];
+
+ if (match)
+ return ins.arg(1);
+ }
+
+ // Type not yet declared, create a new one.
+ uint32_t resultId = this->allocateId();
+ m_typeConstDefs.putIns (op, 2 + argCount);
+ m_typeConstDefs.putWord(resultId);
+
+ for (uint32_t i = 0; i < argCount; i++)
+ m_typeConstDefs.putWord(argIds[i]);
+ return resultId;
+ }
+
+
+ uint32_t SpirvModule::defConst(
+ spv::Op op,
+ uint32_t typeId,
+ uint32_t argCount,
+ const uint32_t* argIds) {
+ // Avoid declaring constants multiple times
+ for (auto ins : m_typeConstDefs) {
+ bool match = ins.opCode() == op
+ && ins.length() == 3 + argCount
+ && ins.arg(1) == typeId;
+
+ for (uint32_t i = 0; i < argCount && match; i++)
+ match &= ins.arg(3 + i) == argIds[i];
+
+ if (!match)
+ continue;
+
+ uint32_t id = ins.arg(2);
+
+ if (m_lateConsts.find(id) == m_lateConsts.end())
+ return id;
+ }
+
+ // Constant not yet declared, make a new one
+ uint32_t resultId = this->allocateId();
+ m_typeConstDefs.putIns (op, 3 + argCount);
+ m_typeConstDefs.putWord(typeId);
+ m_typeConstDefs.putWord(resultId);
+
+ for (uint32_t i = 0; i < argCount; i++)
+ m_typeConstDefs.putWord(argIds[i]);
+ return resultId;
+ }
+
+
+ void SpirvModule::instImportGlsl450() {
+ m_instExtGlsl450 = this->allocateId();
+ const char* name = "GLSL.std.450";
+
+ m_instExt.putIns (spv::OpExtInstImport, 2 + m_instExt.strLen(name));
+ m_instExt.putWord(m_instExtGlsl450);
+ m_instExt.putStr (name);
+ }
+
+
+ uint32_t SpirvModule::getImageOperandWordCount(const SpirvImageOperands& op) const {
+ // Each flag may add one or more operands
+ const uint32_t result
+ = ((op.flags & spv::ImageOperandsBiasMask) ? 1 : 0)
+ + ((op.flags & spv::ImageOperandsLodMask) ? 1 : 0)
+ + ((op.flags & spv::ImageOperandsConstOffsetMask) ? 1 : 0)
+ + ((op.flags & spv::ImageOperandsGradMask) ? 2 : 0)
+ + ((op.flags & spv::ImageOperandsOffsetMask) ? 1 : 0)
+ + ((op.flags & spv::ImageOperandsConstOffsetsMask)? 1 : 0)
+ + ((op.flags & spv::ImageOperandsSampleMask) ? 1 : 0)
+ + ((op.flags & spv::ImageOperandsMinLodMask) ? 1 : 0);
+
+ // Add a DWORD for the operand mask if it is non-zero
+ return result != 0 ? result + 1 : 0;
+ }
+
+
+ void SpirvModule::putImageOperands(const SpirvImageOperands& op) {
+ if (op.flags != 0) {
+ m_code.putWord(op.flags);
+
+ if (op.flags & spv::ImageOperandsBiasMask)
+ m_code.putWord(op.sLodBias);
+
+ if (op.flags & spv::ImageOperandsLodMask)
+ m_code.putWord(op.sLod);
+
+ if (op.flags & spv::ImageOperandsConstOffsetMask)
+ m_code.putWord(op.sConstOffset);
+
+ if (op.flags & spv::ImageOperandsGradMask) {
+ m_code.putWord(op.sGradX);
+ m_code.putWord(op.sGradY);
+ }
+
+ if (op.flags & spv::ImageOperandsOffsetMask)
+ m_code.putWord(op.gOffset);
+
+ if (op.flags & spv::ImageOperandsConstOffsetsMask)
+ m_code.putWord(op.gConstOffsets);
+
+ if (op.flags & spv::ImageOperandsSampleMask)
+ m_code.putWord(op.sSampleId);
+
+ if (op.flags & spv::ImageOperandsMinLodMask)
+ m_code.putWord(op.sMinLod);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.h b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.h
new file mode 100644
index 00000000..7ce5b8f1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/spirv/spirv_module.h
@@ -0,0 +1,1280 @@
+#pragma once
+
+#include <unordered_set>
+
+#include "spirv_code_buffer.h"
+
+namespace dxvk {
+
+ struct SpirvPhiLabel {
+ uint32_t varId = 0;
+ uint32_t labelId = 0;
+ };
+
+ struct SpirvSwitchCaseLabel {
+ uint32_t literal = 0;
+ uint32_t labelId = 0;
+ };
+
+ struct SpirvImageOperands {
+ uint32_t flags = 0;
+ uint32_t sLodBias = 0;
+ uint32_t sLod = 0;
+ uint32_t sConstOffset = 0;
+ uint32_t sGradX = 0;
+ uint32_t sGradY = 0;
+ uint32_t gOffset = 0;
+ uint32_t gConstOffsets = 0;
+ uint32_t sSampleId = 0;
+ uint32_t sMinLod = 0;
+ };
+
+ constexpr uint32_t spvVersion(uint32_t major, uint32_t minor) {
+ return (major << 16) | (minor << 8);
+ }
+
+ /**
+ * \brief SPIR-V module
+ *
+ * This class generates a code buffer containing a full
+ * SPIR-V shader module. Ensures that the module layout
+ * is valid, as defined in the SPIR-V 1.0 specification,
+ * section 2.4 "Logical Layout of a Module".
+ */
+ class SpirvModule {
+
+ public:
+
+ explicit SpirvModule(uint32_t version);
+
+ ~SpirvModule();
+
+ SpirvCodeBuffer compile() const;
+
+ size_t getInsertionPtr() {
+ return m_code.getInsertionPtr();
+ }
+
+ void beginInsertion(size_t ptr) {
+ m_code.beginInsertion(ptr);
+ }
+
+ void endInsertion() {
+ m_code.endInsertion();
+ }
+
+ uint32_t allocateId();
+
+ bool hasCapability(
+ spv::Capability capability);
+
+ void enableCapability(
+ spv::Capability capability);
+
+ void enableExtension(
+ const char* extensionName);
+
+ void addEntryPoint(
+ uint32_t entryPointId,
+ spv::ExecutionModel executionModel,
+ const char* name,
+ uint32_t interfaceCount,
+ const uint32_t* interfaceIds);
+
+ void setMemoryModel(
+ spv::AddressingModel addressModel,
+ spv::MemoryModel memoryModel);
+
+ void setExecutionMode(
+ uint32_t entryPointId,
+ spv::ExecutionMode executionMode);
+
+ void setExecutionMode(
+ uint32_t entryPointId,
+ spv::ExecutionMode executionMode,
+ uint32_t argCount,
+ const uint32_t* args);
+
+ void setInvocations(
+ uint32_t entryPointId,
+ uint32_t invocations);
+
+ void setLocalSize(
+ uint32_t entryPointId,
+ uint32_t x,
+ uint32_t y,
+ uint32_t z);
+
+ void setOutputVertices(
+ uint32_t entryPointId,
+ uint32_t vertexCount);
+
+ uint32_t addDebugString(
+ const char* string);
+
+ void setDebugSource(
+ spv::SourceLanguage language,
+ uint32_t version,
+ uint32_t file,
+ const char* source);
+
+ void setDebugName(
+ uint32_t expressionId,
+ const char* debugName);
+
+ void setDebugMemberName(
+ uint32_t structId,
+ uint32_t memberId,
+ const char* debugName);
+
+ uint32_t constBool(
+ bool v);
+
+ uint32_t consti32(
+ int32_t v);
+
+ uint32_t consti64(
+ int64_t v);
+
+ uint32_t constu32(
+ uint32_t v);
+
+ uint32_t constu64(
+ uint64_t v);
+
+ uint32_t constf32(
+ float v);
+
+ uint32_t constf64(
+ double v);
+
+ uint32_t constvec4i32(
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ int32_t w);
+
+ uint32_t constvec4b32(
+ bool x,
+ bool y,
+ bool z,
+ bool w);
+
+ uint32_t constvec4u32(
+ uint32_t x,
+ uint32_t y,
+ uint32_t z,
+ uint32_t w);
+
+ uint32_t constvec2f32(
+ float x,
+ float y);
+
+ uint32_t constvec3f32(
+ float x,
+ float y,
+ float z);
+
+ uint32_t constvec4f32(
+ float x,
+ float y,
+ float z,
+ float w);
+
+ uint32_t constfReplicant(
+ float replicant,
+ uint32_t count);
+
+ uint32_t constbReplicant(
+ bool replicant,
+ uint32_t count);
+
+ uint32_t constiReplicant(
+ int32_t replicant,
+ uint32_t count);
+
+ uint32_t constuReplicant(
+ int32_t replicant,
+ uint32_t count);
+
+ uint32_t constComposite(
+ uint32_t typeId,
+ uint32_t constCount,
+ const uint32_t* constIds);
+
+ uint32_t constUndef(
+ uint32_t typeId);
+
+ uint32_t lateConst32(
+ uint32_t typeId);
+
+ void setLateConst(
+ uint32_t constId,
+ const uint32_t* argIds);
+
+ uint32_t specConstBool(
+ bool v);
+
+ uint32_t specConst32(
+ uint32_t typeId,
+ uint32_t value);
+
+ void decorate(
+ uint32_t object,
+ spv::Decoration decoration);
+
+ void decorateArrayStride(
+ uint32_t object,
+ uint32_t stride);
+
+ void decorateBinding(
+ uint32_t object,
+ uint32_t binding);
+
+ void decorateBlock(
+ uint32_t object);
+
+ void decorateBuiltIn(
+ uint32_t object,
+ spv::BuiltIn builtIn);
+
+ void decorateComponent(
+ uint32_t object,
+ uint32_t location);
+
+ void decorateDescriptorSet(
+ uint32_t object,
+ uint32_t set);
+
+ void decorateIndex(
+ uint32_t object,
+ uint32_t index);
+
+ void decorateLocation(
+ uint32_t object,
+ uint32_t location);
+
+ void decorateSpecId(
+ uint32_t object,
+ uint32_t specId);
+
+ void decorateXfb(
+ uint32_t object,
+ uint32_t streamId,
+ uint32_t bufferId,
+ uint32_t offset,
+ uint32_t stride);
+
+ void memberDecorateBuiltIn(
+ uint32_t structId,
+ uint32_t memberId,
+ spv::BuiltIn builtIn);
+
+ void memberDecorate(
+ uint32_t structId,
+ uint32_t memberId,
+ spv::Decoration decoration);
+
+ void memberDecorateMatrixStride(
+ uint32_t structId,
+ uint32_t memberId,
+ uint32_t stride);
+
+ void memberDecorateOffset(
+ uint32_t structId,
+ uint32_t memberId,
+ uint32_t offset);
+
+ uint32_t defVoidType();
+
+ uint32_t defBoolType();
+
+ uint32_t defIntType(
+ uint32_t width,
+ uint32_t isSigned);
+
+ uint32_t defFloatType(
+ uint32_t width);
+
+ uint32_t defVectorType(
+ uint32_t elementType,
+ uint32_t elementCount);
+
+ uint32_t defMatrixType(
+ uint32_t columnType,
+ uint32_t columnCount);
+
+ uint32_t defArrayType(
+ uint32_t typeId,
+ uint32_t length);
+
+ uint32_t defArrayTypeUnique(
+ uint32_t typeId,
+ uint32_t length);
+
+ uint32_t defRuntimeArrayType(
+ uint32_t typeId);
+
+ uint32_t defRuntimeArrayTypeUnique(
+ uint32_t typeId);
+
+ uint32_t defFunctionType(
+ uint32_t returnType,
+ uint32_t argCount,
+ const uint32_t* argTypes);
+
+ uint32_t defStructType(
+ uint32_t memberCount,
+ const uint32_t* memberTypes);
+
+ uint32_t defStructTypeUnique(
+ uint32_t memberCount,
+ const uint32_t* memberTypes);
+
+ uint32_t defPointerType(
+ uint32_t variableType,
+ spv::StorageClass storageClass);
+
+ uint32_t defSamplerType();
+
+ uint32_t defImageType(
+ uint32_t sampledType,
+ spv::Dim dimensionality,
+ uint32_t depth,
+ uint32_t arrayed,
+ uint32_t multisample,
+ uint32_t sampled,
+ spv::ImageFormat format);
+
+ uint32_t defSampledImageType(
+ uint32_t imageType);
+
+ uint32_t newVar(
+ uint32_t pointerType,
+ spv::StorageClass storageClass);
+
+ uint32_t newVarInit(
+ uint32_t pointerType,
+ spv::StorageClass storageClass,
+ uint32_t initialValue);
+
+ void functionBegin(
+ uint32_t returnType,
+ uint32_t functionId,
+ uint32_t functionType,
+ spv::FunctionControlMask functionControl);
+
+ uint32_t functionParameter(
+ uint32_t parameterType);
+
+ void functionEnd();
+
+ uint32_t opAccessChain(
+ uint32_t resultType,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray);
+
+ uint32_t opArrayLength(
+ uint32_t resultType,
+ uint32_t structure,
+ uint32_t memberId);
+
+ uint32_t opAny(
+ uint32_t resultType,
+ uint32_t vector);
+
+ uint32_t opAll(
+ uint32_t resultType,
+ uint32_t vector);
+
+ uint32_t opAtomicLoad(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics);
+
+ void opAtomicStore(
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicExchange(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicCompareExchange(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t equal,
+ uint32_t unequal,
+ uint32_t value,
+ uint32_t comparator);
+
+ uint32_t opAtomicIIncrement(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics);
+
+ uint32_t opAtomicIDecrement(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics);
+
+ uint32_t opAtomicIAdd(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicISub(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicSMin(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicSMax(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicUMin(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicUMax(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicAnd(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicOr(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opAtomicXor(
+ uint32_t resultType,
+ uint32_t pointer,
+ uint32_t scope,
+ uint32_t semantics,
+ uint32_t value);
+
+ uint32_t opBitcast(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opBitCount(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opBitReverse(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFindILsb(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFindUMsb(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFindSMsb(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opBitFieldInsert(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t insert,
+ uint32_t offset,
+ uint32_t count);
+
+ uint32_t opBitFieldSExtract(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t offset,
+ uint32_t count);
+
+ uint32_t opBitFieldUExtract(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t offset,
+ uint32_t count);
+
+ uint32_t opBitwiseAnd(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opBitwiseOr(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opBitwiseXor(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opNot(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opShiftLeftLogical(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift);
+
+ uint32_t opShiftRightArithmetic(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift);
+
+ uint32_t opShiftRightLogical(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t shift);
+
+ uint32_t opConvertFtoS(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opConvertFtoU(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opConvertStoF(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opConvertUtoF(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opCompositeConstruct(
+ uint32_t resultType,
+ uint32_t valueCount,
+ const uint32_t* valueArray);
+
+ uint32_t opCompositeExtract(
+ uint32_t resultType,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray);
+
+ uint32_t opCompositeInsert(
+ uint32_t resultType,
+ uint32_t object,
+ uint32_t composite,
+ uint32_t indexCount,
+ const uint32_t* indexArray);
+
+ uint32_t opDpdx(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDpdy(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDpdxCoarse(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDpdyCoarse(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDpdxFine(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDpdyFine(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opVectorExtractDynamic(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t index);
+
+ uint32_t opVectorShuffle(
+ uint32_t resultType,
+ uint32_t vectorLeft,
+ uint32_t vectorRight,
+ uint32_t indexCount,
+ const uint32_t* indexArray);
+
+ uint32_t opSNegate(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFNegate(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opSAbs(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFAbs(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFSign(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFMix(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t y,
+ uint32_t a);
+
+ uint32_t opCross(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t y);
+
+ uint32_t opIAdd(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opISub(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFAdd(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFSub(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opSDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opUDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opSRem(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opUMod(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFDiv(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opIMul(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFMul(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opVectorTimesScalar(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t scalar);
+
+ uint32_t opMatrixTimesMatrix(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opMatrixTimesVector(
+ uint32_t resultType,
+ uint32_t matrix,
+ uint32_t vector);
+
+ uint32_t opVectorTimesMatrix(
+ uint32_t resultType,
+ uint32_t vector,
+ uint32_t matrix);
+
+ uint32_t opTranspose(
+ uint32_t resultType,
+ uint32_t matrix);
+
+ uint32_t opInverse(
+ uint32_t resultType,
+ uint32_t matrix);
+
+ uint32_t opFFma(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b,
+ uint32_t c);
+
+ uint32_t opFMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opNMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opNMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opSMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opSMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opUMax(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opUMin(
+ uint32_t resultType,
+ uint32_t a,
+ uint32_t b);
+
+ uint32_t opFClamp(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t minVal,
+ uint32_t maxVal);
+
+ uint32_t opNClamp(
+ uint32_t resultType,
+ uint32_t x,
+ uint32_t minVal,
+ uint32_t maxVal);
+
+ uint32_t opIEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opINotEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opSLessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opSLessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opSGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opSGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opULessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opULessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opUGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opUGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdNotEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdLessThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdLessThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdGreaterThan(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opFOrdGreaterThanEqual(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opLogicalEqual(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opLogicalNotEqual(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opLogicalAnd(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opLogicalOr(
+ uint32_t resultType,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opLogicalNot(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opDot(
+ uint32_t resultType,
+ uint32_t vector1,
+ uint32_t vector2);
+
+ uint32_t opSin(
+ uint32_t resultType,
+ uint32_t vector);
+
+ uint32_t opCos(
+ uint32_t resultType,
+ uint32_t vector);
+
+ uint32_t opSqrt(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opInverseSqrt(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opNormalize(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opReflect(
+ uint32_t resultType,
+ uint32_t incident,
+ uint32_t normal);
+
+ uint32_t opLength(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opExp2(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opExp(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opLog2(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opPow(
+ uint32_t resultType,
+ uint32_t base,
+ uint32_t exponent);
+
+ uint32_t opFract(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opCeil(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFloor(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opRound(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opRoundEven(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opTrunc(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFConvert(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opPackHalf2x16(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opUnpackHalf2x16(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opSelect(
+ uint32_t resultType,
+ uint32_t condition,
+ uint32_t operand1,
+ uint32_t operand2);
+
+ uint32_t opIsNan(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opIsInf(
+ uint32_t resultType,
+ uint32_t operand);
+
+ uint32_t opFunctionCall(
+ uint32_t resultType,
+ uint32_t functionId,
+ uint32_t argCount,
+ const uint32_t* argIds);
+
+ void opLabel(
+ uint32_t labelId);
+
+ uint32_t opLoad(
+ uint32_t typeId,
+ uint32_t pointerId);
+
+ void opStore(
+ uint32_t pointerId,
+ uint32_t valueId);
+
+ uint32_t opInterpolateAtCentroid(
+ uint32_t resultType,
+ uint32_t interpolant);
+
+ uint32_t opInterpolateAtSample(
+ uint32_t resultType,
+ uint32_t interpolant,
+ uint32_t sample);
+
+ uint32_t opInterpolateAtOffset(
+ uint32_t resultType,
+ uint32_t interpolant,
+ uint32_t offset);
+
+ uint32_t opImage(
+ uint32_t resultType,
+ uint32_t sampledImage);
+
+ uint32_t opImageRead(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ void opImageWrite(
+ uint32_t image,
+ uint32_t coordinates,
+ uint32_t texel,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageTexelPointer(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ uint32_t sample);
+
+ uint32_t opSampledImage(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t sampler);
+
+ uint32_t opImageQuerySizeLod(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t lod);
+
+ uint32_t opImageQuerySize(
+ uint32_t resultType,
+ uint32_t image);
+
+ uint32_t opImageQueryLevels(
+ uint32_t resultType,
+ uint32_t image);
+
+ uint32_t opImageQueryLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates);
+
+ uint32_t opImageQuerySamples(
+ uint32_t resultType,
+ uint32_t image);
+
+ uint32_t opImageFetch(
+ uint32_t resultType,
+ uint32_t image,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageGather(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t component,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageDrefGather(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleProjImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleProjExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleDrefImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleDrefExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleProjDrefImplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands);
+
+ uint32_t opImageSampleProjDrefExplicitLod(
+ uint32_t resultType,
+ uint32_t sampledImage,
+ uint32_t coordinates,
+ uint32_t reference,
+ const SpirvImageOperands& operands);
+
+ uint32_t opGroupNonUniformBallot(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t predicate);
+
+ uint32_t opGroupNonUniformBallotBitCount(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t operation,
+ uint32_t ballot);
+
+ uint32_t opGroupNonUniformElect(
+ uint32_t resultType,
+ uint32_t execution);
+
+ uint32_t opGroupNonUniformBroadcastFirst(
+ uint32_t resultType,
+ uint32_t execution,
+ uint32_t value);
+
+ void opControlBarrier(
+ uint32_t execution,
+ uint32_t memory,
+ uint32_t semantics);
+
+ void opMemoryBarrier(
+ uint32_t memory,
+ uint32_t semantics);
+
+ void opLoopMerge(
+ uint32_t mergeBlock,
+ uint32_t continueTarget,
+ uint32_t loopControl);
+
+ void opSelectionMerge(
+ uint32_t mergeBlock,
+ uint32_t selectionControl);
+
+ void opBranch(
+ uint32_t label);
+
+ void opBranchConditional(
+ uint32_t condition,
+ uint32_t trueLabel,
+ uint32_t falseLabel);
+
+ void opSwitch(
+ uint32_t selector,
+ uint32_t jumpDefault,
+ uint32_t caseCount,
+ const SpirvSwitchCaseLabel* caseLabels);
+
+ uint32_t opPhi(
+ uint32_t resultType,
+ uint32_t sourceCount,
+ const SpirvPhiLabel* sourceLabels);
+
+ void opReturn();
+
+ void opKill();
+
+ void opDemoteToHelperInvocation();
+
+ void opEmitVertex(
+ uint32_t streamId);
+
+ void opEndPrimitive(
+ uint32_t streamId);
+
+ private:
+
+ uint32_t m_version;
+ uint32_t m_id = 1;
+ uint32_t m_instExtGlsl450 = 0;
+
+ SpirvCodeBuffer m_capabilities;
+ SpirvCodeBuffer m_extensions;
+ SpirvCodeBuffer m_instExt;
+ SpirvCodeBuffer m_memoryModel;
+ SpirvCodeBuffer m_entryPoints;
+ SpirvCodeBuffer m_execModeInfo;
+ SpirvCodeBuffer m_debugNames;
+ SpirvCodeBuffer m_annotations;
+ SpirvCodeBuffer m_typeConstDefs;
+ SpirvCodeBuffer m_variables;
+ SpirvCodeBuffer m_code;
+
+ std::unordered_set<uint32_t> m_lateConsts;
+
+ uint32_t defType(
+ spv::Op op,
+ uint32_t argCount,
+ const uint32_t* argIds);
+
+ uint32_t defConst(
+ spv::Op op,
+ uint32_t typeId,
+ uint32_t argCount,
+ const uint32_t* argIds);
+
+ void instImportGlsl450();
+
+ uint32_t getImageOperandWordCount(
+ const SpirvImageOperands& op) const;
+
+ void putImageOperands(
+ const SpirvImageOperands& op);
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.cpp b/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.cpp
new file mode 100644
index 00000000..329d1848
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.cpp
@@ -0,0 +1,28 @@
+#include "com_guid.h"
+
+#include "../../d3d11/d3d11_interfaces.h"
+
+#include "../../dxgi/dxgi_interfaces.h"
+
+std::ostream& operator << (std::ostream& os, REFIID guid) {
+ os << std::hex << std::setfill('0')
+ << std::setw(8) << guid.Data1 << '-';
+
+ os << std::hex << std::setfill('0')
+ << std::setw(4) << guid.Data2 << '-';
+
+ os << std::hex << std::setfill('0')
+ << std::setw(4) << guid.Data3 << '-';
+
+ os << std::hex << std::setfill('0')
+ << std::setw(2) << static_cast<short>(guid.Data4[0])
+ << std::setw(2) << static_cast<short>(guid.Data4[1])
+ << '-'
+ << std::setw(2) << static_cast<short>(guid.Data4[2])
+ << std::setw(2) << static_cast<short>(guid.Data4[3])
+ << std::setw(2) << static_cast<short>(guid.Data4[4])
+ << std::setw(2) << static_cast<short>(guid.Data4[5])
+ << std::setw(2) << static_cast<short>(guid.Data4[6])
+ << std::setw(2) << static_cast<short>(guid.Data4[7]);
+ return os;
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.h b/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.h
new file mode 100644
index 00000000..9a69fc93
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_guid.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <ostream>
+#include <iomanip>
+
+#include "com_include.h"
+
+std::ostream& operator << (std::ostream& os, REFIID guid);
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_include.h b/src/libs/dxvk-native-1.9.2a/src/util/com/com_include.h
new file mode 100644
index 00000000..3c119309
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_include.h
@@ -0,0 +1,17 @@
+#pragma once
+
+// GCC complains about the COM interfaces
+// not having virtual destructors
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif // __GNUC__
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <unknwn.h>
+
+// GCC: -std options disable certain keywords
+// https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
+#if defined(__WINE__) && !defined(typeof)
+#define typeof __typeof
+#endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_object.h b/src/libs/dxvk-native-1.9.2a/src/util/com/com_object.h
new file mode 100644
index 00000000..75188d5c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_object.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include <atomic>
+
+#include "com_include.h"
+
+#include "../util_likely.h"
+
+namespace dxvk {
+
+ template<typename T>
+ class NoWrapper : public T {
+
+ public:
+
+ virtual ~NoWrapper() { }
+
+ };
+
+ /**
+ * \brief Reference-counted COM object
+ *
+ * This can serve as a templated base class for most
+ * COM objects. It implements AddRef and Release from
+ * \c IUnknown, and provides methods to increment and
+ * decrement private references which are not visible
+ * to the application.
+ *
+ * Having two reference counters is sadly necessary
+ * in order to not break games which steal internal
+ * references if the refefence count of an object is
+ + greater than they expect. DXVK sometimes requires
+ * holding on to objects which the application wants
+ * to delete.
+ */
+ template<typename Base>
+ class ComObject : public Base {
+
+ public:
+
+ virtual ~ComObject() { }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ uint32_t refCount = m_refCount++;
+ if (unlikely(!refCount))
+ AddRefPrivate();
+ return refCount + 1;
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ uint32_t refCount = --m_refCount;
+ if (unlikely(!refCount))
+ ReleasePrivate();
+ return refCount;
+ }
+
+
+ void AddRefPrivate() {
+ ++m_refPrivate;
+ }
+
+
+ void ReleasePrivate() {
+ uint32_t refPrivate = --m_refPrivate;
+ if (unlikely(!refPrivate)) {
+ m_refPrivate += 0x80000000;
+ delete this;
+ }
+ }
+
+ ULONG GetPrivateRefCount() {
+ return m_refPrivate.load();
+ }
+
+ protected:
+
+ std::atomic<uint32_t> m_refCount = { 0ul };
+ std::atomic<uint32_t> m_refPrivate = { 0ul };
+
+ };
+
+ /**
+ * \brief Clamped, reference-counted COM object
+ *
+ * This version of ComObject ensures that the reference
+ * count does not wrap around if a release happens at zero.
+ * eg. [m_refCount = 0]
+ * Release()
+ * [m_refCount = 0]
+ * This is a notable quirk of D3D9's COM implementation
+ * and is relied upon by some games.
+ */
+ template<typename Base>
+ class ComObjectClamp : public ComObject<Base> {
+
+ public:
+
+ ULONG STDMETHODCALLTYPE Release() {
+ ULONG refCount = this->m_refCount;
+ if (likely(refCount != 0ul)) {
+ this->m_refCount--;
+ refCount--;
+
+ if (refCount == 0ul)
+ this->ReleasePrivate();
+ }
+
+ return refCount;
+ }
+
+ };
+
+ template<typename T>
+ inline void InitReturnPtr(T** ptr) {
+ if (ptr != nullptr)
+ *ptr = nullptr;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_pointer.h b/src/libs/dxvk-native-1.9.2a/src/util/com/com_pointer.h
new file mode 100644
index 00000000..c81fae24
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_pointer.h
@@ -0,0 +1,146 @@
+#pragma once
+
+#include "com_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Increment public ref count
+ *
+ * If the pointer is not \c nullptr, this
+ * calls \c AddRef for the given object.
+ * \returns Pointer to the object
+ */
+ template<typename T>
+ T* ref(T* object) {
+ if (object != nullptr)
+ object->AddRef();
+ return object;
+ }
+
+
+ /**
+ * \brief Ref count methods for public references
+ */
+ template<typename T, bool Public>
+ struct ComRef_ {
+ static void incRef(T* ptr) { ptr->AddRef(); }
+ static void decRef(T* ptr) { ptr->Release(); }
+ };
+
+
+ /**
+ * \brief Ref count methods for private references
+ */
+ template<typename T>
+ struct ComRef_<T, false> {
+ static void incRef(T* ptr) { ptr->AddRefPrivate(); }
+ static void decRef(T* ptr) { ptr->ReleasePrivate(); }
+ };
+
+
+ /**
+ * \brief COM pointer
+ *
+ * Implements automatic reference
+ * counting for COM objects.
+ */
+ template<typename T, bool Public = true>
+ class Com {
+ using ComRef = ComRef_<T, Public>;
+ public:
+
+ Com() { }
+ Com(std::nullptr_t) { }
+ Com(T* object)
+ : m_ptr(object) {
+ this->incRef();
+ }
+
+ Com(const Com& other)
+ : m_ptr(other.m_ptr) {
+ this->incRef();
+ }
+
+ Com(Com&& other)
+ : m_ptr(other.m_ptr) {
+ other.m_ptr = nullptr;
+ }
+
+ Com& operator = (T* object) {
+ this->decRef();
+ m_ptr = object;
+ this->incRef();
+ return *this;
+ }
+
+ Com& operator = (const Com& other) {
+ other.incRef();
+ this->decRef();
+ m_ptr = other.m_ptr;
+ return *this;
+ }
+
+ Com& operator = (Com&& other) {
+ this->decRef();
+ this->m_ptr = other.m_ptr;
+ other.m_ptr = nullptr;
+ return *this;
+ }
+
+ Com& operator = (std::nullptr_t) {
+ this->decRef();
+ m_ptr = nullptr;
+ return *this;
+ }
+
+ ~Com() {
+ this->decRef();
+ }
+
+ T* operator -> () const {
+ return m_ptr;
+ }
+
+ T** operator & () { return &m_ptr; }
+ T* const* operator & () const { return &m_ptr; }
+
+ template<bool Public_>
+ bool operator == (const Com<T, Public_>& other) const { return m_ptr == other.m_ptr; }
+ template<bool Public_>
+ bool operator != (const Com<T, Public_>& other) const { return m_ptr != other.m_ptr; }
+
+ bool operator == (const T* other) const { return m_ptr == other; }
+ bool operator != (const T* other) const { return m_ptr != other; }
+
+ bool operator == (std::nullptr_t) const { return m_ptr == nullptr; }
+ bool operator != (std::nullptr_t) const { return m_ptr != nullptr; }
+
+ T* ref() const {
+ return dxvk::ref(m_ptr);
+ }
+
+ T* ptr() const {
+ return m_ptr;
+ }
+
+ Com<T, true> pubRef() const { return m_ptr; }
+ Com<T, false> prvRef() const { return m_ptr; }
+
+ private:
+
+ T* m_ptr = nullptr;
+
+ void incRef() const {
+ if (m_ptr != nullptr)
+ ComRef::incRef(m_ptr);
+ }
+
+ void decRef() const {
+ if (m_ptr != nullptr)
+ ComRef::decRef(m_ptr);
+ }
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.cpp b/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.cpp
new file mode 100644
index 00000000..d27a4103
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.cpp
@@ -0,0 +1,171 @@
+#include <cmath>
+#include <cstring>
+#include <cstdlib>
+
+#include "com_private_data.h"
+
+namespace dxvk {
+
+ ComPrivateDataEntry::ComPrivateDataEntry() { }
+ ComPrivateDataEntry::ComPrivateDataEntry(
+ REFGUID guid,
+ UINT size,
+ const void* data)
+ : m_guid(guid),
+ m_type(ComPrivateDataType::Data),
+ m_size(size),
+ m_data(std::malloc(size)) {
+ std::memcpy(m_data, data, size);
+ }
+
+
+ ComPrivateDataEntry::ComPrivateDataEntry(
+ REFGUID guid,
+ const IUnknown* iface)
+ : m_guid (guid),
+ m_type(ComPrivateDataType::Iface),
+ m_iface (const_cast<IUnknown*>(iface)) {
+ if (m_iface)
+ m_iface->AddRef();
+ }
+
+
+ ComPrivateDataEntry::~ComPrivateDataEntry() {
+ this->destroy();
+ }
+
+
+ ComPrivateDataEntry::ComPrivateDataEntry(ComPrivateDataEntry&& other)
+ : m_guid (other.m_guid),
+ m_type (other.m_type),
+ m_size (other.m_size),
+ m_data (other.m_data),
+ m_iface (other.m_iface) {
+ other.m_guid = __uuidof(IUnknown);
+ other.m_type = ComPrivateDataType::None;
+ other.m_size = 0;
+ other.m_data = nullptr;
+ other.m_iface = nullptr;
+ }
+
+
+ ComPrivateDataEntry& ComPrivateDataEntry::operator = (ComPrivateDataEntry&& other) {
+ this->destroy();
+ this->m_guid = other.m_guid;
+ this->m_type = other.m_type;
+ this->m_size = other.m_size;
+ this->m_data = other.m_data;
+ this->m_iface = other.m_iface;
+
+ other.m_guid = __uuidof(IUnknown);
+ other.m_type = ComPrivateDataType::None;
+ other.m_size = 0;
+ other.m_data = nullptr;
+ other.m_iface = nullptr;
+ return *this;
+ }
+
+
+ HRESULT ComPrivateDataEntry::get(UINT& size, void* data) const {
+ UINT minSize = 0;
+
+ if (m_type == ComPrivateDataType::Iface) minSize = sizeof(IUnknown*);
+ if (m_type == ComPrivateDataType::Data) minSize = m_size;
+
+ if (!data) {
+ size = minSize;
+ return S_OK;
+ }
+
+ HRESULT result = size < minSize
+ ? DXGI_ERROR_MORE_DATA
+ : S_OK;
+
+ if (size >= minSize) {
+ if (m_type == ComPrivateDataType::Iface) {
+ if (m_iface)
+ m_iface->AddRef();
+ std::memcpy(data, &m_iface, minSize);
+ } else {
+ std::memcpy(data, m_data, minSize);
+ }
+ }
+
+ size = minSize;
+ return result;
+ }
+
+
+ void ComPrivateDataEntry::destroy() {
+ if (m_data)
+ std::free(m_data);
+ if (m_iface)
+ m_iface->Release();
+ }
+
+
+ HRESULT ComPrivateData::setData(
+ REFGUID guid,
+ UINT size,
+ const void* data) {
+ if (!data) {
+ for (auto it = m_entries.begin(); it != m_entries.end(); ++it) {
+ if (it->hasGuid(guid)) {
+ m_entries.erase(it);
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+ }
+ this->insertEntry(ComPrivateDataEntry(guid, size, data));
+ return S_OK;
+ }
+
+
+ HRESULT ComPrivateData::setInterface(
+ REFGUID guid,
+ const IUnknown* iface) {
+ this->insertEntry(ComPrivateDataEntry(guid, iface));
+ return S_OK;
+ }
+
+
+ HRESULT ComPrivateData::getData(
+ REFGUID guid,
+ UINT* size,
+ void* data) {
+ if (!size)
+ return E_INVALIDARG;
+
+ auto entry = this->findEntry(guid);
+
+ if (!entry) {
+ *size = 0;
+ return DXGI_ERROR_NOT_FOUND;
+ }
+
+ return entry->get(*size, data);
+ }
+
+
+ ComPrivateDataEntry* ComPrivateData::findEntry(REFGUID guid) {
+ for (ComPrivateDataEntry& e : m_entries) {
+ if (e.hasGuid(guid))
+ return &e;
+ }
+
+ return nullptr;
+ }
+
+
+ void ComPrivateData::insertEntry(ComPrivateDataEntry&& entry) {
+ ComPrivateDataEntry srcEntry = std::move(entry);
+ ComPrivateDataEntry* dstEntry = this->findEntry(srcEntry.guid());
+
+ if (dstEntry)
+ *dstEntry = std::move(srcEntry);
+ else
+ m_entries.push_back(std::move(srcEntry));
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.h b/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.h
new file mode 100644
index 00000000..0673f8e2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/com/com_private_data.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <vector>
+
+#include "com_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief COM private data entry type
+ */
+ enum ComPrivateDataType {
+ None,
+ Data,
+ Iface,
+ };
+
+ /**
+ * \brief Data entry for private storage
+ * Stores a single private storage item.
+ */
+ class ComPrivateDataEntry {
+
+ public:
+
+ ComPrivateDataEntry();
+ ComPrivateDataEntry(
+ REFGUID guid,
+ UINT size,
+ const void* data);
+ ComPrivateDataEntry(
+ REFGUID guid,
+ const IUnknown* iface);
+ ~ComPrivateDataEntry();
+
+ ComPrivateDataEntry (ComPrivateDataEntry&& other);
+ ComPrivateDataEntry& operator = (ComPrivateDataEntry&& other);
+
+ /**
+ * \brief The entry's GUID
+ * \returns The GUID
+ */
+ REFGUID guid() const {
+ return m_guid;
+ }
+
+ /**
+ * \brief Checks whether the GUID matches another one
+ *
+ * GUIDs are used to identify private data entries.
+ * \param [in] guid The GUID to compare to
+ * \returns \c true if this entry holds the same GUID
+ */
+ bool hasGuid(REFGUID guid) const {
+ return m_guid == guid;
+ }
+
+ /**
+ * \brief Retrieves stored data
+ *
+ * \param [in,out] size Destination buffer size
+ * \param [in] data Appliaction-provided buffer
+ * \returns \c S_OK on success, or \c DXGI_ERROR_MORE_DATA
+ * if the destination buffer is too small
+ */
+ HRESULT get(UINT& size, void* data) const;
+
+ private:
+
+ GUID m_guid = __uuidof(IUnknown);
+ ComPrivateDataType m_type = ComPrivateDataType::None;
+ UINT m_size = 0;
+ void* m_data = nullptr;
+ IUnknown* m_iface = nullptr;
+
+ void destroy();
+
+ };
+
+
+ /**
+ * \brief Private storage for DXGI objects
+ *
+ * Provides storage for application-defined
+ * byte arrays or COM interfaces that can be
+ * retrieved using GUIDs.
+ */
+ class ComPrivateData {
+
+ public:
+
+ HRESULT setData(
+ REFGUID guid,
+ UINT size,
+ const void* data);
+
+ HRESULT setInterface(
+ REFGUID guid,
+ const IUnknown* iface);
+
+ HRESULT getData(
+ REFGUID guid,
+ UINT* size,
+ void* data);
+
+ private:
+
+ std::vector<ComPrivateDataEntry> m_entries;
+
+ ComPrivateDataEntry* findEntry(REFGUID guid);
+ void insertEntry(ComPrivateDataEntry&& entry);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/config/config.cpp b/src/libs/dxvk-native-1.9.2a/src/util/config/config.cpp
new file mode 100644
index 00000000..f5c940d1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/config/config.cpp
@@ -0,0 +1,723 @@
+#include <array>
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <regex>
+#include <utility>
+
+#include "config.h"
+
+#include "../log/log.h"
+
+#include "../util_env.h"
+
+namespace dxvk {
+
+ const static std::vector<std::pair<const char*, Config>> g_appDefaults = {{
+ /* Assassin's Creed Syndicate: amdags issues */
+ { R"(\\ACS\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* Dissidia Final Fantasy NT Free Edition */
+ { R"(\\dffnt\.exe$)", {{
+ { "dxgi.deferSurfaceCreation", "True" },
+ }} },
+ /* Elite Dangerous: Compiles weird shaders *
+ * when running on AMD hardware */
+ { R"(\\EliteDangerous64\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* The Vanishing of Ethan Carter Redux */
+ { R"(\\EthanCarter-Win64-Shipping\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* The Evil Within: Submits command lists *
+ * multiple times */
+ { R"(\\EvilWithin(Demo)?\.exe$)", {{
+ { "d3d11.dcSingleUseMode", "False" },
+ }} },
+ /* Far Cry 3: Assumes clear(0.5) on an UNORM *
+ * format to result in 128 on AMD and 127 on *
+ * Nvidia. We assume that the Vulkan drivers *
+ * match the clear behaviour of D3D11. */
+ { R"(\\(farcry3|fc3_blooddragon)_d3d11\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Far Cry 4: Same as Far Cry 3 */
+ { R"(\\FarCry4\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Frostpunk: Renders one frame with D3D9 *
+ * after creating the DXGI swap chain */
+ { R"(\\Frostpunk\.exe$)", {{
+ { "dxgi.deferSurfaceCreation", "True" },
+ }} },
+ /* Nioh: See Frostpunk, apparently? */
+ { R"(\\nioh\.exe$)", {{
+ { "dxgi.deferSurfaceCreation", "True" },
+ }} },
+ /* Quantum Break: Mever initializes shared *
+ * memory in one of its compute shaders */
+ { R"(\\QuantumBreak\.exe$)", {{
+ { "d3d11.zeroInitWorkgroupMemory", "True" },
+ }} },
+ /* Anno 2205: Random crashes with state cache */
+ { R"(\\anno2205\.exe$)", {{
+ { "dxvk.enableStateCache", "False" },
+ }} },
+ /* Fifa '19+: Binds typed buffer SRV to shader *
+ * that expects raw/structured buffer SRV */
+ { R"(\\FIFA(19|[2-9][0-9])(_demo)?\.exe$)", {{
+ { "dxvk.useRawSsbo", "True" },
+ }} },
+ /* Resident Evil 2/3: Ignore WaW hazards */
+ { R"(\\re(2|3|3demo)\.exe$)", {{
+ { "d3d11.relaxedBarriers", "True" },
+ }} },
+ /* Devil May Cry 5 */
+ { R"(\\DevilMayCry5\.exe$)", {{
+ { "d3d11.relaxedBarriers", "True" },
+ }} },
+ /* Call of Duty WW2 */
+ { R"(\\s2_sp64_ship\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Need for Speed 2015 */
+ { R"(\\NFS16\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Mass Effect Andromeda */
+ { R"(\\MassEffectAndromeda\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Mirror`s Edge Catalyst: Crashes on AMD */
+ { R"(\\MirrorsEdgeCatalyst(Trial)?\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* Star Wars Battlefront (2015) */
+ { R"(\\starwarsbattlefront(trial)?\.exe$)", {{
+ { "dxgi.nvapiHack", "False" },
+ }} },
+ /* Dark Souls Remastered */
+ { R"(\\DarkSoulsRemastered\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Grim Dawn */
+ { R"(\\Grim Dawn\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* NieR:Automata */
+ { R"(\\NieRAutomata\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* NieR Replicant */
+ { R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
+ { "dxgi.syncInterval", "1" },
+ { "dxgi.maxFrameRate", "60" },
+ }} },
+ /* SteamVR performance test */
+ { R"(\\vr\.exe$)", {{
+ { "d3d11.dcSingleUseMode", "False" },
+ }} },
+ /* Hitman 2 and 3 - requires AGS library */
+ { R"(\\HITMAN(2|3)\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* Modern Warfare Remastered */
+ { R"(\\h1_[ms]p64_ship\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* Titan Quest */
+ { R"(\\TQ\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Saints Row IV */
+ { R"(\\SaintsRowIV\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Saints Row: The Third */
+ { R"(\\SaintsRowTheThird_DX11\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Metal Gear Solid 5 */
+ { R"(\\mgsvtpp\.exe$)", {{
+ { "dxvk.enableOpenVR", "False" },
+ }} },
+ /* Raft */
+ { R"(\\Raft\.exe$)", {{
+ { "dxvk.enableOpenVR", "False" },
+ }} },
+ /* Crysis 3 - slower if it notices AMD card *
+ * Apitrace mode helps massively in cpu bound *
+ * game parts */
+ { R"(\\Crysis3\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Crysis 3 Remastered *
+ * Apitrace mode helps massively in cpu bound *
+ * game parts */
+ { R"(\\Crysis3Remastered\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Atelier series - games try to render video *
+ * with a D3D9 swap chain over the DXGI swap *
+ * chain, which breaks D3D11 presentation */
+ { R"(\\Atelier_(Ayesha|Escha_and_Logy|Shallie)(_EN)?\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Atelier Rorona/Totori/Meruru */
+ { R"(\\A(11R|12V|13V)_x64_Release(_en)?\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Just how many of these games are there? */
+ { R"(\\Atelier_(Lulua|Lydie_and_Suelle|Ryza(_2)?)\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* ... */
+ { R"(\\Atelier_(Lydie_and_Suelle|Firis|Sophie)_DX\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Fairy Tail */
+ { R"(\\FAIRY_TAIL\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Nights of Azure */
+ { R"(\\CNN\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Star Wars Battlefront II: amdags issues */
+ { R"(\\starwarsbattlefrontii\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* F1 games - do not synchronize TGSM access *
+ * in a compute shader, causing artifacts */
+ { R"(\\F1_20(1[89]|[2-9][0-9])\.exe$)", {{
+ { "d3d11.forceTgsmBarriers", "True" },
+ }} },
+ /* Subnautica */
+ { R"(\\Subnautica\.exe$)", {{
+ { "dxvk.enableOpenVR", "False" },
+ }} },
+ /* Blue Reflection */
+ { R"(\\BLUE_REFLECTION\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Secret World Legends */
+ { R"(\\SecretWorldLegendsDX11\.exe$)", {{
+ { "d3d11.constantBufferRangeCheck", "True" },
+ }} },
+ /* Darksiders Warmastered - apparently reads *
+ * from write-only mapped buffers */
+ { R"(\\darksiders1\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Monster Hunter World */
+ { R"(\\MonsterHunterWorld\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Kingdome Come: Deliverance */
+ { R"(\\KingdomCome\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Homefront: The Revolution */
+ { R"(\\Homefront2_Release\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Sniper Ghost Warrior Contracts */
+ { R"(\\SGWContracts\.exe$)", {{
+ { "d3d11.apitraceMode", "True" },
+ }} },
+ /* Shadow of the Tomb Raider - invariant *
+ * position breaks character rendering on NV */
+ { R"(\\SOTTR\.exe$)", {{
+ { "d3d11.invariantPosition", "False" },
+ { "d3d11.floatControls", "False" },
+ }} },
+ /* Nioh 2 */
+ { R"(\\nioh2\.exe$)", {{
+ { "dxgi.deferSurfaceCreation", "True" },
+ }} },
+ /* DIRT 5 - uses amd_ags_x64.dll when it *
+ * detects an AMD GPU */
+ { R"(\\DIRT5\.exe$)", {{
+ { "dxgi.customVendorId", "10de" },
+ }} },
+ /* Crazy Machines 3 - crashes on long device *
+ * descriptions */
+ { R"(\\cm3\.exe$)", {{
+ { "dxgi.customDeviceDesc", "DXVK Adapter" },
+ }} },
+ /* World of Final Fantasy: Broken and useless *
+ * use of 4x MSAA throughout the renderer */
+ { R"(\\WOFF\.exe$)", {{
+ { "d3d11.disableMsaa", "True" },
+ }} },
+
+ /**********************************************/
+ /* D3D9 GAMES */
+ /**********************************************/
+
+ /* A Hat in Time */
+ { R"(\\HatinTimeGame\.exe$)", {{
+ { "d3d9.strictPow", "False" },
+ { "d3d9.lenientClear", "True" },
+ }} },
+ /* Anarchy Online */
+ { R"(\\anarchyonline\.exe$)", {{
+ { "d3d9.memoryTrackTest", "True" },
+ }} },
+ /* Borderlands 2 and The Pre Sequel! */
+ { R"(\\Borderlands(2|PreSequel)\.exe$)", {{
+ { "d3d9.lenientClear", "True" },
+ { "d3d9.supportDFFormats", "False" },
+ }} },
+ /* Borderlands */
+ { R"(\\Borderlands\.exe$)", {{
+ { "d3d9.lenientClear", "True" },
+ }} },
+ /* Gothic 3 */
+ { R"(\\Gothic(3|3Final| III Forsaken Gods)\.exe$)", {{
+ { "d3d9.supportDFFormats", "False" },
+ }} },
+ /* Risen */
+ { R"(\\Risen[23]?\.exe$)", {{
+ { "d3d9.invariantPosition", "True" },
+ }} },
+ /* Sonic Adventure 2 */
+ { R"(\\Sonic Adventure 2\\(launcher|sonic2app)\.exe$)", {{
+ { "d3d9.floatEmulation", "False" },
+ }} },
+ /* The Sims 2,
+ Body Shop,
+ The Sims Life Stories,
+ The Sims Pet Stories,
+ and The Sims Castaway Stories */
+ { R"(\\(Sims2.*|TS2BodyShop|SimsLS|SimsPS|SimsCS)\.exe$)", {{
+ { "d3d9.customVendorId", "10de" },
+ { "d3d9.customDeviceId", "0091" },
+ { "d3d9.customDeviceDesc", "GeForce 7800 GTX" },
+ { "d3d9.disableA8RT", "True" },
+ { "d3d9.supportX4R4G4B4", "False" },
+ { "d3d9.maxAvailableMemory", "2048" },
+ { "d3d9.memoryTrackTest", "True" },
+ // The Sims 2 will try to upload 1024 constants
+ // every frame otherwise, which it never uses
+ // causing a massive discard + upload.
+ { "d3d9.swvpFloatCount", "384" },
+ { "d3d9.swvpIntCount", "16" },
+ { "d3d9.swvpBoolCount", "16" },
+ }} },
+ /* Dead Space uses the a NULL render target instead
+ of a 1x1 one if DF24 is NOT supported */
+ { R"(\\Dead Space\.exe$)", {{
+ { "d3d9.supportDFFormats", "False" },
+ }} },
+ /* Halo 2 */
+ { R"(\\halo2\.exe$)", {{
+ { "d3d9.invariantPosition", "True" },
+ }} },
+ /* Halo CE/HaloPC */
+ { R"(\\halo(ce)?\.exe$)", {{
+ { "d3d9.invariantPosition", "True" },
+ // Game enables minor decal layering fixes
+ // specifically when it detects AMD.
+ // Avoids chip being detected as unsupported
+ // when on intel. Avoids possible path towards
+ // invalid texture addressing methods.
+ { "d3d9.customVendorId", "1002" },
+ // Avoids card not recognized error.
+ // Keeps game's rendering methods consistent
+ // for optimal compatibility.
+ { "d3d9.customDeviceId", "4172" },
+ // The game uses incorrect sampler types in
+ // the shaders for glass rendering which
+ // breaks it on native + us if we don't
+ // spec-constantly chose the sampler type
+ // automagically.
+ { "d3d9.forceSamplerTypeSpecConstants", "True" },
+ }} },
+ /* Counter Strike: Global Offensive
+ Needs NVAPI to avoid a forced AO + Smoke
+ exploit so we must force AMD vendor ID. */
+ { R"(\\csgo\.exe$)", {{
+ { "d3d9.customVendorId", "1002" },
+ }} },
+ /* Vampire - The Masquerade Bloodlines */
+ { R"(\\vampire\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ { "d3d9.memoryTrackTest", "True" },
+ { "d3d9.maxAvailableMemory", "1024" },
+ }} },
+ /* Senran Kagura Shinovi Versus */
+ { R"(\\SKShinoviVersus\.exe$)", {{
+ { "d3d9.forceAspectRatio", "16:9" },
+ }} },
+ /* Metal Slug X */
+ { R"(\\mslugx\.exe$)", {{
+ { "d3d9.supportD32", "False" },
+ }} },
+ /* Skyrim (NVAPI) */
+ { R"(\\TESV\.exe$)", {{
+ { "d3d9.customVendorId", "1002" },
+ }} },
+ /* RTHDRIBL Demo
+ Uses DONOTWAIT after GetRenderTargetData
+ then goes into an infinite loop if it gets
+ D3DERR_WASSTILLDRAWING.
+ This is a better solution than penalizing
+ other apps that use this properly. */
+ { R"(\\rthdribl\.exe$)", {{
+ { "d3d9.allowDoNotWait", "False" },
+ }} },
+ /* Hyperdimension Neptunia U: Action Unleashed */
+ { R"(\\Neptunia\.exe$)", {{
+ { "d3d9.forceAspectRatio", "16:9" },
+ }} },
+ /* D&D - The Temple Of Elemental Evil */
+ { R"(\\ToEE\.exe$)", {{
+ { "d3d9.allowDiscard", "False" },
+ }} },
+ /* ZUSI 3 - Aerosoft Edition */
+ { R"(\\ZusiSim\.exe$)", {{
+ { "d3d9.noExplicitFrontBuffer", "True" },
+ }} },
+ /* GTA IV (NVAPI) */
+ /* Also thinks we're always on Intel *
+ * and will report/use bad amounts of VRAM. */
+ { R"(\\GTAIV\.exe$)", {{
+ { "d3d9.customVendorId", "1002" },
+ { "dxgi.emulateUMA", "True" },
+ }} },
+ /* Battlefield 2 (bad z-pass) */
+ { R"(\\BF2\.exe$)", {{
+ { "d3d9.longMad", "True" },
+ { "d3d9.invariantPosition", "True" },
+ }} },
+ /* SpellForce 2 Series */
+ { R"(\\SpellForce2.*\.exe$)", {{
+ { "d3d9.forceSamplerTypeSpecConstants", "True" },
+ }} },
+ /* Everquest 2 */
+ { R"(\\EverQuest2.*\.exe$)", {{
+ { "d3d9.alphaTestWiggleRoom", "True" },
+ }} },
+ /* Tomb Raider: Legend */
+ { R"(\\trl\.exe$)", {{
+ { "d3d9.apitraceMode", "True" },
+ }} },
+ /* Everquest */
+ { R"(\\eqgame\.exe$)", {{
+ { "d3d9.apitraceMode", "True" },
+ }} },
+ /* Dark Messiah of Might & Magic */
+ { R"(\\mm\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ { "d3d9.memoryTrackTest", "True" },
+ }} },
+ /* TrackMania Forever */
+ { R"(\\TmForever\.exe$)", {{
+ { "d3d9.swvpFloatCount", "256" },
+ { "d3d9.swvpIntCount", "16" },
+ { "d3d9.swvpBoolCount", "16" },
+ }} },
+ /* Mafia 2 */
+ { R"(\\mafia2\.exe$)", {{
+ { "d3d9.customVendorId", "10de" },
+ { "d3d9.customDeviceId", "0402" },
+ }} },
+ /* Warhammer: Online */
+ { R"(\\WAR(-64)?\.exe$)", {{
+ { "d3d9.customVendorId", "1002" },
+ }} },
+ /* Dragon Nest */
+ { R"(\\DragonNest_x64\.exe$)", {{
+ { "d3d9.memoryTrackTest ", "True" },
+ }} },
+ /* Dal Segno */
+ { R"(\\DST\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Kohan II */
+ { R"(\\k2\.exe$)", {{
+ { "d3d9.memoryTrackTest", "True" },
+ }} },
+ /* Ninja Gaiden Sigma 1/2 */
+ { R"(\\NINJA GAIDEN SIGMA(2)?\.exe$)", {{
+ { "d3d9.deferSurfaceCreation", "True" },
+ }} },
+ /* Demon Stone breaks at frame rates > 60fps */
+ { R"(\\Demonstone\.exe$)", {{
+ { "d3d9.maxFrameRate", "60" },
+ }} },
+ /* Far Cry 1 has worse water rendering when it detects AMD GPUs */
+ { R"(\\FarCry\.exe$)", {{
+ { "d3d9.customVendorId", "10de" },
+ }} },
+ /* Earth Defense Force 5 */
+ { R"(\\EDF5\.exe$)", {{
+ { "dxgi.tearFree", "False" },
+ { "dxgi.syncInterval", "1" },
+ }} },
+ /* Sine Mora EX */
+ { R"(\\SineMoraEX\.exe$)", {{
+ { "d3d9.maxFrameRate", "60" },
+ }} },
+ /* Fantasy Grounds */
+ { R"(\\FantasyGrounds\.exe$)", {{
+ { "d3d9.noExplicitFrontBuffer", "True" },
+ }} },
+ }};
+
+
+ static bool isWhitespace(char ch) {
+ return ch == ' ' || ch == '\x9' || ch == '\r';
+ }
+
+
+ static bool isValidKeyChar(char ch) {
+ return (ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z')
+ || (ch >= 'a' && ch <= 'z')
+ || (ch == '.' || ch == '_');
+ }
+
+
+ static size_t skipWhitespace(const std::string& line, size_t n) {
+ while (n < line.size() && isWhitespace(line[n]))
+ n += 1;
+ return n;
+ }
+
+
+ struct ConfigContext {
+ bool active;
+ };
+
+
+ static void parseUserConfigLine(Config& config, ConfigContext& ctx, const std::string& line) {
+ std::stringstream key;
+ std::stringstream value;
+
+ // Extract the key
+ size_t n = skipWhitespace(line, 0);
+
+ if (n < line.size() && line[n] == '[') {
+ n += 1;
+
+ size_t e = line.size() - 1;
+ while (e > n && line[e] != ']')
+ e -= 1;
+
+ while (n < e)
+ key << line[n++];
+
+ ctx.active = key.str() == env::getExeName();
+ } else {
+ while (n < line.size() && isValidKeyChar(line[n]))
+ key << line[n++];
+
+ // Check whether the next char is a '='
+ n = skipWhitespace(line, n);
+ if (n >= line.size() || line[n] != '=')
+ return;
+
+ // Extract the value
+ bool insideString = false;
+ n = skipWhitespace(line, n + 1);
+
+ while (n < line.size()) {
+ if (!insideString && isWhitespace(line[n]))
+ break;
+
+ if (line[n] == '"') {
+ insideString = !insideString;
+ n++;
+ } else
+ value << line[n++];
+ }
+
+ if (ctx.active)
+ config.setOption(key.str(), value.str());
+ }
+ }
+
+
+ Config::Config() { }
+ Config::~Config() { }
+
+
+ Config::Config(OptionMap&& options)
+ : m_options(std::move(options)) { }
+
+
+ void Config::merge(const Config& other) {
+ for (auto& pair : other.m_options)
+ m_options.insert(pair);
+ }
+
+
+ void Config::setOption(const std::string& key, const std::string& value) {
+ m_options.insert_or_assign(key, value);
+ }
+
+
+ std::string Config::getOptionValue(const char* option) const {
+ auto iter = m_options.find(option);
+
+ return iter != m_options.end()
+ ? iter->second : std::string();
+ }
+
+
+ bool Config::parseOptionValue(
+ const std::string& value,
+ std::string& result) {
+ result = value;
+ return true;
+ }
+
+
+ bool Config::parseOptionValue(
+ const std::string& value,
+ bool& result) {
+ static const std::array<std::pair<const char*, bool>, 2> s_lookup = {{
+ { "true", true },
+ { "false", false },
+ }};
+
+ return parseStringOption(value,
+ s_lookup.begin(), s_lookup.end(), result);
+ }
+
+
+ bool Config::parseOptionValue(
+ const std::string& value,
+ int32_t& result) {
+ if (value.size() == 0)
+ return false;
+
+ // Parse sign, don't allow '+'
+ int32_t sign = 1;
+ size_t start = 0;
+
+ if (value[0] == '-') {
+ sign = -1;
+ start = 1;
+ }
+
+ // Parse absolute number
+ int32_t intval = 0;
+
+ for (size_t i = start; i < value.size(); i++) {
+ if (value[i] < '0' || value[i] > '9')
+ return false;
+
+ intval *= 10;
+ intval += value[i] - '0';
+ }
+
+ // Apply sign and return
+ result = sign * intval;
+ return true;
+ }
+
+
+ bool Config::parseOptionValue(
+ const std::string& value,
+ Tristate& result) {
+ static const std::array<std::pair<const char*, Tristate>, 3> s_lookup = {{
+ { "true", Tristate::True },
+ { "false", Tristate::False },
+ { "auto", Tristate::Auto },
+ }};
+
+ return parseStringOption(value,
+ s_lookup.begin(), s_lookup.end(), result);
+ }
+
+
+ template<typename I, typename V>
+ bool Config::parseStringOption(
+ std::string str,
+ I begin,
+ I end,
+ V& value) {
+ std::transform(str.begin(), str.end(), str.begin(),
+ [] (unsigned char c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; });
+
+ for (auto i = begin; i != end; i++) {
+ if (str == i->first) {
+ value = i->second;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ Config Config::getAppConfig(const std::string& appName) {
+ auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.end(),
+ [&appName] (const std::pair<const char*, Config>& pair) {
+ std::regex expr(pair.first, std::regex::extended | std::regex::icase);
+ return std::regex_search(appName, expr);
+ });
+
+ if (appConfig != g_appDefaults.end()) {
+ // Inform the user that we loaded a default config
+ Logger::info(str::format("Found built-in config:"));
+ return appConfig->second;
+ }
+
+ return Config();
+ }
+
+
+ Config Config::getUserConfig() {
+ Config config;
+
+ // Load either $DXVK_CONFIG_FILE or $PWD/dxvk.conf
+ std::string filePath = env::getEnvVar("DXVK_CONFIG_FILE");
+
+ if (filePath == "")
+ filePath = "dxvk.conf";
+
+ // Open the file if it exists
+#ifdef _WIN32
+ std::ifstream stream(str::tows(filePath.c_str()).c_str());
+#else
+ std::ifstream stream(filePath.c_str());
+#endif
+
+ if (!stream)
+ return config;
+
+ // Inform the user that we loaded a file, might
+ // help when debugging configuration issues
+ Logger::info(str::format("Found config file: ", filePath));
+
+ // Initialize parser context
+ ConfigContext ctx;
+ ctx.active = true;
+
+ // Parse the file line by line
+ std::string line;
+
+ while (std::getline(stream, line))
+ parseUserConfigLine(config, ctx, line);
+
+ return config;
+ }
+
+
+ void Config::logOptions() const {
+ if (!m_options.empty()) {
+ Logger::info("Effective configuration:");
+
+ for (auto& pair : m_options)
+ Logger::info(str::format(" ", pair.first, " = ", pair.second));
+ }
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/config/config.h b/src/libs/dxvk-native-1.9.2a/src/util/config/config.h
new file mode 100644
index 00000000..5951a27c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/config/config.h
@@ -0,0 +1,152 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+namespace dxvk {
+
+ /**
+ * \brief Tri-state
+ *
+ * Used to conditionally override
+ * booleans if desired.
+ */
+ enum class Tristate : int32_t {
+ Auto = -1,
+ False = 0,
+ True = 1,
+ };
+
+ /**
+ * \brief Config option set
+ *
+ * Stores configuration options
+ * as a set of key-value pairs.
+ */
+ class Config {
+ using OptionMap = std::unordered_map<std::string, std::string>;
+ public:
+
+ Config();
+ Config(OptionMap&& options);
+ ~Config();
+
+ /**
+ * \brief Merges two configuration sets
+ *
+ * Options specified in this config object will
+ * not be overridden if they are specified in
+ * the second config object.
+ * \param [in] other Config set to merge.
+ */
+ void merge(const Config& other);
+
+ /**
+ * \brief Sets an option
+ *
+ * \param [in] key Option name
+ * \param [in] value Option value
+ */
+ void setOption(
+ const std::string& key,
+ const std::string& value);
+
+ /**
+ * \brief Parses an option value
+ *
+ * Retrieves the option value as a string, and then
+ * tries to convert that string to the given type.
+ * If parsing the string fails because it is either
+ * invalid or if the option is not defined, this
+ * method will return a fallback value.
+ *
+ * Currently, this supports the types \c bool,
+ * \c int32_t, and \c std::string.
+ * \tparam T Return value type
+ * \param [in] option Option name
+ * \param [in] fallback Fallback value
+ * \returns Parsed option value
+ * \returns The parsed option value
+ */
+ template<typename T>
+ T getOption(const char* option, T fallback = T()) const {
+ const std::string& value = getOptionValue(option);
+
+ T result = fallback;
+ parseOptionValue(value, result);
+ return result;
+ }
+
+ /**
+ * \brief Logs option values
+ *
+ * Prints the effective configuration
+ * to the log for debugging purposes.
+ */
+ void logOptions() const;
+
+ /**
+ * \brief Retrieves default options for an app
+ *
+ * \param [in] appName Name of the application
+ * \returns Default options for the application
+ */
+ static Config getAppConfig(const std::string& appName);
+
+ /**
+ * \brief Retrieves user configuration
+ *
+ * Reads options from the configuration file,
+ * if it can be found, or an empty option set.
+ * \returns User-defined configuration options
+ */
+ static Config getUserConfig();
+
+ private:
+
+ OptionMap m_options;
+
+ std::string getOptionValue(
+ const char* option) const;
+
+ static bool parseOptionValue(
+ const std::string& value,
+ std::string& result);
+
+ static bool parseOptionValue(
+ const std::string& value,
+ bool& result);
+
+ static bool parseOptionValue(
+ const std::string& value,
+ int32_t& result);
+
+ static bool parseOptionValue(
+ const std::string& value,
+ Tristate& result);
+
+ template<typename I, typename V>
+ static bool parseStringOption(
+ std::string str,
+ I begin,
+ I end,
+ V& value);
+
+ };
+
+
+ /**
+ * \brief Applies tristate option
+ *
+ * Overrides the given value if \c state is
+ * \c True or \c False, and leaves it intact
+ * otherwise.
+ * \param [out] option The value to override
+ * \param [in] state Tristate to apply
+ */
+ inline void applyTristate(bool& option, Tristate state) {
+ option &= state != Tristate::False;
+ option |= state == Tristate::True;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/log/log.cpp b/src/libs/dxvk-native-1.9.2a/src/util/log/log.cpp
new file mode 100644
index 00000000..e096ee2f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/log/log.cpp
@@ -0,0 +1,146 @@
+#ifdef VBOX
+#include <iprt/log.h>
+#endif
+
+#include "log.h"
+
+#include "../util_env.h"
+
+namespace dxvk {
+
+ Logger::Logger(const std::string& file_name)
+ : m_minLevel(getMinLogLevel()) {
+ if (m_minLevel != LogLevel::None) {
+ auto path = getFileName(file_name);
+
+ if (!path.empty()) {
+#ifdef _WIN32
+ m_fileStream = std::ofstream(str::tows(path.c_str()).c_str());
+#else
+ m_fileStream = std::ofstream(path.c_str());
+#endif
+ }
+ }
+ }
+
+
+ Logger::~Logger() { }
+
+
+ void Logger::trace(const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(LogLevel::Trace, message);
+#else
+ LogRel2(("%s", message.c_str()));
+#endif
+ }
+
+
+ void Logger::debug(const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(LogLevel::Debug, message);
+#else
+ LogFlow(("%s", message.c_str()));
+#endif
+ }
+
+
+ void Logger::info(const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(LogLevel::Info, message);
+#else
+ Log(("%s", message.c_str()));
+#endif
+ }
+
+
+ void Logger::warn(const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(LogLevel::Warn, message);
+#else
+ LogRel(("%s", message.c_str()));
+#endif
+ }
+
+
+ void Logger::err(const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(LogLevel::Error, message);
+#else
+ LogRel(("%s", message.c_str()));
+#endif
+ }
+
+
+ void Logger::log(LogLevel level, const std::string& message) {
+#ifndef VBOX
+ s_instance.emitMsg(level, message);
+#else
+ Log(("%s", message.c_str()));
+#endif
+ }
+
+#ifndef VBOX
+ void Logger::emitMsg(LogLevel level, const std::string& message) {
+ if (level >= m_minLevel) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ static std::array<const char*, 5> s_prefixes
+ = {{ "trace: ", "debug: ", "info: ", "warn: ", "err: " }};
+
+ const char* prefix = s_prefixes.at(static_cast<uint32_t>(level));
+
+ std::stringstream stream(message);
+ std::string line;
+
+ while (std::getline(stream, line, '\n')) {
+ std::cerr << prefix << line << std::endl;
+
+ if (m_fileStream)
+ m_fileStream << prefix << line << std::endl;
+ }
+ }
+ }
+#endif
+
+ LogLevel Logger::getMinLogLevel() {
+#ifndef VBOX
+ const std::array<std::pair<const char*, LogLevel>, 6> logLevels = {{
+ { "trace", LogLevel::Trace },
+ { "debug", LogLevel::Debug },
+ { "info", LogLevel::Info },
+ { "warn", LogLevel::Warn },
+ { "error", LogLevel::Error },
+ { "none", LogLevel::None },
+ }};
+
+ const std::string logLevelStr = env::getEnvVar("DXVK_LOG_LEVEL");
+
+ for (const auto& pair : logLevels) {
+ if (logLevelStr == pair.first)
+ return pair.second;
+ }
+#endif
+ return LogLevel::Info;
+ }
+
+
+ std::string Logger::getFileName(const std::string& base) {
+#ifndef VBOX
+ std::string path = env::getEnvVar("DXVK_LOG_PATH");
+
+ if (path == "none")
+ return "";
+
+ if (!path.empty() && *path.rbegin() != '/')
+ path += '/';
+
+ std::string exeName = env::getExeBaseName();
+ path += exeName + "_" + base;
+ return path;
+#else
+ return "";
+#endif
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/log/log.h b/src/libs/dxvk-native-1.9.2a/src/util/log/log.h
new file mode 100644
index 00000000..93c05ffb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/log/log.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <array>
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "../thread.h"
+
+namespace dxvk {
+
+ enum class LogLevel : uint32_t {
+ Trace = 0,
+ Debug = 1,
+ Info = 2,
+ Warn = 3,
+ Error = 4,
+ None = 5,
+ };
+
+ /**
+ * \brief Logger
+ *
+ * Logger for one DLL. Creates a text file and
+ * writes all log messages to that file.
+ */
+ class Logger {
+
+ public:
+
+ Logger(const std::string& file_name);
+ ~Logger();
+
+ static void trace(const std::string& message);
+ static void debug(const std::string& message);
+ static void info (const std::string& message);
+ static void warn (const std::string& message);
+ static void err (const std::string& message);
+ static void log (LogLevel level, const std::string& message);
+
+ static LogLevel logLevel() {
+#ifndef VBOX
+ return s_instance.m_minLevel;
+#else
+ return LogLevel::Info;
+#endif
+ }
+
+ private:
+
+#ifndef VBOX
+ static Logger s_instance;
+#endif
+
+ const LogLevel m_minLevel;
+
+ dxvk::mutex m_mutex;
+ std::ofstream m_fileStream;
+
+#ifndef VBOX
+ void emitMsg(LogLevel level, const std::string& message);
+#endif
+
+ static LogLevel getMinLogLevel();
+
+ static std::string getFileName(
+ const std::string& base);
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.cpp b/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.cpp
new file mode 100644
index 00000000..c67742ab
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.cpp
@@ -0,0 +1,11 @@
+#include "log_debug.h"
+
+namespace dxvk::debug {
+
+ std::string methodName(const std::string& prettyName) {
+ size_t end = prettyName.find("(");
+ size_t begin = prettyName.substr(0, end).rfind(" ") + 1;
+ return prettyName.substr(begin,end - begin);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.h b/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.h
new file mode 100644
index 00000000..c5084320
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/log/log_debug.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <sstream>
+
+#include "log.h"
+
+#ifdef _MSC_VER
+#define METHOD_NAME __FUNCSIG__
+#else
+#define METHOD_NAME __PRETTY_FUNCTION__
+#endif
+
+#define TRACE_ENABLED
+
+#ifdef TRACE_ENABLED
+#define TRACE(...) \
+ do { dxvk::debug::trace(METHOD_NAME, ##__VA_ARGS__); } while (0)
+#else
+#define TRACE(...) \
+ do { } while (0)
+#endif
+
+namespace dxvk::debug {
+
+ std::string methodName(const std::string& prettyName);
+
+ inline void traceArgs(std::stringstream& stream) { }
+
+ template<typename Arg1>
+ void traceArgs(std::stringstream& stream, const Arg1& arg1) {
+ stream << arg1;
+ }
+
+ template<typename Arg1, typename Arg2, typename... Args>
+ void traceArgs(std::stringstream& stream, const Arg1& arg1, const Arg2& arg2, const Args&... args) {
+ stream << arg1 << ",";
+ traceArgs(stream, arg2, args...);
+ }
+
+ template<typename... Args>
+ void trace(const std::string& funcName, const Args&... args) {
+ std::stringstream stream;
+ stream << methodName(funcName) << "(";
+ traceArgs(stream, args...);
+ stream << ")";
+ Logger::trace(stream.str());
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/meson.build b/src/libs/dxvk-native-1.9.2a/src/util/meson.build
new file mode 100644
index 00000000..dbaba372
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/meson.build
@@ -0,0 +1,49 @@
+util_src = [
+ 'util_env.cpp',
+ 'util_fps_limiter.cpp',
+ 'util_matrix.cpp',
+ 'util_monitor.cpp',
+
+ 'com/com_guid.cpp',
+ 'com/com_private_data.cpp',
+
+ 'config/config.cpp',
+
+ 'log/log.cpp',
+ 'log/log_debug.cpp',
+
+ 'sha1/sha1.c',
+ 'sha1/sha1_util.cpp',
+
+ 'sync/sync_recursive.cpp',
+]
+
+util_src_win32 = [
+ 'util_gdi.cpp',
+
+ 'platform/util_luid_win32.cpp',
+ 'platform/util_env_win32.cpp',
+ 'platform/util_string_win32.cpp'
+]
+
+util_src_linux = [
+ 'platform/util_luid_linux.cpp',
+ 'platform/util_env_linux.cpp',
+ 'platform/util_string_linux.cpp',
+ 'platform/thread_native.cpp',
+]
+
+if dxvk_platform == 'windows'
+ util_src += util_src_win32
+elif dxvk_platform == 'linux'
+ util_src += util_src_linux
+else
+ error('Unknown platform for util')
+endif
+
+util_lib = static_library('util', util_src,
+ include_directories : [ dxvk_include_path ],
+ override_options : ['cpp_std='+dxvk_cpp_std])
+
+util_dep = declare_dependency(
+ link_with : [ util_lib ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/thread_native.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/thread_native.cpp
new file mode 100644
index 00000000..5337afd4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/thread_native.cpp
@@ -0,0 +1,21 @@
+#include "../thread.h"
+#include "../util_likely.h"
+
+#include <atomic>
+
+namespace dxvk::this_thread {
+
+ std::atomic<uint32_t> g_threadCtr = { 0u };
+ thread_local uint32_t g_threadId = 0u;
+
+ // This implementation returns thread ids unique to the current instance.
+ // Ie. if you use this across multiple .so's then you might get conflicting ids.
+ // This isn't an issue for us as we only use it in d3d11, but do check if this changes.
+ uint32_t get_id() {
+ if (unlikely(!g_threadId))
+ g_threadId = ++g_threadCtr;
+
+ return g_threadId;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_linux.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_linux.cpp
new file mode 100644
index 00000000..25b03edc
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_linux.cpp
@@ -0,0 +1,44 @@
+#include "util_env.h"
+
+ #include <array>
+#ifndef VBOX
+#include <filesystem>
+#endif
+#include <unistd.h>
+#include <limits.h>
+
+#ifdef VBOX
+# include <iprt/process.h>
+# include <iprt/path.h>
+#endif
+
+namespace dxvk::env {
+
+ std::string getExePath() {
+#ifndef VBOX
+ std::array<char, PATH_MAX> exePath = {};
+
+ size_t count = readlink("/proc/self/exe", exePath.data(), exePath.size());
+
+ return std::string(exePath.begin(), exePath.begin() + count);
+#else
+ char szExePath[RTPATH_MAX];
+ RTProcGetExecutablePath(&szExePath[0], sizeof(szExePath));
+ return std::string(&szExePath[0]);
+#endif
+ }
+
+
+ void setThreadName(const std::string& name) {
+ }
+
+
+ bool createDirectory(const std::string& path) {
+#ifndef VBOX
+ return std::filesystem::create_directories(path);
+#else
+ return false;
+#endif
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_win32.cpp
new file mode 100644
index 00000000..8b86bccf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_env_win32.cpp
@@ -0,0 +1,38 @@
+#include "util_env.h"
+
+#include "./com/com_include.h"
+
+namespace dxvk::env {
+
+ std::string getExePath() {
+ std::vector<WCHAR> exePath;
+ exePath.resize(MAX_PATH + 1);
+
+ DWORD len = ::GetModuleFileNameW(NULL, exePath.data(), MAX_PATH);
+ exePath.resize(len);
+
+ return str::fromws(exePath.data());
+ }
+
+
+ void setThreadName(const std::string& name) {
+ using SetThreadDescriptionProc = HRESULT (WINAPI *) (HANDLE, PCWSTR);
+
+ static auto proc = reinterpret_cast<SetThreadDescriptionProc>(
+ ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "SetThreadDescription"));
+
+ if (proc != nullptr) {
+ auto wideName = std::vector<WCHAR>(name.length() + 1);
+ str::tows(name.c_str(), wideName.data(), wideName.size());
+ (*proc)(::GetCurrentThread(), wideName.data());
+ }
+ }
+
+
+ bool createDirectory(const std::string& path) {
+ WCHAR widePath[MAX_PATH];
+ str::tows(path.c_str(), widePath);
+ return !!CreateDirectoryW(widePath, nullptr);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_linux.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_linux.cpp
new file mode 100644
index 00000000..9c3aa05b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_linux.cpp
@@ -0,0 +1,13 @@
+#include "util_luid.h"
+
+#include "./log/log.h"
+
+namespace dxvk {
+
+ LUID GetAdapterLUID(UINT Adapter) {
+ Logger::warn("GetAdapterLUID: native stub");
+
+ return LUID();
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_win32.cpp
new file mode 100644
index 00000000..96a2a09a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_luid_win32.cpp
@@ -0,0 +1,34 @@
+#include "util_luid.h"
+#include "util_string.h"
+
+#include "./log/log.h"
+
+#include <mutex>
+#include <vector>
+
+namespace dxvk {
+
+ LUID GetAdapterLUID(UINT Adapter) {
+ static dxvk::mutex s_mutex;
+ static std::vector<LUID> s_luids;
+
+ std::lock_guard<dxvk::mutex> lock(s_mutex);
+ uint32_t newLuidCount = Adapter + 1;
+
+ while (s_luids.size() < newLuidCount) {
+ LUID luid = { 0, 0 };
+
+ if (!::AllocateLocallyUniqueId(&luid))
+ Logger::err("Failed to allocate LUID");
+
+
+ Logger::info(str::format("Adapter LUID ", s_luids.size(), ": ",
+ std::hex, luid.HighPart, ":", luid.LowPart, std::dec));
+
+ s_luids.push_back(luid);
+ }
+
+ return s_luids[Adapter];
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_linux.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_linux.cpp
new file mode 100644
index 00000000..dbce6458
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_linux.cpp
@@ -0,0 +1,19 @@
+#include "util_string.h"
+
+#include <string>
+#include <algorithm>
+
+namespace dxvk::str {
+
+ std::string fromws(const WCHAR *ws) {
+ size_t count = wcslen(ws);
+
+ return std::string(ws, ws + count);
+ }
+
+
+ void tows(const char* mbs, WCHAR* wcs, size_t wcsLen) {
+ std::mbstowcs(wcs, mbs, wcsLen);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_win32.cpp
new file mode 100644
index 00000000..2151c1e4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/platform/util_string_win32.cpp
@@ -0,0 +1,43 @@
+#include "util_string.h"
+
+namespace dxvk::str {
+ std::string fromws(const WCHAR *ws) {
+ size_t len = ::WideCharToMultiByte(CP_UTF8,
+ 0, ws, -1, nullptr, 0, nullptr, nullptr);
+
+ if (len <= 1)
+ return "";
+
+ len -= 1;
+
+ std::string result;
+ result.resize(len);
+ ::WideCharToMultiByte(CP_UTF8, 0, ws, -1,
+ &result.at(0), len, nullptr, nullptr);
+ return result;
+ }
+
+
+ void tows(const char* mbs, WCHAR* wcs, size_t wcsLen) {
+ ::MultiByteToWideChar(
+ CP_UTF8, 0, mbs, -1,
+ wcs, wcsLen);
+ }
+
+ std::wstring tows(const char* mbs) {
+ size_t len = ::MultiByteToWideChar(CP_UTF8,
+ 0, mbs, -1, nullptr, 0);
+
+ if (len <= 1)
+ return L"";
+
+ len -= 1;
+
+ std::wstring result;
+ result.resize(len);
+ ::MultiByteToWideChar(CP_UTF8, 0, mbs, -1,
+ &result.at(0), len);
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc.h b/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc.h
new file mode 100644
index 00000000..c33d0c61
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <atomic>
+
+namespace dxvk {
+
+ /**
+ * \brief Reference-counted object
+ */
+ class RcObject {
+
+ public:
+
+ /**
+ * \brief Increments reference count
+ * \returns New reference count
+ */
+ uint32_t incRef() {
+ return ++m_refCount;
+ }
+
+ /**
+ * \brief Decrements reference count
+ * \returns New reference count
+ */
+ uint32_t decRef() {
+ return --m_refCount;
+ }
+
+ private:
+
+ std::atomic<uint32_t> m_refCount = { 0u };
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc_ptr.h b/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc_ptr.h
new file mode 100644
index 00000000..23c5c43d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/rc/util_rc_ptr.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#include <functional>
+#include <ostream>
+
+namespace dxvk {
+
+ /**
+ * \brief Pointer for reference-counted objects
+ *
+ * This only requires the given type to implement \c incRef
+ * and \c decRef methods that adjust the reference count.
+ * \tparam T Object type
+ */
+ template<typename T>
+ class Rc {
+ template<typename Tx>
+ friend class Rc;
+ public:
+
+ Rc() { }
+ Rc(std::nullptr_t) { }
+
+ Rc(T* object)
+ : m_object(object) {
+ this->incRef();
+ }
+
+ Rc(const Rc& other)
+ : m_object(other.m_object) {
+ this->incRef();
+ }
+
+ template<typename Tx>
+ Rc(const Rc<Tx>& other)
+ : m_object(other.m_object) {
+ this->incRef();
+ }
+
+ Rc(Rc&& other)
+ : m_object(other.m_object) {
+ other.m_object = nullptr;
+ }
+
+ template<typename Tx>
+ Rc(Rc<Tx>&& other)
+ : m_object(other.m_object) {
+ other.m_object = nullptr;
+ }
+
+ Rc& operator = (std::nullptr_t) {
+ this->decRef();
+ m_object = nullptr;
+ return *this;
+ }
+
+ Rc& operator = (const Rc& other) {
+ other.incRef();
+ this->decRef();
+ m_object = other.m_object;
+ return *this;
+ }
+
+ template<typename Tx>
+ Rc& operator = (const Rc<Tx>& other) {
+ other.incRef();
+ this->decRef();
+ m_object = other.m_object;
+ return *this;
+ }
+
+ Rc& operator = (Rc&& other) {
+ this->decRef();
+ this->m_object = other.m_object;
+ other.m_object = nullptr;
+ return *this;
+ }
+
+ template<typename Tx>
+ Rc& operator = (Rc<Tx>&& other) {
+ this->decRef();
+ this->m_object = other.m_object;
+ other.m_object = nullptr;
+ return *this;
+ }
+
+ ~Rc() {
+ this->decRef();
+ }
+
+ T& operator * () const { return *m_object; }
+ T* operator -> () const { return m_object; }
+ T* ptr() const { return m_object; }
+
+ bool operator == (const Rc& other) const { return m_object == other.m_object; }
+ bool operator != (const Rc& other) const { return m_object != other.m_object; }
+
+ bool operator == (std::nullptr_t) const { return m_object == nullptr; }
+ bool operator != (std::nullptr_t) const { return m_object != nullptr; }
+
+ private:
+
+ T* m_object = nullptr;
+
+ void incRef() const {
+ if (m_object != nullptr)
+ m_object->incRef();
+ }
+
+ void decRef() const {
+ if (m_object != nullptr) {
+ if (m_object->decRef() == 0)
+ delete m_object;
+ }
+ }
+
+ };
+
+}
+
+template<typename T>
+std::ostream& operator << (std::ostream& os, const dxvk::Rc<T>& rc) {
+ return os << rc.ptr();
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.c b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.c
new file mode 100644
index 00000000..39e60675
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.c
@@ -0,0 +1,170 @@
+/* $OpenBSD: sha1.c,v 1.26 2015/09/11 09:18:27 guenther Exp $ */
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+typedef union {
+ uint8_t c[64];
+ uint32_t l[16];
+} CHAR64LONG16;
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+void
+SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d, e;
+ uint8_t workspace[SHA1_BLOCK_LENGTH];
+ CHAR64LONG16 *block = (CHAR64LONG16 *)workspace;
+
+ (void)memcpy(block, buffer, SHA1_BLOCK_LENGTH);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/*
+ * SHA1Init - Initialize new context
+ */
+void
+SHA1Init(SHA1_CTX *context)
+{
+
+ /* SHA1 initialization constants */
+ context->count = 0;
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+}
+
+
+/*
+ * Run your data through this.
+ */
+void
+SHA1Update(SHA1_CTX *context, const uint8_t *data, size_t len)
+{
+ size_t i, j;
+
+ j = (size_t)((context->count >> 3) & 63);
+ context->count += (len << 3);
+ if ((j + len) > 63) {
+ (void)memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64)
+ SHA1Transform(context->state, (uint8_t *)&data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+ (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+void
+SHA1Pad(SHA1_CTX *context)
+{
+ uint8_t finalcount[8];
+ uint32_t i;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (uint8_t)((context->count >>
+ ((7 - (i & 7)) * 8)) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (uint8_t *)"\200", 1);
+ while ((context->count & 504) != 448)
+ SHA1Update(context, (uint8_t *)"\0", 1);
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+}
+
+void
+SHA1Final(uint8_t digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
+{
+ uint32_t i;
+
+ SHA1Pad(context);
+ for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ digest[i] = (uint8_t)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ memset(context, 0, sizeof(*context));
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.h b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.h
new file mode 100644
index 00000000..029a0ae8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: sha1.h,v 1.24 2012/12/05 23:19:57 deraadt Exp $ */
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ */
+
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define SHA1_BLOCK_LENGTH 64
+#define SHA1_DIGEST_LENGTH 20
+#define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _SHA1_CTX {
+ uint32_t state[5];
+ uint64_t count;
+ uint8_t buffer[SHA1_BLOCK_LENGTH];
+} SHA1_CTX;
+
+void SHA1Init(SHA1_CTX *);
+void SHA1Pad(SHA1_CTX *);
+void SHA1Transform(uint32_t [5], const uint8_t [SHA1_BLOCK_LENGTH]);
+void SHA1Update(SHA1_CTX *, const uint8_t *, size_t);
+void SHA1Final(uint8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *);
+
+#define HTONDIGEST(x) do { \
+ x[0] = htonl(x[0]); \
+ x[1] = htonl(x[1]); \
+ x[2] = htonl(x[2]); \
+ x[3] = htonl(x[3]); \
+ x[4] = htonl(x[4]); } while (0)
+
+#define NTOHDIGEST(x) do { \
+ x[0] = ntohl(x[0]); \
+ x[1] = ntohl(x[1]); \
+ x[2] = ntohl(x[2]); \
+ x[3] = ntohl(x[3]); \
+ x[4] = ntohl(x[4]); } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SHA1_H */
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.cpp b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.cpp
new file mode 100644
index 00000000..eefc9275
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.cpp
@@ -0,0 +1,48 @@
+#include "sha1.h"
+#include "sha1_util.h"
+
+namespace dxvk {
+
+ std::string Sha1Hash::toString() const {
+ static const char nibbles[]
+ = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ std::string result;
+ result.resize(2 * m_digest.size());
+
+ for (uint32_t i = 0; i < m_digest.size(); i++) {
+ result.at(2 * i + 0) = nibbles[(m_digest[i] >> 4) & 0xF];
+ result.at(2 * i + 1) = nibbles[(m_digest[i] >> 0) & 0xF];
+ }
+
+ return result;
+ }
+
+
+ Sha1Hash Sha1Hash::compute(
+ const void* data,
+ size_t size) {
+ Sha1Data chunk = { data, size };
+ return compute(1, &chunk);
+ }
+
+
+ Sha1Hash Sha1Hash::compute(
+ size_t numChunks,
+ const Sha1Data* chunks) {
+ Sha1Digest digest;
+
+ SHA1_CTX ctx;
+ SHA1Init(&ctx);
+
+ for (size_t i = 0; i < numChunks; i++) {
+ auto ptr = reinterpret_cast<const uint8_t*>(chunks[i].data);
+ SHA1Update(&ctx, ptr, chunks[i].size);
+ }
+
+ SHA1Final(digest.data(), &ctx);
+ return Sha1Hash(digest);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.h b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.h
new file mode 100644
index 00000000..9d83ab8c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sha1/sha1_util.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <array>
+#include <cstring>
+#include <string>
+
+namespace dxvk {
+
+ using Sha1Digest = std::array<uint8_t, 20>;
+
+ struct Sha1Data {
+ const void* data;
+ size_t size;
+ };
+
+ class Sha1Hash {
+
+ public:
+
+ Sha1Hash() { }
+ Sha1Hash(const Sha1Digest& digest)
+ : m_digest(digest) { }
+
+ std::string toString() const;
+
+ uint32_t dword(uint32_t id) const {
+ return uint32_t(m_digest[4 * id + 0]) << 0
+ | uint32_t(m_digest[4 * id + 1]) << 8
+ | uint32_t(m_digest[4 * id + 2]) << 16
+ | uint32_t(m_digest[4 * id + 3]) << 24;
+ }
+
+ bool operator == (const Sha1Hash& other) const {
+ return !std::memcmp(
+ this->m_digest.data(),
+ other.m_digest.data(),
+ other.m_digest.size());
+ }
+
+ bool operator != (const Sha1Hash& other) const {
+ return !this->operator == (other);
+ }
+
+ static Sha1Hash compute(
+ const void* data,
+ size_t size);
+
+ static Sha1Hash compute(
+ size_t numChunks,
+ const Sha1Data* chunks);
+
+ template<typename T>
+ static Sha1Hash compute(const T& data) {
+ return compute(&data, sizeof(T));
+ }
+
+ private:
+
+ Sha1Digest m_digest;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.cpp b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.cpp
new file mode 100644
index 00000000..180d3f1f
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.cpp
@@ -0,0 +1,37 @@
+#include "sync_recursive.h"
+#include "sync_spinlock.h"
+#include "../thread.h"
+
+namespace dxvk::sync {
+
+ void RecursiveSpinlock::lock() {
+ spin(2000, [this] { return try_lock(); });
+ }
+
+
+ void RecursiveSpinlock::unlock() {
+ if (likely(m_counter == 0))
+ m_owner.store(0, std::memory_order_release);
+ else
+ m_counter -= 1;
+ }
+
+
+ bool RecursiveSpinlock::try_lock() {
+ uint32_t threadId = dxvk::this_thread::get_id();
+ uint32_t expected = 0;
+
+ bool status = m_owner.compare_exchange_weak(
+ expected, threadId, std::memory_order_acquire);
+
+ if (status)
+ return true;
+
+ if (expected != threadId)
+ return false;
+
+ m_counter += 1;
+ return true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.h b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.h
new file mode 100644
index 00000000..1bb64db1
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_recursive.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <atomic>
+
+#include "../com/com_include.h"
+
+namespace dxvk::sync {
+
+ /**
+ * \brief Recursive spinlock
+ *
+ * Implements a spinlock that can be acquired
+ * by the same thread multiple times.
+ */
+ class RecursiveSpinlock {
+
+ public:
+
+ void lock();
+
+ void unlock();
+
+ bool try_lock();
+
+ private:
+
+ std::atomic<uint32_t> m_owner = { 0u };
+ uint32_t m_counter = { 0u };
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_signal.h b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_signal.h
new file mode 100644
index 00000000..cdbcae82
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_signal.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <list>
+
+#include "../rc/util_rc.h"
+
+#include "../thread.h"
+
+namespace dxvk::sync {
+
+ /**
+ * \brief Signal
+ *
+ * Interface for a CPU-side fence. Can be signaled
+ * to a given value, and any thread waiting for a
+ * lower value will be woken up.
+ */
+ class Signal : public RcObject {
+
+ public:
+
+ virtual ~Signal() { }
+
+ /**
+ * \brief Last signaled value
+ * \returns Last signaled value
+ */
+ virtual uint64_t value() const = 0;
+
+ /**
+ * \brief Notifies signal
+ *
+ * Wakes up all threads currently waiting for
+ * a value lower than \c value. Note that
+ * \c value must monotonically increase.
+ * \param [in] value Value to signal to
+ */
+ virtual void signal(uint64_t value) = 0;
+
+ /**
+ * \brief Waits for signal
+ *
+ * Blocks the calling thread until another
+ * thread signals it with a value equal to
+ * or greater than \c value.
+ * \param [in] value The value to wait for
+ */
+ virtual void wait(uint64_t value) = 0;
+
+ };
+
+
+ /**
+ * \brief Fence
+ *
+ * Simple CPU-side fence.
+ */
+ class Fence final : public Signal {
+
+ public:
+
+ Fence()
+ : m_value(0ull) { }
+
+ explicit Fence(uint64_t value)
+ : m_value(value) { }
+
+ uint64_t value() const {
+ return m_value.load(std::memory_order_acquire);
+ }
+
+ void signal(uint64_t value) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_value.store(value, std::memory_order_release);
+ m_cond.notify_all();
+ }
+
+ void wait(uint64_t value) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_cond.wait(lock, [this, value] {
+ return value <= m_value.load(std::memory_order_acquire);
+ });
+ }
+
+ private:
+
+ std::atomic<uint64_t> m_value;
+ dxvk::mutex m_mutex;
+ dxvk::condition_variable m_cond;
+
+ };
+
+
+ /**
+ * \brief Callback signal
+ *
+ * CPU-side fence with the ability to call a
+ * function when signaled to a given value.
+ */
+ class CallbackFence final : public Signal {
+
+ public:
+
+ CallbackFence()
+ : m_value(0ull) { }
+
+ explicit CallbackFence(uint64_t value)
+ : m_value(value) { }
+
+ uint64_t value() const {
+ return m_value.load(std::memory_order_acquire);
+ }
+
+ void signal(uint64_t value) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_value.store(value, std::memory_order_release);
+ m_cond.notify_all();
+
+ for (auto i = m_callbacks.begin(); i != m_callbacks.end(); ) {
+ if (value >= i->first) {
+ i->second();
+ i = m_callbacks.erase(i);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ void wait(uint64_t value) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+ m_cond.wait(lock, [this, value] {
+ return value <= m_value.load(std::memory_order_acquire);
+ });
+ }
+
+ template<typename Fn>
+ void setCallback(uint64_t value, Fn&& proc) {
+ std::unique_lock<dxvk::mutex> lock(m_mutex);
+
+ if (value > this->value())
+ m_callbacks.emplace_back(std::piecewise_construct,
+ std::make_tuple(value),
+ std::make_tuple(proc));
+ else
+ proc();
+ }
+
+ private:
+
+ std::atomic<uint64_t> m_value;
+ dxvk::mutex m_mutex;
+ dxvk::condition_variable m_cond;
+
+ std::list<std::pair<uint64_t, std::function<void ()>>> m_callbacks;
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_spinlock.h b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_spinlock.h
new file mode 100644
index 00000000..27157929
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_spinlock.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <atomic>
+
+#include "../thread.h"
+
+#include "../util_bit.h"
+#include "../util_likely.h"
+
+namespace dxvk::sync {
+
+ /**
+ * \brief Generic spin function
+ *
+ * Blocks calling thread until a condition becomes
+ * \c true, calling \c yield every few iterations.
+ * \param [in] spinCount Number of probes between each yield
+ * \param [in] fn Condition to test
+ */
+ template<typename Fn>
+ void spin(uint32_t spinCount, const Fn& fn) {
+ while (unlikely(!fn())) {
+ for (uint32_t i = 1; i < spinCount; i++) {
+ _mm_pause();
+ if (fn())
+ return;
+ }
+
+ dxvk::this_thread::yield();
+ }
+ }
+
+ /**
+ * \brief Spin lock
+ *
+ * A low-overhead spin lock which can be used to
+ * protect data structures for a short duration
+ * in case the structure is not likely contested.
+ */
+ class Spinlock {
+
+ public:
+
+ Spinlock() { }
+ ~Spinlock() { }
+
+ Spinlock (const Spinlock&) = delete;
+ Spinlock& operator = (const Spinlock&) = delete;
+
+ void lock() {
+ spin(200, [this] { return try_lock(); });
+ }
+
+ void unlock() {
+ m_lock.store(0, std::memory_order_release);
+ }
+
+ bool try_lock() {
+ return likely(!m_lock.load())
+ && likely(!m_lock.exchange(1, std::memory_order_acquire));
+ }
+
+ private:
+
+ std::atomic<uint32_t> m_lock = { 0 };
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_ticketlock.h b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_ticketlock.h
new file mode 100644
index 00000000..1c47f839
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/sync/sync_ticketlock.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <atomic>
+
+#include "../thread.h"
+
+namespace dxvk::sync {
+
+ /**
+ * \brief Ticket spinlock
+ *
+ * A fair spinlock implementation that should
+ * be preferred over \ref Spinlock when one of
+ * the threads accessing the lock is likely to
+ * starve another.
+ */
+ class TicketLock {
+
+ public:
+
+ void lock() {
+ uint32_t ticket = m_counter.fetch_add(1);
+
+ while (m_serving.load(std::memory_order_acquire) != ticket)
+ continue;
+ }
+
+ void unlock() {
+ uint32_t serveNext = m_serving.load() + 1;
+ m_serving.store(serveNext, std::memory_order_release);
+ }
+
+ private:
+
+ std::atomic<uint32_t> m_counter = { 0 };
+ std::atomic<uint32_t> m_serving = { 0 };
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/thread.h b/src/libs/dxvk-native-1.9.2a/src/util/thread.h
new file mode 100644
index 00000000..0545faeb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/thread.h
@@ -0,0 +1,351 @@
+#pragma once
+
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#ifndef _WIN32
+#include <thread>
+#endif
+
+#include "util_error.h"
+
+#include "./com/com_include.h"
+
+#include "./rc/util_rc.h"
+#include "./rc/util_rc_ptr.h"
+
+namespace dxvk {
+
+#ifdef _WIN32
+ /**
+ * \brief Thread priority
+ */
+ enum class ThreadPriority : int32_t {
+ Lowest = THREAD_PRIORITY_LOWEST,
+ Low = THREAD_PRIORITY_BELOW_NORMAL,
+ Normal = THREAD_PRIORITY_NORMAL,
+ High = THREAD_PRIORITY_ABOVE_NORMAL,
+ Highest = THREAD_PRIORITY_HIGHEST,
+ };
+
+ /**
+ * \brief Thread helper class
+ *
+ * This is needed mostly for winelib builds. Wine needs to setup each thread that
+ * calls Windows APIs. It means that in winelib builds, we can't let standard C++
+ * library create threads and need to use Wine for that instead. We use a thin wrapper
+ * around Windows thread functions so that the rest of code just has to use
+ * dxvk::thread class instead of std::thread.
+ */
+ class ThreadFn : public RcObject {
+ using Proc = std::function<void()>;
+ public:
+
+ ThreadFn(Proc&& proc)
+ : m_proc(std::move(proc)) {
+ // Reference for the thread function
+ this->incRef();
+
+ m_handle = ::CreateThread(nullptr, 0x100000,
+ ThreadFn::threadProc, this, STACK_SIZE_PARAM_IS_A_RESERVATION,
+ nullptr);
+
+ if (m_handle == nullptr)
+ throw DxvkError("Failed to create thread");
+ }
+
+ ~ThreadFn() {
+ if (this->joinable())
+ std::terminate();
+ }
+
+ void detach() {
+ ::CloseHandle(m_handle);
+ m_handle = nullptr;
+ }
+
+ void join() {
+ if(::WaitForSingleObjectEx(m_handle, INFINITE, FALSE) == WAIT_FAILED)
+ throw DxvkError("Failed to join thread");
+ this->detach();
+ }
+
+ bool joinable() const {
+ return m_handle != nullptr;
+ }
+
+ void set_priority(ThreadPriority priority) {
+ ::SetThreadPriority(m_handle, int32_t(priority));
+ }
+
+ private:
+
+ Proc m_proc;
+ HANDLE m_handle;
+
+ static DWORD WINAPI threadProc(void *arg) {
+ auto thread = reinterpret_cast<ThreadFn*>(arg);
+ thread->m_proc();
+ thread->decRef();
+ return 0;
+ }
+
+ };
+
+
+ /**
+ * \brief RAII thread wrapper
+ *
+ * Wrapper for \c ThreadFn that can be used
+ * as a drop-in replacement for \c std::thread.
+ */
+ class thread {
+
+ public:
+
+ thread() { }
+
+ explicit thread(std::function<void()>&& func)
+ : m_thread(new ThreadFn(std::move(func))) { }
+
+ thread(thread&& other)
+ : m_thread(std::move(other.m_thread)) { }
+
+ thread& operator = (thread&& other) {
+ m_thread = std::move(other.m_thread);
+ return *this;
+ }
+
+ void detach() {
+ m_thread->detach();
+ }
+
+ void join() {
+ m_thread->join();
+ }
+
+ bool joinable() const {
+ return m_thread != nullptr
+ && m_thread->joinable();
+ }
+
+ void set_priority(ThreadPriority priority) {
+ m_thread->set_priority(priority);
+ }
+
+ static uint32_t hardware_concurrency() {
+ SYSTEM_INFO info = { };
+ ::GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+ }
+
+ private:
+
+ Rc<ThreadFn> m_thread;
+
+ };
+
+
+ namespace this_thread {
+ inline void yield() {
+ SwitchToThread();
+ }
+
+ inline uint32_t get_id() {
+ return GetCurrentThreadId();
+ }
+ }
+
+
+ /**
+ * \brief SRW-based mutex implementation
+ *
+ * Drop-in replacement for \c std::mutex that uses Win32
+ * SRW locks, which are implemented with \c futex in wine.
+ */
+ class mutex {
+
+ public:
+
+ using native_handle_type = PSRWLOCK;
+
+ mutex() { }
+
+ mutex(const mutex&) = delete;
+ mutex& operator = (const mutex&) = delete;
+
+ void lock() {
+ AcquireSRWLockExclusive(&m_lock);
+ }
+
+ void unlock() {
+ ReleaseSRWLockExclusive(&m_lock);
+ }
+
+ bool try_lock() {
+ return TryAcquireSRWLockExclusive(&m_lock);
+ }
+
+ native_handle_type native_handle() {
+ return &m_lock;
+ }
+
+ private:
+
+ SRWLOCK m_lock = SRWLOCK_INIT;
+
+ };
+
+
+ /**
+ * \brief Recursive mutex implementation
+ *
+ * Drop-in replacement for \c std::recursive_mutex that
+ * uses Win32 critical sections.
+ */
+ class recursive_mutex {
+
+ public:
+
+ using native_handle_type = PCRITICAL_SECTION;
+
+ recursive_mutex() {
+ InitializeCriticalSection(&m_lock);
+ }
+
+ ~recursive_mutex() {
+ DeleteCriticalSection(&m_lock);
+ }
+
+ recursive_mutex(const recursive_mutex&) = delete;
+ recursive_mutex& operator = (const recursive_mutex&) = delete;
+
+ void lock() {
+ EnterCriticalSection(&m_lock);
+ }
+
+ void unlock() {
+ LeaveCriticalSection(&m_lock);
+ }
+
+ bool try_lock() {
+ return TryEnterCriticalSection(&m_lock);
+ }
+
+ native_handle_type native_handle() {
+ return &m_lock;
+ }
+
+ private:
+
+ CRITICAL_SECTION m_lock;
+
+ };
+
+
+ /**
+ * \brief SRW-based condition variable implementation
+ *
+ * Drop-in replacement for \c std::condition_variable that
+ * uses Win32 condition variables on SRW locks.
+ */
+ class condition_variable {
+
+ public:
+
+ using native_handle_type = PCONDITION_VARIABLE;
+
+ condition_variable() {
+ InitializeConditionVariable(&m_cond);
+ }
+
+ condition_variable(condition_variable&) = delete;
+
+ condition_variable& operator = (condition_variable&) = delete;
+
+ void notify_one() {
+ WakeConditionVariable(&m_cond);
+ }
+
+ void notify_all() {
+ WakeAllConditionVariable(&m_cond);
+ }
+
+ void wait(std::unique_lock<dxvk::mutex>& lock) {
+ auto srw = lock.mutex()->native_handle();
+ SleepConditionVariableSRW(&m_cond, srw, INFINITE, 0);
+ }
+
+ template<typename Predicate>
+ void wait(std::unique_lock<dxvk::mutex>& lock, Predicate pred) {
+ while (!pred())
+ wait(lock);
+ }
+
+ template<typename Clock, typename Duration>
+ std::cv_status wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time) {
+ auto now = Clock::now();
+
+ return (now < time)
+ ? wait_for(lock, now - time)
+ : std::cv_status::timeout;
+ }
+
+ template<typename Clock, typename Duration, typename Predicate>
+ bool wait_until(std::unique_lock<dxvk::mutex>& lock, const std::chrono::time_point<Clock, Duration>& time, Predicate pred) {
+ if (pred())
+ return true;
+
+ auto now = Clock::now();
+ return now < time && wait_for(lock, now - time, pred);
+ }
+
+ template<typename Rep, typename Period>
+ std::cv_status wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout) {
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
+ auto srw = lock.mutex()->native_handle();
+
+ return SleepConditionVariableSRW(&m_cond, srw, ms.count(), 0)
+ ? std::cv_status::no_timeout
+ : std::cv_status::timeout;
+ }
+
+ template<typename Rep, typename Period, typename Predicate>
+ bool wait_for(std::unique_lock<dxvk::mutex>& lock, const std::chrono::duration<Rep, Period>& timeout, Predicate pred) {
+ bool result = pred();
+
+ if (!result && wait_for(lock, timeout) == std::cv_status::no_timeout)
+ result = pred();
+
+ return result;
+ }
+
+ native_handle_type native_handle() {
+ return &m_cond;
+ }
+
+ private:
+
+ CONDITION_VARIABLE m_cond;
+
+ };
+
+#else
+
+ using mutex = std::mutex;
+ using thread = std::thread;
+ using recursive_mutex = std::recursive_mutex;
+ using condition_variable = std::condition_variable;
+
+ namespace this_thread {
+ inline void yield() {
+ std::this_thread::yield();
+ }
+
+ uint32_t get_id();
+ }
+
+#endif
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_bit.h b/src/libs/dxvk-native-1.9.2a/src/util/util_bit.h
new file mode 100644
index 00000000..3c65c70d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_bit.h
@@ -0,0 +1,349 @@
+#pragma once
+
+#ifndef _MSC_VER
+#if defined(__WINE__) && defined(__clang__)
+#pragma push_macro("_WIN32")
+#undef _WIN32
+#endif
+#include <x86intrin.h>
+#if defined(__WINE__) && defined(__clang__)
+#pragma pop_macro("_WIN32")
+#endif
+#else
+#include <intrin.h>
+#endif
+
+#include "util_likely.h"
+#include "util_math.h"
+
+#include <cstring>
+#include <iterator>
+#include <type_traits>
+
+namespace dxvk::bit {
+
+ template<typename T, typename J>
+ T cast(const J& src) {
+ static_assert(sizeof(T) == sizeof(J));
+ static_assert(std::is_trivially_copyable<J>::value && std::is_trivial<T>::value);
+
+ T dst;
+ std::memcpy(&dst, &src, sizeof(T));
+ return dst;
+ }
+
+ template<typename T>
+ T extract(T value, uint32_t fst, uint32_t lst) {
+ return (value >> fst) & ~(~T(0) << (lst - fst + 1));
+ }
+
+ inline uint32_t popcntStep(uint32_t n, uint32_t mask, uint32_t shift) {
+ return (n & mask) + ((n & ~mask) >> shift);
+ }
+
+ inline uint32_t popcnt(uint32_t n) {
+ n = popcntStep(n, 0x55555555, 1);
+ n = popcntStep(n, 0x33333333, 2);
+ n = popcntStep(n, 0x0F0F0F0F, 4);
+ n = popcntStep(n, 0x00FF00FF, 8);
+ n = popcntStep(n, 0x0000FFFF, 16);
+ return n;
+ }
+
+ inline uint32_t tzcnt(uint32_t n) {
+ #if defined(_MSC_VER) && !defined(__clang__)
+ return _tzcnt_u32(n);
+ #elif defined(__BMI__)
+ return __tzcnt_u32(n);
+ #elif defined(__GNUC__) || defined(__clang__)
+ uint32_t res;
+ uint32_t tmp;
+ asm (
+ "mov $32, %1;"
+ "bsf %2, %0;"
+ "cmovz %1, %0;"
+ : "=&r" (res), "=&r" (tmp)
+ : "r" (n));
+ return res;
+ #else
+ uint32_t r = 31;
+ n &= -n;
+ r -= (n & 0x0000FFFF) ? 16 : 0;
+ r -= (n & 0x00FF00FF) ? 8 : 0;
+ r -= (n & 0x0F0F0F0F) ? 4 : 0;
+ r -= (n & 0x33333333) ? 2 : 0;
+ r -= (n & 0x55555555) ? 1 : 0;
+ return n != 0 ? r : 32;
+ #endif
+ }
+
+ inline uint32_t bsf(uint32_t n) {
+ #if defined(_MSC_VER) && !defined(__clang__)
+ unsigned long index;
+ _BitScanForward(&index, n);
+ return uint32_t(index);
+ #elif defined(__GNUC__) || defined(__clang__)
+ return __builtin_ctz(n);
+ #else
+ uint32_t r = 31;
+ n &= -n;
+ r -= (n & 0x0000FFFF) ? 16 : 0;
+ r -= (n & 0x00FF00FF) ? 8 : 0;
+ r -= (n & 0x0F0F0F0F) ? 4 : 0;
+ r -= (n & 0x33333333) ? 2 : 0;
+ r -= (n & 0x55555555) ? 1 : 0;
+ return r;
+ #endif
+ }
+
+ inline uint32_t lzcnt(uint32_t n) {
+ #if (defined(_MSC_VER) && !defined(__clang__)) || defined(__LZCNT__)
+ return _lzcnt_u32(n);
+ #elif defined(__GNUC__) || defined(__clang__)
+ return n != 0 ? __builtin_clz(n) : 32;
+ #else
+ uint32_t r = 0;
+
+ if (n == 0) return 32;
+
+ if (n <= 0x0000FFFF) { r += 16; n <<= 16; }
+ if (n <= 0x00FFFFFF) { r += 8; n <<= 8; }
+ if (n <= 0x0FFFFFFF) { r += 4; n <<= 4; }
+ if (n <= 0x3FFFFFFF) { r += 2; n <<= 2; }
+ if (n <= 0x7FFFFFFF) { r += 1; n <<= 1; }
+
+ return r;
+ #endif
+ }
+
+ template<typename T>
+ uint32_t pack(T& dst, uint32_t& shift, T src, uint32_t count) {
+ constexpr uint32_t Bits = 8 * sizeof(T);
+ if (likely(shift < Bits))
+ dst |= src << shift;
+ shift += count;
+ return shift > Bits ? shift - Bits : 0;
+ }
+
+ template<typename T>
+ uint32_t unpack(T& dst, T src, uint32_t& shift, uint32_t count) {
+ constexpr uint32_t Bits = 8 * sizeof(T);
+ if (likely(shift < Bits))
+ dst = (src >> shift) & ((T(1) << count) - 1);
+ shift += count;
+ return shift > Bits ? shift - Bits : 0;
+ }
+
+ /**
+ * \brief Compares two aligned structs bit by bit
+ *
+ * \param [in] a First struct
+ * \param [in] b Second struct
+ * \returns \c true if the structs are equal
+ */
+ template<typename T>
+ bool bcmpeq(const T* a, const T* b) {
+ static_assert(alignof(T) >= 16);
+ #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
+ auto ai = reinterpret_cast<const __m128i*>(a);
+ auto bi = reinterpret_cast<const __m128i*>(b);
+
+ size_t i = 0;
+
+ #if defined(__clang__)
+ #pragma nounroll
+ #elif defined(__GNUC__)
+ #pragma GCC unroll 0
+ #endif
+
+ for ( ; i < 2 * (sizeof(T) / 32); i += 2) {
+ __m128i eq0 = _mm_cmpeq_epi8(
+ _mm_load_si128(ai + i),
+ _mm_load_si128(bi + i));
+ __m128i eq1 = _mm_cmpeq_epi8(
+ _mm_load_si128(ai + i + 1),
+ _mm_load_si128(bi + i + 1));
+ __m128i eq = _mm_and_si128(eq0, eq1);
+
+ int mask = _mm_movemask_epi8(eq);
+ if (mask != 0xFFFF)
+ return false;
+ }
+
+ for ( ; i < sizeof(T) / 16; i++) {
+ __m128i eq = _mm_cmpeq_epi8(
+ _mm_load_si128(ai + i),
+ _mm_load_si128(bi + i));
+
+ int mask = _mm_movemask_epi8(eq);
+ if (mask != 0xFFFF)
+ return false;
+ }
+
+ return true;
+ #else
+ return !std::memcmp(a, b, sizeof(T));
+ #endif
+ }
+
+ template <size_t Bits>
+ class bitset {
+ static constexpr size_t Dwords = align(Bits, 32) / 32;
+ public:
+
+ constexpr bitset()
+ : m_dwords() {
+
+ }
+
+ constexpr bool get(uint32_t idx) const {
+ uint32_t dword = 0;
+ uint32_t bit = idx;
+
+ // Compiler doesn't remove this otherwise.
+ if constexpr (Dwords > 1) {
+ dword = idx / 32;
+ bit = idx % 32;
+ }
+
+ return m_dwords[dword] & (1u << bit);
+ }
+
+ constexpr void set(uint32_t idx, bool value) {
+ uint32_t dword = 0;
+ uint32_t bit = idx;
+
+ // Compiler doesn't remove this otherwise.
+ if constexpr (Dwords > 1) {
+ dword = idx / 32;
+ bit = idx % 32;
+ }
+
+ if (value)
+ m_dwords[dword] |= 1u << bit;
+ else
+ m_dwords[dword] &= ~(1u << bit);
+ }
+
+ constexpr bool exchange(uint32_t idx, bool value) {
+ bool oldValue = get(idx);
+ set(idx, value);
+ return oldValue;
+ }
+
+ constexpr void flip(uint32_t idx) {
+ uint32_t dword = 0;
+ uint32_t bit = idx;
+
+ // Compiler doesn't remove this otherwise.
+ if constexpr (Dwords > 1) {
+ dword = idx / 32;
+ bit = idx % 32;
+ }
+
+ m_dwords[dword] ^= 1u << bit;
+ }
+
+ constexpr void setAll() {
+ if constexpr (Bits % 32 == 0) {
+ for (size_t i = 0; i < Dwords; i++)
+ m_dwords[i] = std::numeric_limits<uint32_t>::max();
+ }
+ else {
+ for (size_t i = 0; i < Dwords - 1; i++)
+ m_dwords[i] = std::numeric_limits<uint32_t>::max();
+
+ m_dwords[Dwords - 1] = (1u << (Bits % 32)) - 1;
+ }
+ }
+
+ constexpr void clearAll() {
+ for (size_t i = 0; i < Dwords; i++)
+ m_dwords[i] = 0;
+ }
+
+ constexpr bool any() const {
+ for (size_t i = 0; i < Dwords; i++) {
+ if (m_dwords[i] != 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ constexpr uint32_t& dword(uint32_t idx) {
+ return m_dwords[idx];
+ }
+
+ constexpr size_t bitCount() {
+ return Bits;
+ }
+
+ constexpr size_t dwordCount() {
+ return Dwords;
+ }
+
+ constexpr bool operator [] (uint32_t idx) const {
+ return get(idx);
+ }
+
+ private:
+
+ uint32_t m_dwords[Dwords];
+
+ };
+
+ class BitMask {
+
+ public:
+
+ class iterator: public std::iterator<std::input_iterator_tag,
+ uint32_t, uint32_t, const uint32_t*, uint32_t> {
+ public:
+
+ explicit iterator(uint32_t flags)
+ : m_mask(flags) { }
+
+ iterator& operator ++ () {
+ m_mask &= m_mask - 1;
+ return *this;
+ }
+
+ iterator operator ++ (int) {
+ iterator retval = *this;
+ m_mask &= m_mask - 1;
+ return retval;
+ }
+
+ uint32_t operator * () const {
+ return bsf(m_mask);
+ }
+
+ bool operator == (iterator other) const { return m_mask == other.m_mask; }
+ bool operator != (iterator other) const { return m_mask != other.m_mask; }
+
+ private:
+
+ uint32_t m_mask;
+
+ };
+
+ BitMask() { }
+
+ BitMask(uint32_t n)
+ : m_mask(n) { }
+
+ iterator begin() {
+ return iterator(m_mask);
+ }
+
+ iterator end() {
+ return iterator(0);
+ }
+
+ private:
+
+ uint32_t m_mask;
+
+ };
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_enum.h b/src/libs/dxvk-native-1.9.2a/src/util/util_enum.h
new file mode 100644
index 00000000..85b9b21b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_enum.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#define ENUM_NAME(name) \
+ case name: return os << #name
+
+#define ENUM_DEFAULT(name) \
+ default: return os << static_cast<int32_t>(e)
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_env.cpp b/src/libs/dxvk-native-1.9.2a/src/util/util_env.cpp
new file mode 100644
index 00000000..3993ea65
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_env.cpp
@@ -0,0 +1,71 @@
+#include <numeric>
+
+#include "util_env.h"
+
+namespace dxvk::env {
+
+#ifndef DXVK_NATIVE
+ constexpr char dirSlash = '\\';
+#else
+ constexpr char dirSlash = '/';
+#endif
+
+
+ std::string getEnvVar(const char* name) {
+#ifdef DXVK_NATIVE
+ char* result = std::getenv(name);
+ return (result)
+ ? result
+ : "";
+#else
+ std::vector<WCHAR> result;
+ result.resize(MAX_PATH + 1);
+
+ DWORD len = ::GetEnvironmentVariableW(str::tows(name).c_str(), result.data(), MAX_PATH);
+ result.resize(len);
+
+ return str::fromws(result.data());
+#endif
+ }
+
+
+ size_t matchFileExtension(const std::string& name, const char* ext) {
+ auto pos = name.find_last_of('.');
+
+ if (pos == std::string::npos)
+ return pos;
+
+ bool matches = std::accumulate(name.begin() + pos + 1, name.end(), true,
+ [&ext] (bool current, char a) {
+ if (a >= 'A' && a <= 'Z')
+ a += 'a' - 'A';
+ return current && *ext && a == *(ext++);
+ });
+
+ return matches ? pos : std::string::npos;
+ }
+
+
+ std::string getExeName() {
+ std::string fullPath = getExePath();
+ auto n = fullPath.find_last_of(dirSlash);
+
+ return (n != std::string::npos)
+ ? fullPath.substr(n + 1)
+ : fullPath;
+ }
+
+
+ std::string getExeBaseName() {
+ auto exeName = getExeName();
+#ifndef DXVK_NATIVE
+ auto extp = matchFileExtension(exeName, "exe");
+
+ if (extp != std::string::npos)
+ exeName.erase(extp);
+#endif
+
+ return exeName;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_env.h b/src/libs/dxvk-native-1.9.2a/src/util/util_env.h
new file mode 100644
index 00000000..cb4aa2a0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_env.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "util_string.h"
+
+namespace dxvk::env {
+
+ /**
+ * \brief Checks whether the host platform is 32-bit
+ */
+ constexpr bool is32BitHostPlatform() {
+ return sizeof(void*) == 4;
+ }
+
+ /**
+ * \brief Gets environment variable
+ *
+ * If the variable is not defined, this will return
+ * an empty string. Note that environment variables
+ * may be defined with an empty value.
+ * \param [in] name Name of the variable
+ * \returns Value of the variable
+ */
+ std::string getEnvVar(const char* name);
+
+ /**
+ * \brief Checks whether a file name has a given extension
+ *
+ * \param [in] name File name
+ * \param [in] ext Extension to match, in lowercase letters
+ * \returns Position of the extension within the file name, or
+ * \c std::string::npos if the file has a different extension
+ */
+ size_t matchFileExtension(const std::string& name, const char* ext);
+
+ /**
+ * \brief Gets the executable name
+ *
+ * Returns the base name (not the full path) of the
+ * program executable, including the file extension.
+ * This function should be used to identify programs.
+ * \returns Executable name
+ */
+ std::string getExeName();
+
+ /**
+ * \brief Gets the executable name without extension
+ *
+ * Same as \ref getExeName but without the file extension.
+ * \returns Executable name
+ */
+ std::string getExeBaseName();
+
+ /**
+ * \brief Gets full path to executable
+ * \returns Path to executable
+ */
+ std::string getExePath();
+
+ /**
+ * \brief Sets name of the calling thread
+ * \param [in] name Thread name
+ */
+ void setThreadName(const std::string& name);
+
+ /**
+ * \brief Creates a directory
+ *
+ * \param [in] path Path to directory
+ * \returns \c true on success
+ */
+ bool createDirectory(const std::string& path);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_error.h b/src/libs/dxvk-native-1.9.2a/src/util/util_error.h
new file mode 100644
index 00000000..2cfd45ff
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_error.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <string>
+
+namespace dxvk {
+
+ /**
+ * \brief DXVK error
+ *
+ * A generic exception class that stores a
+ * message. Exceptions should be logged.
+ */
+ class DxvkError {
+
+ public:
+
+ DxvkError() { }
+ DxvkError(std::string&& message)
+ : m_message(std::move(message)) { }
+
+ const std::string& message() const {
+ return m_message;
+ }
+
+ private:
+
+ std::string m_message;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_flags.h b/src/libs/dxvk-native-1.9.2a/src/util/util_flags.h
new file mode 100644
index 00000000..f67b4a2e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_flags.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include <type_traits>
+
+#include "util_bit.h"
+
+namespace dxvk {
+
+ template<typename T>
+ class Flags {
+
+ public:
+
+ using IntType = std::underlying_type_t<T>;
+
+ Flags() { }
+
+ Flags(IntType t)
+ : m_bits(t) { }
+
+ template<typename... Tx>
+ Flags(T f, Tx... fx) {
+ this->set(f, fx...);
+ }
+
+ template<typename... Tx>
+ void set(Tx... fx) {
+ m_bits |= bits(fx...);
+ }
+
+ void set(Flags flags) {
+ m_bits |= flags.m_bits;
+ }
+
+ template<typename... Tx>
+ void clr(Tx... fx) {
+ m_bits &= ~bits(fx...);
+ }
+
+ void clr(Flags flags) {
+ m_bits &= ~flags.m_bits;
+ }
+
+ template<typename... Tx>
+ bool any(Tx... fx) const {
+ return (m_bits & bits(fx...)) != 0;
+ }
+
+ template<typename... Tx>
+ bool all(Tx... fx) const {
+ const IntType mask = bits(fx...);
+ return (m_bits & mask) == mask;
+ }
+
+ bool test(T f) const {
+ return this->any(f);
+ }
+
+ bool isClear() const {
+ return m_bits == 0;
+ }
+
+ void clrAll() {
+ m_bits = 0;
+ }
+
+ IntType raw() const {
+ return m_bits;
+ }
+
+ Flags operator & (const Flags& other) const {
+ return Flags(m_bits & other.m_bits);
+ }
+
+ Flags operator | (const Flags& other) const {
+ return Flags(m_bits | other.m_bits);
+ }
+
+ Flags operator ^ (const Flags& other) const {
+ return Flags(m_bits ^ other.m_bits);
+ }
+
+ bool operator == (const Flags& other) const {
+ return m_bits == other.m_bits;
+ }
+
+ bool operator != (const Flags& other) const {
+ return m_bits != other.m_bits;
+ }
+
+ private:
+
+ IntType m_bits = 0;
+
+ static IntType bit(T f) {
+ return IntType(1) << static_cast<IntType>(f);
+ }
+
+ template<typename... Tx>
+ static IntType bits(T f, Tx... fx) {
+ return bit(f) | bits(fx...);
+ }
+
+ static IntType bits() {
+ return 0;
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.cpp b/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.cpp
new file mode 100644
index 00000000..5256c8d6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.cpp
@@ -0,0 +1,175 @@
+#include <thread>
+
+#include "thread.h"
+#include "util_env.h"
+#include "util_fps_limiter.h"
+#include "util_string.h"
+
+#include "./log/log.h"
+
+namespace dxvk {
+
+ FpsLimiter::FpsLimiter() {
+ std::string env = env::getEnvVar("DXVK_FRAME_RATE");
+
+ if (!env.empty()) {
+ try {
+ setTargetFrameRate(std::stod(env));
+ m_envOverride = true;
+ } catch (const std::invalid_argument&) {
+ // no-op
+ }
+ }
+ }
+
+
+ FpsLimiter::~FpsLimiter() {
+
+ }
+
+
+ void FpsLimiter::setTargetFrameRate(double frameRate) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (!m_envOverride) {
+ m_targetInterval = frameRate > 0.0
+ ? NtTimerDuration(int64_t(double(NtTimerDuration::period::den) / frameRate))
+ : NtTimerDuration::zero();
+
+ if (isEnabled() && !m_initialized)
+ initialize();
+ }
+ }
+
+
+ void FpsLimiter::setDisplayRefreshRate(double refreshRate) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ m_refreshInterval = refreshRate > 0.0
+ ? NtTimerDuration(int64_t(double(NtTimerDuration::period::den) / refreshRate))
+ : NtTimerDuration::zero();
+ }
+
+
+ void FpsLimiter::delay(bool vsyncEnabled) {
+ std::lock_guard<dxvk::mutex> lock(m_mutex);
+
+ if (!isEnabled())
+ return;
+
+ // If the swap chain is known to have vsync enabled and the
+ // refresh rate is similar to the target frame rate, disable
+ // the limiter so it does not screw up frame times
+ if (vsyncEnabled && !m_envOverride
+ && m_refreshInterval * 100 > m_targetInterval * 97)
+ return;
+
+ auto t0 = m_lastFrame;
+ auto t1 = dxvk::high_resolution_clock::now();
+
+ auto frameTime = std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
+
+ if (frameTime * 100 > m_targetInterval * 103 - m_deviation * 100) {
+ // If we have a slow frame, reset the deviation since we
+ // do not want to compensate for low performance later on
+ m_deviation = NtTimerDuration::zero();
+ } else {
+ // Don't call sleep if the amount of time to sleep is shorter
+ // than the time the function calls are likely going to take
+ NtTimerDuration sleepDuration = m_targetInterval - m_deviation - frameTime;
+ t1 = sleep(t1, sleepDuration);
+
+ // Compensate for any sleep inaccuracies in the next frame, and
+ // limit cumulative deviation in order to avoid stutter in case we
+ // have a number of slow frames immediately followed by a fast one.
+ frameTime = std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
+ m_deviation += frameTime - m_targetInterval;
+ m_deviation = std::min(m_deviation, m_targetInterval / 16);
+ }
+
+ m_lastFrame = t1;
+ }
+
+
+ FpsLimiter::TimePoint FpsLimiter::sleep(TimePoint t0, NtTimerDuration duration) {
+ if (duration <= NtTimerDuration::zero())
+ return t0;
+
+ // On wine, we can rely on NtDelayExecution waiting for more or
+ // less exactly the desired amount of time, and we want to avoid
+ // spamming QueryPerformanceCounter for performance reasons.
+ // On Windows, we busy-wait for the last couple of milliseconds
+ // since sleeping is highly inaccurate and inconsistent.
+ NtTimerDuration sleepThreshold = m_sleepThreshold;
+
+ if (m_sleepGranularity != NtTimerDuration::zero())
+ sleepThreshold += duration / 6;
+
+ NtTimerDuration remaining = duration;
+ TimePoint t1 = t0;
+
+ while (remaining > sleepThreshold) {
+ NtTimerDuration sleepDuration = remaining - sleepThreshold;
+
+ if (NtDelayExecution) {
+ LARGE_INTEGER ticks;
+ ticks.QuadPart = -sleepDuration.count();
+
+ NtDelayExecution(FALSE, &ticks);
+ } else {
+ std::this_thread::sleep_for(sleepDuration);
+ }
+
+ t1 = dxvk::high_resolution_clock::now();
+ remaining -= std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
+ t0 = t1;
+ }
+
+ // Busy-wait until we have slept long enough
+ while (remaining > NtTimerDuration::zero()) {
+ t1 = dxvk::high_resolution_clock::now();
+ remaining -= std::chrono::duration_cast<NtTimerDuration>(t1 - t0);
+ t0 = t1;
+ }
+
+ return t1;
+ }
+
+
+ void FpsLimiter::initialize() {
+#ifdef _WIN32
+ HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
+
+ if (ntdll) {
+ NtDelayExecution = reinterpret_cast<NtDelayExecutionProc>(
+ ::GetProcAddress(ntdll, "NtDelayExecution"));
+ auto NtQueryTimerResolution = reinterpret_cast<NtQueryTimerResolutionProc>(
+ ::GetProcAddress(ntdll, "NtQueryTimerResolution"));
+ auto NtSetTimerResolution = reinterpret_cast<NtSetTimerResolutionProc>(
+ ::GetProcAddress(ntdll, "NtSetTimerResolution"));
+
+ ULONG min, max, cur;
+
+ // Wine's implementation of these functions is a stub as of 6.10, which is fine
+ // since it uses select() in NtDelayExecution. This is only relevant for Windows.
+ if (NtQueryTimerResolution && !NtQueryTimerResolution(&min, &max, &cur)) {
+ m_sleepGranularity = NtTimerDuration(cur);
+
+ if (NtSetTimerResolution && !NtSetTimerResolution(max, TRUE, &cur)) {
+ Logger::info(str::format("Setting timer interval to ", (double(max) / 10.0), " us"));
+ m_sleepGranularity = NtTimerDuration(max);
+ }
+ }
+ } else
+#endif
+ {
+ // Assume 1ms sleep granularity by default
+ m_sleepGranularity = NtTimerDuration(10000);
+ }
+
+ m_sleepThreshold = 4 * m_sleepGranularity;
+ m_lastFrame = dxvk::high_resolution_clock::now();
+ m_initialized = true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.h b/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.h
new file mode 100644
index 00000000..9601dc96
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_fps_limiter.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "thread.h"
+#include "util_time.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Frame rate limiter
+ *
+ * Provides functionality to stall an application
+ * thread in order to maintain a given frame rate.
+ */
+ class FpsLimiter {
+
+ public:
+
+ /**
+ * \brief Creates frame rate limiter
+ */
+ FpsLimiter();
+
+ ~FpsLimiter();
+
+ /**
+ * \brief Sets target frame rate
+ * \param [in] frameRate Target frame rate
+ */
+ void setTargetFrameRate(double frameRate);
+
+ /**
+ * \brief Sets display refresh rate
+ *
+ * This information is used to decide whether or not
+ * the limiter should be active in the first place in
+ * case vertical synchronization is enabled.
+ * \param [in] refreshRate Current refresh rate
+ */
+ void setDisplayRefreshRate(double refreshRate);
+
+ /**
+ * \brief Stalls calling thread as necessary
+ *
+ * Blocks the calling thread if the limiter is enabled
+ * and the time since the last call to \ref delay is
+ * shorter than the target interval.
+ * \param [in] vsyncEnabled \c true if vsync is enabled
+ */
+ void delay(bool vsyncEnabled);
+
+ /**
+ * \brief Checks whether the frame rate limiter is enabled
+ * \returns \c true if the target frame rate is non-zero.
+ */
+ bool isEnabled() const {
+ return m_targetInterval != NtTimerDuration::zero();
+ }
+
+ private:
+
+ using TimePoint = dxvk::high_resolution_clock::time_point;
+
+ using NtTimerDuration = std::chrono::duration<int64_t, std::ratio<1, 10000000>>;
+ using NtQueryTimerResolutionProc = UINT (WINAPI *) (ULONG*, ULONG*, ULONG*);
+ using NtSetTimerResolutionProc = UINT (WINAPI *) (ULONG, BOOL, ULONG*);
+ using NtDelayExecutionProc = UINT (WINAPI *) (BOOL, LARGE_INTEGER*);
+
+ dxvk::mutex m_mutex;
+
+ NtTimerDuration m_targetInterval = NtTimerDuration::zero();
+ NtTimerDuration m_refreshInterval = NtTimerDuration::zero();
+ NtTimerDuration m_deviation = NtTimerDuration::zero();
+ TimePoint m_lastFrame;
+
+ bool m_initialized = false;
+ bool m_envOverride = false;
+
+ NtTimerDuration m_sleepGranularity = NtTimerDuration::zero();
+ NtTimerDuration m_sleepThreshold = NtTimerDuration::zero();
+
+ NtDelayExecutionProc NtDelayExecution = nullptr;
+
+ TimePoint sleep(TimePoint t0, NtTimerDuration duration);
+
+ void initialize();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.cpp b/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.cpp
new file mode 100644
index 00000000..901dd05c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.cpp
@@ -0,0 +1,33 @@
+#include "util_gdi.h"
+#include "log/log.h"
+
+namespace dxvk {
+
+ HMODULE GetGDIModule() {
+ static HMODULE module = LoadLibraryA("gdi32.dll");
+ return module;
+ }
+
+ NTSTATUS D3DKMTCreateDCFromMemory(D3DKMT_CREATEDCFROMMEMORY* Arg1) {
+ static auto func = (D3DKMTCreateDCFromMemoryType)
+ GetProcAddress(GetGDIModule(), "D3DKMTCreateDCFromMemory");
+
+ if (func != nullptr)
+ return func(Arg1);
+
+ Logger::warn("D3DKMTCreateDCFromMemory: Unable to query proc address.");
+ return -1;
+ }
+
+ NTSTATUS D3DKMTDestroyDCFromMemory(D3DKMT_DESTROYDCFROMMEMORY* Arg1) {
+ static auto func = (D3DKMTDestroyDCFromMemoryType)
+ GetProcAddress(GetGDIModule(), "D3DKMTDestroyDCFromMemory");
+
+ if (func != nullptr)
+ return func(Arg1);
+
+ Logger::warn("D3DKMTDestroyDCFromMemory: Unable to query proc address.");
+ return -1;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.h b/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.h
new file mode 100644
index 00000000..58724b15
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_gdi.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <d3d9.h>
+
+namespace dxvk {
+ using NTSTATUS = LONG;
+
+ // Slightly modified definitions...
+ struct D3DKMT_CREATEDCFROMMEMORY {
+ void* pMemory;
+ D3DFORMAT Format;
+ UINT Width;
+ UINT Height;
+ UINT Pitch;
+ HDC hDeviceDc;
+ PALETTEENTRY* pColorTable;
+ HDC hDc;
+ HANDLE hBitmap;
+ };
+
+ struct D3DKMT_DESTROYDCFROMMEMORY {
+ HDC hDC = nullptr;
+ HANDLE hBitmap = nullptr;
+ };
+
+ using D3DKMTCreateDCFromMemoryType = NTSTATUS(STDMETHODCALLTYPE*) (D3DKMT_CREATEDCFROMMEMORY*);
+ NTSTATUS D3DKMTCreateDCFromMemory (D3DKMT_CREATEDCFROMMEMORY* Arg1);
+
+ using D3DKMTDestroyDCFromMemoryType = NTSTATUS(STDMETHODCALLTYPE*) (D3DKMT_DESTROYDCFROMMEMORY*);
+ NTSTATUS D3DKMTDestroyDCFromMemory(D3DKMT_DESTROYDCFROMMEMORY* Arg1);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_lazy.h b/src/libs/dxvk-native-1.9.2a/src/util/util_lazy.h
new file mode 100644
index 00000000..f17febb8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_lazy.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mutex>
+
+namespace dxvk {
+
+ /**
+ * \brief Lazy-initialized object
+ *
+ * Creates an object on demand with
+ * the given constructor arguments.
+ */
+ template<typename T>
+ class Lazy {
+
+ public:
+
+ template<typename... Args>
+ T& get(Args... args) {
+ if (m_object)
+ return *m_object;
+
+ std::lock_guard lock(m_mutex);
+
+ if (!m_object) {
+ m_object = std::make_unique<T>(
+ std::forward<Args>(args)...);
+ }
+
+ return *m_object;
+ }
+
+ private:
+
+ dxvk::mutex m_mutex;
+ std::unique_ptr<T> m_object;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_likely.h b/src/libs/dxvk-native-1.9.2a/src/util/util_likely.h
new file mode 100644
index 00000000..7eba9818
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_likely.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#ifdef __GNUC__
+#define likely(x) __builtin_expect((x),1)
+#define unlikely(x) __builtin_expect((x),0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_luid.h b/src/libs/dxvk-native-1.9.2a/src/util/util_luid.h
new file mode 100644
index 00000000..718040e3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_luid.h
@@ -0,0 +1,15 @@
+#include "./com/com_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Retrieves an adapter LUID
+ *
+ * Note that this only works reliably within the
+ * module that this function was compiled into.
+ * \param [in] Adapter The adapter index
+ * \returns LUID An LUID for that adapter
+ */
+ LUID GetAdapterLUID(UINT Adapter);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_math.h b/src/libs/dxvk-native-1.9.2a/src/util/util_math.h
new file mode 100644
index 00000000..fdb3762b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_math.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <cmath>
+
+namespace dxvk {
+
+ constexpr size_t CACHE_LINE_SIZE = 64;
+
+ template<typename T>
+ constexpr T clamp(T n, T lo, T hi) {
+ if (n < lo) return lo;
+ if (n > hi) return hi;
+ return n;
+ }
+
+ template<typename T, typename U = T>
+ constexpr T align(T what, U to) {
+ return (what + to - 1) & ~(to - 1);
+ }
+
+ template<typename T, typename U = T>
+ constexpr T alignDown(T what, U to) {
+ return (what / to) * to;
+ }
+
+ // Equivalent of std::clamp for use with floating point numbers
+ // Handles (-){INFINITY,NAN} cases.
+ // Will return min in cases of NAN, etc.
+ inline float fclamp(float value, float min, float max) {
+ return std::fmin(
+ std::fmax(value, min), max);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.cpp b/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.cpp
new file mode 100644
index 00000000..2c5e9314
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.cpp
@@ -0,0 +1,232 @@
+#include "util_matrix.h"
+
+namespace dxvk {
+
+ Vector4& Matrix4::operator[](size_t index) { return data[index]; }
+ const Vector4& Matrix4::operator[](size_t index) const { return data[index]; }
+
+ bool Matrix4::operator==(const Matrix4& m2) const {
+ const Matrix4& m1 = *this;
+ for (uint32_t i = 0; i < 4; i++) {
+ if (m1[i] != m2[i])
+ return false;
+ }
+ return true;
+ }
+
+ bool Matrix4::operator!=(const Matrix4& m2) const { return !operator==(m2); }
+
+ Matrix4 Matrix4::operator+(const Matrix4& other) const {
+ Matrix4 mat;
+ for (uint32_t i = 0; i < 4; i++)
+ mat[i] = data[i] + other.data[i];
+ return mat;
+ }
+
+ Matrix4 Matrix4::operator-(const Matrix4& other) const {
+ Matrix4 mat;
+ for (uint32_t i = 0; i < 4; i++)
+ mat[i] = data[i] - other.data[i];
+ return mat;
+ }
+
+ Matrix4 Matrix4::operator*(const Matrix4& m2) const {
+ const Matrix4& m1 = *this;
+
+ const Vector4 srcA0 = { m1[0] };
+ const Vector4 srcA1 = { m1[1] };
+ const Vector4 srcA2 = { m1[2] };
+ const Vector4 srcA3 = { m1[3] };
+
+ const Vector4 srcB0 = { m2[0] };
+ const Vector4 srcB1 = { m2[1] };
+ const Vector4 srcB2 = { m2[2] };
+ const Vector4 srcB3 = { m2[3] };
+
+ Matrix4 result;
+ result[0] = srcA0 * srcB0[0] + srcA1 * srcB0[1] + srcA2 * srcB0[2] + srcA3 * srcB0[3];
+ result[1] = srcA0 * srcB1[0] + srcA1 * srcB1[1] + srcA2 * srcB1[2] + srcA3 * srcB1[3];
+ result[2] = srcA0 * srcB2[0] + srcA1 * srcB2[1] + srcA2 * srcB2[2] + srcA3 * srcB2[3];
+ result[3] = srcA0 * srcB3[0] + srcA1 * srcB3[1] + srcA2 * srcB3[2] + srcA3 * srcB3[3];
+ return result;
+ }
+
+ Vector4 Matrix4::operator*(const Vector4& v) const {
+ const Matrix4& m = *this;
+
+ const Vector4 mul0 = { m[0] * v[0] };
+ const Vector4 mul1 = { m[1] * v[1] };
+ const Vector4 mul2 = { m[2] * v[2] };
+ const Vector4 mul3 = { m[3] * v[3] };
+
+ const Vector4 add0 = { mul0 + mul1 };
+ const Vector4 add1 = { mul2 + mul3 };
+
+ return add0 + add1;
+ }
+
+ Matrix4 Matrix4::operator*(float scalar) const {
+ Matrix4 mat;
+ for (uint32_t i = 0; i < 4; i++)
+ mat[i] = data[i] * scalar;
+ return mat;
+ }
+
+ Matrix4 Matrix4::operator/(float scalar) const {
+ Matrix4 mat;
+ for (uint32_t i = 0; i < 4; i++)
+ mat[i] = data[i] / scalar;
+ return mat;
+ }
+
+ Matrix4& Matrix4::operator+=(const Matrix4& other) {
+ for (uint32_t i = 0; i < 4; i++)
+ data[i] += other.data[i];
+ return *this;
+ }
+
+ Matrix4& Matrix4::operator-=(const Matrix4& other) {
+ for (uint32_t i = 0; i < 4; i++)
+ data[i] -= other.data[i];
+ return *this;
+ }
+
+ Matrix4& Matrix4::operator*=(const Matrix4& other) {
+ return (*this = (*this) * other);
+ }
+
+ Matrix4 transpose(const Matrix4& m) {
+ Matrix4 result;
+
+ for (uint32_t i = 0; i < 4; i++) {
+ for (uint32_t j = 0; j < 4; j++)
+ result[i][j] = m.data[j][i];
+ }
+ return result;
+ }
+
+ float determinant(const Matrix4& m) {
+ float coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+ float coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+ float coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+
+ float coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+ float coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+ float coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+
+ float coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+ float coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+ float coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+
+ float coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+ float coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+ float coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+
+ float coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+ float coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+ float coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+
+ float coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+ float coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+ float coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+ Vector4 fac0 = { coef00, coef00, coef02, coef03 };
+ Vector4 fac1 = { coef04, coef04, coef06, coef07 };
+ Vector4 fac2 = { coef08, coef08, coef10, coef11 };
+ Vector4 fac3 = { coef12, coef12, coef14, coef15 };
+ Vector4 fac4 = { coef16, coef16, coef18, coef19 };
+ Vector4 fac5 = { coef20, coef20, coef22, coef23 };
+
+ Vector4 vec0 = { m[1][0], m[0][0], m[0][0], m[0][0] };
+ Vector4 vec1 = { m[1][1], m[0][1], m[0][1], m[0][1] };
+ Vector4 vec2 = { m[1][2], m[0][2], m[0][2], m[0][2] };
+ Vector4 vec3 = { m[1][3], m[0][3], m[0][3], m[0][3] };
+
+ Vector4 inv0 = { vec1 * fac0 - vec2 * fac1 + vec3 * fac2 };
+ Vector4 inv1 = { vec0 * fac0 - vec2 * fac3 + vec3 * fac4 };
+ Vector4 inv2 = { vec0 * fac1 - vec1 * fac3 + vec3 * fac5 };
+ Vector4 inv3 = { vec0 * fac2 - vec1 * fac4 + vec2 * fac5 };
+
+ Vector4 signA = { +1, -1, +1, -1 };
+ Vector4 signB = { -1, +1, -1, +1 };
+ Matrix4 inverse = { inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB };
+
+ Vector4 row0 = { inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0] };
+
+ Vector4 dot0 = { m[0] * row0 };
+
+ return (dot0.x + dot0.y) + (dot0.z + dot0.w);
+ }
+
+ Matrix4 inverse(const Matrix4& m)
+ {
+ float coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+ float coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+ float coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+ float coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+ float coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+ float coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+ float coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+ float coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+ float coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+ float coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+ float coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+ float coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+ float coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+ float coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+ float coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+ float coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+ float coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+ float coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+ Vector4 fac0 = { coef00, coef00, coef02, coef03 };
+ Vector4 fac1 = { coef04, coef04, coef06, coef07 };
+ Vector4 fac2 = { coef08, coef08, coef10, coef11 };
+ Vector4 fac3 = { coef12, coef12, coef14, coef15 };
+ Vector4 fac4 = { coef16, coef16, coef18, coef19 };
+ Vector4 fac5 = { coef20, coef20, coef22, coef23 };
+
+ Vector4 vec0 = { m[1][0], m[0][0], m[0][0], m[0][0] };
+ Vector4 vec1 = { m[1][1], m[0][1], m[0][1], m[0][1] };
+ Vector4 vec2 = { m[1][2], m[0][2], m[0][2], m[0][2] };
+ Vector4 vec3 = { m[1][3], m[0][3], m[0][3], m[0][3] };
+
+ Vector4 inv0 = { vec1 * fac0 - vec2 * fac1 + vec3 * fac2 };
+ Vector4 inv1 = { vec0 * fac0 - vec2 * fac3 + vec3 * fac4 };
+ Vector4 inv2 = { vec0 * fac1 - vec1 * fac3 + vec3 * fac5 };
+ Vector4 inv3 = { vec0 * fac2 - vec1 * fac4 + vec2 * fac5 };
+
+ Vector4 signA = { +1, -1, +1, -1 };
+ Vector4 signB = { -1, +1, -1, +1 };
+ Matrix4 inverse = { inv0 * signA, inv1 * signB, inv2 * signA, inv3 * signB };
+
+ Vector4 row0 = { inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0] };
+
+ Vector4 dot0 = { m[0] * row0 };
+ float dot1 = (dot0.x + dot0.y) + (dot0.z + dot0.w);
+
+ return inverse * (1.0f / dot1);
+ }
+
+ Matrix4 hadamardProduct(const Matrix4& a, const Matrix4& b) {
+ Matrix4 result;
+
+ for (uint32_t i = 0; i < 4; i++)
+ result[i] = a[i] * b[i];
+
+ return result;
+ }
+
+ std::ostream& operator<<(std::ostream& os, const Matrix4& m) {
+ os << "Matrix4(";
+ for (uint32_t i = 0; i < 4; i++) {
+ os << "\n\t" << m[i];
+ if (i < 3)
+ os << ", ";
+ }
+ os << "\n)";
+
+ return os;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.h b/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.h
new file mode 100644
index 00000000..98f260f8
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_matrix.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "util_vector.h"
+
+namespace dxvk {
+
+ class Matrix4 {
+
+ public:
+
+ // Identity
+ inline Matrix4() {
+ data[0] = { 1, 0, 0, 0 };
+ data[1] = { 0, 1, 0, 0 };
+ data[2] = { 0, 0, 1, 0 };
+ data[3] = { 0, 0, 0, 1 };
+ }
+
+ // Produces a scalar matrix, x * Identity
+ inline explicit Matrix4(float x) {
+ data[0] = { x, 0, 0, 0 };
+ data[1] = { 0, x, 0, 0 };
+ data[2] = { 0, 0, x, 0 };
+ data[3] = { 0, 0, 0, x };
+ }
+
+ inline Matrix4(
+ const Vector4& v0,
+ const Vector4& v1,
+ const Vector4& v2,
+ const Vector4& v3) {
+ data[0] = v0;
+ data[1] = v1;
+ data[2] = v2;
+ data[3] = v3;
+ }
+
+ inline Matrix4(const float matrix[4][4]) {
+ data[0] = Vector4(matrix[0]);
+ data[1] = Vector4(matrix[1]);
+ data[2] = Vector4(matrix[2]);
+ data[3] = Vector4(matrix[3]);
+ }
+
+ Matrix4(const Matrix4& other) = default;
+
+ Vector4& operator[](size_t index);
+ const Vector4& operator[](size_t index) const;
+
+ bool operator==(const Matrix4& m2) const;
+ bool operator!=(const Matrix4& m2) const;
+
+ Matrix4 operator+(const Matrix4& other) const;
+ Matrix4 operator-(const Matrix4& other) const;
+
+ Matrix4 operator*(const Matrix4& m2) const;
+ Vector4 operator*(const Vector4& v) const;
+ Matrix4 operator*(float scalar) const;
+
+ Matrix4 operator/(float scalar) const;
+
+ Matrix4& operator+=(const Matrix4& other);
+ Matrix4& operator-=(const Matrix4& other);
+
+ Matrix4& operator*=(const Matrix4& other);
+
+ Vector4 data[4];
+
+ };
+
+ static_assert(sizeof(Matrix4) == sizeof(Vector4) * 4);
+
+ inline Matrix4 operator*(float scalar, const Matrix4& m) { return m * scalar; }
+
+ Matrix4 transpose(const Matrix4& m);
+
+ float determinant(const Matrix4& m);
+
+ Matrix4 inverse(const Matrix4& m);
+
+ Matrix4 hadamardProduct(const Matrix4& a, const Matrix4& b);
+
+ std::ostream& operator<<(std::ostream& os, const Matrix4& m);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.cpp b/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.cpp
new file mode 100644
index 00000000..7e1b7c6d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.cpp
@@ -0,0 +1,51 @@
+#include "util_monitor.h"
+#include "util_string.h"
+
+#include "../wsi/wsi_mode.h"
+#include "../wsi/wsi_monitor.h"
+#include "../wsi/wsi_window.h"
+
+#include "./log/log.h"
+
+namespace dxvk {
+
+ HMONITOR GetDefaultMonitor() {
+ return wsi::getDefaultMonitor();
+ }
+
+
+ void GetWindowClientSize(
+ HWND hWnd,
+ UINT* pWidth,
+ UINT* pHeight) {
+ wsi::getWindowSize(hWnd, pWidth, pHeight);
+ }
+
+
+ void GetMonitorClientSize(
+ HMONITOR hMonitor,
+ UINT* pWidth,
+ UINT* pHeight) {
+ RECT rect;
+
+ if (!wsi::getDesktopCoordinates(hMonitor, &rect)) {
+ Logger::err("D3D9: Failed to query monitor info");
+ return;
+ }
+
+ if (pWidth)
+ *pWidth = rect.right - rect.left;
+
+ if (pHeight)
+ *pHeight = rect.bottom - rect.top;
+ }
+
+
+ void GetMonitorRect(
+ HMONITOR hMonitor,
+ RECT* pRect) {
+ if (!wsi::getDesktopCoordinates(hMonitor, pRect))
+ Logger::err("D3D9: Failed to query monitor info");
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.h b/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.h
new file mode 100644
index 00000000..81d0a587
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_monitor.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "./com/com_include.h"
+
+namespace dxvk {
+
+ /**
+ * \brief Retrieves primary monitor
+ * \returns The primary monitor
+ */
+ HMONITOR GetDefaultMonitor();
+
+ /**
+ * \brief Queries window client size
+ *
+ * \param [in] hWnd Window to query
+ * \param [out] pWidth Client width
+ * \param [out] pHeight Client height
+ */
+ void GetWindowClientSize(
+ HWND hWnd,
+ UINT* pWidth,
+ UINT* pHeight);
+
+ /**
+ * \brief Queries monitor size
+ *
+ * \param [in] hMonitor Monitor to query
+ * \param [out] pWidth Client width
+ * \param [out] pHeight Client height
+ */
+ void GetMonitorClientSize(
+ HMONITOR hMonitor,
+ UINT* pWidth,
+ UINT* pHeight);
+
+ /**
+ * \brief Queries monitor rect
+ *
+ * \param [in] hMonitor Monitor to query
+ * \param [out] pRect The rect to return
+ */
+ void GetMonitorRect(
+ HMONITOR hMonitor,
+ RECT* pRect);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_ratio.h b/src/libs/dxvk-native-1.9.2a/src/util/util_ratio.h
new file mode 100644
index 00000000..0257ad99
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_ratio.h
@@ -0,0 +1,88 @@
+#include <numeric>
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <charconv>
+
+namespace dxvk {
+
+ /**
+ * \brief Simplest ratio helper
+ */
+ template <typename T>
+ class Ratio {
+
+ public:
+
+ Ratio(T num, T denom) {
+ set(num, denom);
+ }
+
+ Ratio(std::string_view view) {
+ set(0, 0);
+
+ size_t colon = view.find(":");
+
+ if (colon == std::string_view::npos)
+ return;
+
+ std::string_view numStr = view.substr(0, colon);
+ std::string_view denomStr = view.substr(colon + 1);
+
+ T num = 0, denom = 0;
+ std::from_chars(numStr.data(), numStr.data() + numStr.size(), num);
+ std::from_chars(denomStr.data(), denomStr.data() + denomStr.size(), denom);
+
+ set(num, denom);
+ }
+
+ inline T num() const { return m_num; }
+ inline T denom() const { return m_denom; }
+
+ inline bool undefined() const { return m_denom == 0; }
+
+ inline void set(T num, T denom) {
+ const T gcd = std::gcd(num, denom);
+
+ if (gcd == 0) {
+ m_num = 0;
+ m_denom = 0;
+
+ return;
+ }
+
+ m_num = num / gcd;
+ m_denom = denom / gcd;
+ }
+
+ inline bool operator == (const Ratio& other) const {
+ return num() == other.num() && denom() == other.denom();
+ }
+
+ inline bool operator != (const Ratio& other) const {
+ return !(*this == other);
+ }
+
+ inline bool operator >= (const Ratio& other) const {
+ return num() * other.denom() >= other.num() * denom();
+ }
+
+ inline bool operator > (const Ratio& other) const {
+ return num() * other.denom() > other.num() * denom();
+ }
+
+ inline bool operator < (const Ratio& other) const {
+ return !(*this >= other);
+ }
+
+ inline bool operator <= (const Ratio& other) const {
+ return !(*this > other);
+ }
+
+ private:
+
+ T m_num, m_denom;
+
+ };
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_small_vector.h b/src/libs/dxvk-native-1.9.2a/src/util/util_small_vector.h
new file mode 100644
index 00000000..c313ca4b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_small_vector.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#include <type_traits>
+
+namespace dxvk {
+
+ template<typename T, size_t N>
+ class small_vector {
+ using storage = std::aligned_storage_t<sizeof(T), alignof(T)>;
+ public:
+
+ small_vector() { }
+
+ small_vector (const small_vector&) = delete;
+ small_vector& operator = (const small_vector&) = delete;
+
+ ~small_vector() {
+ for (size_t i = 0; i < m_size; i++)
+ ptr(i)->~T();
+
+ if (m_capacity > N)
+ delete[] u.m_ptr;
+ }
+
+ size_t size() const {
+ return m_size;
+ }
+
+ void reserve(size_t n) {
+ n = pick_capacity(n);
+
+ if (n <= m_capacity)
+ return;
+
+ storage* data = new storage[n];
+
+ for (size_t i = 0; i < m_size; i++) {
+ new (&data[i]) T(std::move(*ptr(i)));
+ ptr(i)->~T();
+ }
+
+ if (m_capacity > N)
+ delete[] u.m_ptr;
+
+ m_capacity = n;
+ u.m_ptr = data;
+ }
+
+ const T* data() const { return ptr(0); }
+ T* data() { return ptr(0); }
+
+ void resize(size_t n) {
+ reserve(n);
+
+ for (size_t i = n; i < m_size; i++)
+ ptr(i)->~T();
+
+ for (size_t i = m_size; i < n; i++)
+ new (ptr(i)) T();
+ }
+
+ void push_back(const T& object) {
+ reserve(m_size + 1);
+ new (ptr(m_size++)) T(object);
+ }
+
+ void push_back(T&& object) {
+ reserve(m_size + 1);
+ new (ptr(m_size++)) T(std::move(object));
+ }
+
+ template<typename... Args>
+ void emplace_back(Args... args) {
+ reserve(m_size + 1);
+ new (ptr(m_size++)) T(std::forward<Args>(args)...);
+ }
+
+ void erase(size_t idx) {
+ ptr(idx)->~T();
+
+ for (size_t i = idx; i < m_size - 1; i++) {
+ new (ptr(i)) T(std::move(*ptr(i + 1)));
+ ptr(i + 1)->~T();
+ }
+ }
+
+ void pop_back() {
+ ptr(--m_size)->~T();
+ }
+
+ T& operator [] (size_t idx) { return *ptr(idx); }
+ const T& operator [] (size_t idx) const { return *ptr(idx); }
+
+ T& front() { return *ptr(0); }
+ const T& front() const { return *ptr(0); }
+
+ T& back() { return *ptr(m_size - 1); }
+ const T& back() const { return *ptr(m_size - 1); }
+
+ private:
+
+ size_t m_capacity = N;
+ size_t m_size = 0;
+
+ union {
+ storage* m_ptr;
+ storage m_data[sizeof(T) * N];
+ } u;
+
+ size_t pick_capacity(size_t n) {
+ size_t capacity = m_capacity;
+
+ while (capacity < n)
+ capacity *= 2;
+
+ return capacity;
+ }
+
+ T* ptr(size_t idx) {
+ return m_capacity == N
+ ? reinterpret_cast<T*>(&u.m_data[idx])
+ : reinterpret_cast<T*>(&u.m_ptr[idx]);
+ }
+
+ const T* ptr(size_t idx) const {
+ return m_capacity == N
+ ? reinterpret_cast<const T*>(&u.m_data[idx])
+ : reinterpret_cast<const T*>(&u.m_ptr[idx]);
+ }
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_string.h b/src/libs/dxvk-native-1.9.2a/src/util/util_string.h
new file mode 100644
index 00000000..cd738477
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_string.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "./com/com_include.h"
+
+namespace dxvk::str {
+
+ std::string fromws(const WCHAR *ws);
+
+ void tows(const char* mbs, WCHAR* wcs, size_t wcsLen);
+
+ template <size_t N>
+ void tows(const char* mbs, WCHAR (&wcs)[N]) {
+ return tows(mbs, wcs, N);
+ }
+
+ std::wstring tows(const char* mbs);
+
+ inline void format1(std::stringstream&) { }
+
+ template<typename... Tx>
+ void format1(std::stringstream& str, const WCHAR *arg, const Tx&... args) {
+ str << fromws(arg);
+ format1(str, args...);
+ }
+
+ template<typename T, typename... Tx>
+ void format1(std::stringstream& str, const T& arg, const Tx&... args) {
+ str << arg;
+ format1(str, args...);
+ }
+
+ template<typename... Args>
+ std::string format(const Args&... args) {
+ std::stringstream stream;
+ format1(stream, args...);
+ return stream.str();
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_time.h b/src/libs/dxvk-native-1.9.2a/src/util/util_time.h
new file mode 100644
index 00000000..cbadfa5d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_time.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+
+#if defined(_WIN32) && !defined(__WINE__)
+#include <windows.h>
+#endif
+
+namespace dxvk {
+
+#if defined(_WIN32) && !defined(__WINE__)
+ struct high_resolution_clock {
+ static constexpr bool is_steady = true;
+
+ using rep = int64_t;
+ using period = std::nano;
+ using duration = std::chrono::nanoseconds;
+ using time_point = std::chrono::time_point<high_resolution_clock>;
+
+ static inline time_point now() noexcept {
+ // Keep the frequency static, this doesn't change at all.
+ static const int64_t freq = getFrequency();
+ const int64_t counter = getCounter();
+
+ const int64_t whole = (counter / freq) * period::den;
+ const int64_t part = (counter % freq) * period::den / freq;
+
+ return time_point(duration(whole + part));
+ }
+
+ static inline int64_t getFrequency() {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+
+ return freq.QuadPart;
+ }
+
+ static inline int64_t getCounter() {
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+
+ return count.QuadPart;
+ }
+ };
+#else
+ using high_resolution_clock = std::chrono::high_resolution_clock;
+#endif
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/util/util_vector.h b/src/libs/dxvk-native-1.9.2a/src/util/util_vector.h
new file mode 100644
index 00000000..77cdf294
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/util/util_vector.h
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <iostream>
+
+#include "util_bit.h"
+#include "util_math.h"
+
+namespace dxvk {
+
+ template <typename T>
+ struct Vector4Base {
+ Vector4Base()
+ : x{ }, y{ }, z{ }, w{ } { }
+
+ Vector4Base(T splat)
+ : x(splat), y(splat), z(splat), w(splat) { }
+
+ Vector4Base(T x, T y, T z, T w)
+ : x(x), y(y), z(z), w(w) { }
+
+ Vector4Base(const T xyzw[4])
+ : x(xyzw[0]), y(xyzw[1]), z(xyzw[2]), w(xyzw[3]) { }
+
+ Vector4Base(const Vector4Base<T>& other) = default;
+
+ inline T& operator[](size_t index) { return data[index]; }
+ inline const T& operator[](size_t index) const { return data[index]; }
+
+ bool operator==(const Vector4Base<T>& other) const {
+ for (uint32_t i = 0; i < 4; i++) {
+ if (data[i] != other.data[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ bool operator!=(const Vector4Base<T>& other) const {
+ return !operator==(other);
+ }
+
+ Vector4Base operator-() const { return {-x, -y, -z, -w}; }
+
+ Vector4Base operator+(const Vector4Base<T>& other) const {
+ return {x + other.x, y + other.y, z + other.z, w + other.w};
+ }
+
+ Vector4Base operator-(const Vector4Base<T>& other) const {
+ return {x - other.x, y - other.y, z - other.z, w - other.w};
+ }
+
+ Vector4Base operator*(T scalar) const {
+ return {scalar * x, scalar * y, scalar * z, scalar * w};
+ }
+
+ Vector4Base operator*(const Vector4Base<T>& other) const {
+ Vector4Base result;
+ for (uint32_t i = 0; i < 4; i++)
+ result[i] = data[i] * other.data[i];
+ return result;
+ }
+
+ Vector4Base operator/(const Vector4Base<T>& other) const {
+ Vector4Base result;
+ for (uint32_t i = 0; i < 4; i++)
+ result[i] = data[i] / other.data[i];
+ return result;
+ }
+
+ Vector4Base operator/(T scalar) const {
+ return {x / scalar, y / scalar, z / scalar, w / scalar};
+ }
+
+ Vector4Base& operator+=(const Vector4Base<T>& other) {
+ x += other.x;
+ y += other.y;
+ z += other.z;
+ w += other.w;
+
+ return *this;
+ }
+
+ Vector4Base& operator-=(const Vector4Base<T>& other) {
+ x -= other.x;
+ y -= other.y;
+ z -= other.z;
+ w -= other.w;
+
+ return *this;
+ }
+
+ Vector4Base& operator*=(T scalar) {
+ x *= scalar;
+ y *= scalar;
+ z *= scalar;
+ w *= scalar;
+
+ return *this;
+ }
+
+ Vector4Base& operator/=(T scalar) {
+ x /= scalar;
+ y /= scalar;
+ z /= scalar;
+ w /= scalar;
+
+ return *this;
+ }
+
+ union {
+ T data[4];
+ struct {
+ T x, y, z, w;
+ };
+ struct {
+ T r, g, b, a;
+ };
+ };
+
+ };
+
+ template <typename T>
+ inline Vector4Base<T> operator*(T scalar, const Vector4Base<T>& vector) {
+ return vector * scalar;
+ }
+
+ template <typename T>
+ float dot(const Vector4Base<T>& a, const Vector4Base<T>& b) {
+ return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
+ }
+
+ template <typename T>
+ T lengthSqr(const Vector4Base<T>& a) { return dot(a, a); }
+
+ template <typename T>
+ float length(const Vector4Base<T>& a) { return std::sqrt(float(lengthSqr(a))); }
+
+ template <typename T>
+ Vector4Base<T> normalize(const Vector4Base<T>& a) { return a * T(1.0f / length(a)); }
+
+ template <typename T>
+ std::ostream& operator<<(std::ostream& os, const Vector4Base<T>& v) {
+ return os << "Vector4(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")";
+ }
+
+ using Vector4 = Vector4Base<float>;
+ using Vector4i = Vector4Base<int>;
+
+ static_assert(sizeof(Vector4) == sizeof(float) * 4);
+ static_assert(sizeof(Vector4i) == sizeof(int) * 4);
+
+ inline Vector4 replaceNaN(Vector4 a) {
+ Vector4 result;
+ __m128 value = _mm_load_ps(a.data);
+ __m128 mask = _mm_cmpeq_ps(value, value);
+ value = _mm_and_ps(value, mask);
+ _mm_store_ps(result.data, value);
+ return result;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/meson.build b/src/libs/dxvk-native-1.9.2a/src/vulkan/meson.build
new file mode 100644
index 00000000..d075531d
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/meson.build
@@ -0,0 +1,18 @@
+vkcommon_src = [
+ 'vulkan_loader.cpp',
+ 'vulkan_names.cpp',
+ 'vulkan_presenter.cpp',
+]
+
+thread_dep = dependency('threads')
+
+vkcommon_deps = [ thread_dep, wsi_dep, lib_vulkan ]
+
+vkcommon_lib = static_library('vkcommon', vkcommon_src,
+ dependencies : vkcommon_deps,
+ override_options : ['cpp_std='+dxvk_cpp_std],
+ include_directories : [ dxvk_include_path ])
+
+vkcommon_dep = declare_dependency(
+ link_with : [ vkcommon_lib ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.cpp b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.cpp
new file mode 100644
index 00000000..e9738934
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.cpp
@@ -0,0 +1,82 @@
+#include "vulkan_loader.h"
+
+#ifdef VBOX
+# include <iprt/ldr.h>
+# include <iprt/once.h>
+
+# ifdef RT_OS_DARWIN
+# define VBOX_VULKAN_LIBRARY_NAME "libMoltenVK"
+# else
+# define VBOX_VULKAN_LIBRARY_NAME "libvulkan.so.1"
+# endif
+#endif
+
+namespace dxvk::vk {
+
+#ifndef VBOX
+ static const PFN_vkGetInstanceProcAddr GetInstanceProcAddr = vkGetInstanceProcAddr;
+#else
+ static PFN_vkGetInstanceProcAddr GetInstanceProcAddr = NULL;
+ static RTONCE s_VkLibLoadOnce = RTONCE_INITIALIZER;
+
+ static DECLCALLBACK(int32_t) loadVkLib(void *pvUser)
+ {
+ RT_NOREF(pvUser);
+ dxvk::vk::GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)RTLdrGetSystemSymbol(VBOX_VULKAN_LIBRARY_NAME, "vkGetInstanceProcAddr");
+ return dxvk::vk::GetInstanceProcAddr ? VINF_SUCCESS : VERR_NOT_FOUND;
+ }
+#endif
+
+ PFN_vkVoidFunction LibraryLoader::sym(const char* name) const {
+#ifndef VBOX
+ return dxvk::vk::GetInstanceProcAddr(nullptr, name);
+#else
+ int rc = RTOnce(&dxvk::vk::s_VkLibLoadOnce, dxvk::vk::loadVkLib, NULL /*pvUser*/);
+ if (RT_SUCCESS(rc))
+ return dxvk::vk::GetInstanceProcAddr(nullptr, name);
+
+ return NULL;
+#endif
+ }
+
+
+ InstanceLoader::InstanceLoader(bool owned, VkInstance instance)
+ : m_instance(instance), m_owned(owned) { }
+
+
+ PFN_vkVoidFunction InstanceLoader::sym(const char* name) const {
+ return dxvk::vk::GetInstanceProcAddr(m_instance, name);
+ }
+
+
+ DeviceLoader::DeviceLoader(bool owned, VkInstance instance, VkDevice device)
+ : m_getDeviceProcAddr(reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+ dxvk::vk::GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"))),
+ m_device(device), m_owned(owned) { }
+
+
+ PFN_vkVoidFunction DeviceLoader::sym(const char* name) const {
+ return m_getDeviceProcAddr(m_device, name);
+ }
+
+
+ LibraryFn::LibraryFn() { }
+ LibraryFn::~LibraryFn() { }
+
+
+ InstanceFn::InstanceFn(bool owned, VkInstance instance)
+ : InstanceLoader(owned, instance) { }
+ InstanceFn::~InstanceFn() {
+ if (m_owned)
+ this->vkDestroyInstance(m_instance, nullptr);
+ }
+
+
+ DeviceFn::DeviceFn(bool owned, VkInstance instance, VkDevice device)
+ : DeviceLoader(owned, instance, device) { }
+ DeviceFn::~DeviceFn() {
+ if (m_owned)
+ this->vkDestroyDevice(m_device, nullptr);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.h b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.h
new file mode 100644
index 00000000..c2e47409
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_loader.h
@@ -0,0 +1,374 @@
+#pragma once
+
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
+#ifdef _WIN32
+#define VK_USE_PLATFORM_WIN32_KHR 1
+#endif
+#include <vulkan/vulkan.h>
+#ifdef DXVK_NATIVE
+#include <vulkan/vulkan_native.h>
+#endif
+
+#define VULKAN_FN(name) \
+ ::PFN_ ## name name = reinterpret_cast<::PFN_ ## name>(sym(#name))
+
+namespace dxvk::vk {
+
+ /**
+ * \brief Vulkan library loader
+ *
+ * Provides methods to load Vulkan functions that
+ * can be called before creating a instance.
+ */
+ struct LibraryLoader : public RcObject {
+ PFN_vkVoidFunction sym(const char* name) const;
+ };
+
+
+ /**
+ * \brief Vulkan instance loader
+ *
+ * Loads Vulkan functions that can be
+ * called for a specific instance.
+ */
+ struct InstanceLoader : public RcObject {
+ InstanceLoader(bool owned, VkInstance instance);
+ PFN_vkVoidFunction sym(const char* name) const;
+ VkInstance instance() const { return m_instance; }
+ protected:
+ const VkInstance m_instance;
+ const bool m_owned;
+ };
+
+
+ /**
+ * \brief Vulkan device loader
+ *
+ * Loads Vulkan functions for a
+ * specific device.
+ */
+ struct DeviceLoader : public RcObject {
+ DeviceLoader(bool owned, VkInstance instance, VkDevice device);
+ PFN_vkVoidFunction sym(const char* name) const;
+ VkDevice device() const { return m_device; }
+ protected:
+ const PFN_vkGetDeviceProcAddr m_getDeviceProcAddr;
+ const VkDevice m_device;
+ const bool m_owned;
+ };
+
+
+ /**
+ * \brief Vulkan library functions
+ *
+ * Vulkan functions that are called before
+ * creating an actual Vulkan instance.
+ */
+ struct LibraryFn : LibraryLoader {
+ LibraryFn();
+ ~LibraryFn();
+
+ VULKAN_FN(vkCreateInstance);
+ VULKAN_FN(vkEnumerateInstanceLayerProperties);
+ VULKAN_FN(vkEnumerateInstanceExtensionProperties);
+ };
+
+
+ /**
+ * \brief Vulkan instance functions
+ *
+ * Vulkan functions for a given instance that
+ * are independent of any Vulkan devices.
+ */
+ struct InstanceFn : InstanceLoader {
+ InstanceFn(bool owned, VkInstance instance);
+ ~InstanceFn();
+
+ VULKAN_FN(vkCreateDevice);
+ VULKAN_FN(vkDestroyInstance);
+ VULKAN_FN(vkEnumerateDeviceExtensionProperties);
+ VULKAN_FN(vkEnumeratePhysicalDevices);
+ VULKAN_FN(vkGetPhysicalDeviceFeatures);
+ VULKAN_FN(vkGetPhysicalDeviceFeatures2);
+ VULKAN_FN(vkGetPhysicalDeviceFormatProperties);
+ VULKAN_FN(vkGetPhysicalDeviceFormatProperties2);
+ VULKAN_FN(vkGetPhysicalDeviceProperties2);
+ VULKAN_FN(vkGetPhysicalDeviceImageFormatProperties);
+ VULKAN_FN(vkGetPhysicalDeviceImageFormatProperties2);
+ VULKAN_FN(vkGetPhysicalDeviceMemoryProperties);
+ VULKAN_FN(vkGetPhysicalDeviceMemoryProperties2);
+ VULKAN_FN(vkGetPhysicalDeviceProperties);
+ VULKAN_FN(vkGetPhysicalDeviceQueueFamilyProperties);
+ VULKAN_FN(vkGetPhysicalDeviceQueueFamilyProperties2);
+ VULKAN_FN(vkGetPhysicalDeviceSparseImageFormatProperties);
+ VULKAN_FN(vkGetPhysicalDeviceSparseImageFormatProperties2);
+
+ #ifdef VK_KHR_get_surface_capabilities2
+ VULKAN_FN(vkGetPhysicalDeviceSurfaceCapabilities2KHR);
+ VULKAN_FN(vkGetPhysicalDeviceSurfaceFormats2KHR);
+ #endif
+
+ #ifdef VK_KHR_surface
+ #ifdef VK_USE_PLATFORM_XCB_KHR
+ VULKAN_FN(vkCreateXcbSurfaceKHR);
+ VULKAN_FN(vkGetPhysicalDeviceXcbPresentationSupportKHR);
+ #endif
+
+ #ifdef VK_USE_PLATFORM_XLIB_KHR
+ VULKAN_FN(vkCreateXlibSurfaceKHR);
+ VULKAN_FN(vkGetPhysicalDeviceXlibPresentationSupportKHR);
+ #endif
+
+ #ifdef VK_USE_PLATFORM_WAYLAND_KHR
+ VULKAN_FN(vkCreateWaylandSurfaceKHR);
+ VULKAN_FN(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
+ #endif
+
+ #ifdef VK_USE_PLATFORM_WIN32_KHR
+ VULKAN_FN(vkCreateWin32SurfaceKHR);
+ VULKAN_FN(vkGetPhysicalDeviceWin32PresentationSupportKHR);
+ #endif
+
+ VULKAN_FN(vkDestroySurfaceKHR);
+
+ VULKAN_FN(vkGetPhysicalDeviceSurfaceSupportKHR);
+ VULKAN_FN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+ VULKAN_FN(vkGetPhysicalDeviceSurfaceFormatsKHR);
+ VULKAN_FN(vkGetPhysicalDeviceSurfacePresentModesKHR);
+ #endif
+
+ #ifdef VK_EXT_debug_report
+ VULKAN_FN(vkCreateDebugReportCallbackEXT);
+ VULKAN_FN(vkDestroyDebugReportCallbackEXT);
+ VULKAN_FN(vkDebugReportMessageEXT);
+ #endif
+
+ #ifdef VK_EXT_debug_utils
+ VULKAN_FN(vkCmdBeginDebugUtilsLabelEXT);
+ VULKAN_FN(vkCmdEndDebugUtilsLabelEXT);
+ VULKAN_FN(vkCmdInsertDebugUtilsLabelEXT);
+ #endif
+
+ #ifdef VK_EXT_full_screen_exclusive
+ VULKAN_FN(vkGetPhysicalDeviceSurfacePresentModes2EXT);
+ #endif
+ };
+
+
+ /**
+ * \brief Vulkan device functions
+ *
+ * Vulkan functions for a specific Vulkan device.
+ * This ensures that no slow dispatch code is executed.
+ */
+ struct DeviceFn : DeviceLoader {
+ DeviceFn(bool owned, VkInstance instance, VkDevice device);
+ ~DeviceFn();
+
+ VULKAN_FN(vkDestroyDevice);
+ VULKAN_FN(vkGetDeviceQueue);
+ VULKAN_FN(vkQueueSubmit);
+ VULKAN_FN(vkQueueWaitIdle);
+ VULKAN_FN(vkDeviceWaitIdle);
+ VULKAN_FN(vkAllocateMemory);
+ VULKAN_FN(vkFreeMemory);
+ VULKAN_FN(vkMapMemory);
+ VULKAN_FN(vkUnmapMemory);
+ VULKAN_FN(vkFlushMappedMemoryRanges);
+ VULKAN_FN(vkInvalidateMappedMemoryRanges);
+ VULKAN_FN(vkGetDeviceMemoryCommitment);
+ VULKAN_FN(vkBindBufferMemory);
+ VULKAN_FN(vkBindImageMemory);
+ VULKAN_FN(vkGetBufferMemoryRequirements);
+ VULKAN_FN(vkGetBufferMemoryRequirements2);
+ VULKAN_FN(vkGetImageMemoryRequirements);
+ VULKAN_FN(vkGetImageMemoryRequirements2);
+ VULKAN_FN(vkGetImageSparseMemoryRequirements);
+ VULKAN_FN(vkGetImageSparseMemoryRequirements2);
+ VULKAN_FN(vkQueueBindSparse);
+ VULKAN_FN(vkCreateFence);
+ VULKAN_FN(vkDestroyFence);
+ VULKAN_FN(vkResetFences);
+ VULKAN_FN(vkGetFenceStatus);
+ VULKAN_FN(vkWaitForFences);
+ VULKAN_FN(vkCreateSemaphore);
+ VULKAN_FN(vkDestroySemaphore);
+ VULKAN_FN(vkCreateEvent);
+ VULKAN_FN(vkDestroyEvent);
+ VULKAN_FN(vkGetEventStatus);
+ VULKAN_FN(vkSetEvent);
+ VULKAN_FN(vkResetEvent);
+ VULKAN_FN(vkCreateQueryPool);
+ VULKAN_FN(vkDestroyQueryPool);
+ VULKAN_FN(vkGetQueryPoolResults);
+ VULKAN_FN(vkCreateBuffer);
+ VULKAN_FN(vkDestroyBuffer);
+ VULKAN_FN(vkCreateBufferView);
+ VULKAN_FN(vkDestroyBufferView);
+ VULKAN_FN(vkCreateImage);
+ VULKAN_FN(vkDestroyImage);
+ VULKAN_FN(vkGetImageSubresourceLayout);
+ VULKAN_FN(vkCreateImageView);
+ VULKAN_FN(vkDestroyImageView);
+ VULKAN_FN(vkCreateShaderModule);
+ VULKAN_FN(vkDestroyShaderModule);
+ VULKAN_FN(vkCreatePipelineCache);
+ VULKAN_FN(vkDestroyPipelineCache);
+ VULKAN_FN(vkGetPipelineCacheData);
+ VULKAN_FN(vkMergePipelineCaches);
+ VULKAN_FN(vkCreateGraphicsPipelines);
+ VULKAN_FN(vkCreateComputePipelines);
+ VULKAN_FN(vkDestroyPipeline);
+ VULKAN_FN(vkCreatePipelineLayout);
+ VULKAN_FN(vkDestroyPipelineLayout);
+ VULKAN_FN(vkCreateSampler);
+ VULKAN_FN(vkDestroySampler);
+ VULKAN_FN(vkCreateDescriptorSetLayout);
+ VULKAN_FN(vkDestroyDescriptorSetLayout);
+ VULKAN_FN(vkCreateDescriptorPool);
+ VULKAN_FN(vkDestroyDescriptorPool);
+ VULKAN_FN(vkResetDescriptorPool);
+ VULKAN_FN(vkAllocateDescriptorSets);
+ VULKAN_FN(vkFreeDescriptorSets);
+ VULKAN_FN(vkUpdateDescriptorSets);
+ VULKAN_FN(vkCreateFramebuffer);
+ VULKAN_FN(vkDestroyFramebuffer);
+ VULKAN_FN(vkCreateRenderPass);
+ VULKAN_FN(vkDestroyRenderPass);
+ VULKAN_FN(vkGetRenderAreaGranularity);
+ VULKAN_FN(vkCreateCommandPool);
+ VULKAN_FN(vkDestroyCommandPool);
+ VULKAN_FN(vkResetCommandPool);
+ VULKAN_FN(vkAllocateCommandBuffers);
+ VULKAN_FN(vkFreeCommandBuffers);
+ VULKAN_FN(vkBeginCommandBuffer);
+ VULKAN_FN(vkEndCommandBuffer);
+ VULKAN_FN(vkResetCommandBuffer);
+ VULKAN_FN(vkCreateDescriptorUpdateTemplate);
+ VULKAN_FN(vkDestroyDescriptorUpdateTemplate);
+ VULKAN_FN(vkUpdateDescriptorSetWithTemplate);
+ VULKAN_FN(vkCmdBindPipeline);
+ VULKAN_FN(vkCmdSetViewport);
+ VULKAN_FN(vkCmdSetScissor);
+ VULKAN_FN(vkCmdSetLineWidth);
+ VULKAN_FN(vkCmdSetDepthBias);
+ VULKAN_FN(vkCmdSetBlendConstants);
+ VULKAN_FN(vkCmdSetDepthBounds);
+ VULKAN_FN(vkCmdSetStencilCompareMask);
+ VULKAN_FN(vkCmdSetStencilWriteMask);
+ VULKAN_FN(vkCmdSetStencilReference);
+ VULKAN_FN(vkCmdBindDescriptorSets);
+ VULKAN_FN(vkCmdBindIndexBuffer);
+ VULKAN_FN(vkCmdBindVertexBuffers);
+ VULKAN_FN(vkCmdDraw);
+ VULKAN_FN(vkCmdDrawIndexed);
+ VULKAN_FN(vkCmdDrawIndirect);
+ VULKAN_FN(vkCmdDrawIndexedIndirect);
+ VULKAN_FN(vkCmdDispatch);
+ VULKAN_FN(vkCmdDispatchIndirect);
+ VULKAN_FN(vkCmdCopyBuffer);
+ VULKAN_FN(vkCmdCopyImage);
+ VULKAN_FN(vkCmdBlitImage);
+ VULKAN_FN(vkCmdCopyBufferToImage);
+ VULKAN_FN(vkCmdCopyImageToBuffer);
+ VULKAN_FN(vkCmdUpdateBuffer);
+ VULKAN_FN(vkCmdFillBuffer);
+ VULKAN_FN(vkCmdClearColorImage);
+ VULKAN_FN(vkCmdClearDepthStencilImage);
+ VULKAN_FN(vkCmdClearAttachments);
+ VULKAN_FN(vkCmdResolveImage);
+ VULKAN_FN(vkCmdSetEvent);
+ VULKAN_FN(vkCmdResetEvent);
+ VULKAN_FN(vkCmdWaitEvents);
+ VULKAN_FN(vkCmdPipelineBarrier);
+ VULKAN_FN(vkCmdBeginQuery);
+ VULKAN_FN(vkCmdEndQuery);
+ VULKAN_FN(vkCmdResetQueryPool);
+ VULKAN_FN(vkCmdWriteTimestamp);
+ VULKAN_FN(vkCmdCopyQueryPoolResults);
+ VULKAN_FN(vkCmdPushConstants);
+ VULKAN_FN(vkCmdBeginRenderPass);
+ VULKAN_FN(vkCmdNextSubpass);
+ VULKAN_FN(vkCmdEndRenderPass);
+ VULKAN_FN(vkCmdExecuteCommands);
+
+ #ifdef VK_KHR_create_renderpass2
+ VULKAN_FN(vkCreateRenderPass2KHR);
+ VULKAN_FN(vkCmdBeginRenderPass2KHR);
+ VULKAN_FN(vkCmdNextSubpass2KHR);
+ VULKAN_FN(vkCmdEndRenderPass2KHR);
+ #endif
+
+ #ifdef VK_KHR_draw_indirect_count
+ VULKAN_FN(vkCmdDrawIndirectCountKHR);
+ VULKAN_FN(vkCmdDrawIndexedIndirectCountKHR);
+ #endif
+
+ #ifdef VK_KHR_swapchain
+ VULKAN_FN(vkCreateSwapchainKHR);
+ VULKAN_FN(vkDestroySwapchainKHR);
+ VULKAN_FN(vkGetSwapchainImagesKHR);
+ VULKAN_FN(vkAcquireNextImageKHR);
+ VULKAN_FN(vkQueuePresentKHR);
+ #endif
+
+ #ifdef VK_EXT_conditional_rendering
+ VULKAN_FN(vkCmdBeginConditionalRenderingEXT);
+ VULKAN_FN(vkCmdEndConditionalRenderingEXT);
+ #endif
+
+ #ifdef VK_EXT_extended_dynamic_state
+ VULKAN_FN(vkCmdBindVertexBuffers2EXT);
+ VULKAN_FN(vkCmdSetCullModeEXT);
+ VULKAN_FN(vkCmdSetDepthBoundsTestEnableEXT);
+ VULKAN_FN(vkCmdSetDepthCompareOpEXT);
+ VULKAN_FN(vkCmdSetDepthTestEnableEXT);
+ VULKAN_FN(vkCmdSetDepthWriteEnableEXT);
+ VULKAN_FN(vkCmdSetFrontFaceEXT);
+ VULKAN_FN(vkCmdSetPrimitiveTopologyEXT);
+ VULKAN_FN(vkCmdSetScissorWithCountEXT);
+ VULKAN_FN(vkCmdSetStencilOpEXT);
+ VULKAN_FN(vkCmdSetStencilTestEnableEXT);
+ VULKAN_FN(vkCmdSetViewportWithCountEXT);
+ #endif
+
+ #ifdef VK_EXT_full_screen_exclusive
+ VULKAN_FN(vkAcquireFullScreenExclusiveModeEXT);
+ VULKAN_FN(vkReleaseFullScreenExclusiveModeEXT);
+ VULKAN_FN(vkGetDeviceGroupSurfacePresentModes2EXT);
+ #endif
+
+ #ifdef VK_EXT_host_query_reset
+ VULKAN_FN(vkResetQueryPoolEXT);
+ #endif
+
+ #ifdef VK_EXT_transform_feedback
+ VULKAN_FN(vkCmdBindTransformFeedbackBuffersEXT);
+ VULKAN_FN(vkCmdBeginTransformFeedbackEXT);
+ VULKAN_FN(vkCmdEndTransformFeedbackEXT);
+ VULKAN_FN(vkCmdDrawIndirectByteCountEXT);
+ VULKAN_FN(vkCmdBeginQueryIndexedEXT);
+ VULKAN_FN(vkCmdEndQueryIndexedEXT);
+ #endif
+
+ #ifdef VK_NVX_image_view_handle
+ VULKAN_FN(vkGetImageViewHandleNVX);
+ VULKAN_FN(vkGetImageViewAddressNVX);
+ #endif
+
+ #ifdef VK_NVX_binary_import
+ VULKAN_FN(vkCreateCuModuleNVX);
+ VULKAN_FN(vkCreateCuFunctionNVX);
+ VULKAN_FN(vkDestroyCuModuleNVX);
+ VULKAN_FN(vkDestroyCuFunctionNVX);
+ VULKAN_FN(vkCmdCuLaunchKernelNVX);
+ #endif
+
+ #ifdef VK_KHR_buffer_device_address
+ VULKAN_FN(vkGetBufferDeviceAddressKHR);
+ #endif
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.cpp b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.cpp
new file mode 100644
index 00000000..1dd6d7cf
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.cpp
@@ -0,0 +1,333 @@
+#include "vulkan_names.h"
+
+std::ostream& operator << (std::ostream& os, VkPipelineCacheHeaderVersion e) {
+ switch (e) {
+ ENUM_NAME(VK_PIPELINE_CACHE_HEADER_VERSION_ONE);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkResult e) {
+ switch (e) {
+ ENUM_NAME(VK_SUCCESS);
+ ENUM_NAME(VK_NOT_READY);
+ ENUM_NAME(VK_TIMEOUT);
+ ENUM_NAME(VK_EVENT_SET);
+ ENUM_NAME(VK_EVENT_RESET);
+ ENUM_NAME(VK_INCOMPLETE);
+ ENUM_NAME(VK_ERROR_OUT_OF_HOST_MEMORY);
+ ENUM_NAME(VK_ERROR_OUT_OF_DEVICE_MEMORY);
+ ENUM_NAME(VK_ERROR_INITIALIZATION_FAILED);
+ ENUM_NAME(VK_ERROR_DEVICE_LOST);
+ ENUM_NAME(VK_ERROR_MEMORY_MAP_FAILED);
+ ENUM_NAME(VK_ERROR_LAYER_NOT_PRESENT);
+ ENUM_NAME(VK_ERROR_EXTENSION_NOT_PRESENT);
+ ENUM_NAME(VK_ERROR_FEATURE_NOT_PRESENT);
+ ENUM_NAME(VK_ERROR_INCOMPATIBLE_DRIVER);
+ ENUM_NAME(VK_ERROR_TOO_MANY_OBJECTS);
+ ENUM_NAME(VK_ERROR_FORMAT_NOT_SUPPORTED);
+ ENUM_NAME(VK_ERROR_FRAGMENTED_POOL);
+ ENUM_NAME(VK_ERROR_SURFACE_LOST_KHR);
+ ENUM_NAME(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
+ ENUM_NAME(VK_SUBOPTIMAL_KHR);
+ ENUM_NAME(VK_ERROR_OUT_OF_DATE_KHR);
+ ENUM_NAME(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
+ ENUM_NAME(VK_ERROR_VALIDATION_FAILED_EXT);
+ ENUM_NAME(VK_ERROR_INVALID_SHADER_NV);
+ ENUM_NAME(VK_ERROR_OUT_OF_POOL_MEMORY_KHR);
+ ENUM_NAME(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkFormat e) {
+ switch (e) {
+ ENUM_NAME(VK_FORMAT_UNDEFINED);
+ ENUM_NAME(VK_FORMAT_R4G4_UNORM_PACK8);
+ ENUM_NAME(VK_FORMAT_R4G4B4A4_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_B4G4R4A4_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_R5G6B5_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_B5G6R5_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_R5G5B5A1_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_B5G5R5A1_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_A1R5G5B5_UNORM_PACK16);
+ ENUM_NAME(VK_FORMAT_R8_UNORM);
+ ENUM_NAME(VK_FORMAT_R8_SNORM);
+ ENUM_NAME(VK_FORMAT_R8_USCALED);
+ ENUM_NAME(VK_FORMAT_R8_SSCALED);
+ ENUM_NAME(VK_FORMAT_R8_UINT);
+ ENUM_NAME(VK_FORMAT_R8_SINT);
+ ENUM_NAME(VK_FORMAT_R8_SRGB);
+ ENUM_NAME(VK_FORMAT_R8G8_UNORM);
+ ENUM_NAME(VK_FORMAT_R8G8_SNORM);
+ ENUM_NAME(VK_FORMAT_R8G8_USCALED);
+ ENUM_NAME(VK_FORMAT_R8G8_SSCALED);
+ ENUM_NAME(VK_FORMAT_R8G8_UINT);
+ ENUM_NAME(VK_FORMAT_R8G8_SINT);
+ ENUM_NAME(VK_FORMAT_R8G8_SRGB);
+ ENUM_NAME(VK_FORMAT_R8G8B8_UNORM);
+ ENUM_NAME(VK_FORMAT_R8G8B8_SNORM);
+ ENUM_NAME(VK_FORMAT_R8G8B8_USCALED);
+ ENUM_NAME(VK_FORMAT_R8G8B8_SSCALED);
+ ENUM_NAME(VK_FORMAT_R8G8B8_UINT);
+ ENUM_NAME(VK_FORMAT_R8G8B8_SINT);
+ ENUM_NAME(VK_FORMAT_R8G8B8_SRGB);
+ ENUM_NAME(VK_FORMAT_B8G8R8_UNORM);
+ ENUM_NAME(VK_FORMAT_B8G8R8_SNORM);
+ ENUM_NAME(VK_FORMAT_B8G8R8_USCALED);
+ ENUM_NAME(VK_FORMAT_B8G8R8_SSCALED);
+ ENUM_NAME(VK_FORMAT_B8G8R8_UINT);
+ ENUM_NAME(VK_FORMAT_B8G8R8_SINT);
+ ENUM_NAME(VK_FORMAT_B8G8R8_SRGB);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_UNORM);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_SNORM);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_USCALED);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_SSCALED);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_UINT);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_SINT);
+ ENUM_NAME(VK_FORMAT_R8G8B8A8_SRGB);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_UNORM);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_SNORM);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_USCALED);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_SSCALED);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_UINT);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_SINT);
+ ENUM_NAME(VK_FORMAT_B8G8R8A8_SRGB);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_UNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_SNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_USCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_SSCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_UINT_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_SINT_PACK32);
+ ENUM_NAME(VK_FORMAT_A8B8G8R8_SRGB_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_UNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_SNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_USCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_SSCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_UINT_PACK32);
+ ENUM_NAME(VK_FORMAT_A2R10G10B10_SINT_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_UNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_SNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_USCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_SSCALED_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_UINT_PACK32);
+ ENUM_NAME(VK_FORMAT_A2B10G10R10_SINT_PACK32);
+ ENUM_NAME(VK_FORMAT_R16_UNORM);
+ ENUM_NAME(VK_FORMAT_R16_SNORM);
+ ENUM_NAME(VK_FORMAT_R16_USCALED);
+ ENUM_NAME(VK_FORMAT_R16_SSCALED);
+ ENUM_NAME(VK_FORMAT_R16_UINT);
+ ENUM_NAME(VK_FORMAT_R16_SINT);
+ ENUM_NAME(VK_FORMAT_R16_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R16G16_UNORM);
+ ENUM_NAME(VK_FORMAT_R16G16_SNORM);
+ ENUM_NAME(VK_FORMAT_R16G16_USCALED);
+ ENUM_NAME(VK_FORMAT_R16G16_SSCALED);
+ ENUM_NAME(VK_FORMAT_R16G16_UINT);
+ ENUM_NAME(VK_FORMAT_R16G16_SINT);
+ ENUM_NAME(VK_FORMAT_R16G16_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R16G16B16_UNORM);
+ ENUM_NAME(VK_FORMAT_R16G16B16_SNORM);
+ ENUM_NAME(VK_FORMAT_R16G16B16_USCALED);
+ ENUM_NAME(VK_FORMAT_R16G16B16_SSCALED);
+ ENUM_NAME(VK_FORMAT_R16G16B16_UINT);
+ ENUM_NAME(VK_FORMAT_R16G16B16_SINT);
+ ENUM_NAME(VK_FORMAT_R16G16B16_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_UNORM);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_SNORM);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_USCALED);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_SSCALED);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_UINT);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_SINT);
+ ENUM_NAME(VK_FORMAT_R16G16B16A16_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R32_UINT);
+ ENUM_NAME(VK_FORMAT_R32_SINT);
+ ENUM_NAME(VK_FORMAT_R32_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R32G32_UINT);
+ ENUM_NAME(VK_FORMAT_R32G32_SINT);
+ ENUM_NAME(VK_FORMAT_R32G32_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R32G32B32_UINT);
+ ENUM_NAME(VK_FORMAT_R32G32B32_SINT);
+ ENUM_NAME(VK_FORMAT_R32G32B32_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R32G32B32A32_UINT);
+ ENUM_NAME(VK_FORMAT_R32G32B32A32_SINT);
+ ENUM_NAME(VK_FORMAT_R32G32B32A32_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R64_UINT);
+ ENUM_NAME(VK_FORMAT_R64_SINT);
+ ENUM_NAME(VK_FORMAT_R64_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R64G64_UINT);
+ ENUM_NAME(VK_FORMAT_R64G64_SINT);
+ ENUM_NAME(VK_FORMAT_R64G64_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R64G64B64_UINT);
+ ENUM_NAME(VK_FORMAT_R64G64B64_SINT);
+ ENUM_NAME(VK_FORMAT_R64G64B64_SFLOAT);
+ ENUM_NAME(VK_FORMAT_R64G64B64A64_UINT);
+ ENUM_NAME(VK_FORMAT_R64G64B64A64_SINT);
+ ENUM_NAME(VK_FORMAT_R64G64B64A64_SFLOAT);
+ ENUM_NAME(VK_FORMAT_B10G11R11_UFLOAT_PACK32);
+ ENUM_NAME(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32);
+ ENUM_NAME(VK_FORMAT_D16_UNORM);
+ ENUM_NAME(VK_FORMAT_X8_D24_UNORM_PACK32);
+ ENUM_NAME(VK_FORMAT_D32_SFLOAT);
+ ENUM_NAME(VK_FORMAT_S8_UINT);
+ ENUM_NAME(VK_FORMAT_D16_UNORM_S8_UINT);
+ ENUM_NAME(VK_FORMAT_D24_UNORM_S8_UINT);
+ ENUM_NAME(VK_FORMAT_D32_SFLOAT_S8_UINT);
+ ENUM_NAME(VK_FORMAT_BC1_RGB_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC1_RGB_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC1_RGBA_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC1_RGBA_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC2_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC2_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC3_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC3_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC4_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC4_SNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC5_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC5_SNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC6H_UFLOAT_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC6H_SFLOAT_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC7_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_BC7_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_EAC_R11_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_EAC_R11_SNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_EAC_R11G11_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_EAC_R11G11_SNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_4x4_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_4x4_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_5x4_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_5x4_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_5x5_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_5x5_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_6x5_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_6x5_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_6x6_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_6x6_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x5_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x5_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x6_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x6_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x8_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_8x8_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x5_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x5_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x6_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x6_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x8_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x8_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x10_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_10x10_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_12x10_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_12x10_SRGB_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_12x12_UNORM_BLOCK);
+ ENUM_NAME(VK_FORMAT_ASTC_12x12_SRGB_BLOCK);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkImageType e) {
+ switch (e) {
+ ENUM_NAME(VK_IMAGE_TYPE_1D);
+ ENUM_NAME(VK_IMAGE_TYPE_2D);
+ ENUM_NAME(VK_IMAGE_TYPE_3D);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkImageTiling e) {
+ switch (e) {
+ ENUM_NAME(VK_IMAGE_TILING_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_TILING_LINEAR);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkImageLayout e) {
+ switch (e) {
+ ENUM_NAME(VK_IMAGE_LAYOUT_UNDEFINED);
+ ENUM_NAME(VK_IMAGE_LAYOUT_GENERAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ ENUM_NAME(VK_IMAGE_LAYOUT_PREINITIALIZED);
+ ENUM_NAME(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ ENUM_NAME(VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkImageViewType e) {
+ switch (e) {
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_1D);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_2D);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_3D);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_CUBE);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_1D_ARRAY);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_2D_ARRAY);
+ ENUM_NAME(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkPresentModeKHR e) {
+ switch (e) {
+ ENUM_NAME(VK_PRESENT_MODE_IMMEDIATE_KHR);
+ ENUM_NAME(VK_PRESENT_MODE_MAILBOX_KHR);
+ ENUM_NAME(VK_PRESENT_MODE_FIFO_KHR);
+ ENUM_NAME(VK_PRESENT_MODE_FIFO_RELAXED_KHR);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkColorSpaceKHR e) {
+ switch (e) {
+ ENUM_NAME(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
+ ENUM_DEFAULT(e);
+ }
+ return os;
+}
+
+
+std::ostream& operator << (std::ostream& os, VkOffset2D e) {
+ return os << "(" << e.x << "," << e.y << ")";
+}
+
+
+std::ostream& operator << (std::ostream& os, VkOffset3D e) {
+ return os << "(" << e.x << "," << e.y << "," << e.z << ")";
+}
+
+
+std::ostream& operator << (std::ostream& os, VkExtent2D e) {
+ return os << "(" << e.width << "," << e.height << ")";
+}
+
+
+std::ostream& operator << (std::ostream& os, VkExtent3D e) {
+ return os << "(" << e.width << "," << e.height << "," << e.depth << ")";
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.h b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.h
new file mode 100644
index 00000000..6752a12c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_names.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <ostream>
+
+#include "../util/util_enum.h"
+
+#include "vulkan_loader.h"
+
+std::ostream& operator << (std::ostream& os, VkPipelineCacheHeaderVersion e);
+std::ostream& operator << (std::ostream& os, VkResult e);
+std::ostream& operator << (std::ostream& os, VkFormat e);
+std::ostream& operator << (std::ostream& os, VkImageType e);
+std::ostream& operator << (std::ostream& os, VkImageTiling e);
+std::ostream& operator << (std::ostream& os, VkImageLayout e);
+std::ostream& operator << (std::ostream& os, VkImageViewType e);
+std::ostream& operator << (std::ostream& os, VkPresentModeKHR e);
+std::ostream& operator << (std::ostream& os, VkColorSpaceKHR e);
+std::ostream& operator << (std::ostream& os, VkOffset2D e);
+std::ostream& operator << (std::ostream& os, VkOffset3D e);
+std::ostream& operator << (std::ostream& os, VkExtent2D e);
+std::ostream& operator << (std::ostream& os, VkExtent3D e);
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.cpp b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.cpp
new file mode 100644
index 00000000..01811000
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.cpp
@@ -0,0 +1,493 @@
+#include "vulkan_presenter.h"
+
+#include "../dxvk/dxvk_format.h"
+#include "../wsi/wsi_presenter.h"
+
+namespace dxvk::vk {
+
+ Presenter::Presenter(
+ HWND window,
+ const Rc<InstanceFn>& vki,
+ const Rc<DeviceFn>& vkd,
+ PresenterDevice device,
+ const PresenterDesc& desc)
+ : m_vki(vki), m_vkd(vkd), m_device(device), m_window(window) {
+#ifndef DXVK_NATIVE
+ // As of Wine 5.9, winevulkan provides this extension, but does
+ // not filter the pNext chain for VkSwapchainCreateInfoKHR properly
+ // before passing it to the Linux sude, which breaks RenderDoc.
+ if (m_device.features.fullScreenExclusive && ::GetModuleHandle("winevulkan.dll")) {
+ Logger::warn("winevulkan detected, disabling exclusive fullscreen support");
+ m_device.features.fullScreenExclusive = false;
+ }
+#endif
+
+ if (createSurface() != VK_SUCCESS)
+ throw DxvkError("Failed to create surface");
+
+ if (recreateSwapChain(desc) != VK_SUCCESS)
+ throw DxvkError("Failed to create swap chain");
+ }
+
+
+ Presenter::~Presenter() {
+ destroySwapchain();
+ destroySurface();
+ }
+
+
+ PresenterInfo Presenter::info() const {
+ return m_info;
+ }
+
+
+ PresenterImage Presenter::getImage(uint32_t index) const {
+ return m_images.at(index);
+ }
+
+
+ VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) {
+ sync = m_semaphores.at(m_frameIndex);
+
+ // Don't acquire more than one image at a time
+ if (m_acquireStatus == VK_NOT_READY) {
+ m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(),
+ m_swapchain, std::numeric_limits<uint64_t>::max(),
+ sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
+ }
+
+ if (m_acquireStatus != VK_SUCCESS && m_acquireStatus != VK_SUBOPTIMAL_KHR)
+ return m_acquireStatus;
+
+ index = m_imageIndex;
+ return m_acquireStatus;
+ }
+
+
+ VkResult Presenter::presentImage() {
+ PresenterSync sync = m_semaphores.at(m_frameIndex);
+
+ VkPresentInfoKHR info;
+ info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ info.pNext = nullptr;
+ info.waitSemaphoreCount = 1;
+ info.pWaitSemaphores = &sync.present;
+ info.swapchainCount = 1;
+ info.pSwapchains = &m_swapchain;
+ info.pImageIndices = &m_imageIndex;
+ info.pResults = nullptr;
+
+ VkResult status = m_vkd->vkQueuePresentKHR(m_device.queue, &info);
+
+ if (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR)
+ return status;
+
+ // Try to acquire next image already, in order to hide
+ // potential delays from the application thread.
+ m_frameIndex += 1;
+ m_frameIndex %= m_semaphores.size();
+
+ sync = m_semaphores.at(m_frameIndex);
+
+ m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(),
+ m_swapchain, std::numeric_limits<uint64_t>::max(),
+ sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
+
+ bool vsync = m_info.presentMode == VK_PRESENT_MODE_FIFO_KHR
+ || m_info.presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR;
+
+ m_fpsLimiter.delay(vsync);
+ return status;
+ }
+
+
+ VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) {
+ if (m_swapchain)
+ destroySwapchain();
+
+ // Query surface capabilities. Some properties might
+ // have changed, including the size limits and supported
+ // present modes, so we'll just query everything again.
+ VkSurfaceCapabilitiesKHR caps;
+ std::vector<VkSurfaceFormatKHR> formats;
+ std::vector<VkPresentModeKHR> modes;
+
+ VkResult status;
+
+ if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ m_device.adapter, m_surface, &caps)) != VK_SUCCESS) {
+ if (status == VK_ERROR_SURFACE_LOST_KHR) {
+ // Recreate the surface and try again.
+ if (m_surface)
+ destroySurface();
+ if ((status = createSurface()) != VK_SUCCESS)
+ return status;
+ status = m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ m_device.adapter, m_surface, &caps);
+ }
+ if (status != VK_SUCCESS)
+ return status;
+ }
+
+ if ((status = getSupportedFormats(formats, desc)) != VK_SUCCESS)
+ return status;
+
+ if ((status = getSupportedPresentModes(modes, desc)) != VK_SUCCESS)
+ return status;
+
+ // Select actual swap chain properties and create swap chain
+ m_info.format = pickFormat(formats.size(), formats.data(), desc.numFormats, desc.formats);
+ m_info.presentMode = pickPresentMode(modes.size(), modes.data(), desc.numPresentModes, desc.presentModes);
+ m_info.imageExtent = pickImageExtent(caps, desc.imageExtent);
+ m_info.imageCount = pickImageCount(caps, m_info.presentMode, desc.imageCount);
+
+ if (!m_info.imageExtent.width || !m_info.imageExtent.height) {
+ m_info.imageCount = 0;
+ m_info.format = { VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
+ return VK_SUCCESS;
+ }
+
+ VkSurfaceFullScreenExclusiveInfoEXT fullScreenInfo;
+ fullScreenInfo.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT;
+ fullScreenInfo.pNext = nullptr;
+ fullScreenInfo.fullScreenExclusive = desc.fullScreenExclusive;
+
+ VkSwapchainCreateInfoKHR swapInfo;
+ swapInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swapInfo.pNext = nullptr;
+ swapInfo.flags = 0;
+ swapInfo.surface = m_surface;
+ swapInfo.minImageCount = m_info.imageCount;
+ swapInfo.imageFormat = m_info.format.format;
+ swapInfo.imageColorSpace = m_info.format.colorSpace;
+ swapInfo.imageExtent = m_info.imageExtent;
+ swapInfo.imageArrayLayers = 1;
+ swapInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ swapInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapInfo.queueFamilyIndexCount = 0;
+ swapInfo.pQueueFamilyIndices = nullptr;
+ swapInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ swapInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ swapInfo.presentMode = m_info.presentMode;
+ swapInfo.clipped = VK_TRUE;
+ swapInfo.oldSwapchain = VK_NULL_HANDLE;
+
+ if (m_device.features.fullScreenExclusive)
+ swapInfo.pNext = &fullScreenInfo;
+
+ Logger::info(str::format(
+ "Presenter: Actual swap chain properties:"
+ "\n Format: ", m_info.format.format,
+ "\n Present mode: ", m_info.presentMode,
+ "\n Buffer size: ", m_info.imageExtent.width, "x", m_info.imageExtent.height,
+ "\n Image count: ", m_info.imageCount,
+ "\n Exclusive FS: ", desc.fullScreenExclusive));
+
+ if ((status = m_vkd->vkCreateSwapchainKHR(m_vkd->device(),
+ &swapInfo, nullptr, &m_swapchain)) != VK_SUCCESS)
+ return status;
+
+ // Acquire images and create views
+ std::vector<VkImage> images;
+
+ if ((status = getSwapImages(images)) != VK_SUCCESS)
+ return status;
+
+ // Update actual image count
+ m_info.imageCount = images.size();
+ m_images.resize(m_info.imageCount);
+
+ for (uint32_t i = 0; i < m_info.imageCount; i++) {
+ m_images[i].image = images[i];
+
+ VkImageViewCreateInfo viewInfo;
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.pNext = nullptr;
+ viewInfo.flags = 0;
+ viewInfo.image = images[i];
+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = m_info.format.format;
+ viewInfo.components = VkComponentMapping {
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
+ viewInfo.subresourceRange = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, 1, 0, 1 };
+
+ if ((status = m_vkd->vkCreateImageView(m_vkd->device(),
+ &viewInfo, nullptr, &m_images[i].view)) != VK_SUCCESS)
+ return status;
+ }
+
+ // Create one set of semaphores per swap image
+ m_semaphores.resize(m_info.imageCount);
+
+ for (uint32_t i = 0; i < m_semaphores.size(); i++) {
+ VkSemaphoreCreateInfo semInfo;
+ semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semInfo.pNext = nullptr;
+ semInfo.flags = 0;
+
+ if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
+ &semInfo, nullptr, &m_semaphores[i].acquire)) != VK_SUCCESS)
+ return status;
+
+ if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
+ &semInfo, nullptr, &m_semaphores[i].present)) != VK_SUCCESS)
+ return status;
+ }
+
+ // Invalidate indices
+ m_imageIndex = 0;
+ m_frameIndex = 0;
+ m_acquireStatus = VK_NOT_READY;
+ return VK_SUCCESS;
+ }
+
+
+ void Presenter::setFrameRateLimit(double frameRate) {
+ m_fpsLimiter.setTargetFrameRate(frameRate);
+ }
+
+
+ void Presenter::setFrameRateLimiterRefreshRate(double refreshRate) {
+ m_fpsLimiter.setDisplayRefreshRate(refreshRate);
+ }
+
+
+ VkResult Presenter::getSupportedFormats(std::vector<VkSurfaceFormatKHR>& formats, const PresenterDesc& desc) {
+ uint32_t numFormats = 0;
+
+ VkSurfaceFullScreenExclusiveInfoEXT fullScreenInfo;
+ fullScreenInfo.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT;
+ fullScreenInfo.pNext = nullptr;
+ fullScreenInfo.fullScreenExclusive = desc.fullScreenExclusive;
+
+ VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo;
+ surfaceInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
+ surfaceInfo.pNext = &fullScreenInfo;
+ surfaceInfo.surface = m_surface;
+
+ VkResult status;
+
+ if (m_device.features.fullScreenExclusive) {
+ status = m_vki->vkGetPhysicalDeviceSurfaceFormats2KHR(
+ m_device.adapter, &surfaceInfo, &numFormats, nullptr);
+ } else {
+ status = m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
+ m_device.adapter, m_surface, &numFormats, nullptr);
+ }
+
+ if (status != VK_SUCCESS)
+ return status;
+
+ formats.resize(numFormats);
+
+ if (m_device.features.fullScreenExclusive) {
+ std::vector<VkSurfaceFormat2KHR> tmpFormats(numFormats,
+ { VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR, nullptr, VkSurfaceFormatKHR() });
+
+ status = m_vki->vkGetPhysicalDeviceSurfaceFormats2KHR(
+ m_device.adapter, &surfaceInfo, &numFormats, tmpFormats.data());
+
+ for (uint32_t i = 0; i < numFormats; i++)
+ formats[i] = tmpFormats[i].surfaceFormat;
+ } else {
+ status = m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
+ m_device.adapter, m_surface, &numFormats, formats.data());
+ }
+
+ return status;
+ }
+
+
+ VkResult Presenter::getSupportedPresentModes(std::vector<VkPresentModeKHR>& modes, const PresenterDesc& desc) {
+ uint32_t numModes = 0;
+
+ VkSurfaceFullScreenExclusiveInfoEXT fullScreenInfo;
+ fullScreenInfo.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT;
+ fullScreenInfo.pNext = nullptr;
+ fullScreenInfo.fullScreenExclusive = desc.fullScreenExclusive;
+
+ VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo;
+ surfaceInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
+ surfaceInfo.pNext = &fullScreenInfo;
+ surfaceInfo.surface = m_surface;
+
+ VkResult status;
+
+ if (m_device.features.fullScreenExclusive) {
+ status = m_vki->vkGetPhysicalDeviceSurfacePresentModes2EXT(
+ m_device.adapter, &surfaceInfo, &numModes, nullptr);
+ } else {
+ status = m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
+ m_device.adapter, m_surface, &numModes, nullptr);
+ }
+
+ if (status != VK_SUCCESS)
+ return status;
+
+ modes.resize(numModes);
+
+ if (m_device.features.fullScreenExclusive) {
+ status = m_vki->vkGetPhysicalDeviceSurfacePresentModes2EXT(
+ m_device.adapter, &surfaceInfo, &numModes, modes.data());
+ } else {
+ status = m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
+ m_device.adapter, m_surface, &numModes, modes.data());
+ }
+
+ return status;
+ }
+
+
+ VkResult Presenter::getSwapImages(std::vector<VkImage>& images) {
+ uint32_t imageCount = 0;
+
+ VkResult status = m_vkd->vkGetSwapchainImagesKHR(
+ m_vkd->device(), m_swapchain, &imageCount, nullptr);
+
+ if (status != VK_SUCCESS)
+ return status;
+
+ images.resize(imageCount);
+
+ return m_vkd->vkGetSwapchainImagesKHR(
+ m_vkd->device(), m_swapchain, &imageCount, images.data());
+ }
+
+
+ VkSurfaceFormatKHR Presenter::pickFormat(
+ uint32_t numSupported,
+ const VkSurfaceFormatKHR* pSupported,
+ uint32_t numDesired,
+ const VkSurfaceFormatKHR* pDesired) {
+ if (numDesired > 0) {
+ // If the implementation allows us to freely choose
+ // the format, we'll just use the preferred format.
+ if (numSupported == 1 && pSupported[0].format == VK_FORMAT_UNDEFINED)
+ return pDesired[0];
+
+ // If the preferred format is explicitly listed in
+ // the array of supported surface formats, use it
+ for (uint32_t i = 0; i < numDesired; i++) {
+ for (uint32_t j = 0; j < numSupported; j++) {
+ if (pSupported[j].format == pDesired[i].format
+ && pSupported[j].colorSpace == pDesired[i].colorSpace)
+ return pSupported[j];
+ }
+ }
+
+ // If that didn't work, we'll fall back to a format
+ // which has similar properties to the preferred one
+ DxvkFormatFlags prefFlags = imageFormatInfo(pDesired[0].format)->flags;
+
+ for (uint32_t j = 0; j < numSupported; j++) {
+ auto currFlags = imageFormatInfo(pSupported[j].format)->flags;
+
+ if ((currFlags & DxvkFormatFlag::ColorSpaceSrgb)
+ == (prefFlags & DxvkFormatFlag::ColorSpaceSrgb))
+ return pSupported[j];
+ }
+ }
+
+ // Otherwise, fall back to the first supported format
+ return pSupported[0];
+ }
+
+
+ VkPresentModeKHR Presenter::pickPresentMode(
+ uint32_t numSupported,
+ const VkPresentModeKHR* pSupported,
+ uint32_t numDesired,
+ const VkPresentModeKHR* pDesired) {
+ // Just pick the first desired and supported mode
+ for (uint32_t i = 0; i < numDesired; i++) {
+ for (uint32_t j = 0; j < numSupported; j++) {
+ if (pSupported[j] == pDesired[i])
+ return pSupported[j];
+ }
+ }
+
+ // Guaranteed to be available
+ return VK_PRESENT_MODE_FIFO_KHR;
+ }
+
+
+ VkExtent2D Presenter::pickImageExtent(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkExtent2D desired) {
+ if (caps.currentExtent.width != std::numeric_limits<uint32_t>::max())
+ return caps.currentExtent;
+
+ VkExtent2D actual;
+ actual.width = clamp(desired.width, caps.minImageExtent.width, caps.maxImageExtent.width);
+ actual.height = clamp(desired.height, caps.minImageExtent.height, caps.maxImageExtent.height);
+ return actual;
+ }
+
+
+ uint32_t Presenter::pickImageCount(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkPresentModeKHR presentMode,
+ uint32_t desired) {
+ uint32_t count = caps.minImageCount;
+
+ if (presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR)
+ count = caps.minImageCount + 1;
+
+ if (count < desired)
+ count = desired;
+
+ if (count > caps.maxImageCount && caps.maxImageCount != 0)
+ count = caps.maxImageCount;
+
+ return count;
+ }
+
+
+ VkResult Presenter::createSurface() {
+ VkResult status = wsi::createSurface(m_window, m_vki, &m_surface);
+
+ if (status != VK_SUCCESS)
+ return status;
+
+ VkBool32 supportStatus = VK_FALSE;
+
+ if ((status = m_vki->vkGetPhysicalDeviceSurfaceSupportKHR(m_device.adapter,
+ m_device.queueFamily, m_surface, &supportStatus)) != VK_SUCCESS)
+ return status;
+
+ if (!supportStatus) {
+ m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr);
+ return VK_ERROR_OUT_OF_HOST_MEMORY; // just abuse this
+ }
+
+ return VK_SUCCESS;
+ }
+
+
+ void Presenter::destroySwapchain() {
+ for (const auto& img : m_images)
+ m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr);
+
+ for (const auto& sem : m_semaphores) {
+ m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr);
+ m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr);
+ }
+
+ m_vkd->vkDestroySwapchainKHR(m_vkd->device(), m_swapchain, nullptr);
+
+ m_images.clear();
+ m_semaphores.clear();
+
+ m_swapchain = VK_NULL_HANDLE;
+ }
+
+
+ void Presenter::destroySurface() {
+ m_vki->vkDestroySurfaceKHR(m_vki->instance(), m_surface, nullptr);
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.h b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.h
new file mode 100644
index 00000000..40562f6e
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter.h
@@ -0,0 +1,248 @@
+#pragma once
+
+#include <vector>
+
+#include "../util/log/log.h"
+
+#include "../util/util_error.h"
+#include "../util/util_fps_limiter.h"
+#include "../util/util_math.h"
+#include "../util/util_string.h"
+
+#include "vulkan_loader.h"
+
+namespace dxvk::vk {
+
+ /**
+ * \brief Presenter description
+ *
+ * Contains the desired properties of
+ * the swap chain. This is passed as
+ * an input during swap chain creation.
+ */
+ struct PresenterDesc {
+ VkExtent2D imageExtent;
+ uint32_t imageCount;
+ uint32_t numFormats;
+ VkSurfaceFormatKHR formats[4];
+ uint32_t numPresentModes;
+ VkPresentModeKHR presentModes[4];
+ VkFullScreenExclusiveEXT fullScreenExclusive;
+ };
+
+ /**
+ * \brief Presenter properties
+ *
+ * Contains the actual properties
+ * of the underlying swap chain.
+ */
+ struct PresenterInfo {
+ VkSurfaceFormatKHR format;
+ VkPresentModeKHR presentMode;
+ VkExtent2D imageExtent;
+ uint32_t imageCount;
+ };
+
+ /**
+ * \brief Presenter features
+ */
+ struct PresenterFeatures {
+ bool fullScreenExclusive : 1;
+ };
+
+ /**
+ * \brief Adapter and queue
+ */
+ struct PresenterDevice {
+ uint32_t queueFamily = 0;
+ VkQueue queue = VK_NULL_HANDLE;
+ VkPhysicalDevice adapter = VK_NULL_HANDLE;
+ PresenterFeatures features = { };
+ };
+
+ /**
+ * \brief Swap image and view
+ */
+ struct PresenterImage {
+ VkImage image = VK_NULL_HANDLE;
+ VkImageView view = VK_NULL_HANDLE;
+ };
+
+ /**
+ * \brief Presenter semaphores
+ *
+ * Pair of semaphores used for acquire and present
+ * operations, including the command buffers used
+ * in between. Also stores a fence to signal on
+ * image acquisition.
+ */
+ struct PresenterSync {
+ VkSemaphore acquire;
+ VkSemaphore present;
+ };
+
+ /**
+ * \brief Vulkan presenter
+ *
+ * Provides abstractions for some of the
+ * more complicated aspects of Vulkan's
+ * window system integration.
+ */
+ class Presenter : public RcObject {
+
+ public:
+
+ Presenter(
+ HWND window,
+ const Rc<InstanceFn>& vki,
+ const Rc<DeviceFn>& vkd,
+ PresenterDevice device,
+ const PresenterDesc& desc);
+
+ ~Presenter();
+
+ /**
+ * \brief Actual presenter info
+ * \returns Swap chain properties
+ */
+ PresenterInfo info() const;
+
+ /**
+ * \brief Retrieves image by index
+ *
+ * Can be used to create per-image objects.
+ * \param [in] index Image index
+ * \returns Image handle
+ */
+ PresenterImage getImage(
+ uint32_t index) const;
+
+ /**
+ * \brief Acquires next image
+ *
+ * Potentially blocks the calling thread.
+ * If this returns an error, the swap chain
+ * must be recreated and a new image must
+ * be acquired before proceeding.
+ * \param [out] sync Synchronization semaphores
+ * \param [out] index Acquired image index
+ * \returns Status of the operation
+ */
+ VkResult acquireNextImage(
+ PresenterSync& sync,
+ uint32_t& index);
+
+ /**
+ * \brief Presents current image
+ *
+ * Presents the current image. If this returns
+ * an error, the swap chain must be recreated,
+ * but do not present before acquiring an image.
+ * \returns Status of the operation
+ */
+ VkResult presentImage();
+
+ /**
+ * \brief Changes presenter properties
+ *
+ * Recreates the swap chain immediately. Note that
+ * no swap chain resources must be in use by the
+ * GPU at the time this is called.
+ * \param [in] desc Swap chain description
+ */
+ VkResult recreateSwapChain(
+ const PresenterDesc& desc);
+
+ /**
+ * \brief Changes maximum frame rate
+ *
+ * \param [in] frameRate Target frame rate. Set
+ * to 0 in order to disable the limiter.
+ */
+ void setFrameRateLimit(double frameRate);
+
+ /**
+ * \brief Notifies frame rate limiter about the display refresh rate
+ *
+ * Used to dynamically disable the frame rate limiter in case
+ * vertical synchronization is used and the target frame rate
+ * roughly equals the display's refresh rate.
+ * \param [in] refresnRate Current refresh rate
+ */
+ void setFrameRateLimiterRefreshRate(double refreshRate);
+
+ /**
+ * \brief Checks whether a Vulkan swap chain exists
+ *
+ * On Windows, there are situations where we cannot create
+ * a swap chain as the surface size can reach zero, and no
+ * presentation can be performed.
+ * \returns \c true if the presenter has a swap chain.
+ */
+ bool hasSwapChain() const {
+ return m_swapchain;
+ }
+
+ private:
+
+ Rc<InstanceFn> m_vki;
+ Rc<DeviceFn> m_vkd;
+
+ PresenterDevice m_device;
+ PresenterInfo m_info;
+
+ HWND m_window = nullptr;
+ VkSurfaceKHR m_surface = VK_NULL_HANDLE;
+ VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
+
+ std::vector<PresenterImage> m_images;
+ std::vector<PresenterSync> m_semaphores;
+
+ uint32_t m_imageIndex = 0;
+ uint32_t m_frameIndex = 0;
+
+ VkResult m_acquireStatus = VK_NOT_READY;
+
+ FpsLimiter m_fpsLimiter;
+
+ VkResult getSupportedFormats(
+ std::vector<VkSurfaceFormatKHR>& formats,
+ const PresenterDesc& desc);
+
+ VkResult getSupportedPresentModes(
+ std::vector<VkPresentModeKHR>& modes,
+ const PresenterDesc& desc);
+
+ VkResult getSwapImages(
+ std::vector<VkImage>& images);
+
+ VkSurfaceFormatKHR pickFormat(
+ uint32_t numSupported,
+ const VkSurfaceFormatKHR* pSupported,
+ uint32_t numDesired,
+ const VkSurfaceFormatKHR* pDesired);
+
+ VkPresentModeKHR pickPresentMode(
+ uint32_t numSupported,
+ const VkPresentModeKHR* pSupported,
+ uint32_t numDesired,
+ const VkPresentModeKHR* pDesired);
+
+ VkExtent2D pickImageExtent(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkExtent2D desired);
+
+ uint32_t pickImageCount(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkPresentModeKHR presentMode,
+ uint32_t desired);
+
+ VkResult createSurface();
+
+ void destroySwapchain();
+
+ void destroySurface();
+
+ };
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter_headless.cpp b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter_headless.cpp
new file mode 100644
index 00000000..998e13e7
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_presenter_headless.cpp
@@ -0,0 +1,177 @@
+#include "vulkan_presenter.h"
+
+#include "../dxvk/dxvk_format.h"
+#include "../wsi/wsi_presenter.h"
+
+namespace dxvk::vk {
+
+ Presenter::Presenter(
+ HWND window,
+ const Rc<InstanceFn>& vki,
+ const Rc<DeviceFn>& vkd,
+ PresenterDevice device,
+ const PresenterDesc& desc)
+ : m_vki(vki), m_vkd(vkd), m_device(device), m_window(window) {
+ }
+
+
+ Presenter::~Presenter() {
+ }
+
+
+ PresenterInfo Presenter::info() const {
+ return m_info;
+ }
+
+
+ PresenterImage Presenter::getImage(uint32_t index) const {
+ return m_images.at(index);
+ }
+
+
+ VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) {
+ return VK_SUCCESS;
+ }
+
+
+ VkResult Presenter::presentImage() {
+ return VK_SUCCESS;
+ }
+
+
+ VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) {
+ return VK_SUCCESS;
+ }
+
+
+ void Presenter::setFrameRateLimit(double frameRate) {
+ m_fpsLimiter.setTargetFrameRate(frameRate);
+ }
+
+
+ void Presenter::setFrameRateLimiterRefreshRate(double refreshRate) {
+ m_fpsLimiter.setDisplayRefreshRate(refreshRate);
+ }
+
+
+ VkResult Presenter::getSupportedFormats(std::vector<VkSurfaceFormatKHR>& formats, const PresenterDesc& desc) {
+ return VK_SUCCESS;
+ }
+
+
+ VkResult Presenter::getSupportedPresentModes(std::vector<VkPresentModeKHR>& modes, const PresenterDesc& desc) {
+ return VK_SUCCESS;
+ }
+
+
+ VkResult Presenter::getSwapImages(std::vector<VkImage>& images) {
+ return VK_SUCCESS;
+ }
+
+
+ VkSurfaceFormatKHR Presenter::pickFormat(
+ uint32_t numSupported,
+ const VkSurfaceFormatKHR* pSupported,
+ uint32_t numDesired,
+ const VkSurfaceFormatKHR* pDesired) {
+ if (numDesired > 0) {
+ // If the implementation allows us to freely choose
+ // the format, we'll just use the preferred format.
+ if (numSupported == 1 && pSupported[0].format == VK_FORMAT_UNDEFINED)
+ return pDesired[0];
+
+ // If the preferred format is explicitly listed in
+ // the array of supported surface formats, use it
+ for (uint32_t i = 0; i < numDesired; i++) {
+ for (uint32_t j = 0; j < numSupported; j++) {
+ if (pSupported[j].format == pDesired[i].format
+ && pSupported[j].colorSpace == pDesired[i].colorSpace)
+ return pSupported[j];
+ }
+ }
+
+ // If that didn't work, we'll fall back to a format
+ // which has similar properties to the preferred one
+ DxvkFormatFlags prefFlags = imageFormatInfo(pDesired[0].format)->flags;
+
+ for (uint32_t j = 0; j < numSupported; j++) {
+ auto currFlags = imageFormatInfo(pSupported[j].format)->flags;
+
+ if ((currFlags & DxvkFormatFlag::ColorSpaceSrgb)
+ == (prefFlags & DxvkFormatFlag::ColorSpaceSrgb))
+ return pSupported[j];
+ }
+ }
+
+ // Otherwise, fall back to the first supported format
+ return pSupported[0];
+ }
+
+
+ VkPresentModeKHR Presenter::pickPresentMode(
+ uint32_t numSupported,
+ const VkPresentModeKHR* pSupported,
+ uint32_t numDesired,
+ const VkPresentModeKHR* pDesired) {
+ // Just pick the first desired and supported mode
+ for (uint32_t i = 0; i < numDesired; i++) {
+ for (uint32_t j = 0; j < numSupported; j++) {
+ if (pSupported[j] == pDesired[i])
+ return pSupported[j];
+ }
+ }
+
+ // Guaranteed to be available
+ return VK_PRESENT_MODE_FIFO_KHR;
+ }
+
+
+ VkExtent2D Presenter::pickImageExtent(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkExtent2D desired) {
+ if (caps.currentExtent.width != std::numeric_limits<uint32_t>::max())
+ return caps.currentExtent;
+
+ VkExtent2D actual;
+ actual.width = clamp(desired.width, caps.minImageExtent.width, caps.maxImageExtent.width);
+ actual.height = clamp(desired.height, caps.minImageExtent.height, caps.maxImageExtent.height);
+ return actual;
+ }
+
+
+ uint32_t Presenter::pickImageCount(
+ const VkSurfaceCapabilitiesKHR& caps,
+ VkPresentModeKHR presentMode,
+ uint32_t desired) {
+ uint32_t count = caps.minImageCount;
+
+ if (presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR)
+ count = caps.minImageCount + 1;
+
+ if (count < desired)
+ count = desired;
+
+ if (count > caps.maxImageCount && caps.maxImageCount != 0)
+ count = caps.maxImageCount;
+
+ return count;
+ }
+
+
+ VkResult Presenter::createSurface() {
+ return VK_SUCCESS;
+ }
+
+
+ void Presenter::destroySwapchain() {
+ m_images.clear();
+ m_semaphores.clear();
+
+ m_swapchain = VK_NULL_HANDLE;
+ }
+
+
+ void Presenter::destroySurface() {
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_util.h b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_util.h
new file mode 100644
index 00000000..38e0217c
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/vulkan/vulkan_util.h
@@ -0,0 +1,247 @@
+#pragma once
+
+#include <utility>
+
+#include "vulkan_loader.h"
+
+namespace dxvk::vk {
+
+ inline VkImageSubresourceRange makeSubresourceRange(
+ const VkImageSubresourceLayers& layers) {
+ VkImageSubresourceRange range;
+ range.aspectMask = layers.aspectMask;
+ range.baseMipLevel = layers.mipLevel;
+ range.levelCount = 1;
+ range.baseArrayLayer = layers.baseArrayLayer;
+ range.layerCount = layers.layerCount;
+ return range;
+ }
+
+ inline VkImageSubresourceRange makeSubresourceRange(
+ const VkImageSubresource& subres) {
+ VkImageSubresourceRange range;
+ range.aspectMask = subres.aspectMask;
+ range.baseMipLevel = subres.mipLevel;
+ range.levelCount = 1;
+ range.baseArrayLayer = subres.arrayLayer;
+ range.layerCount = 1;
+ return range;
+ }
+
+ inline VkImageSubresourceLayers makeSubresourceLayers(
+ const VkImageSubresource& subres) {
+ VkImageSubresourceLayers layers;
+ layers.aspectMask = subres.aspectMask;
+ layers.mipLevel = subres.mipLevel;
+ layers.baseArrayLayer = subres.arrayLayer;
+ layers.layerCount = 1;
+ return layers;
+ }
+
+ inline VkImageSubresourceLayers pickSubresourceLayers(
+ const VkImageSubresourceRange& range,
+ uint32_t level) {
+ VkImageSubresourceLayers layers;
+ layers.aspectMask = range.aspectMask;
+ layers.mipLevel = range.baseMipLevel + level;
+ layers.baseArrayLayer = range.baseArrayLayer;
+ layers.layerCount = range.layerCount;
+ return layers;
+ }
+
+ inline VkImageSubresource pickSubresource(
+ const VkImageSubresourceLayers& range,
+ uint32_t layer) {
+ VkImageSubresource subres;
+ subres.aspectMask = range.aspectMask;
+ subres.mipLevel = range.mipLevel;
+ subres.arrayLayer = range.baseArrayLayer + layer;
+ return subres;
+ }
+
+ inline VkImageSubresource pickSubresource(
+ const VkImageSubresourceRange& range,
+ uint32_t level,
+ uint32_t layer) {
+ VkImageSubresource subres;
+ subres.aspectMask = range.aspectMask;
+ subres.mipLevel = range.baseMipLevel + level;
+ subres.arrayLayer = range.baseArrayLayer + layer;
+ return subres;
+ }
+
+ inline bool checkSubresourceRangeOverlap(
+ const VkImageSubresourceRange& a,
+ const VkImageSubresourceRange& b) {
+ return a.baseMipLevel < b.baseMipLevel + b.levelCount
+ && a.baseMipLevel + a.levelCount > b.baseMipLevel
+ && a.baseArrayLayer < b.baseArrayLayer + b.layerCount
+ && a.baseArrayLayer + a.layerCount > b.baseArrayLayer;
+ }
+
+ inline bool checkSubresourceRangeSuperset(
+ const VkImageSubresourceRange& a,
+ const VkImageSubresourceRange& b) {
+ return a.baseMipLevel <= b.baseMipLevel
+ && a.baseMipLevel + a.levelCount >= b.baseMipLevel + b.levelCount
+ && a.baseArrayLayer <= b.baseArrayLayer
+ && a.baseArrayLayer + a.layerCount >= b.baseArrayLayer + b.layerCount;
+ }
+
+ inline VkImageAspectFlags getWritableAspectsForLayout(VkImageLayout layout) {
+ switch (layout) {
+ case VK_IMAGE_LAYOUT_GENERAL:
+ return VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ return VK_IMAGE_ASPECT_COLOR_BIT;
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+ return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
+ return VK_IMAGE_ASPECT_DEPTH_BIT;
+ case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
+ return VK_IMAGE_ASPECT_STENCIL_BIT;
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+ return 0;
+ default:
+ Logger::err(str::format("Unhandled image layout ", layout));
+ return 0;
+ }
+ }
+
+ inline uint32_t getPlaneCount(VkImageAspectFlags aspects) {
+ // Use a 16-bit integer as a lookup table. This works because
+ // plane aspects use consecutive bits in the image aspect enum.
+ const uint32_t shift = (aspects / VK_IMAGE_ASPECT_PLANE_0_BIT) * 2;
+ const uint32_t counts = 0xffa5;
+ return (counts >> shift) & 0x3;
+ }
+
+ inline uint32_t getPlaneIndex(VkImageAspectFlags aspect) {
+ // Works for up to PLANE_2_BIT due to enum poperties
+ return aspect / VK_IMAGE_ASPECT_PLANE_1_BIT;
+ }
+
+ inline VkImageAspectFlagBits getPlaneAspect(uint32_t plane) {
+ return VkImageAspectFlagBits(VK_IMAGE_ASPECT_PLANE_0_BIT << plane);
+ }
+
+ inline VkImageAspectFlags getNextAspect(VkImageAspectFlags& mask) {
+ if (likely(mask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
+ // Depth-stencil isn't considered multi-planar
+ return std::exchange(mask, VkImageAspectFlags(0));
+ } else {
+ VkImageAspectFlags result = mask & -mask;
+ mask &= ~result;
+ return result;
+ }
+ }
+
+ template<typename T>
+ struct ChainStruct {
+ VkStructureType sType;
+ T* pNext;
+ };
+
+ template<typename T>
+ void removeStructFromPNextChain(T** ppNext, VkStructureType sType) {
+ while (*ppNext) {
+ auto pStruct = reinterpret_cast<ChainStruct<T>*>(*ppNext);
+
+ if (pStruct->sType == sType) {
+ *ppNext = pStruct->pNext;
+ return;
+ }
+
+ ppNext = &pStruct->pNext;
+ }
+ }
+
+}
+
+
+inline bool operator == (
+ const VkImageSubresourceRange& a,
+ const VkImageSubresourceRange& b) {
+ return a.aspectMask == b.aspectMask
+ && a.baseMipLevel == b.baseMipLevel
+ && a.levelCount == b.levelCount
+ && a.baseArrayLayer == b.baseArrayLayer
+ && a.layerCount == b.layerCount;
+}
+
+
+inline bool operator != (
+ const VkImageSubresourceRange& a,
+ const VkImageSubresourceRange& b) {
+ return !operator == (a, b);
+}
+
+
+inline bool operator == (
+ const VkImageSubresourceLayers& a,
+ const VkImageSubresourceLayers& b) {
+ return a.aspectMask == b.aspectMask
+ && a.mipLevel == b.mipLevel
+ && a.baseArrayLayer == b.baseArrayLayer
+ && a.layerCount == b.layerCount;
+}
+
+
+inline bool operator != (
+ const VkImageSubresourceLayers& a,
+ const VkImageSubresourceLayers& b) {
+ return !operator == (a, b);
+}
+
+
+inline bool operator == (VkExtent3D a, VkExtent3D b) {
+ return a.width == b.width
+ && a.height == b.height
+ && a.depth == b.depth;
+}
+
+
+inline bool operator != (VkExtent3D a, VkExtent3D b) {
+ return a.width != b.width
+ || a.height != b.height
+ || a.depth != b.depth;
+}
+
+
+inline bool operator == (VkExtent2D a, VkExtent2D b) {
+ return a.width == b.width
+ && a.height == b.height;
+}
+
+
+inline bool operator != (VkExtent2D a, VkExtent2D b) {
+ return a.width != b.width
+ || a.height != b.height;
+}
+
+
+inline bool operator == (VkOffset3D a, VkOffset3D b) {
+ return a.x == b.x
+ && a.y == b.y
+ && a.z == b.z;
+}
+
+
+inline bool operator != (VkOffset3D a, VkOffset3D b) {
+ return a.x != b.x
+ || a.y != b.y
+ || a.z != b.z;
+}
+
+
+inline bool operator == (VkOffset2D a, VkOffset2D b) {
+ return a.x == b.x
+ && a.y == b.y;
+}
+
+
+inline bool operator != (VkOffset2D a, VkOffset2D b) {
+ return a.x != b.x
+ || a.y != b.y;
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_helpers_headless.h b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_helpers_headless.h
new file mode 100644
index 00000000..fc6cc9a4
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_helpers_headless.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "../wsi_monitor.h"
+
+namespace dxvk {
+
+ inline bool isDisplayValid(int32_t displayId) {
+ return displayId == 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_mode_headless.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_mode_headless.cpp
new file mode 100644
index 00000000..645475d3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_mode_headless.cpp
@@ -0,0 +1,62 @@
+#include "../wsi_mode.h"
+
+#include "wsi_helpers_headless.h"
+
+#include <wsi/native_wsi.h>
+
+#include "../../util/util_string.h"
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ static inline void setMode(WsiMode* pMode) {
+ pMode->width = 1024;
+ pMode->height = 1024;
+ pMode->refreshRate = WsiRational{60 * 1000, 1000 };
+ // BPP should always be a power of two
+ // to match Windows behaviour of including padding.
+ pMode->bitsPerPixel = 8;
+ pMode->interlaced = false;
+ }
+
+
+ bool getDisplayMode(
+ HMONITOR hMonitor,
+ uint32_t ModeNumber,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ setMode(pMode);
+ return true;
+ }
+
+
+ bool getCurrentDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ setMode(pMode);
+ return true;
+ }
+
+
+ bool getDesktopDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ setMode(pMode);
+ return true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_monitor_headless.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_monitor_headless.cpp
new file mode 100644
index 00000000..19186594
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_monitor_headless.cpp
@@ -0,0 +1,60 @@
+#include "../wsi_monitor.h"
+
+#include "wsi_helpers_headless.h"
+
+#include <windows.h>
+#include <wsi/native_wsi.h>
+
+#include <string>
+#include <sstream>
+
+namespace dxvk::wsi {
+
+ HMONITOR getDefaultMonitor() {
+ return enumMonitors(0);
+ }
+
+
+ HMONITOR enumMonitors(uint32_t index) {
+ return isDisplayValid(int32_t(index))
+ ? toHmonitor(index)
+ : nullptr;
+ }
+
+ bool getDisplayName(
+ HMONITOR hMonitor,
+ WCHAR (&Name)[32]) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ std::wstringstream nameStream;
+ nameStream << LR"(\\.\DISPLAY)" << (displayId + 1);
+
+ std::wstring name = nameStream.str();
+
+ std::memset(Name, 0, sizeof(Name));
+ name.copy(Name, name.length(), 0);
+
+ return true;
+ }
+
+
+ bool getDesktopCoordinates(
+ HMONITOR hMonitor,
+ RECT* pRect) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ pRect->left = 0;
+ pRect->top = 0;
+ pRect->right = 1024;
+ pRect->bottom = 1024;
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_presenter_headless.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_presenter_headless.cpp
new file mode 100644
index 00000000..3fc63b7b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_presenter_headless.cpp
@@ -0,0 +1,14 @@
+#include "../wsi_presenter.h"
+
+#include <wsi/native_wsi.h>
+
+namespace dxvk::wsi {
+
+ VkResult createSurface(
+ HWND hWindow,
+ const Rc<vk::InstanceFn>& vki,
+ VkSurfaceKHR* pSurface) {
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_window_headless.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_window_headless.cpp
new file mode 100644
index 00000000..9119ee20
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/headless/wsi_window_headless.cpp
@@ -0,0 +1,83 @@
+#include "../wsi_window.h"
+
+#include "wsi_helpers_headless.h"
+
+#include <windows.h>
+#include <wsi/native_wsi.h>
+
+#include "../../util/util_string.h"
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ void getWindowSize(
+ HWND hWindow,
+ uint32_t* pWidth,
+ uint32_t* pHeight) {
+ if (pWidth)
+ *pWidth = 1024;
+
+ if (pHeight)
+ *pHeight = 1024;
+ }
+
+
+ void resizeWindow(
+ HWND hWindow,
+ DxvkWindowState* pState,
+ uint32_t Width,
+ uint32_t Height) {
+ }
+
+
+ bool setWindowMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ const WsiMode* pMode,
+ bool EnteringFullscreen) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ return true;
+ }
+
+
+
+ bool enterFullscreenMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ DxvkWindowState* pState,
+ bool ModeSwitch) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+ return true;
+ }
+
+
+ bool leaveFullscreenMode(
+ HWND hWindow,
+ DxvkWindowState* pState) {
+ return true;
+ }
+
+
+ bool restoreDisplayMode(HMONITOR hMonitor) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+ return isDisplayValid(displayId);
+ }
+
+
+ HMONITOR getWindowMonitor(HWND hWindow) {
+ return toHmonitor(0);
+ }
+
+
+ bool isWindow(HWND hWindow) {
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/meson.build b/src/libs/dxvk-native-1.9.2a/src/wsi/meson.build
new file mode 100644
index 00000000..6ab147be
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/meson.build
@@ -0,0 +1,32 @@
+wsi_win32_src = [
+ 'win32/wsi_mode_win32.cpp',
+ 'win32/wsi_monitor_win32.cpp',
+ 'win32/wsi_presenter_win32.cpp',
+ 'win32/wsi_window_win32.cpp',
+]
+
+wsi_sdl2_src = [
+ 'sdl2/wsi_mode_sdl2.cpp',
+ 'sdl2/wsi_monitor_sdl2.cpp',
+ 'sdl2/wsi_presenter_sdl2.cpp',
+ 'sdl2/wsi_window_sdl2.cpp',
+]
+
+if dxvk_wsi == 'win32'
+ wsi_src = wsi_win32_src
+ wsi_deps = []
+elif dxvk_wsi == 'sdl2'
+ wsi_src = wsi_sdl2_src
+ wsi_deps = [ lib_sdl2 ]
+else
+ error('Unknown wsi')
+endif
+
+wsi_lib = static_library('wsi', wsi_src,
+ dependencies : wsi_deps,
+ override_options : ['cpp_std='+dxvk_cpp_std],
+ include_directories : [ dxvk_include_path ])
+
+wsi_dep = declare_dependency(
+ link_with : [ wsi_lib ],
+ include_directories : [ dxvk_include_path ])
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_helpers_sdl2.h b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_helpers_sdl2.h
new file mode 100644
index 00000000..781a6882
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_helpers_sdl2.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+
+#include "../wsi_monitor.h"
+
+namespace dxvk {
+
+ inline bool isDisplayValid(int32_t displayId) {
+ const int32_t displayCount = SDL_GetNumVideoDisplays();
+
+ return displayId < displayCount && displayId >= 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_mode_sdl2.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_mode_sdl2.cpp
new file mode 100644
index 00000000..c75a293a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_mode_sdl2.cpp
@@ -0,0 +1,93 @@
+#include "../wsi_mode.h"
+
+#include "wsi_helpers_sdl2.h"
+
+#include <wsi/native_wsi.h>
+
+#include "../../util/util_string.h"
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ static inline uint32_t roundToNextPow2(uint32_t num) {
+ if (num-- == 0)
+ return 0;
+
+ num |= num >> 1; num |= num >> 2;
+ num |= num >> 4; num |= num >> 8;
+ num |= num >> 16;
+
+ return ++num;
+ }
+
+
+ static inline void convertMode(const SDL_DisplayMode& mode, WsiMode* pMode) {
+ pMode->width = uint32_t(mode.w);
+ pMode->height = uint32_t(mode.h);
+ pMode->refreshRate = WsiRational{ uint32_t(mode.refresh_rate) * 1000, 1000 };
+ // BPP should always be a power of two
+ // to match Windows behaviour of including padding.
+ pMode->bitsPerPixel = roundToNextPow2(SDL_BITSPERPIXEL(mode.format));
+ pMode->interlaced = false;
+ }
+
+
+ bool getDisplayMode(
+ HMONITOR hMonitor,
+ uint32_t ModeNumber,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ SDL_DisplayMode mode = { };
+ if (SDL_GetDisplayMode(displayId, ModeNumber, &mode) != 0)
+ return false;
+
+ convertMode(mode, pMode);
+
+ return true;
+ }
+
+
+ bool getCurrentDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ SDL_DisplayMode mode = { };
+ if (SDL_GetCurrentDisplayMode(displayId, &mode) != 0) {
+ Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError()));
+ return false;
+ }
+
+ convertMode(mode, pMode);
+
+ return true;
+ }
+
+
+ bool getDesktopDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ SDL_DisplayMode mode = { };
+ if (SDL_GetDesktopDisplayMode(displayId, &mode) != 0) {
+ Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError()));
+ return false;
+ }
+
+ convertMode(mode, pMode);
+
+ return true;
+ }
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_monitor_sdl2.cpp
new file mode 100644
index 00000000..4125457b
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_monitor_sdl2.cpp
@@ -0,0 +1,63 @@
+#include "../wsi_monitor.h"
+
+#include "wsi_helpers_sdl2.h"
+
+#include <windows.h>
+#include <wsi/native_wsi.h>
+
+#include <string>
+#include <sstream>
+
+namespace dxvk::wsi {
+
+ HMONITOR getDefaultMonitor() {
+ return enumMonitors(0);
+ }
+
+
+ HMONITOR enumMonitors(uint32_t index) {
+ return isDisplayValid(int32_t(index))
+ ? toHmonitor(index)
+ : nullptr;
+ }
+
+ bool getDisplayName(
+ HMONITOR hMonitor,
+ WCHAR (&Name)[32]) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ std::wstringstream nameStream;
+ nameStream << LR"(\\.\DISPLAY)" << (displayId + 1);
+
+ std::wstring name = nameStream.str();
+
+ std::memset(Name, 0, sizeof(Name));
+ name.copy(Name, name.length(), 0);
+
+ return true;
+ }
+
+
+ bool getDesktopCoordinates(
+ HMONITOR hMonitor,
+ RECT* pRect) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ SDL_Rect rect = { };
+ SDL_GetDisplayBounds(displayId, &rect);
+
+ pRect->left = rect.x;
+ pRect->top = rect.y;
+ pRect->right = rect.x + rect.w;
+ pRect->bottom = rect.y + rect.h;
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_presenter_sdl2.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_presenter_sdl2.cpp
new file mode 100644
index 00000000..1bf222f3
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_presenter_sdl2.cpp
@@ -0,0 +1,21 @@
+#include "../wsi_presenter.h"
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_vulkan.h>
+
+#include <wsi/native_wsi.h>
+
+namespace dxvk::wsi {
+
+ VkResult createSurface(
+ HWND hWindow,
+ const Rc<vk::InstanceFn>& vki,
+ VkSurfaceKHR* pSurface) {
+ SDL_Window* window = fromHwnd(hWindow);
+
+ return SDL_Vulkan_CreateSurface(window, vki->instance(), pSurface)
+ ? VK_SUCCESS
+ : VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_window_sdl2.cpp
new file mode 100644
index 00000000..47fffeb6
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/sdl2/wsi_window_sdl2.cpp
@@ -0,0 +1,135 @@
+#include "../wsi_window.h"
+
+#include "wsi_helpers_sdl2.h"
+
+#include <windows.h>
+#include <wsi/native_wsi.h>
+
+#include "../../util/util_string.h"
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ void getWindowSize(
+ HWND hWindow,
+ uint32_t* pWidth,
+ uint32_t* pHeight) {
+ SDL_Window* window = fromHwnd(hWindow);
+
+ int32_t w, h;
+ SDL_GetWindowSize(window, &w, &h);
+
+ if (pWidth)
+ *pWidth = uint32_t(w);
+
+ if (pHeight)
+ *pHeight = uint32_t(h);
+ }
+
+
+ void resizeWindow(
+ HWND hWindow,
+ DxvkWindowState* pState,
+ uint32_t Width,
+ uint32_t Height) {
+ SDL_Window* window = fromHwnd(hWindow);
+
+ SDL_SetWindowSize(window, int32_t(Width), int32_t(Height));
+ }
+
+
+ bool setWindowMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ const WsiMode* pMode,
+ bool EnteringFullscreen) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+ SDL_Window* window = fromHwnd(hWindow);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ SDL_DisplayMode wantedMode = { };
+ wantedMode.w = pMode->width;
+ wantedMode.h = pMode->height;
+ wantedMode.refresh_rate = pMode->refreshRate.numerator != 0
+ ? pMode->refreshRate.numerator / pMode->refreshRate.denominator
+ : 0;
+ // TODO: Implement lookup format for bitsPerPixel here.
+
+ SDL_DisplayMode mode = { };
+ if (SDL_GetClosestDisplayMode(displayId, &wantedMode, &mode) == nullptr) {
+ Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_GetClosestDisplayMode: ", SDL_GetError()));
+ return false;
+ }
+
+ if (SDL_SetWindowDisplayMode(window, &mode) != 0) {
+ Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", SDL_GetError()));
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ bool enterFullscreenMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ DxvkWindowState* pState,
+ bool ModeSwitch) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+ SDL_Window* window = fromHwnd(hWindow);
+
+ if (!isDisplayValid(displayId))
+ return false;
+
+ uint32_t flags = ModeSwitch
+ ? SDL_WINDOW_FULLSCREEN
+ : SDL_WINDOW_FULLSCREEN_DESKTOP;
+
+ // TODO: Set this on the correct monitor.
+ // Docs aren't clear on this...
+ if (SDL_SetWindowFullscreen(window, flags) != 0) {
+ Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError()));
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool leaveFullscreenMode(
+ HWND hWindow,
+ DxvkWindowState* pState) {
+ SDL_Window* window = fromHwnd(hWindow);
+
+ if (SDL_SetWindowFullscreen(window, 0) != 0) {
+ Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError()));
+ return false;
+ }
+
+ return true;
+ }
+
+
+ bool restoreDisplayMode(HMONITOR hMonitor) {
+ const int32_t displayId = fromHmonitor(hMonitor);
+ return isDisplayValid(displayId);
+ }
+
+
+ HMONITOR getWindowMonitor(HWND hWindow) {
+ SDL_Window* window = fromHwnd(hWindow);
+ const int32_t displayId = SDL_GetWindowDisplayIndex(window);
+
+ return toHmonitor(displayId);
+ }
+
+
+ bool isWindow(HWND hWindow) {
+ SDL_Window* window = fromHwnd(hWindow);
+ return window != nullptr;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_mode_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_mode_win32.cpp
new file mode 100644
index 00000000..45987945
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_mode_win32.cpp
@@ -0,0 +1,62 @@
+#include "../wsi_mode.h"
+
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ static inline void convertMode(const DEVMODEW& mode, WsiMode* pMode) {
+ pMode->width = mode.dmPelsWidth;
+ pMode->height = mode.dmPelsHeight;
+ pMode->refreshRate = WsiRational{ mode.dmDisplayFrequency * 1000, 1000 };
+ pMode->bitsPerPixel = mode.dmBitsPerPel;
+ pMode->interlaced = mode.dmDisplayFlags & DM_INTERLACED;
+ }
+
+
+ static inline bool retrieveDisplayMode(
+ HMONITOR hMonitor,
+ DWORD ModeNumber,
+ WsiMode* pMode) {
+ // Query monitor info to get the device name
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Win32 WSI: retrieveDisplayMode: Failed to query monitor info");
+ return false;
+ }
+
+ DEVMODEW devMode = { };
+ devMode.dmSize = sizeof(devMode);
+
+ if (!::EnumDisplaySettingsW(monInfo.szDevice, ModeNumber, &devMode))
+ return false;
+
+ convertMode(devMode, pMode);
+
+ return true;
+ }
+
+
+ bool getDisplayMode(
+ HMONITOR hMonitor,
+ uint32_t ModeNumber,
+ WsiMode* pMode) {
+ return retrieveDisplayMode(hMonitor, ModeNumber, pMode);
+ }
+
+
+ bool getCurrentDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode);
+ }
+
+
+ bool getDesktopDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode) {
+ return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_monitor_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_monitor_win32.cpp
new file mode 100644
index 00000000..b6b135f0
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_monitor_win32.cpp
@@ -0,0 +1,79 @@
+#include "../wsi_monitor.h"
+
+#include "../../util/log/log.h"
+
+#include <cstring>
+
+namespace dxvk::wsi {
+
+ HMONITOR getDefaultMonitor() {
+ return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
+ }
+
+ struct MonitorEnumInfo {
+ UINT iMonitorId;
+ HMONITOR oMonitor;
+ };
+
+ static BOOL CALLBACK MonitorEnumProc(
+ HMONITOR hmon,
+ HDC hdc,
+ LPRECT rect,
+ LPARAM lp) {
+ auto data = reinterpret_cast<MonitorEnumInfo*>(lp);
+
+ if (data->iMonitorId--)
+ return TRUE; /* continue */
+
+ data->oMonitor = hmon;
+ return FALSE; /* stop */
+ }
+
+ HMONITOR enumMonitors(uint32_t index) {
+ MonitorEnumInfo info;
+ info.iMonitorId = index;
+ info.oMonitor = nullptr;
+
+ ::EnumDisplayMonitors(
+ nullptr, nullptr, &MonitorEnumProc,
+ reinterpret_cast<LPARAM>(&info));
+
+ return info.oMonitor;
+ }
+
+
+ bool getDisplayName(
+ HMONITOR hMonitor,
+ WCHAR (&Name)[32]) {
+ // Query monitor info to get the device name
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Win32 WSI: getDisplayName: Failed to query monitor info");
+ return false;
+ }
+
+ std::memcpy(Name, monInfo.szDevice, sizeof(Name));
+
+ return true;
+ }
+
+
+ bool getDesktopCoordinates(
+ HMONITOR hMonitor,
+ RECT* pRect) {
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Win32 WSI: getDisplayName: Failed to query monitor info");
+ return false;
+ }
+
+ *pRect = monInfo.rcMonitor;
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_presenter_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_presenter_win32.cpp
new file mode 100644
index 00000000..b3ff9b5a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_presenter_win32.cpp
@@ -0,0 +1,23 @@
+#include "../wsi_presenter.h"
+
+namespace dxvk::wsi {
+
+ VkResult createSurface(
+ HWND hWindow,
+ const Rc<vk::InstanceFn>& vki,
+ VkSurfaceKHR* pSurface) {
+ HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(
+ GetWindowLongPtr(hWindow, GWLP_HINSTANCE));
+
+ VkWin32SurfaceCreateInfoKHR info;
+ info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ info.pNext = nullptr;
+ info.flags = 0;
+ info.hinstance = hInstance;
+ info.hwnd = hWindow;
+
+ return vki->vkCreateWin32SurfaceKHR(
+ vki->instance(), &info, nullptr, pSurface);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_window_win32.cpp b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_window_win32.cpp
new file mode 100644
index 00000000..1c37dc7a
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/win32/wsi_window_win32.cpp
@@ -0,0 +1,266 @@
+#include "../wsi_window.h"
+#include "../wsi_mode.h"
+#include "../wsi_monitor.h"
+
+#include "../../util/util_string.h"
+#include "../../util/log/log.h"
+
+namespace dxvk::wsi {
+
+ static bool getMonitorDisplayMode(
+ HMONITOR hMonitor,
+ DWORD modeNum,
+ DEVMODEW* pMode) {
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Failed to query monitor info");
+ return false;
+ }
+
+ return ::EnumDisplaySettingsW(monInfo.szDevice, modeNum, pMode);
+ }
+
+
+ static bool setMonitorDisplayMode(
+ HMONITOR hMonitor,
+ DEVMODEW* pMode) {
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Failed to query monitor info");
+ return E_FAIL;
+ }
+
+ Logger::info(str::format("Setting display mode: ",
+ pMode->dmPelsWidth, "x", pMode->dmPelsHeight, "@",
+ pMode->dmDisplayFrequency));
+
+ DEVMODEW curMode = { };
+ curMode.dmSize = sizeof(curMode);
+
+ if (getMonitorDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, &curMode)) {
+ bool eq = curMode.dmPelsWidth == pMode->dmPelsWidth
+ && curMode.dmPelsHeight == pMode->dmPelsHeight
+ && curMode.dmBitsPerPel == pMode->dmBitsPerPel;
+
+ if (pMode->dmFields & DM_DISPLAYFREQUENCY)
+ eq &= curMode.dmDisplayFrequency == pMode->dmDisplayFrequency;
+
+ if (eq)
+ return true;
+ }
+
+ LONG status = ::ChangeDisplaySettingsExW(monInfo.szDevice,
+ pMode, nullptr, CDS_FULLSCREEN, nullptr);
+
+ if (status != DISP_CHANGE_SUCCESSFUL) {
+ pMode->dmFields &= ~DM_DISPLAYFREQUENCY;
+
+ status = ::ChangeDisplaySettingsExW(monInfo.szDevice,
+ pMode, nullptr, CDS_FULLSCREEN, nullptr);
+ }
+
+ return status == DISP_CHANGE_SUCCESSFUL;
+ }
+
+
+ static BOOL CALLBACK restoreMonitorDisplayModeCallback(
+ HMONITOR hMonitor,
+ HDC hDC,
+ LPRECT pRect,
+ LPARAM pUserdata) {
+ auto success = reinterpret_cast<bool*>(pUserdata);
+
+ DEVMODEW devMode = { };
+ devMode.dmSize = sizeof(devMode);
+
+ if (!getMonitorDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, &devMode)) {
+ *success = false;
+ return false;
+ }
+
+ Logger::info(str::format("Restoring display mode: ",
+ devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@",
+ devMode.dmDisplayFrequency));
+
+ if (!setMonitorDisplayMode(hMonitor, &devMode)) {
+ *success = false;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ void getWindowSize(
+ HWND hWindow,
+ uint32_t* pWidth,
+ uint32_t* pHeight) {
+ RECT rect = { };
+ ::GetClientRect(hWindow, &rect);
+
+ if (pWidth)
+ *pWidth = rect.right - rect.left;
+
+ if (pHeight)
+ *pHeight = rect.bottom - rect.top;
+ }
+
+
+ void resizeWindow(
+ HWND hWindow,
+ DxvkWindowState* pState,
+ uint32_t Width,
+ uint32_t Height) {
+ // Adjust window position and size
+ RECT newRect = { 0, 0, 0, 0 };
+ RECT oldRect = { 0, 0, 0, 0 };
+
+ ::GetWindowRect(hWindow, &oldRect);
+ ::MapWindowPoints(HWND_DESKTOP, ::GetParent(hWindow), reinterpret_cast<POINT*>(&oldRect), 1);
+ ::SetRect(&newRect, 0, 0, Width, Height);
+ ::AdjustWindowRectEx(&newRect,
+ ::GetWindowLongW(hWindow, GWL_STYLE), FALSE,
+ ::GetWindowLongW(hWindow, GWL_EXSTYLE));
+ ::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top);
+ ::OffsetRect(&newRect, oldRect.left, oldRect.top);
+ ::MoveWindow(hWindow, newRect.left, newRect.top,
+ newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
+ }
+
+
+ bool setWindowMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ const WsiMode* pMode,
+ bool EnteringFullscreen) {
+ ::MONITORINFOEXW monInfo;
+ monInfo.cbSize = sizeof(monInfo);
+
+ if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
+ Logger::err("Win32 WSI: setWindowMode: Failed to query monitor info");
+ return false;
+ }
+
+ DEVMODEW devMode = { };
+ devMode.dmSize = sizeof(devMode);
+ devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
+ devMode.dmPelsWidth = pMode->width;
+ devMode.dmPelsHeight = pMode->height;
+ devMode.dmBitsPerPel = pMode->bitsPerPixel;
+
+ if (pMode->refreshRate.numerator != 0) {
+ devMode.dmFields |= DM_DISPLAYFREQUENCY;
+ devMode.dmDisplayFrequency = pMode->refreshRate.numerator
+ / pMode->refreshRate.denominator;
+ }
+
+ Logger::info(str::format("Setting display mode: ",
+ devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@",
+ devMode.dmDisplayFrequency));
+
+ bool status = setMonitorDisplayMode(hMonitor, &devMode);
+
+ if (status && !EnteringFullscreen && hWindow != nullptr) {
+ RECT newRect = { };
+ getDesktopCoordinates(hMonitor, &newRect);
+
+ ::MoveWindow(hWindow, newRect.left, newRect.top,
+ newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
+ }
+
+ return status == DISP_CHANGE_SUCCESSFUL;
+ }
+
+
+ bool enterFullscreenMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ DxvkWindowState* pState,
+ bool ModeSwitch) {
+ // Find a display mode that matches what we need
+ ::GetWindowRect(hWindow, &pState->rect);
+
+ // Change the window flags to remove the decoration etc.
+ LONG style = ::GetWindowLongW(hWindow, GWL_STYLE);
+ LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE);
+
+ pState->style = style;
+ pState->exstyle = exstyle;
+
+ style &= ~WS_OVERLAPPEDWINDOW;
+ exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
+
+ ::SetWindowLongW(hWindow, GWL_STYLE, style);
+ ::SetWindowLongW(hWindow, GWL_EXSTYLE, exstyle);
+
+ RECT rect = { };
+ getDesktopCoordinates(hMonitor, &rect);
+
+ ::SetWindowPos(hWindow, HWND_TOPMOST,
+ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
+ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+
+ return true;
+ }
+
+
+ bool leaveFullscreenMode(
+ HWND hWindow,
+ DxvkWindowState* pState) {
+ // Only restore the window style if the application hasn't
+ // changed them. This is in line with what native DXGI does.
+ LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE;
+ LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
+
+ if (curStyle == (pState->style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
+ && curExstyle == (pState->exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
+ ::SetWindowLongW(hWindow, GWL_STYLE, pState->style);
+ ::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->exstyle);
+ }
+
+ // Restore window position and apply the style
+ const RECT rect = pState->rect;
+
+ ::SetWindowPos(hWindow, (pState->exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST,
+ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE);
+
+ return true;
+ }
+
+
+ bool restoreDisplayMode(HMONITOR hMonitor) {
+ if (!hMonitor)
+ return false;
+
+ bool success = true;
+ bool result = ::EnumDisplayMonitors(nullptr, nullptr,
+ &restoreMonitorDisplayModeCallback,
+ reinterpret_cast<LPARAM>(&success));
+
+ return result && success;
+ }
+
+
+ HMONITOR getWindowMonitor(HWND hWindow) {
+ RECT windowRect = { 0, 0, 0, 0 };
+ ::GetWindowRect(hWindow, &windowRect);
+
+ HMONITOR monitor = ::MonitorFromPoint(
+ { (windowRect.left + windowRect.right) / 2,
+ (windowRect.top + windowRect.bottom) / 2 },
+ MONITOR_DEFAULTTOPRIMARY);
+
+ return monitor;
+ }
+
+
+ bool isWindow(HWND hWindow) {
+ return ::IsWindow(hWindow);
+ }
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_mode.h b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_mode.h
new file mode 100644
index 00000000..fb622367
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_mode.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <cstdint>
+
+#include <windows.h>
+
+#include "wsi_monitor.h"
+
+namespace dxvk::wsi {
+
+ /**
+ * \brief Rational number. Eg. 2/3
+ */
+ struct WsiRational {
+ uint32_t numerator;
+ uint32_t denominator;
+ };
+
+ /**
+ * \brief Display mode
+ */
+ struct WsiMode {
+ uint32_t width;
+ uint32_t height;
+ WsiRational refreshRate;
+ uint32_t bitsPerPixel;
+ bool interlaced;
+ };
+
+ /**
+ * \brief Get the nth display mode
+ *
+ * \param [in] hMonitor The monitor
+ * \param [in] ModeNumber The nth mode
+ * \param [out] pMode The resultant mode
+ * \returns \c true on success, \c false if the mode could not be found
+ */
+ bool getDisplayMode(
+ HMONITOR hMonitor,
+ uint32_t ModeNumber,
+ WsiMode* pMode);
+
+ /**
+ * \brief Get the current display mode
+ *
+ * This is the display mode right now.
+ *
+ * \param [in] hMonitor The monitor
+ * \param [out] pMode The resultant mode
+ * \returns \c true on success, \c false on failure
+ */
+ bool getCurrentDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode);
+
+ /**
+ * \brief Get the current display mode
+ *
+ * This is the display mode of the user's
+ * default desktop.
+ *
+ * \param [in] hMonitor The monitor
+ * \param [out] pMode The resultant mode
+ * \returns \c true on success, \c false on failure
+ */
+ bool getDesktopDisplayMode(
+ HMONITOR hMonitor,
+ WsiMode* pMode);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_monitor.h b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_monitor.h
new file mode 100644
index 00000000..d0d324cb
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_monitor.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <windows.h>
+
+#include <array>
+#include <cstdint>
+
+namespace dxvk::wsi {
+
+ /**
+ * \brief Default monitor
+ *
+ * \returns The monitor of given index
+ */
+ HMONITOR getDefaultMonitor();
+
+ /**
+ * \brief Enumerators monitors on the system
+ *
+ * \returns The monitor of given index
+ */
+ HMONITOR enumMonitors(uint32_t index);
+
+ /**
+ * \brief Get the GDI name of a HMONITOR
+ *
+ * Get the GDI Device Name of a HMONITOR to
+ * return to the end user.
+ *
+ * This typically looks like \.\\DISPLAY1
+ * and has a maximum length of 32 chars.
+ *
+ * \param [in] hMonitor The monitor
+ * \param [out] Name The GDI display name
+ * \returns \c true on success, \c false if an error occured
+ */
+ bool getDisplayName(
+ HMONITOR hMonitor,
+ WCHAR (&Name)[32]);
+
+ /**
+ * \brief Get the encompassing coords of a monitor
+ */
+ bool getDesktopCoordinates(
+ HMONITOR hMonitor,
+ RECT* pRect);
+
+}
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_presenter.h b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_presenter.h
new file mode 100644
index 00000000..152d05a5
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_presenter.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <windows.h>
+
+#include "../vulkan/vulkan_loader.h"
+
+namespace dxvk::wsi {
+
+ /**
+ * \brief Create a surface for a window
+ *
+ * \param [in] hWindow The window
+ * \param [in] vki The instance
+ * \param [out] pSurface The surface
+ */
+ VkResult createSurface(
+ HWND hWindow,
+ const Rc<vk::InstanceFn>& vki,
+ VkSurfaceKHR* pSurface);
+
+} \ No newline at end of file
diff --git a/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_window.h b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_window.h
new file mode 100644
index 00000000..5de022b2
--- /dev/null
+++ b/src/libs/dxvk-native-1.9.2a/src/wsi/wsi_window.h
@@ -0,0 +1,115 @@
+#pragma once
+
+// The windows.h will define HWND/HMONITOR
+// to be types that it wants for the wsi we are compiling against.
+// ie. HWND = their own window data ptr (eg. SDL_Window)
+// HMONTIOR = their own monitor data ptr/a display index
+
+#include <windows.h>
+
+#include "wsi_mode.h"
+
+namespace dxvk::wsi {
+
+ /**
+ * \brief Impl-dependent state
+ */
+ struct DxvkWindowState {
+#ifdef DXVK_WSI_WIN32
+ LONG style = 0;
+ LONG exstyle = 0;
+ RECT rect = { 0, 0, 0, 0 };
+#endif
+ };
+
+ /**
+ * \brief The size of the window
+ *
+ * \param [in] hWindow The window
+ * \param [out] pWidth The width (optional)
+ * \param [out] pHeight The height (optional)
+ */
+ void getWindowSize(
+ HWND hWindow,
+ uint32_t* pWidth,
+ uint32_t* pWeight);
+
+ /**
+ * \brief Resize a window
+ *
+ * \param [in] hWindow The window
+ * \param [in] pState The swapchain's window state
+ * \param [in] Width The new width
+ * \param [in] Height The new height
+ */
+ void resizeWindow(
+ HWND hWindow,
+ DxvkWindowState* pState,
+ uint32_t Width,
+ uint32_t Height);
+
+ /**
+ * \brief Sets the display mode for a window/monitor
+ *
+ * \param [in] hMonitor The monitor
+ * \param [in] hWindow The window
+ * \param [in] pMode The mode
+ * \param [in] EnteringFullscreen Are we entering fullscreen?
+ * \returns \c true on success, \c false on failure
+ */
+ bool setWindowMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ const WsiMode* pMode,
+ bool EnteringFullscreen);
+
+ /**
+ * \brief Enter fullscreen mode for a window & monitor
+ *
+ * \param [in] hMonitor The monitor
+ * \param [in] hWindow The window
+ * \param [in] pState The swapchain's window state
+ * \param [in] ModeSwitch Whether mode switching is allowed
+ * \returns \c true on success, \c false on failure
+ */
+ bool enterFullscreenMode(
+ HMONITOR hMonitor,
+ HWND hWindow,
+ DxvkWindowState* pState,
+ bool ModeSwitch);
+
+ /**
+ * \brief Exit fullscreen mode for a window
+ *
+ * \param [in] hWindow The window
+ * \param [in] pState The swapchain's window state
+ * \returns \c true on success, \c false on failure
+ */
+ bool leaveFullscreenMode(
+ HWND hWindow,
+ DxvkWindowState* pState);
+
+ /**
+ * \brief Restores the display mode if necessary
+ *
+ * \param [in] hMonitor The monitor to restore the mode of
+ * \returns \c true on success, \c false on failure
+ */
+ bool restoreDisplayMode(HMONITOR hMonitor);
+
+ /**
+ * \brief The monitor a window is on
+ *
+ * \param [in] hWindow The window
+ * \returns The monitor the window is on
+ */
+ HMONITOR getWindowMonitor(HWND hWindow);
+
+ /**
+ * \brief Is a HWND a window?
+ *
+ * \param [in] hWindow The window
+ * \returns Is it a window?
+ */
+ bool isWindow(HWND hWindow);
+} \ No newline at end of file