Skip to content

Commit

Permalink
Add Direct3D 12 RenderingDevice implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomShaper committed Dec 12, 2023
1 parent 208c102 commit 2f47c57
Show file tree
Hide file tree
Showing 42 changed files with 75,707 additions and 14 deletions.
24 changes: 23 additions & 1 deletion .github/workflows/windows_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "dxc_path=${{github.workspace}}/dxc" "mesa_libs=${{github.workspace}}/godot-nir-static"
SCONS_CACHE_MSVC_CONFIG: true

concurrency:
Expand Down Expand Up @@ -49,6 +49,28 @@ jobs:
- name: Setup python and scons
uses: ./.github/actions/godot-deps

- name: Download pre-built DirectX Shader Compiler
uses: dsaltares/fetch-gh-release-asset@1.0.0
with:
repo: Microsoft/DirectXShaderCompiler
version: tags/v1.7.2308
file: dxc_2023_08_14.zip
target: dxc.zip

- name: Extract pre-built DirectX Shader Compiler
run: 7z x dxc.zip -o${{github.workspace}}/dxc

- name: Download pre-built Mesa-NIR
uses: dsaltares/fetch-gh-release-asset@1.0.0
with:
repo: godotengine/godot-nir-static
version: tags/23.1.0-devel
file: godot-nir-23.1.0-1-devel.zip
target: godot-nir-static.zip

- name: Extract pre-built Mesa-NIR
run: 7z x godot-nir-static.zip -o${{github.workspace}}/godot-nir-static

- name: Setup MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master

Expand Down
10 changes: 10 additions & 0 deletions COPYRIGHT.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ Copyright: 2018, Eric Lasota
2018, Microsoft Corp.
License: Expat

Files: ./thirdparty/d3d12ma/
Comment: D3D12 Memory Allocator
Copyright: 2019-2022 Advanced Micro Devices, Inc.
License: Expat

Files: ./thirdparty/directx_headers/
Comment: DirectX Headers
Copyright: Microsoft Corporation
License: Expat

Files: ./thirdparty/doctest/
Comment: doctest
Copyright: 2016-2023, Viktor Kirilov
Expand Down
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ opts.Add(BoolVariable("brotli", "Enable Brotli for decompresson and WOFF2 fonts
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
opts.Add(BoolVariable("d3d12", "Enable the Direct3D 12 rendering driver (Windows only)", False))
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
Expand Down
8 changes: 7 additions & 1 deletion core/config/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);

#ifdef VULKAN_ENABLED
#if defined(VULKAN_ENABLED) || defined(D3D12_ENABLED)
features.append("Forward Plus");
features.append("Mobile");
#endif
Expand Down Expand Up @@ -1399,6 +1399,12 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
GLOBAL_DEF("rendering/rendering_device/pipeline_cache/save_chunk_size_mb", 3.0);
GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", 16384);
custom_prop_info["rendering/rendering_device/d3d12/max_resource_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_resource_descriptors_per_frame", PROPERTY_HINT_RANGE, "512,262144");
GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", 1024);
custom_prop_info["rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame", PROPERTY_HINT_RANGE, "256,2048");
GLOBAL_DEF_RST("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", 512);
custom_prop_info["rendering/rendering_device/d3d12/max_misc_descriptors_per_frame"] = PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/max_misc_descriptors_per_frame", PROPERTY_HINT_RANGE, "32,4096");

GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ void OS::_bind_methods() {

BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
BIND_ENUM_CONSTANT(RENDERING_DRIVER_D3D12);

BIND_ENUM_CONSTANT(SYSTEM_DIR_DESKTOP);
BIND_ENUM_CONSTANT(SYSTEM_DIR_DCIM);
Expand Down
1 change: 1 addition & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class OS : public Object {
enum RenderingDriver {
RENDERING_DRIVER_VULKAN,
RENDERING_DRIVER_OPENGL3,
RENDERING_DRIVER_D3D12,
};

virtual PackedStringArray get_connected_midi_inputs();
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,9 @@
<constant name="RENDERING_DRIVER_OPENGL3" value="1" enum="RenderingDriver">
The OpenGL 3 rendering driver. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web.
</constant>
<constant name="RENDERING_DRIVER_D3D12" value="2" enum="RenderingDriver">
The Direct3D 12 rendering driver.
</constant>
<constant name="SYSTEM_DIR_DESKTOP" value="0" enum="SystemDir">
Desktop directory path.
</constant>
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2616,6 +2616,18 @@
<member name="rendering/renderer/rendering_method.web" type="String" setter="" getter="" default="&quot;gl_compatibility&quot;">
Override for [member rendering/renderer/rendering_method] on web.
</member>
<member name="rendering/rendering_device/d3d12/max_misc_descriptors_per_frame" type="int" setter="" getter="" default="512">
The number of entries in the miscellaneous descriptors heap the Direct3D 12 rendering driver uses each frame, used for various operations like clearing a texture.
Depending on the complexity of scenes, this value may be lowered or may need to be raised.
</member>
<member name="rendering/rendering_device/d3d12/max_resource_descriptors_per_frame" type="int" setter="" getter="" default="16384">
The number of entries in the resource descriptors heap the Direct3D 12 rendering driver uses each frame, used for most rendering operations.
Depending on the complexity of scenes, this value may be lowered or may need to be raised.
</member>
<member name="rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame" type="int" setter="" getter="" default="1024">
The number of entries in the sampler descriptors heap the Direct3D 12 rendering driver uses each frame, used for most rendering operations.
Depending on the complexity of scenes, this value may be lowered or may need to be raised.
</member>
<member name="rendering/rendering_device/driver" type="String" setter="" getter="">
Sets the driver to be used by the renderer when using a RenderingDevice-based renderer like the clustered renderer or the mobile renderer. This property can not be edited directly, instead, set the driver using the platform-specific overrides.
</member>
Expand Down
2 changes: 2 additions & 0 deletions drivers/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ SConscript("winmidi/SCsub")
# Graphics drivers
if env["vulkan"]:
SConscript("vulkan/SCsub")
if env["d3d12"]:
SConscript("d3d12/SCsub")
if env["opengl3"]:
SConscript("gl_context/SCsub")
SConscript("gles3/SCsub")
Expand Down
151 changes: 151 additions & 0 deletions drivers/d3d12/SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env python

import os
from pathlib import Path

Import("env")

env_d3d12_rd = env.Clone()

thirdparty_obj = []


# DirectX Headers (must take precedence over Windows SDK's).

env.Prepend(CPPPATH=["#thirdparty/directx_headers"])
env_d3d12_rd.Prepend(CPPPATH=["#thirdparty/directx_headers"])


# Direct3D 12 Memory Allocator.

env.Append(CPPPATH=["#thirdparty/d3d12ma"])
env_d3d12_rd.Append(CPPPATH=["#thirdparty/d3d12ma"])


# Agility SDK.

if env["agility_sdk_path"] != "":
env_d3d12_rd.Append(CPPDEFINES=["AGILITY_SDK_ENABLED"])
if env["agility_sdk_multiarch"]:
env_d3d12_rd.Append(CPPDEFINES=["AGILITY_SDK_MULTIARCH_ENABLED"])


# PIX.

if env["pix_path"] != "":
env_d3d12_rd.Append(CPPDEFINES=["PIX_ENABLED"])
env_d3d12_rd.Append(CPPPATH=[env["pix_path"] + "/Include"])


# Mesa (SPIR-V to DXIL functionality).

mesa_dir = (env["mesa_libs"] + "/godot-mesa").replace("\\", "/")
mesa_gen_dir = (env["mesa_libs"] + "/godot-mesa/generated").replace("\\", "/")
mesa_absdir = Dir(mesa_dir).abspath
mesa_gen_absdir = Dir(mesa_dir + "/generated").abspath

custom_build_steps = [
[
"src/compiler",
"glsl/ir_expression_operation.py enum > %s/ir_expression_operation.h",
"ir_expression_operation.h",
],
["src/compiler/nir", "nir_builder_opcodes_h.py > %s/nir_builder_opcodes.h", "nir_builder_opcodes.h"],
["src/compiler/nir", "nir_constant_expressions.py > %s/nir_constant_expressions.c", "nir_constant_expressions.c"],
["src/compiler/nir", "nir_intrinsics_h.py --outdir %s", "nir_intrinsics.h"],
["src/compiler/nir", "nir_intrinsics_c.py --outdir %s", "nir_intrinsics.c"],
["src/compiler/nir", "nir_intrinsics_indices_h.py --outdir %s", "nir_intrinsics_indices.h"],
["src/compiler/nir", "nir_opcodes_h.py > %s/nir_opcodes.h", "nir_opcodes.h"],
["src/compiler/nir", "nir_opcodes_c.py > %s/nir_opcodes.c", "nir_opcodes.c"],
["src/compiler/nir", "nir_opt_algebraic.py > %s/nir_opt_algebraic.c", "nir_opt_algebraic.c"],
["src/compiler/spirv", "vtn_generator_ids_h.py spir-v.xml %s/vtn_generator_ids.h", "vtn_generator_ids.h"],
[
"src/microsoft/compiler",
"dxil_nir_algebraic.py -p ../../../src/compiler/nir > %s/dxil_nir_algebraic.c",
"dxil_nir_algebraic.c",
],
["src/util", "format_srgb.py > %s/format_srgb.c", "format_srgb.c"],
["src/util/format", "u_format_table.py u_format.csv --header > %s/u_format_pack.h", "u_format_pack.h"],
["src/util/format", "u_format_table.py u_format.csv > %s/u_format_table.c", "u_format_table.c"],
]

mesa_gen_include_paths = [mesa_gen_dir + "/src"]

# See update_mesa.sh for explanation.
for v in custom_build_steps:
subdir = v[0]
cmd = v[1]
gen_filename = v[2]

in_dir = str(Path(mesa_absdir + "/" + subdir))
out_full_path = mesa_dir + "/generated/" + subdir
out_file_full_path = out_full_path + "/" + gen_filename

if gen_filename.endswith(".h"):
mesa_gen_include_paths += [out_full_path.replace("\\", "/")]

mesa_private_inc_paths = [v[0] for v in os.walk(mesa_absdir)]
mesa_private_inc_paths = [v.replace(mesa_absdir, mesa_dir) for v in mesa_private_inc_paths]
mesa_private_inc_paths = [v.replace("\\", "/") for v in mesa_private_inc_paths]
# Avoid build results depending on if generated files already exist.
mesa_private_inc_paths = [v for v in mesa_private_inc_paths if not v.startswith(mesa_gen_dir)]
mesa_private_inc_paths.sort()
# Include the list of the generated ones now, so out-of-the-box sources can include generated headers.
mesa_private_inc_paths += mesa_gen_include_paths
# We have to blacklist some because we are bindly adding every Mesa directory
# to the include path and in some cases that causes the wrong header to be included.
mesa_blacklist_inc_paths = [
"src/c11",
]
mesa_blacklist_inc_paths = [mesa_dir + "/" + v for v in mesa_blacklist_inc_paths]
mesa_private_inc_paths = [v for v in mesa_private_inc_paths if v not in mesa_blacklist_inc_paths]

# Added by ourselves.
extra_defines = [
"WINDOWS_NO_FUTEX",
]

# These defines are inspired by the Meson build scripts in the original repo.
extra_defines += [
"__STDC_CONSTANT_MACROS",
"__STDC_FORMAT_MACROS",
"__STDC_LIMIT_MACROS",
("PACKAGE_VERSION", '\\"' + Path(mesa_absdir + "/VERSION").read_text().strip() + '\\"'),
("PACKAGE_BUGREPORT", '\\"https://gitlab.freedesktop.org/mesa/mesa/-/issues\\"'),
"PIPE_SUBSYSTEM_WINDOWS_USER",
("_Static_assert", "static_assert"),
]

if env.msvc:
extra_defines += [
"_USE_MATH_DEFINES",
"VC_EXTRALEAN",
"_CRT_SECURE_NO_WARNINGS",
"_CRT_SECURE_NO_DEPRECATE",
"_SCL_SECURE_NO_WARNINGS",
"_SCL_SECURE_NO_DEPRECATE",
"_ALLOW_KEYWORD_MACROS",
("_HAS_EXCEPTIONS", 0),
"NOMINMAX",
"HAVE_STRUCT_TIMESPEC",
]

# This is needed since rendering_device_d3d12.cpp needs to include some Mesa internals.
env_d3d12_rd.Prepend(CPPPATH=mesa_private_inc_paths)
# For the same reason as above, the defines must be the same as in the 3rd-party code itself.
env_d3d12_rd.Append(CPPDEFINES=extra_defines)


# Add all.

env.drivers_sources += thirdparty_obj


# Godot source files.

driver_obj = []
env_d3d12_rd.add_source_files(driver_obj, "*.cpp")
env.drivers_sources += driver_obj

# Needed to force rebuilding the driver files when the thirdparty code is updated.
env.Depends(driver_obj, thirdparty_obj)
Loading

0 comments on commit 2f47c57

Please sign in to comment.