Skip to content

Commit

Permalink
Merge pull request #70315 from RandomShaper/d3d12_mesa
Browse files Browse the repository at this point in the history
Direct3D 12 Rendering Driver (Mesa NIR approach)
  • Loading branch information
akien-mga authored Dec 12, 2023
2 parents 84692c6 + 2f47c57 commit 41365c6
Show file tree
Hide file tree
Showing 45 changed files with 75,735 additions and 19 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
5 changes: 5 additions & 0 deletions core/object/worker_thread_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
task_mutex.unlock();
}

int WorkerThreadPool::get_thread_index() {
Thread::ID tid = Thread::get_caller_id();
return singleton->thread_ids.has(tid) ? singleton->thread_ids[tid] : -1;
}

void WorkerThreadPool::init(int p_thread_count, bool p_use_native_threads_low_priority, float p_low_priority_task_ratio) {
ERR_FAIL_COND(threads.size() > 0);
if (p_thread_count < 0) {
Expand Down
2 changes: 2 additions & 0 deletions core/object/worker_thread_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ class WorkerThreadPool : public Object {
_FORCE_INLINE_ int get_thread_count() const { return threads.size(); }

static WorkerThreadPool *get_singleton() { return singleton; }
static int get_thread_index();

void init(int p_thread_count = -1, bool p_use_native_threads_low_priority = true, float p_low_priority_task_ratio = 0.3);
void finish();
WorkerThreadPool();
Expand Down
26 changes: 21 additions & 5 deletions core/string/ustring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4842,6 +4842,7 @@ String String::sprintf(const Array &values, bool *error) const {
bool pad_with_zeros = false;
bool left_justified = false;
bool show_sign = false;
bool as_unsigned = false;

if (error) {
*error = true;
Expand Down Expand Up @@ -4882,16 +4883,27 @@ String String::sprintf(const Array &values, bool *error) const {
case 'x':
break;
case 'X':
base = 16;
capitalize = true;
break;
}
// Get basic number.
String str = String::num_int64(ABS(value), base, capitalize);
String str;
if (!as_unsigned) {
str = String::num_int64(ABS(value), base, capitalize);
} else {
uint64_t uvalue = *((uint64_t *)&value);
// In unsigned hex, if the value fits in 32 bits, trim it down to that.
if (base == 16 && value < 0 && value >= INT32_MIN) {
uvalue &= 0xffffffff;
}
str = String::num_uint64(uvalue, base, capitalize);
}
int number_len = str.length();

bool negative = value < 0 && !as_unsigned;

// Padding.
int pad_chars_count = (value < 0 || show_sign) ? min_chars - 1 : min_chars;
int pad_chars_count = (negative || show_sign) ? min_chars - 1 : min_chars;
String pad_char = pad_with_zeros ? String("0") : String(" ");
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
Expand All @@ -4900,8 +4912,8 @@ String String::sprintf(const Array &values, bool *error) const {
}

// Sign.
if (show_sign || value < 0) {
String sign_char = value < 0 ? "-" : "+";
if (show_sign || negative) {
String sign_char = negative ? "-" : "+";
if (left_justified) {
str = str.insert(0, sign_char);
} else {
Expand Down Expand Up @@ -5094,6 +5106,10 @@ String String::sprintf(const Array &values, bool *error) const {
show_sign = true;
break;
}
case 'u': { // Treat as unsigned (for int/hex).
as_unsigned = true;
break;
}
case '0':
case '1':
case '2':
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 41365c6

Please sign in to comment.