Bläddra i källkod

Finish splitting functionality of the Vulkan and D3D12 backends into RenderingDeviceDriver.

Dario 1 år sedan
förälder
incheckning
73eff10c76
74 ändrade filer med 4857 tillägg och 5746 borttagningar
  1. 2 0
      core/config/project_settings.cpp
  2. 14 0
      doc/classes/ProjectSettings.xml
  3. 2 1
      doc/classes/RenderingDevice.xml
  4. 0 1142
      drivers/d3d12/d3d12_context.cpp
  5. 0 261
      drivers/d3d12/d3d12_context.h
  6. 1 1
      drivers/d3d12/d3d12ma.cpp
  7. 313 0
      drivers/d3d12/rendering_context_driver_d3d12.cpp
  8. 120 0
      drivers/d3d12/rendering_context_driver_d3d12.h
  9. 554 133
      drivers/d3d12/rendering_device_driver_d3d12.cpp
  10. 163 22
      drivers/d3d12/rendering_device_driver_d3d12.h
  11. 0 3
      drivers/gles3/rasterizer_gles3.cpp
  12. 0 1
      drivers/gles3/rasterizer_gles3.h
  13. 686 0
      drivers/vulkan/rendering_context_driver_vulkan.cpp
  14. 161 0
      drivers/vulkan/rendering_context_driver_vulkan.h
  15. 1207 51
      drivers/vulkan/rendering_device_driver_vulkan.cpp
  16. 183 25
      drivers/vulkan/rendering_device_driver_vulkan.h
  17. 0 2915
      drivers/vulkan/vulkan_context.cpp
  18. 0 348
      drivers/vulkan/vulkan_context.h
  19. 15 3
      drivers/vulkan/vulkan_hooks.cpp
  20. 10 4
      drivers/vulkan/vulkan_hooks.h
  21. 7 0
      misc/extension_api_validation/4.2-stable.expected
  22. 7 7
      modules/glslang/register_types.cpp
  23. 52 2
      modules/lightmapper_rd/lightmapper_rd.cpp
  24. 8 12
      modules/openxr/extensions/platform/openxr_vulkan_extension.cpp
  25. 9 7
      modules/openxr/extensions/platform/openxr_vulkan_extension.h
  26. 1 1
      modules/openxr/openxr_platform_inc.h
  27. 1 1
      platform/android/SCsub
  28. 44 32
      platform/android/display_server_android.cpp
  29. 2 2
      platform/android/display_server_android.h
  30. 18 18
      platform/android/rendering_context_driver_vulkan_android.cpp
  31. 13 12
      platform/android/rendering_context_driver_vulkan_android.h
  32. 1 1
      platform/ios/SCsub
  33. 2 2
      platform/ios/display_server_ios.h
  34. 29 25
      platform/ios/display_server_ios.mm
  35. 1 1
      platform/ios/os_ios.h
  36. 12 9
      platform/ios/rendering_context_driver_vulkan_ios.h
  37. 20 14
      platform/ios/rendering_context_driver_vulkan_ios.mm
  38. 1 1
      platform/linuxbsd/wayland/SCsub
  39. 34 27
      platform/linuxbsd/wayland/display_server_wayland.cpp
  40. 2 2
      platform/linuxbsd/wayland/display_server_wayland.h
  41. 25 14
      platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
  42. 14 14
      platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h
  43. 1 1
      platform/linuxbsd/x11/SCsub
  44. 44 29
      platform/linuxbsd/x11/display_server_x11.cpp
  45. 2 2
      platform/linuxbsd/x11/display_server_x11.h
  46. 20 15
      platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
  47. 12 9
      platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h
  48. 1 1
      platform/macos/SCsub
  49. 2 2
      platform/macos/display_server_macos.h
  50. 39 33
      platform/macos/display_server_macos.mm
  51. 12 9
      platform/macos/rendering_context_driver_vulkan_macos.h
  52. 19 14
      platform/macos/rendering_context_driver_vulkan_macos.mm
  53. 1 1
      platform/windows/SCsub
  54. 53 31
      platform/windows/display_server_windows.cpp
  55. 1 8
      platform/windows/display_server_windows.h
  56. 0 7
      platform/windows/os_windows.h
  57. 25 19
      platform/windows/rendering_context_driver_vulkan_windows.cpp
  58. 17 9
      platform/windows/rendering_context_driver_vulkan_windows.h
  59. 0 1
      servers/rendering/dummy/rasterizer_dummy.h
  60. 0 1
      servers/rendering/renderer_compositor.h
  61. 0 82
      servers/rendering/renderer_rd/api_context_rd.h
  62. 9 9
      servers/rendering/renderer_rd/renderer_compositor_rd.cpp
  63. 0 1
      servers/rendering/renderer_rd/renderer_compositor_rd.h
  64. 1 2
      servers/rendering/renderer_rd/shader_rd.cpp
  65. 0 3
      servers/rendering/renderer_viewport.cpp
  66. 85 0
      servers/rendering/rendering_context_driver.cpp
  67. 101 0
      servers/rendering/rendering_context_driver.h
  68. 5 0
      servers/rendering/rendering_device.compat.inc
  69. 475 242
      servers/rendering/rendering_device.cpp
  70. 63 63
      servers/rendering/rendering_device.h
  71. 11 0
      servers/rendering/rendering_device_commons.h
  72. 105 25
      servers/rendering/rendering_device_driver.h
  73. 17 12
      servers/rendering/rendering_device_graph.cpp
  74. 2 1
      servers/rendering/rendering_device_graph.h

+ 2 - 0
core/config/project_settings.cpp

@@ -1470,6 +1470,8 @@ ProjectSettings::ProjectSettings() {
 	GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true);
 	GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true);
 
+	GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/vsync/frame_queue_size", PROPERTY_HINT_RANGE, "2,3,1"), 2);
+	GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/vsync/swapchain_image_count", PROPERTY_HINT_RANGE, "2,4,1"), 3);
 	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
 	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
 	GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);

+ 14 - 0
doc/classes/ProjectSettings.xml

@@ -2698,6 +2698,20 @@
 		</member>
 		<member name="rendering/rendering_device/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
 		</member>
+		<member name="rendering/rendering_device/vsync/frame_queue_size" type="int" setter="" getter="" default="2">
+			The number of frames to track on the CPU side before stalling to wait for the GPU.
+			Try the [url=https://darksylinc.github.io/vsync_simulator/]V-Sync Simulator[/url], an interactive interface that simulates presentation to better understand how it is affected by different variables under various conditions.
+			[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
+		</member>
+		<member name="rendering/rendering_device/vsync/swapchain_image_count" type="int" setter="" getter="" default="3">
+			The number of images the swapchain will consist of (back buffers + front buffer).
+			[code]2[/code] corresponds to double-buffering and [code]3[/code] to triple-buffering.
+			Double-buffering may give you the lowest lag/latency but if V-Sync is on and the system can't render at 60 fps, the framerate will go down in multiples of it (e.g. 30 fps, 15, 7.5, etc.). Triple buffering gives you higher framerate (specially if the system can't reach a constant 60 fps) at the cost of up to 1 frame of latency, with [constant DisplayServer.VSYNC_ENABLED] (FIFO).
+			Use double-buffering with [constant DisplayServer.VSYNC_ENABLED]. Triple-buffering is a must if you plan on using [constant DisplayServer.VSYNC_MAILBOX] mode.
+			Try the [url=https://darksylinc.github.io/vsync_simulator/]V-Sync Simulator[/url], an interactive interface that simulates presentation to better understand how it is affected by different variables under various conditions.
+			[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
+			[b]Note:[/b] Some platforms may restrict the actual value.
+		</member>
 		<member name="rendering/rendering_device/vulkan/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
 		</member>
 		<member name="rendering/scaling_3d/fsr_sharpness" type="float" setter="" getter="" default="0.2">

+ 2 - 1
doc/classes/RenderingDevice.xml

@@ -590,8 +590,9 @@
 		</method>
 		<method name="screen_get_framebuffer_format" qualifiers="const">
 			<return type="int" />
+			<param index="0" name="screen" type="int" default="0" />
 			<description>
-				Returns the screen's framebuffer format.
+				Returns the framebuffer format of the given screen.
 				[b]Note:[/b] Only the main [RenderingDevice] returned by [method RenderingServer.get_rendering_device] has a format. If called on a local [RenderingDevice], this method prints an error and returns [constant INVALID_ID].
 			</description>
 		</method>

+ 0 - 1142
drivers/d3d12/d3d12_context.cpp

@@ -1,1142 +0,0 @@
-/**************************************************************************/
-/*  d3d12_context.cpp                                                     */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "d3d12_context.h"
-
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
-#include "core/string/ustring.h"
-#include "core/templates/local_vector.h"
-#include "core/version.h"
-#include "servers/rendering/rendering_device.h"
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wswitch"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-
-#include "dxcapi.h"
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-#if !defined(_MSC_VER)
-#include <guiddef.h>
-
-#include <dxguids.h>
-#endif
-
-// Note: symbol is not available in MinGW and old MSVC import libraries.
-const CLSID CLSID_D3D12DeviceFactoryGodot = __uuidof(ID3D12DeviceFactory);
-const CLSID CLSID_D3D12DebugGodot = __uuidof(ID3D12Debug);
-const CLSID CLSID_D3D12SDKConfigurationGodot = __uuidof(ID3D12SDKConfiguration);
-
-extern "C" {
-char godot_nir_arch_name[32];
-}
-
-#ifdef PIX_ENABLED
-#if defined(__GNUC__)
-#define _MSC_VER 1800
-#endif
-#define USE_PIX
-#include "WinPixEventRuntime/pix3.h"
-#if defined(__GNUC__)
-#undef _MSC_VER
-#endif
-#endif
-
-#define D3D12_DEBUG_LAYER_BREAK_ON_ERROR 0
-
-void D3D12Context::_debug_message_func(
-		D3D12_MESSAGE_CATEGORY p_category,
-		D3D12_MESSAGE_SEVERITY p_severity,
-		D3D12_MESSAGE_ID p_id,
-		LPCSTR p_description,
-		void *p_context) {
-	String type_string;
-	switch (p_category) {
-		case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED:
-			type_string = "APPLICATION_DEFINED";
-			break;
-		case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS:
-			type_string = "MISCELLANEOUS";
-			break;
-		case D3D12_MESSAGE_CATEGORY_INITIALIZATION:
-			type_string = "INITIALIZATION";
-			break;
-		case D3D12_MESSAGE_CATEGORY_CLEANUP:
-			type_string = "CLEANUP";
-			break;
-		case D3D12_MESSAGE_CATEGORY_COMPILATION:
-			type_string = "COMPILATION";
-			break;
-		case D3D12_MESSAGE_CATEGORY_STATE_CREATION:
-			type_string = "STATE_CREATION";
-			break;
-		case D3D12_MESSAGE_CATEGORY_STATE_SETTING:
-			type_string = "STATE_SETTING";
-			break;
-		case D3D12_MESSAGE_CATEGORY_STATE_GETTING:
-			type_string = "STATE_GETTING";
-			break;
-		case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION:
-			type_string = "RESOURCE_MANIPULATION";
-			break;
-		case D3D12_MESSAGE_CATEGORY_EXECUTION:
-			type_string = "EXECUTION";
-			break;
-		case D3D12_MESSAGE_CATEGORY_SHADER:
-			type_string = "SHADER";
-			break;
-	}
-
-	String error_message(type_string +
-			" - Message Id Number: " + String::num_int64(p_id) +
-			"\n\t" + p_description);
-
-	// Convert D3D12 severity to our own log macros.
-	switch (p_severity) {
-		case D3D12_MESSAGE_SEVERITY_MESSAGE:
-			print_verbose(error_message);
-			break;
-		case D3D12_MESSAGE_SEVERITY_INFO:
-			print_line(error_message);
-			break;
-		case D3D12_MESSAGE_SEVERITY_WARNING:
-			WARN_PRINT(error_message);
-			break;
-		case D3D12_MESSAGE_SEVERITY_ERROR:
-		case D3D12_MESSAGE_SEVERITY_CORRUPTION:
-			ERR_PRINT(error_message);
-			CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),
-					"Crashing, because abort on GPU errors is enabled.");
-			break;
-	}
-}
-
-uint32_t D3D12Context::SubgroupCapabilities::supported_stages_flags_rd() const {
-	// If there's a way to check exactly which are supported, I have yet to find it.
-	return (
-			RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT |
-			RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT);
-}
-
-uint32_t D3D12Context::SubgroupCapabilities::supported_operations_flags_rd() const {
-	if (!wave_ops_supported) {
-		return 0;
-	} else {
-		return (
-				RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT |
-				RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT);
-	}
-}
-
-Error D3D12Context::_check_capabilities() {
-	// Assume not supported until proven otherwise.
-	vrs_capabilities.draw_call_supported = false;
-	vrs_capabilities.primitive_supported = false;
-	vrs_capabilities.primitive_in_multiviewport = false;
-	vrs_capabilities.ss_image_supported = false;
-	vrs_capabilities.ss_image_tile_size = 1;
-	vrs_capabilities.additional_rates_supported = false;
-	multiview_capabilities.is_supported = false;
-	multiview_capabilities.geometry_shader_is_supported = false;
-	multiview_capabilities.tessellation_shader_is_supported = false;
-	multiview_capabilities.max_view_count = 0;
-	multiview_capabilities.max_instance_count = 0;
-	multiview_capabilities.is_supported = false;
-	subgroup_capabilities.size = 0;
-	subgroup_capabilities.wave_ops_supported = false;
-	shader_capabilities.shader_model = D3D_SHADER_MODEL_6_0;
-	shader_capabilities.native_16bit_ops = false;
-	storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false;
-	format_capabilities.relaxed_casting_supported = false;
-
-	{
-		D3D12_FEATURE_DATA_SHADER_MODEL shader_model = {};
-		shader_model.HighestShaderModel = MIN(D3D_HIGHEST_SHADER_MODEL, D3D_SHADER_MODEL_6_6);
-		HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model));
-		ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-		shader_capabilities.shader_model = shader_model.HighestShaderModel;
-	}
-	print_verbose("- Shader:");
-	print_verbose("  model: " + itos(shader_capabilities.shader_model >> 4) + "." + itos(shader_capabilities.shader_model & 0xf));
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
-	HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
-	if (SUCCEEDED(res)) {
-		storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = options.TypedUAVLoadAdditionalFormats;
-	}
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1 = {};
-	res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1));
-	if (SUCCEEDED(res)) {
-		subgroup_capabilities.size = options1.WaveLaneCountMin;
-		subgroup_capabilities.wave_ops_supported = options1.WaveOps;
-	}
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
-	res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));
-	if (SUCCEEDED(res)) {
-		// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_view_instancing_tier
-		// https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#sv_viewid
-		if (options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_1) {
-			multiview_capabilities.is_supported = true;
-			multiview_capabilities.geometry_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
-			multiview_capabilities.tessellation_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
-			multiview_capabilities.max_view_count = D3D12_MAX_VIEW_INSTANCE_COUNT;
-			multiview_capabilities.max_instance_count = UINT32_MAX;
-		}
-	}
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};
-	res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4));
-	if (SUCCEEDED(res)) {
-		shader_capabilities.native_16bit_ops = options4.Native16BitShaderOpsSupported;
-	}
-	print_verbose(String("  16-bit ops supported: ") + (shader_capabilities.native_16bit_ops ? "yes" : "no"));
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
-	res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6));
-	if (SUCCEEDED(res)) {
-		if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1) {
-			vrs_capabilities.draw_call_supported = true;
-			if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2) {
-				vrs_capabilities.primitive_supported = true;
-				vrs_capabilities.primitive_in_multiviewport = options6.PerPrimitiveShadingRateSupportedWithViewportIndexing;
-				vrs_capabilities.ss_image_supported = true;
-				vrs_capabilities.ss_image_tile_size = options6.ShadingRateImageTileSize;
-				vrs_capabilities.additional_rates_supported = options6.AdditionalShadingRatesSupported;
-			}
-		}
-	}
-
-	D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {};
-	res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &options12, sizeof(options12));
-	if (SUCCEEDED(res)) {
-		format_capabilities.relaxed_casting_supported = options12.RelaxedFormatCastingSupported;
-	}
-
-	if (vrs_capabilities.draw_call_supported || vrs_capabilities.primitive_supported || vrs_capabilities.ss_image_supported) {
-		print_verbose("- D3D12 Variable Rate Shading supported:");
-		if (vrs_capabilities.draw_call_supported) {
-			print_verbose("  Draw call");
-		}
-		if (vrs_capabilities.primitive_supported) {
-			print_verbose(String("  Per-primitive (multi-viewport: ") + (vrs_capabilities.primitive_in_multiviewport ? "yes" : "no") + ")");
-		}
-		if (vrs_capabilities.ss_image_supported) {
-			print_verbose(String("  Screen-space image (tile size: ") + itos(vrs_capabilities.ss_image_tile_size) + ")");
-		}
-		if (vrs_capabilities.additional_rates_supported) {
-			print_verbose(String("  Additional rates: ") + (vrs_capabilities.additional_rates_supported ? "yes" : "no"));
-		}
-	} else {
-		print_verbose("- D3D12 Variable Rate Shading not supported");
-	}
-
-	if (multiview_capabilities.is_supported) {
-		print_verbose("- D3D12 multiview supported:");
-		print_verbose("  max view count: " + itos(multiview_capabilities.max_view_count));
-		//print_verbose("  max instances: " + itos(multiview_capabilities.max_instance_count)); // Hardcoded; not very useful at the moment.
-	} else {
-		print_verbose("- D3D12 multiview not supported");
-	}
-
-	if (format_capabilities.relaxed_casting_supported) {
-		print_verbose("- Relaxed casting supported");
-	} else {
-		print_verbose("- Relaxed casting not supported");
-	}
-
-	return OK;
-}
-
-Error D3D12Context::_initialize_debug_layers() {
-	ComPtr<ID3D12Debug> debug_controller;
-	HRESULT res;
-	if (device_factory) {
-		res = device_factory->GetConfigurationInterface(CLSID_D3D12DebugGodot, IID_PPV_ARGS(&debug_controller));
-	} else {
-		res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller));
-	}
-	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED);
-	debug_controller->EnableDebugLayer();
-	return OK;
-}
-
-Error D3D12Context::_select_adapter(int &r_index) {
-	{
-		UINT flags = _use_validation_layers() ? DXGI_CREATE_FACTORY_DEBUG : 0;
-		HRESULT res = CreateDXGIFactory2(flags, IID_PPV_ARGS(&dxgi_factory));
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-	}
-
-	ComPtr<IDXGIFactory6> factory6;
-	dxgi_factory.As(&factory6);
-
-	// TODO: Use IDXCoreAdapterList, which gives more comprehensive information.
-	LocalVector<IDXGIAdapter1 *> adapters;
-	while (true) {
-		IDXGIAdapter1 *curr_adapter = nullptr;
-		if (factory6) {
-			if (factory6->EnumAdapterByGpuPreference(adapters.size(), DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&curr_adapter)) == DXGI_ERROR_NOT_FOUND) {
-				break;
-			}
-		} else {
-			if (dxgi_factory->EnumAdapters1(adapters.size(), &curr_adapter) == DXGI_ERROR_NOT_FOUND) {
-				break;
-			}
-		}
-		adapters.push_back(curr_adapter);
-	}
-
-	ERR_FAIL_COND_V_MSG(adapters.is_empty(), ERR_CANT_CREATE, "Adapters enumeration reported zero accessible devices.");
-
-	// The device should really be a preference, but for now choosing a discrete GPU over the
-	// integrated one is better than the default.
-
-	int32_t adapter_index = -1;
-	int type_selected = -1;
-	LocalVector<RenderingDevice::DeviceType> adapter_types;
-	print_verbose("D3D12 devices:");
-	for (uint32_t i = 0; i < adapters.size(); ++i) {
-		DXGI_ADAPTER_DESC1 desc = {};
-		adapters[i]->GetDesc1(&desc);
-
-		String name = desc.Description;
-		String dev_type;
-		RenderingDevice::DeviceType type = {};
-		if (((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE))) {
-			type = RenderingDevice::DEVICE_TYPE_CPU;
-		} else {
-			type = desc.DedicatedVideoMemory ? RenderingDevice::DEVICE_TYPE_DISCRETE_GPU : RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU;
-		}
-		adapter_types.push_back(type);
-
-		switch (type) {
-			case RenderingDevice::DEVICE_TYPE_DISCRETE_GPU: {
-				dev_type = "Discrete";
-			} break;
-			case RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU: {
-				dev_type = "Integrated";
-			} break;
-			case RenderingDevice::DEVICE_TYPE_VIRTUAL_GPU: {
-				dev_type = "Virtual";
-			} break;
-			case RenderingDevice::DEVICE_TYPE_CPU: {
-				dev_type = "CPU";
-			} break;
-			default: {
-				dev_type = "Other";
-			} break;
-		}
-		print_verbose("  #" + itos(i) + ": " + name + ", " + dev_type);
-
-		switch (type) {
-			case RenderingDevice::DEVICE_TYPE_DISCRETE_GPU: {
-				if (type_selected < 4) {
-					type_selected = 4;
-					adapter_index = i;
-				}
-			} break;
-			case RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU: {
-				if (type_selected < 3) {
-					type_selected = 3;
-					adapter_index = i;
-				}
-			} break;
-			case RenderingDevice::DEVICE_TYPE_VIRTUAL_GPU: {
-				if (type_selected < 2) {
-					type_selected = 2;
-					adapter_index = i;
-				}
-			} break;
-			case RenderingDevice::DEVICE_TYPE_CPU: {
-				if (type_selected < 1) {
-					type_selected = 1;
-					adapter_index = i;
-				}
-			} break;
-			default: {
-				if (type_selected < 0) {
-					type_selected = 0;
-					adapter_index = i;
-				}
-			} break;
-		}
-	}
-
-	int32_t user_adapter_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
-	if (user_adapter_index >= 0 && user_adapter_index < (int32_t)adapters.size()) {
-		adapter_index = user_adapter_index;
-	}
-
-	ERR_FAIL_COND_V_MSG(adapter_index == -1, ERR_CANT_CREATE, "None of D3D12 devices supports hardware rendering.");
-
-	gpu = adapters[adapter_index];
-	for (uint32_t i = 0; i < adapters.size(); ++i) {
-		adapters[i]->Release();
-	}
-
-	adapter_type = adapter_types[adapter_index];
-
-	ComPtr<IDXGIFactory5> factory5;
-	dxgi_factory.As(&factory5);
-	if (factory5) {
-		BOOL result = FALSE; // sizeof(bool) != sizeof(BOOL), in general.
-		HRESULT res = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &result, sizeof(result));
-		if (SUCCEEDED(res)) {
-			tearing_supported = result;
-		} else {
-			ERR_PRINT("CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-		}
-	}
-
-	r_index = adapter_index;
-
-	return OK;
-}
-
-void D3D12Context::_dump_adapter_info(int p_index) {
-	{
-		const D3D_FEATURE_LEVEL FEATURE_LEVELS[] = {
-			D3D_FEATURE_LEVEL_11_0,
-			D3D_FEATURE_LEVEL_11_1,
-			D3D_FEATURE_LEVEL_12_0,
-			D3D_FEATURE_LEVEL_12_1,
-			D3D_FEATURE_LEVEL_12_2,
-		};
-
-		D3D12_FEATURE_DATA_FEATURE_LEVELS feat_levels = {};
-		feat_levels.NumFeatureLevels = ARRAY_SIZE(FEATURE_LEVELS);
-		feat_levels.pFeatureLevelsRequested = FEATURE_LEVELS;
-
-		HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feat_levels, sizeof(feat_levels));
-		ERR_FAIL_COND_MSG(!SUCCEEDED(res), "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-
-		// Example: D3D_FEATURE_LEVEL_12_1 = 0xc100.
-		uint32_t feat_level_major = feat_levels.MaxSupportedFeatureLevel >> 12;
-		uint32_t feat_level_minor = (feat_levels.MaxSupportedFeatureLevel >> 16) & 0xff;
-		feature_level = feat_level_major * 10 + feat_level_minor;
-	}
-
-	String rendering_method;
-	if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
-		rendering_method = "Forward Mobile";
-	} else {
-		rendering_method = "Forward+";
-	}
-
-	static const struct {
-		uint32_t id;
-		const char *name;
-	} vendor_names[] = {
-		{ 0x1002, "AMD" },
-		{ 0x1010, "ImgTec" },
-		{ 0x106B, "Apple" },
-		{ 0x10DE, "NVIDIA" },
-		{ 0x13B5, "ARM" },
-		{ 0x1414, "Microsoft" },
-		{ 0x5143, "Qualcomm" },
-		{ 0x8086, "Intel" },
-		{ 0, nullptr },
-	};
-
-	DXGI_ADAPTER_DESC gpu_desc = {};
-	gpu->GetDesc(&gpu_desc);
-
-	adapter_name = gpu_desc.Description;
-	pipeline_cache_id = String::hex_encode_buffer((uint8_t *)&gpu_desc.AdapterLuid, sizeof(LUID));
-	pipeline_cache_id += "-driver-" + itos(gpu_desc.Revision);
-	{
-		adapter_vendor = "Unknown";
-		uint32_t vendor_idx = 0;
-		while (vendor_names[vendor_idx].name != nullptr) {
-			if (gpu_desc.VendorId == vendor_names[vendor_idx].id) {
-				adapter_vendor = vendor_names[vendor_idx].name;
-				break;
-			}
-			vendor_idx++;
-		}
-	}
-
-	print_line(vformat("D3D12 feature level %s - %s - Using D3D12 Adapter #%d: %s", get_device_api_version(), rendering_method, p_index, adapter_name));
-}
-
-Error D3D12Context::_create_device(DeviceBasics &r_basics) {
-	HRESULT res;
-	if (device_factory) {
-		res = device_factory->CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf()));
-	} else {
-		res = D3D12CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf()));
-	}
-	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-
-	// Create direct command queue.
-	D3D12_COMMAND_QUEUE_DESC queue_desc = {};
-	queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
-	queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
-	res = r_basics.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(r_basics.queue.GetAddressOf()));
-	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-
-	// Create sync objects.
-	res = r_basics.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(r_basics.fence.GetAddressOf()));
-	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-	r_basics.fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
-	ERR_FAIL_NULL_V(r_basics.fence_event, ERR_CANT_CREATE);
-
-	if (_use_validation_layers()) {
-		ComPtr<ID3D12InfoQueue> info_queue;
-		res = r_basics.device.As(&info_queue);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-
-		ComPtr<ID3D12InfoQueue1> info_queue_1;
-		r_basics.device.As(&info_queue_1);
-		if (info_queue_1) {
-			// Custom printing supported (added in Windows 10 Release Preview build 20236).
-
-			info_queue_1->SetMuteDebugOutput(TRUE);
-
-			res = info_queue_1->RegisterMessageCallback(&_debug_message_func, D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS, nullptr, 0);
-			ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-		} else {
-			// Rely on D3D12's own debug printing.
-
-			if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) {
-				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
-				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
-				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-				res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
-				ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-			}
-		}
-		D3D12_MESSAGE_SEVERITY severities_to_mute[] = {
-			D3D12_MESSAGE_SEVERITY_INFO,
-		};
-
-		D3D12_MESSAGE_ID messages_to_mute[] = {
-			D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
-			D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
-			// These happen due to how D3D12MA manages buffers; seem bening.
-			D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE,
-			D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS,
-		};
-
-		D3D12_INFO_QUEUE_FILTER filter = {};
-		filter.DenyList.NumSeverities = ARRAY_SIZE(severities_to_mute);
-		filter.DenyList.pSeverityList = severities_to_mute;
-		filter.DenyList.NumIDs = ARRAY_SIZE(messages_to_mute);
-		filter.DenyList.pIDList = messages_to_mute;
-
-		res = info_queue->PushStorageFilter(&filter);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-
-#if D3D12_DEBUG_LAYER_BREAK_ON_ERROR
-		res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-#endif
-	}
-
-	return OK;
-}
-
-Error D3D12Context::_get_device_limits() {
-	D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
-	HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
-	ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-
-	// https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
-	gpu_limits.max_srvs_per_shader_stage = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 128 : UINT64_MAX;
-	gpu_limits.max_cbvs_per_shader_stage = options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ? 14 : UINT64_MAX;
-	gpu_limits.max_samplers_across_all_stages = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 16 : 2048;
-	if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) {
-		gpu_limits.max_uavs_across_all_stages = feature_level <= 110 ? 8 : 64;
-	} else if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_2) {
-		gpu_limits.max_uavs_across_all_stages = 64;
-	} else {
-		gpu_limits.max_uavs_across_all_stages = UINT64_MAX;
-	}
-
-	md.queue->GetTimestampFrequency(&gpu_limits.timestamp_frequency);
-
-	return OK;
-}
-
-bool D3D12Context::_use_validation_layers() {
-	return Engine::get_singleton()->is_validation_layers_enabled();
-}
-
-Error D3D12Context::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
-
-	Window window;
-	window.hwnd = ((const WindowPlatformData *)p_platform_data)->window;
-	window.width = p_width;
-	window.height = p_height;
-	window.vsync_mode = p_vsync_mode;
-
-	{
-		RDD::Attachment attachment;
-		attachment.samples = RD::TEXTURE_SAMPLES_1;
-		attachment.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
-		attachment.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
-		window.render_pass.attachments.push_back(attachment);
-
-		RDD::Subpass subpass;
-		{
-			RDD::AttachmentReference color_ref;
-			color_ref.attachment = 0;
-			color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
-			subpass.color_references.push_back(color_ref);
-		}
-		window.render_pass.subpasses.push_back(subpass);
-	}
-
-	for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
-		Error err = window.framebuffers[i].rtv_heap.allocate(md.device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1, false);
-		ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-		window.framebuffers[i].is_screen = true;
-		window.framebuffers[i].attachments_handle_inds.push_back(0);
-	}
-
-	Error err = _update_swap_chain(&window);
-	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-
-	windows[p_window_id] = window;
-
-	return OK;
-}
-
-void D3D12Context::window_resize(DisplayServer::WindowID p_window, int p_width, int p_height) {
-	ERR_FAIL_COND(!windows.has(p_window));
-	windows[p_window].width = p_width;
-	windows[p_window].height = p_height;
-	_update_swap_chain(&windows[p_window]);
-}
-
-int D3D12Context::window_get_width(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), -1);
-	return windows[p_window].width;
-}
-
-int D3D12Context::window_get_height(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), -1);
-	return windows[p_window].height;
-}
-
-bool D3D12Context::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), false);
-	Window *w = &windows[p_window];
-	return (bool)w->swapchain;
-}
-
-RDD::RenderPassID D3D12Context::window_get_render_pass(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), RDD::RenderPassID());
-	Window *w = &windows[p_window];
-	return RDD::RenderPassID(&w->render_pass);
-}
-
-RDD::FramebufferID D3D12Context::window_get_framebuffer(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), RDD::FramebufferID());
-	ERR_FAIL_COND_V(!buffers_prepared, RDD::FramebufferID());
-	Window *w = &windows[p_window];
-	if (w->swapchain) {
-		return RDD::FramebufferID(&w->framebuffers[w->current_buffer]);
-	} else {
-		return RDD::FramebufferID();
-	}
-}
-
-void D3D12Context::window_destroy(DisplayServer::WindowID p_window_id) {
-	ERR_FAIL_COND(!windows.has(p_window_id));
-	_wait_for_idle_queue(md.queue.Get());
-	windows.erase(p_window_id);
-}
-
-Error D3D12Context::_update_swap_chain(Window *window) {
-	if (window->width == 0 || window->height == 0) {
-		// Likely window minimized, no swapchain created.
-		return ERR_SKIP;
-	}
-
-	DisplayServer::VSyncMode curr_vsync_mode = window->vsync_mode;
-	bool vsync_mode_available = false;
-	UINT swapchain_flags = 0;
-	do {
-		switch (window->vsync_mode) {
-			case DisplayServer::VSYNC_MAILBOX: {
-				window->sync_interval = 1;
-				window->present_flags = DXGI_PRESENT_RESTART;
-				swapchain_flags = 0;
-				vsync_mode_available = true;
-			} break;
-			case DisplayServer::VSYNC_ADAPTIVE: {
-				vsync_mode_available = false; // I don't know how to set this up.
-			} break;
-			case DisplayServer::VSYNC_ENABLED: {
-				window->sync_interval = 1;
-				window->present_flags = 0;
-				swapchain_flags = 0;
-				vsync_mode_available = true;
-			} break;
-			case DisplayServer::VSYNC_DISABLED: {
-				window->sync_interval = 0;
-				window->present_flags = tearing_supported ? DXGI_PRESENT_ALLOW_TEARING : 0;
-				swapchain_flags = tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
-				vsync_mode_available = true;
-			} break;
-		}
-
-		// Set the windows swap effect if it is available, otherwise FLIP_DISCARD is used.
-		if (vsync_mode_available) {
-			if (window->vsync_mode != curr_vsync_mode || !window->swapchain) {
-				window->vsync_mode = curr_vsync_mode;
-				print_verbose("Using swapchain flags: " + itos(swapchain_flags) + ", sync interval: " + itos(window->sync_interval) + ", present flags: " + itos(window->present_flags));
-			}
-		} else {
-			String present_mode_string;
-			switch (window->vsync_mode) {
-				case DisplayServer::VSYNC_MAILBOX:
-					present_mode_string = "Mailbox";
-					break;
-				case DisplayServer::VSYNC_ADAPTIVE:
-					present_mode_string = "Adaptive";
-					break;
-				case DisplayServer::VSYNC_ENABLED:
-					present_mode_string = "Enabled";
-					break;
-				case DisplayServer::VSYNC_DISABLED:
-					present_mode_string = "Disabled";
-					break;
-			}
-			WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
-			window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
-		}
-	} while (!vsync_mode_available);
-
-	if (window->swapchain) {
-		_wait_for_idle_queue(md.queue.Get());
-		for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
-			window->render_targets[i].Reset();
-		}
-
-		// D3D12 docs: "IDXGISwapChain::ResizeBuffers can't be used to add or remove this flag."
-		bool allow_tearing_flag_changed = (swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) != (window->swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
-		if (allow_tearing_flag_changed) {
-			window->swapchain.Reset();
-		}
-	}
-
-	if (!window->swapchain) {
-		DXGI_SWAP_CHAIN_DESC1 swapchain_desc = {};
-		swapchain_desc.BufferCount = IMAGE_COUNT;
-		swapchain_desc.Width = 0;
-		swapchain_desc.Height = 0;
-		swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
-		swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
-		swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
-		swapchain_desc.SampleDesc.Count = 1;
-		swapchain_desc.Flags = swapchain_flags;
-		swapchain_desc.Scaling = DXGI_SCALING_NONE;
-
-		ComPtr<IDXGISwapChain1> swapchain;
-		HRESULT res = dxgi_factory->CreateSwapChainForHwnd(md.queue.Get(), window->hwnd, &swapchain_desc, nullptr, nullptr, swapchain.GetAddressOf());
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-		swapchain.As(&window->swapchain);
-		ERR_FAIL_NULL_V(window->swapchain, ERR_CANT_CREATE);
-
-		format = swapchain_desc.Format;
-
-		res = dxgi_factory->MakeWindowAssociation(window->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-
-		res = window->swapchain->GetDesc1(&swapchain_desc);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-		ERR_FAIL_COND_V(swapchain_desc.BufferCount != IMAGE_COUNT, ERR_BUG);
-		window->width = swapchain_desc.Width;
-		window->height = swapchain_desc.Height;
-
-	} else {
-		HRESULT res = window->swapchain->ResizeBuffers(IMAGE_COUNT, window->width, window->height, DXGI_FORMAT_UNKNOWN, swapchain_flags);
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);
-	}
-
-	window->swapchain_flags = swapchain_flags;
-	window->current_buffer = window->swapchain->GetCurrentBackBufferIndex();
-
-	for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
-		RenderingDeviceDriverD3D12::FramebufferInfo *fb_info = &window->framebuffers[i];
-		RenderingDeviceDriverD3D12::DescriptorsHeap::Walker walker = fb_info->rtv_heap.make_walker();
-
-		HRESULT res = window->swapchain->GetBuffer(i, IID_PPV_ARGS(&window->render_targets[i]));
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-
-		md.device->CreateRenderTargetView(window->render_targets[i].Get(), nullptr, walker.get_curr_cpu_handle());
-	}
-
-	return OK;
-}
-
-void D3D12Context::_init_device_factory() {
-	uint32_t agility_sdk_version = GLOBAL_GET("rendering/rendering_device/d3d12/agility_sdk_version");
-	String agility_sdk_path = String(".\\") + Engine::get_singleton()->get_architecture_name();
-
-	// Note: symbol is not available in MinGW import library.
-	PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(LoadLibraryW(L"D3D12.dll"), "D3D12GetInterface");
-	ERR_FAIL_COND(!d3d_D3D12GetInterface);
-
-	ID3D12SDKConfiguration *sdk_config = nullptr;
-	if (SUCCEEDED(d3d_D3D12GetInterface(CLSID_D3D12SDKConfigurationGodot, IID_PPV_ARGS(&sdk_config)))) {
-		ID3D12SDKConfiguration1 *sdk_config1 = nullptr;
-		if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) {
-			if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, agility_sdk_path.ascii().get_data(), IID_PPV_ARGS(device_factory.GetAddressOf())))) {
-				d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
-			} else if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, ".\\", IID_PPV_ARGS(device_factory.GetAddressOf())))) {
-				d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
-			}
-			sdk_config1->Release();
-		}
-		sdk_config->Release();
-	}
-}
-
-Error D3D12Context::initialize() {
-	_init_device_factory();
-
-	if (_use_validation_layers()) {
-		Error err = _initialize_debug_layers();
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	}
-
-	int adapter_index = 0;
-
-	Error err = _select_adapter(adapter_index);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	err = _create_device(md);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	_dump_adapter_info(adapter_index);
-
-	err = _check_capabilities();
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	err = _get_device_limits();
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	{
-		HRESULT res = md.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(frame_fence.GetAddressOf()));
-		ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
-		frame_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
-		ERR_FAIL_NULL_V(frame_fence_event, ERR_CANT_CREATE);
-	}
-
-	md.driver = memnew(RenderingDeviceDriverD3D12(this, md.device.Get(), IMAGE_COUNT + 1));
-
-	return OK;
-}
-
-void D3D12Context::set_setup_buffer(RDD::CommandBufferID p_command_buffer) {
-	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
-	command_list_queue[0] = cmd_buf_info->cmd_list.Get();
-}
-
-void D3D12Context::append_command_buffer(RDD::CommandBufferID p_command_buffer) {
-	if (command_list_queue.size() <= command_list_count) {
-		command_list_queue.resize(command_list_count + 1);
-	}
-
-	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
-	command_list_queue[command_list_count] = cmd_buf_info->cmd_list.Get();
-	command_list_count++;
-}
-
-void D3D12Context::_wait_for_idle_queue(ID3D12CommandQueue *p_queue) {
-	md.fence_value++;
-	p_queue->Signal(md.fence.Get(), md.fence_value);
-	md.fence->SetEventOnCompletion(md.fence_value, md.fence_event);
-	WaitForSingleObjectEx(md.fence_event, INFINITE, FALSE);
-#ifdef PIX_ENABLED
-	PIXNotifyWakeFromFenceSignal(md.fence_event);
-#endif
-}
-
-void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) {
-	ERR_FAIL_COND_MSG(!p_sync, "Flush without sync is not supported."); // This is a special case for Vulkan on mobile XR hardware, not applicable to D3D12
-
-	if (p_flush_setup && command_list_queue[0]) {
-		md.queue->ExecuteCommandLists(1, command_list_queue.ptr());
-		command_list_queue[0] = nullptr;
-	}
-
-	if (p_flush_pending && command_list_count > 1) {
-		md.queue->ExecuteCommandLists(command_list_count - 1, command_list_queue.ptr() + 1);
-		command_list_count = 1;
-	}
-
-	if (p_flush_setup || p_flush_pending) {
-		_wait_for_idle_queue(md.queue.Get());
-	}
-}
-
-Error D3D12Context::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
-	// Ensure no more than FRAME_LAG renderings are outstanding.
-	if (frame >= IMAGE_COUNT) {
-		UINT64 min_value = frame - IMAGE_COUNT;
-		if (frame_fence->GetCompletedValue() < min_value) {
-			frame_fence->SetEventOnCompletion(min_value, frame_fence_event);
-			WaitForSingleObjectEx(frame_fence_event, INFINITE, FALSE);
-#ifdef PIX_ENABLED
-			PIXNotifyWakeFromFenceSignal(frame_fence_event);
-#endif
-		}
-	}
-
-	D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
-	uint32_t n = 0;
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-		w->current_buffer = w->swapchain->GetCurrentBackBufferIndex();
-		barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
-	}
-	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
-	cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
-
-	buffers_prepared = true;
-
-	return OK;
-}
-
-void D3D12Context::postpare_buffers(RDD::CommandBufferID p_command_buffer) {
-	D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
-
-	uint32_t n = 0;
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-		barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
-	}
-
-	const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
-	cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
-}
-
-Error D3D12Context::swap_buffers() {
-	ID3D12CommandList *const *commands_ptr = nullptr;
-	UINT commands_to_submit = 0;
-
-	if (command_list_queue[0] == nullptr) {
-		// No setup command, but commands to submit, submit from the first and skip command.
-		if (command_list_count > 1) {
-			commands_ptr = command_list_queue.ptr() + 1;
-			commands_to_submit = command_list_count - 1;
-		}
-	} else {
-		commands_ptr = command_list_queue.ptr();
-		commands_to_submit = command_list_count;
-	}
-
-	md.queue->ExecuteCommandLists(commands_to_submit, commands_ptr);
-
-	command_list_queue[0] = nullptr;
-	command_list_count = 1;
-
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-
-		if (!w->swapchain) {
-			continue;
-		}
-		HRESULT res = w->swapchain->Present(w->sync_interval, w->present_flags);
-		if (!SUCCEEDED(res)) {
-			print_verbose("D3D12: Presenting swapchain of window " + itos(E.key) + " failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
-		}
-	}
-
-	md.queue->Signal(frame_fence.Get(), frame);
-	frame++;
-
-	buffers_prepared = false;
-	return OK;
-}
-
-void D3D12Context::resize_notify() {
-}
-
-RenderingDevice::Capabilities D3D12Context::get_device_capabilities() const {
-	RenderingDevice::Capabilities c;
-	c.device_family = RenderingDevice::DEVICE_DIRECTX;
-	c.version_major = feature_level / 10;
-	c.version_minor = feature_level % 10;
-	return c;
-}
-
-ID3D12Device *D3D12Context::get_device() {
-	return md.device.Get();
-}
-
-IDXGIAdapter *D3D12Context::get_adapter() {
-	return gpu.Get();
-}
-
-int D3D12Context::get_swapchain_image_count() const {
-	return IMAGE_COUNT;
-}
-
-DXGI_FORMAT D3D12Context::get_screen_format() const {
-	return format;
-}
-
-const D3D12Context::DeviceLimits &D3D12Context::get_device_limits() const {
-	return gpu_limits;
-}
-
-RID D3D12Context::local_device_create() {
-	LocalDevice ld;
-	_create_device(ld);
-	ld.driver = memnew(RenderingDeviceDriverD3D12(this, ld.device.Get(), 1));
-	return local_device_owner.make_rid(ld);
-}
-
-void D3D12Context::local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	ERR_FAIL_COND(ld->waiting);
-
-	ld->queue->ExecuteCommandLists(p_count, (ID3D12CommandList *const *)p_buffers);
-
-	ld->waiting = true;
-}
-
-void D3D12Context::local_device_sync(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	ERR_FAIL_COND(!ld->waiting);
-
-	ld->fence_value++;
-	ld->queue->Signal(ld->fence.Get(), ld->fence_value);
-	ld->fence->SetEventOnCompletion(ld->fence_value, ld->fence_event);
-	WaitForSingleObjectEx(ld->fence_event, INFINITE, FALSE);
-#ifdef PIX_ENABLED
-	PIXNotifyWakeFromFenceSignal(ld->fence_event);
-#endif
-
-	ld->waiting = false;
-}
-
-void D3D12Context::local_device_free(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	memdelete(ld->driver);
-	CloseHandle(ld->fence_event);
-	local_device_owner.free(p_local_device);
-}
-
-void D3D12Context::set_object_name(ID3D12Object *p_object, String p_object_name) {
-	ERR_FAIL_NULL(p_object);
-	int name_len = p_object_name.size();
-	WCHAR *name_w = (WCHAR *)alloca(sizeof(WCHAR) * (name_len + 1));
-	MultiByteToWideChar(CP_UTF8, 0, p_object_name.utf8().get_data(), -1, name_w, name_len);
-	p_object->SetName(name_w);
-}
-
-String D3D12Context::get_device_vendor_name() const {
-	return adapter_vendor;
-}
-String D3D12Context::get_device_name() const {
-	return adapter_name;
-}
-
-RenderingDevice::DeviceType D3D12Context::get_device_type() const {
-	return adapter_type;
-}
-
-String D3D12Context::get_device_api_version() const {
-	return vformat("%d_%d", feature_level / 10, feature_level % 10);
-}
-
-String D3D12Context::get_device_pipeline_cache_uuid() const {
-	return pipeline_cache_id;
-}
-
-DisplayServer::VSyncMode D3D12Context::get_vsync_mode(DisplayServer::WindowID p_window) const {
-	ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
-	return windows[p_window].vsync_mode;
-}
-
-void D3D12Context::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
-	ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
-	windows[p_window].vsync_mode = p_mode;
-	_update_swap_chain(&windows[p_window]);
-}
-
-RenderingDeviceDriver *D3D12Context::get_driver(RID p_local_device) {
-	if (p_local_device.is_valid()) {
-		LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-		ERR_FAIL_NULL_V(ld, nullptr);
-		return ld->driver;
-	} else {
-		return md.driver;
-	}
-}
-
-bool D3D12Context::is_debug_utils_enabled() const {
-#ifdef PIX_ENABLED
-	return true;
-#else
-	return false;
-#endif
-}
-
-D3D12Context::D3D12Context() {
-	command_list_queue.resize(1); // First one is always the setup command.
-	command_list_queue[0] = nullptr;
-
-	CharString cs = Engine::get_singleton()->get_architecture_name().ascii();
-	memcpy(godot_nir_arch_name, (const char *)cs.get_data(), cs.size());
-}
-
-D3D12Context::~D3D12Context() {
-	if (md.fence_event) {
-		CloseHandle(md.fence_event);
-	}
-	if (frame_fence_event) {
-		CloseHandle(frame_fence_event);
-	}
-}

+ 0 - 261
drivers/d3d12/d3d12_context.h

@@ -1,261 +0,0 @@
-/**************************************************************************/
-/*  d3d12_context.h                                                       */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#ifndef D3D12_CONTEXT_H
-#define D3D12_CONTEXT_H
-
-#include "core/error/error_list.h"
-#include "core/os/mutex.h"
-#include "core/string/ustring.h"
-#include "core/templates/rid_owner.h"
-#include "rendering_device_driver_d3d12.h"
-#include "servers/display_server.h"
-#include "servers/rendering/renderer_rd/api_context_rd.h"
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wswitch"
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
-#endif
-
-#if defined(AS)
-#undef AS
-#endif
-
-#include "d3dx12.h"
-#include <dxgi1_6.h>
-
-#include <wrl/client.h>
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-using Microsoft::WRL::ComPtr;
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-class D3D12Context : public ApiContextRD {
-public:
-	struct DeviceLimits {
-		uint64_t max_srvs_per_shader_stage;
-		uint64_t max_cbvs_per_shader_stage;
-		uint64_t max_samplers_across_all_stages;
-		uint64_t max_uavs_across_all_stages;
-		uint64_t timestamp_frequency;
-	};
-
-	struct SubgroupCapabilities {
-		uint32_t size;
-		bool wave_ops_supported;
-		uint32_t supported_stages_flags_rd() const;
-		uint32_t supported_operations_flags_rd() const;
-	};
-
-	struct VRSCapabilities {
-		bool draw_call_supported; // We can specify our fragment rate on a draw call level.
-		bool primitive_supported; // We can specify our fragment rate on each drawcall.
-		bool primitive_in_multiviewport;
-		bool ss_image_supported; // We can provide a density map attachment on our framebuffer.
-		uint32_t ss_image_tile_size;
-		bool additional_rates_supported;
-	};
-
-	struct ShaderCapabilities {
-		D3D_SHADER_MODEL shader_model;
-		bool native_16bit_ops;
-	};
-
-	struct StorageBufferCapabilities {
-		bool storage_buffer_16_bit_access_is_supported;
-	};
-
-	struct FormatCapabilities {
-		bool relaxed_casting_supported;
-	};
-
-private:
-	enum {
-		FRAME_LAG = 2,
-		IMAGE_COUNT = FRAME_LAG + 1,
-	};
-
-	ComPtr<ID3D12DeviceFactory> device_factory;
-	ComPtr<IDXGIFactory2> dxgi_factory;
-	ComPtr<IDXGIAdapter> gpu;
-	DeviceLimits gpu_limits = {};
-	struct DeviceBasics {
-		ComPtr<ID3D12Device> device;
-		ComPtr<ID3D12CommandQueue> queue;
-		ComPtr<ID3D12Fence> fence;
-		HANDLE fence_event = nullptr;
-		UINT64 fence_value = 0;
-		RenderingDeviceDriverD3D12 *driver = nullptr;
-	} md; // 'Main device', as opposed to local device.
-
-	uint32_t feature_level = 0; // Major * 10 + minor.
-	bool tearing_supported = false;
-	SubgroupCapabilities subgroup_capabilities;
-	RDD::MultiviewCapabilities multiview_capabilities;
-	VRSCapabilities vrs_capabilities;
-	ShaderCapabilities shader_capabilities;
-	StorageBufferCapabilities storage_buffer_capabilities;
-	FormatCapabilities format_capabilities;
-
-	String adapter_vendor;
-	String adapter_name;
-	RenderingDevice::DeviceType adapter_type = {};
-	String pipeline_cache_id;
-
-	bool buffers_prepared = false;
-
-	DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
-	uint32_t frame = 0;
-	ComPtr<ID3D12Fence> frame_fence;
-	HANDLE frame_fence_event = nullptr;
-
-	struct Window {
-		HWND hwnd = nullptr;
-		ComPtr<IDXGISwapChain3> swapchain;
-		UINT swapchain_flags = 0;
-		UINT sync_interval = 1;
-		UINT present_flags = 0;
-		ComPtr<ID3D12Resource> render_targets[IMAGE_COUNT];
-		uint32_t current_buffer = 0;
-		int width = 0;
-		int height = 0;
-		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
-		RenderingDeviceDriverD3D12::RenderPassInfo render_pass;
-		RenderingDeviceDriverD3D12::FramebufferInfo framebuffers[IMAGE_COUNT];
-	};
-
-	struct LocalDevice : public DeviceBasics {
-		bool waiting = false;
-		HANDLE fence_event = nullptr;
-		UINT64 fence_value = 0;
-	};
-
-	RID_Owner<LocalDevice, true> local_device_owner;
-
-	HashMap<DisplayServer::WindowID, Window> windows;
-
-	// Commands.
-
-	LocalVector<ID3D12CommandList *> command_list_queue;
-	uint32_t command_list_count = 1;
-
-	static void STDMETHODCALLTYPE _debug_message_func(
-			D3D12_MESSAGE_CATEGORY p_category,
-			D3D12_MESSAGE_SEVERITY p_severity,
-			D3D12_MESSAGE_ID p_id,
-			LPCSTR p_description,
-			void *p_context);
-
-	Error _initialize_debug_layers();
-	void _init_device_factory();
-
-	Error _select_adapter(int &r_index);
-	void _dump_adapter_info(int p_index);
-	Error _create_device(DeviceBasics &r_basics);
-	Error _get_device_limits();
-	Error _check_capabilities();
-
-	Error _update_swap_chain(Window *window);
-
-	void _wait_for_idle_queue(ID3D12CommandQueue *p_queue);
-
-protected:
-	virtual bool _use_validation_layers();
-
-public:
-	virtual const char *get_api_name() const override final { return "D3D12"; };
-	virtual RenderingDevice::Capabilities get_device_capabilities() const override final;
-	const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
-	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const override final { return multiview_capabilities; };
-	const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
-	const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
-	const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
-	const FormatCapabilities &get_format_capabilities() const { return format_capabilities; };
-
-	ID3D12Device *get_device();
-	IDXGIAdapter *get_adapter();
-	virtual int get_swapchain_image_count() const override final;
-
-	struct WindowPlatformData {
-		HWND window;
-	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
-	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override final;
-	virtual int window_get_width(DisplayServer::WindowID p_window = 0) override final;
-	virtual int window_get_height(DisplayServer::WindowID p_window = 0) override final;
-	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) override final;
-	virtual void window_destroy(DisplayServer::WindowID p_window_id) override final;
-	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) override final;
-	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) override final;
-
-	virtual RID local_device_create() override final;
-	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) override final;
-	virtual void local_device_sync(RID p_local_device) override final;
-	virtual void local_device_free(RID p_local_device) override final;
-
-	DXGI_FORMAT get_screen_format() const;
-	const DeviceLimits &get_device_limits() const;
-
-	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
-	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
-	void resize_notify();
-	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final;
-	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
-	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
-	virtual Error swap_buffers() override final;
-	virtual Error initialize() override final;
-
-	void set_object_name(ID3D12Object *p_object, String p_object_name);
-
-	virtual String get_device_vendor_name() const override final;
-	virtual String get_device_name() const override final;
-	virtual RDD::DeviceType get_device_type() const override final;
-	virtual String get_device_api_version() const override final;
-	virtual String get_device_pipeline_cache_uuid() const override final;
-
-	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) override final;
-	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
-
-	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
-	virtual bool is_debug_utils_enabled() const override final;
-
-	D3D12Context();
-	virtual ~D3D12Context();
-};
-
-#endif // D3D12_CONTEXT_H

+ 1 - 1
drivers/d3d12/d3d12ma.cpp

@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#include "d3d12_context.h"
+#include "rendering_context_driver_d3d12.h"
 
 #if defined(__GNUC__) && !defined(__clang__)
 #pragma GCC diagnostic push

+ 313 - 0
drivers/d3d12/rendering_context_driver_d3d12.cpp

@@ -0,0 +1,313 @@
+/**************************************************************************/
+/*  rendering_context_driver_d3d12.cpp                                    */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_context_driver_d3d12.h"
+
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/string/ustring.h"
+#include "core/templates/local_vector.h"
+#include "core/version.h"
+#include "servers/rendering/rendering_device.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+#include "dxcapi.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#if !defined(_MSC_VER)
+#include <guiddef.h>
+
+#include <dxguids.h>
+#endif
+
+// Note: symbols are not available in MinGW and old MSVC import libraries.
+const CLSID CLSID_D3D12DeviceFactoryGodot = __uuidof(ID3D12DeviceFactory);
+const CLSID CLSID_D3D12DebugGodot = __uuidof(ID3D12Debug);
+const CLSID CLSID_D3D12SDKConfigurationGodot = __uuidof(ID3D12SDKConfiguration);
+
+extern "C" {
+char godot_nir_arch_name[32];
+}
+
+#ifdef PIX_ENABLED
+#if defined(__GNUC__)
+#define _MSC_VER 1800
+#endif
+#define USE_PIX
+#include "WinPixEventRuntime/pix3.h"
+#if defined(__GNUC__)
+#undef _MSC_VER
+#endif
+#endif
+
+RenderingContextDriverD3D12::RenderingContextDriverD3D12() {
+	CharString cs = Engine::get_singleton()->get_architecture_name().ascii();
+	memcpy(godot_nir_arch_name, (const char *)cs.get_data(), cs.size());
+}
+
+RenderingContextDriverD3D12::~RenderingContextDriverD3D12() {
+}
+
+Error RenderingContextDriverD3D12::_init_device_factory() {
+	uint32_t agility_sdk_version = GLOBAL_GET("rendering/rendering_device/d3d12/agility_sdk_version");
+	String agility_sdk_path = String(".\\") + Engine::get_singleton()->get_architecture_name();
+
+	// Note: symbol is not available in MinGW import library.
+	PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(LoadLibraryW(L"D3D12.dll"), "D3D12GetInterface");
+	if (d3d_D3D12GetInterface == nullptr) {
+		// FIXME: Is it intended for this to silently return when it fails to find the symbol?
+		return OK;
+	}
+
+	ID3D12SDKConfiguration *sdk_config = nullptr;
+	if (SUCCEEDED(d3d_D3D12GetInterface(CLSID_D3D12SDKConfigurationGodot, IID_PPV_ARGS(&sdk_config)))) {
+		ID3D12SDKConfiguration1 *sdk_config1 = nullptr;
+		if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) {
+			if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, agility_sdk_path.ascii().get_data(), IID_PPV_ARGS(device_factory.GetAddressOf())))) {
+				d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
+			} else if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, ".\\", IID_PPV_ARGS(device_factory.GetAddressOf())))) {
+				d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
+			}
+			sdk_config1->Release();
+		}
+		sdk_config->Release();
+	}
+
+	return OK;
+}
+
+Error RenderingContextDriverD3D12::_initialize_debug_layers() {
+	ComPtr<ID3D12Debug> debug_controller;
+	HRESULT res;
+	if (device_factory) {
+		res = device_factory->GetConfigurationInterface(CLSID_D3D12DebugGodot, IID_PPV_ARGS(&debug_controller));
+	} else {
+		res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller));
+	}
+	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED);
+	debug_controller->EnableDebugLayer();
+	return OK;
+}
+
+Error RenderingContextDriverD3D12::_initialize_devices() {
+	const UINT dxgi_factory_flags = use_validation_layers() ? DXGI_CREATE_FACTORY_DEBUG : 0;
+	HRESULT res = CreateDXGIFactory2(dxgi_factory_flags, IID_PPV_ARGS(&dxgi_factory));
+	ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+	// Enumerate all possible adapters.
+	LocalVector<IDXGIAdapter1 *> adapters;
+	IDXGIAdapter1 *adapter = nullptr;
+	do {
+		adapter = create_adapter(adapters.size());
+		if (adapter != nullptr) {
+			adapters.push_back(adapter);
+		}
+	} while (adapter != nullptr);
+
+	ERR_FAIL_COND_V_MSG(adapters.is_empty(), ERR_CANT_CREATE, "Adapters enumeration reported zero accessible devices.");
+
+	// Fill the device descriptions with the adapters.
+	driver_devices.resize(adapters.size());
+	for (uint32_t i = 0; i < adapters.size(); ++i) {
+		DXGI_ADAPTER_DESC1 desc = {};
+		adapters[i]->GetDesc1(&desc);
+
+		Device &device = driver_devices[i];
+		device.name = desc.Description;
+		device.vendor = Vendor(desc.VendorId);
+
+		if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
+			device.type = DEVICE_TYPE_CPU;
+		} else {
+			const bool has_dedicated_vram = desc.DedicatedVideoMemory > 0;
+			device.type = has_dedicated_vram ? DEVICE_TYPE_DISCRETE_GPU : DEVICE_TYPE_INTEGRATED_GPU;
+		}
+	}
+
+	// Release all created adapters.
+	for (uint32_t i = 0; i < adapters.size(); ++i) {
+		adapters[i]->Release();
+	}
+
+	ComPtr<IDXGIFactory5> factory_5;
+	dxgi_factory.As(&factory_5);
+	if (factory_5 != nullptr) {
+		// The type is important as in general, sizeof(bool) != sizeof(BOOL).
+		BOOL feature_supported = FALSE;
+		res = factory_5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &feature_supported, sizeof(feature_supported));
+		if (SUCCEEDED(res)) {
+			tearing_supported = feature_supported;
+		} else {
+			ERR_PRINT("CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+		}
+	}
+
+	return OK;
+}
+
+bool RenderingContextDriverD3D12::use_validation_layers() const {
+	return Engine::get_singleton()->is_validation_layers_enabled();
+}
+
+Error RenderingContextDriverD3D12::initialize() {
+	Error err = _init_device_factory();
+	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+
+	if (use_validation_layers()) {
+		err = _initialize_debug_layers();
+		ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+	}
+
+	err = _initialize_devices();
+	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+
+	return OK;
+}
+
+const RenderingContextDriver::Device &RenderingContextDriverD3D12::device_get(uint32_t p_device_index) const {
+	DEV_ASSERT(p_device_index < driver_devices.size());
+	return driver_devices[p_device_index];
+}
+
+uint32_t RenderingContextDriverD3D12::device_get_count() const {
+	return driver_devices.size();
+}
+
+bool RenderingContextDriverD3D12::device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const {
+	// All devices should support presenting to any surface.
+	return true;
+}
+
+RenderingDeviceDriver *RenderingContextDriverD3D12::driver_create() {
+	return memnew(RenderingDeviceDriverD3D12(this));
+}
+
+void RenderingContextDriverD3D12::driver_free(RenderingDeviceDriver *p_driver) {
+	memdelete(p_driver);
+}
+
+RenderingContextDriver::SurfaceID RenderingContextDriverD3D12::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
+	Surface *surface = memnew(Surface);
+	surface->hwnd = wpd->window;
+	return SurfaceID(surface);
+}
+
+void RenderingContextDriverD3D12::surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->width = p_width;
+	surface->height = p_height;
+	surface->needs_resize = true;
+}
+
+void RenderingContextDriverD3D12::surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->vsync_mode = p_vsync_mode;
+	surface->needs_resize = true;
+}
+
+DisplayServer::VSyncMode RenderingContextDriverD3D12::surface_get_vsync_mode(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->vsync_mode;
+}
+
+uint32_t RenderingContextDriverD3D12::surface_get_width(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->width;
+}
+
+uint32_t RenderingContextDriverD3D12::surface_get_height(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->height;
+}
+
+void RenderingContextDriverD3D12::surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->needs_resize = p_needs_resize;
+}
+
+bool RenderingContextDriverD3D12::surface_get_needs_resize(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->needs_resize;
+}
+
+void RenderingContextDriverD3D12::surface_destroy(SurfaceID p_surface) {
+	Surface *surface = (Surface *)(p_surface);
+	memdelete(surface);
+}
+
+bool RenderingContextDriverD3D12::is_debug_utils_enabled() const {
+#ifdef PIX_ENABLED
+	return true;
+#else
+	return false;
+#endif
+}
+
+IDXGIAdapter1 *RenderingContextDriverD3D12::create_adapter(uint32_t p_adapter_index) const {
+	ComPtr<IDXGIFactory6> factory_6;
+	dxgi_factory.As(&factory_6);
+
+	// TODO: Use IDXCoreAdapterList, which gives more comprehensive information.
+	IDXGIAdapter1 *adapter = nullptr;
+	if (factory_6) {
+		if (factory_6->EnumAdapterByGpuPreference(p_adapter_index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) == DXGI_ERROR_NOT_FOUND) {
+			return nullptr;
+		}
+	} else {
+		if (dxgi_factory->EnumAdapters1(p_adapter_index, &adapter) == DXGI_ERROR_NOT_FOUND) {
+			return nullptr;
+		}
+	}
+
+	return adapter;
+}
+
+ID3D12DeviceFactory *RenderingContextDriverD3D12::device_factory_get() const {
+	return device_factory.Get();
+}
+
+IDXGIFactory2 *RenderingContextDriverD3D12::dxgi_factory_get() const {
+	return dxgi_factory.Get();
+}
+
+bool RenderingContextDriverD3D12::get_tearing_supported() const {
+	return tearing_supported;
+}

+ 120 - 0
drivers/d3d12/rendering_context_driver_d3d12.h

@@ -0,0 +1,120 @@
+/**************************************************************************/
+/*  rendering_context_driver_d3d12.h                                      */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_CONTEXT_DRIVER_D3D12_H
+#define RENDERING_CONTEXT_DRIVER_D3D12_H
+
+#include "core/error/error_list.h"
+#include "core/os/mutex.h"
+#include "core/string/ustring.h"
+#include "core/templates/rid_owner.h"
+#include "rendering_device_driver_d3d12.h"
+#include "servers/display_server.h"
+#include "servers/rendering/rendering_context_driver.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wswitch"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#endif
+
+#if defined(AS)
+#undef AS
+#endif
+
+#include "d3dx12.h"
+#include <dxgi1_6.h>
+
+#include <wrl/client.h>
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+using Microsoft::WRL::ComPtr;
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+class RenderingContextDriverD3D12 : public RenderingContextDriver {
+	ComPtr<ID3D12DeviceFactory> device_factory;
+	ComPtr<IDXGIFactory2> dxgi_factory;
+	TightLocalVector<Device> driver_devices;
+	bool tearing_supported = false;
+
+	Error _init_device_factory();
+	Error _initialize_debug_layers();
+	Error _initialize_devices();
+
+public:
+	virtual Error initialize() override;
+	virtual const Device &device_get(uint32_t p_device_index) const override;
+	virtual uint32_t device_get_count() const override;
+	virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const override;
+	virtual RenderingDeviceDriver *driver_create() override;
+	virtual void driver_free(RenderingDeviceDriver *p_driver) override;
+	virtual SurfaceID surface_create(const void *p_platform_data) override;
+	virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) override;
+	virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) override;
+	virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const override;
+	virtual uint32_t surface_get_width(SurfaceID p_surface) const override;
+	virtual uint32_t surface_get_height(SurfaceID p_surface) const override;
+	virtual void surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) override;
+	virtual bool surface_get_needs_resize(SurfaceID p_surface) const override;
+	virtual void surface_destroy(SurfaceID p_surface) override;
+	virtual bool is_debug_utils_enabled() const override;
+
+	// Platform-specific data for the Windows embedded in this driver.
+	struct WindowPlatformData {
+		HWND window;
+	};
+
+	// D3D12-only methods.
+	struct Surface {
+		HWND hwnd = NULL;
+		uint32_t width = 0;
+		uint32_t height = 0;
+		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
+		bool needs_resize = false;
+	};
+
+	IDXGIAdapter1 *create_adapter(uint32_t p_adapter_index) const;
+	ID3D12DeviceFactory *device_factory_get() const;
+	IDXGIFactory2 *dxgi_factory_get() const;
+	bool get_tearing_supported() const;
+	bool use_validation_layers() const;
+
+	RenderingContextDriverD3D12();
+	virtual ~RenderingContextDriverD3D12() override;
+};
+
+#endif // RENDERING_CONTEXT_DRIVER_D3D12_H

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 554 - 133
drivers/d3d12/rendering_device_driver_d3d12.cpp


+ 163 - 22
drivers/d3d12/rendering_device_driver_d3d12.h

@@ -65,14 +65,11 @@ using Microsoft::WRL::ComPtr;
 #define D3D12_BITCODE_OFFSETS_NUM_STAGES 3
 
 struct dxil_validator;
-
-class D3D12Context;
+class RenderingContextDriverD3D12;
 
 // Design principles:
 // - D3D12 structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply).
 class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
-	friend class D3D12Context; // For FramebufferInfo, RenderPassInfo and CommandBufferInfo.
-
 	/*****************/
 	/**** GENERIC ****/
 	/*****************/
@@ -86,8 +83,58 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
 
 	static const D3D12Format RD_TO_D3D12_FORMAT[RDD::DATA_FORMAT_MAX];
 
-	D3D12Context *context = nullptr;
-	ID3D12Device *device = nullptr; // Owned by the context.
+	struct DeviceLimits {
+		uint64_t max_srvs_per_shader_stage = 0;
+		uint64_t max_cbvs_per_shader_stage = 0;
+		uint64_t max_samplers_across_all_stages = 0;
+		uint64_t max_uavs_across_all_stages = 0;
+		uint64_t timestamp_frequency = 0;
+	};
+
+	struct SubgroupCapabilities {
+		uint32_t size = 0;
+		bool wave_ops_supported = false;
+		uint32_t supported_stages_flags_rd() const;
+		uint32_t supported_operations_flags_rd() const;
+	};
+
+	struct VRSCapabilities {
+		bool draw_call_supported = false; // We can specify our fragment rate on a draw call level.
+		bool primitive_supported = false; // We can specify our fragment rate on each drawcall.
+		bool primitive_in_multiviewport = false;
+		bool ss_image_supported = false; // We can provide a density map attachment on our framebuffer.
+		uint32_t ss_image_tile_size = 0;
+		bool additional_rates_supported = false;
+	};
+
+	struct ShaderCapabilities {
+		D3D_SHADER_MODEL shader_model = (D3D_SHADER_MODEL)0;
+		bool native_16bit_ops = false;
+	};
+
+	struct StorageBufferCapabilities {
+		bool storage_buffer_16_bit_access_is_supported = false;
+	};
+
+	struct FormatCapabilities {
+		bool relaxed_casting_supported = false;
+	};
+
+	RenderingContextDriverD3D12 *context_driver = nullptr;
+	RenderingContextDriver::Device context_device;
+	ComPtr<IDXGIAdapter> adapter;
+	DXGI_ADAPTER_DESC adapter_desc;
+	ComPtr<ID3D12Device> device;
+	DeviceLimits device_limits;
+	RDD::Capabilities device_capabilities;
+	uint32_t feature_level = 0; // Major * 10 + minor.
+	SubgroupCapabilities subgroup_capabilities;
+	RDD::MultiviewCapabilities multiview_capabilities;
+	VRSCapabilities vrs_capabilities;
+	ShaderCapabilities shader_capabilities;
+	StorageBufferCapabilities storage_buffer_capabilities;
+	FormatCapabilities format_capabilities;
+	String pipeline_cache_id;
 
 	class DescriptorsHeap {
 		D3D12_DESCRIPTOR_HEAP_DESC desc = {};
@@ -127,6 +174,19 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
 		ComPtr<ID3D12CommandSignature> dispatch;
 	} indirect_cmd_signatures;
 
+	static void STDMETHODCALLTYPE _debug_message_func(D3D12_MESSAGE_CATEGORY p_category, D3D12_MESSAGE_SEVERITY p_severity, D3D12_MESSAGE_ID p_id, LPCSTR p_description, void *p_context);
+	void _set_object_name(ID3D12Object *p_object, String p_object_name);
+	Error _initialize_device();
+	Error _check_capabilities();
+	Error _get_device_limits();
+	Error _initialize_allocator();
+	Error _initialize_frames(uint32_t p_frame_count);
+	Error _initialize_command_signatures();
+
+public:
+	Error initialize(uint32_t p_device_index, uint32_t p_frame_count) override final;
+
+private:
 	/****************/
 	/**** MEMORY ****/
 	/****************/
@@ -183,7 +243,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
 			uint64_t subres_mask[MAX_SUBRESOURCES / 64] = {};
 		} groups[MAX_GROUPS];
 		uint8_t groups_count = 0;
-		static const D3D12_RESOURCE_STATES DELETED_GROUP = D3D12_RESOURCE_STATE_COMMON;
+		static const D3D12_RESOURCE_STATES DELETED_GROUP = D3D12_RESOURCE_STATES(0xFFFFFFFFU);
 	};
 	PagedAllocator<HashMapElement<ResourceInfo::States *, BarrierRequest>> res_barriers_requests_allocator;
 	HashMap<ResourceInfo::States *, BarrierRequest, HashMapHasherDefault, HashMapComparatorDefault<ResourceInfo::States *>, decltype(res_barriers_requests_allocator)> res_barriers_requests;
@@ -307,13 +367,65 @@ public:
 			VectorView<RDD::BufferBarrier> p_buffer_barriers,
 			VectorView<RDD::TextureBarrier> p_texture_barriers) override final;
 
-	/*************************/
-	/**** COMMAND BUFFERS ****/
-	/*************************/
+private:
+	/****************/
+	/**** FENCES ****/
+	/****************/
+
+	struct FenceInfo {
+		ComPtr<ID3D12Fence> d3d_fence = nullptr;
+		HANDLE event_handle = NULL;
+		UINT64 fence_value = 0;
+	};
+
+public:
+	virtual FenceID fence_create() override;
+	virtual Error fence_wait(FenceID p_fence) override;
+	virtual void fence_free(FenceID p_fence) override;
+
+private:
+	/********************/
+	/**** SEMAPHORES ****/
+	/********************/
+
+	struct SemaphoreInfo {
+		ComPtr<ID3D12Fence> d3d_fence = nullptr;
+		UINT64 fence_value = 0;
+	};
+
+	virtual SemaphoreID semaphore_create() override;
+	virtual void semaphore_free(SemaphoreID p_semaphore) override;
+
+	/******************/
+	/**** COMMANDS ****/
+	/******************/
+
+	// ----- QUEUE FAMILY -----
 
+	virtual CommandQueueFamilyID command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface = 0) override;
+
+private:
+	// ----- QUEUE -----
+
+	struct CommandQueueInfo {
+		ComPtr<ID3D12CommandQueue> d3d_queue;
+	};
+
+public:
+	virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override;
+	virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override;
+	virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override;
+	virtual void command_queue_free(CommandQueueID p_cmd_queue) override;
+
+private:
 	// ----- POOL -----
+	struct CommandPoolInfo {
+		CommandQueueFamilyID queue_family;
+		CommandBufferType buffer_type = COMMAND_BUFFER_TYPE_PRIMARY;
+	};
 
-	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) override final;
+public:
+	virtual CommandPoolID command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) override final;
 	virtual void command_pool_free(CommandPoolID p_cmd_pool) override final;
 
 	// ----- BUFFER -----
@@ -347,17 +459,45 @@ private:
 		uint32_t compute_root_signature_crc = 0;
 
 		RenderPassState render_pass_state;
+		bool descriptor_heaps_set = false;
 	};
-	RBMap<CommandPoolID, LocalVector<CommandBufferInfo *>> pools_command_buffers;
-	CommandPoolID last_command_pool_id;
 
 public:
-	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) override final;
+	virtual CommandBufferID command_buffer_create(CommandPoolID p_cmd_pool) override final;
 	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) override final;
 	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) override final;
 	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) override final;
 	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) override final;
 
+private:
+	/********************/
+	/**** SWAP CHAIN ****/
+	/********************/
+
+	struct SwapChain {
+		ComPtr<IDXGISwapChain3> d3d_swap_chain;
+		RenderingContextDriver::SurfaceID surface = RenderingContextDriver::SurfaceID();
+		UINT present_flags = 0;
+		UINT sync_interval = 1;
+		UINT creation_flags = 0;
+		RenderPassID render_pass;
+		TightLocalVector<ID3D12Resource *> render_targets;
+		TightLocalVector<TextureInfo> render_targets_info;
+		TightLocalVector<FramebufferID> framebuffers;
+		RDD::DataFormat data_format = DATA_FORMAT_MAX;
+	};
+
+	void _swap_chain_release(SwapChain *p_swap_chain);
+	void _swap_chain_release_buffers(SwapChain *p_swap_chain);
+
+public:
+	virtual SwapChainID swap_chain_create(RenderingContextDriver::SurfaceID p_surface) override;
+	virtual Error swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) override;
+	virtual FramebufferID swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) override;
+	virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) override;
+	virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override;
+	virtual void swap_chain_free(SwapChainID p_swap_chain) override;
+
 	/*********************/
 	/**** FRAMEBUFFER ****/
 	/*********************/
@@ -376,6 +516,8 @@ private:
 	D3D12_RENDER_TARGET_VIEW_DESC _make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases = true);
 	D3D12_DEPTH_STENCIL_VIEW_DESC _make_dsv_for_texture(const TextureInfo *p_texture_info);
 
+	FramebufferID _framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height, bool p_is_screen);
+
 public:
 	virtual FramebufferID framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) override final;
 	virtual void framebuffer_free(FramebufferID p_framebuffer) override final;
@@ -602,6 +744,7 @@ public:
 	virtual void command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) override final;
 
 private:
+	void _command_check_descriptor_sets(CommandBufferID p_cmd_buffer);
 	void _command_bind_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index, bool p_for_compute);
 
 public:
@@ -777,12 +920,6 @@ public:
 	virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
 	virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
 
-	/****************/
-	/**** SCREEN ****/
-	/****************/
-
-	virtual DataFormat screen_get_format() override final;
-
 	/********************/
 	/**** SUBMISSION ****/
 	/********************/
@@ -821,7 +958,7 @@ private:
 	bool segment_begun = false;
 
 public:
-	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
+	virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
 	virtual void end_segment() override final;
 
 	/**************/
@@ -835,6 +972,10 @@ public:
 	virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
 	virtual bool has_feature(Features p_feature) override final;
 	virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
+	virtual String get_api_name() const override final;
+	virtual String get_api_version() const override final;
+	virtual String get_pipeline_cache_uuid() const override final;
+	virtual const Capabilities &get_capabilities() const override final;
 
 private:
 	/*********************/
@@ -858,7 +999,7 @@ private:
 	/******************/
 
 public:
-	RenderingDeviceDriverD3D12(D3D12Context *p_context, ID3D12Device *p_device, uint32_t p_frame_count);
+	RenderingDeviceDriverD3D12(RenderingContextDriverD3D12 *p_context_driver);
 	virtual ~RenderingDeviceDriverD3D12();
 };
 

+ 0 - 3
drivers/gles3/rasterizer_gles3.cpp

@@ -356,9 +356,6 @@ RasterizerGLES3::RasterizerGLES3() {
 RasterizerGLES3::~RasterizerGLES3() {
 }
 
-void RasterizerGLES3::prepare_for_blitting_render_targets() {
-}
-
 void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) {
 	GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
 

+ 0 - 1
drivers/gles3/rasterizer_gles3.h

@@ -90,7 +90,6 @@ public:
 	void initialize();
 	void begin_frame(double frame_step);
 
-	void prepare_for_blitting_render_targets();
 	void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
 
 	void end_viewport(bool p_swap_buffers);

+ 686 - 0
drivers/vulkan/rendering_context_driver_vulkan.cpp

@@ -0,0 +1,686 @@
+/**************************************************************************/
+/*  rendering_context_driver_vulkan.cpp                                   */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifdef VULKAN_ENABLED
+
+#include "rendering_context_driver_vulkan.h"
+
+#include "vk_enum_string_helper.h"
+
+#include "core/config/project_settings.h"
+#include "core/version.h"
+
+#include "rendering_device_driver_vulkan.h"
+#include "vulkan_hooks.h"
+
+RenderingContextDriverVulkan::RenderingContextDriverVulkan() {
+	// Empty constructor.
+}
+
+RenderingContextDriverVulkan::~RenderingContextDriverVulkan() {
+	if (debug_messenger != VK_NULL_HANDLE && functions.DestroyDebugUtilsMessengerEXT != nullptr) {
+		functions.DestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr);
+	}
+
+	if (debug_report != VK_NULL_HANDLE && functions.DestroyDebugReportCallbackEXT != nullptr) {
+		functions.DestroyDebugReportCallbackEXT(instance, debug_report, nullptr);
+	}
+
+	if (instance != VK_NULL_HANDLE) {
+		vkDestroyInstance(instance, nullptr);
+	}
+}
+
+Error RenderingContextDriverVulkan::_initialize_vulkan_version() {
+	// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
+	// For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
+	typedef VkResult(VKAPI_PTR * _vkEnumerateInstanceVersion)(uint32_t *);
+	_vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
+	if (func != nullptr) {
+		uint32_t api_version;
+		VkResult res = func(&api_version);
+		if (res == VK_SUCCESS) {
+			instance_api_version = api_version;
+		} else {
+			// According to the documentation this shouldn't fail with anything except a memory allocation error
+			// in which case we're in deep trouble anyway.
+			ERR_FAIL_V(ERR_CANT_CREATE);
+		}
+	} else {
+		print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
+		instance_api_version = VK_API_VERSION_1_0;
+	}
+
+	return OK;
+}
+
+void RenderingContextDriverVulkan::_register_requested_instance_extension(const CharString &p_extension_name, bool p_required) {
+	ERR_FAIL_COND(requested_instance_extensions.has(p_extension_name));
+	requested_instance_extensions[p_extension_name] = p_required;
+}
+
+Error RenderingContextDriverVulkan::_initialize_instance_extensions() {
+	enabled_instance_extension_names.clear();
+
+	// The surface extension and the platform-specific surface extension are core requirements.
+	_register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
+	if (_get_platform_surface_extension()) {
+		_register_requested_instance_extension(_get_platform_surface_extension(), true);
+	}
+
+	if (_use_validation_layers()) {
+		_register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
+	}
+
+	// This extension allows us to use the properties2 features to query additional device capabilities.
+	_register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
+
+	// Only enable debug utils in verbose mode or DEV_ENABLED.
+	// End users would get spammed with messages of varying verbosity due to the
+	// mess that thirdparty layers/extensions and drivers seem to leave in their
+	// wake, making the Windows registry a bottomless pit of broken layer JSON.
+#ifdef DEV_ENABLED
+	bool want_debug_utils = true;
+#else
+	bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
+#endif
+	if (want_debug_utils) {
+		_register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false);
+	}
+
+	// Load instance extensions that are available.
+	uint32_t instance_extension_count = 0;
+	VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
+	ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
+	ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions were found.");
+
+	TightLocalVector<VkExtensionProperties> instance_extensions;
+	instance_extensions.resize(instance_extension_count);
+	err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.ptr());
+	if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
+		ERR_FAIL_V(ERR_CANT_CREATE);
+	}
+
+#ifdef DEV_ENABLED
+	for (uint32_t i = 0; i < instance_extension_count; i++) {
+		print_verbose(String("VULKAN: Found instance extension ") + String::utf8(instance_extensions[i].extensionName) + String("."));
+	}
+#endif
+
+	// Enable all extensions that are supported and requested.
+	for (uint32_t i = 0; i < instance_extension_count; i++) {
+		CharString extension_name(instance_extensions[i].extensionName);
+		if (requested_instance_extensions.has(extension_name)) {
+			enabled_instance_extension_names.insert(extension_name);
+		}
+	}
+
+	// Now check our requested extensions.
+	for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) {
+		if (!enabled_instance_extension_names.has(requested_extension.key)) {
+			if (requested_extension.value) {
+				ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String::utf8(requested_extension.key) + String(" not found."));
+			} else {
+				print_verbose(String("Optional extension ") + String::utf8(requested_extension.key) + String(" not found."));
+			}
+		}
+	}
+
+	return OK;
+}
+
+Error RenderingContextDriverVulkan::_find_validation_layers(TightLocalVector<const char *> &r_layer_names) const {
+	r_layer_names.clear();
+
+	uint32_t instance_layer_count = 0;
+	VkResult err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+	if (instance_layer_count > 0) {
+		TightLocalVector<VkLayerProperties> layer_properties;
+		layer_properties.resize(instance_layer_count);
+		err = vkEnumerateInstanceLayerProperties(&instance_layer_count, layer_properties.ptr());
+		ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+
+		// Preferred set of validation layers.
+		const std::initializer_list<const char *> preferred = { "VK_LAYER_KHRONOS_validation" };
+
+		// Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers.
+		const std::initializer_list<const char *> lunarg = { "VK_LAYER_LUNARG_standard_validation" };
+
+		// Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers.
+		const std::initializer_list<const char *> google = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" };
+
+		// Verify all the layers of the list are present.
+		for (const std::initializer_list<const char *> &list : { preferred, lunarg, google }) {
+			bool layers_found = false;
+			for (const char *layer_name : list) {
+				layers_found = false;
+
+				for (const VkLayerProperties &properties : layer_properties) {
+					if (!strcmp(properties.layerName, layer_name)) {
+						layers_found = true;
+						break;
+					}
+				}
+
+				if (!layers_found) {
+					break;
+				}
+			}
+
+			if (layers_found) {
+				r_layer_names.reserve(list.size());
+				for (const char *layer_name : list) {
+					r_layer_names.push_back(layer_name);
+				}
+
+				break;
+			}
+		}
+	}
+
+	return OK;
+}
+
+VKAPI_ATTR VkBool32 VKAPI_CALL RenderingContextDriverVulkan::_debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data) {
+	// This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors.
+	if (strstr(p_callback_data->pMessage, "Mapping an image with layout") != nullptr && strstr(p_callback_data->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) {
+		return VK_FALSE;
+	}
+	// This needs to be ignored because Validator is wrong here.
+	if (strstr(p_callback_data->pMessage, "Invalid SPIR-V binary version 1.3") != nullptr) {
+		return VK_FALSE;
+	}
+	// This needs to be ignored because Validator is wrong here.
+	if (strstr(p_callback_data->pMessage, "Shader requires flag") != nullptr) {
+		return VK_FALSE;
+	}
+
+	// This needs to be ignored because Validator is wrong here.
+	if (strstr(p_callback_data->pMessage, "SPIR-V module not valid: Pointer operand") != nullptr && strstr(p_callback_data->pMessage, "must be a memory object") != nullptr) {
+		return VK_FALSE;
+	}
+
+	if (p_callback_data->pMessageIdName && strstr(p_callback_data->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
+		return VK_FALSE;
+	}
+
+	String type_string;
+	switch (p_message_type) {
+		case (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT):
+			type_string = "GENERAL";
+			break;
+		case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT):
+			type_string = "VALIDATION";
+			break;
+		case (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
+			type_string = "PERFORMANCE";
+			break;
+		case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
+			type_string = "VALIDATION|PERFORMANCE";
+			break;
+	}
+
+	String objects_string;
+	if (p_callback_data->objectCount > 0) {
+		objects_string = "\n\tObjects - " + String::num_int64(p_callback_data->objectCount);
+		for (uint32_t object = 0; object < p_callback_data->objectCount; ++object) {
+			objects_string +=
+					"\n\t\tObject[" + String::num_int64(object) + "]" +
+					" - " + string_VkObjectType(p_callback_data->pObjects[object].objectType) +
+					", Handle " + String::num_int64(p_callback_data->pObjects[object].objectHandle);
+
+			if (p_callback_data->pObjects[object].pObjectName != nullptr && strlen(p_callback_data->pObjects[object].pObjectName) > 0) {
+				objects_string += ", Name \"" + String(p_callback_data->pObjects[object].pObjectName) + "\"";
+			}
+		}
+	}
+
+	String labels_string;
+	if (p_callback_data->cmdBufLabelCount > 0) {
+		labels_string = "\n\tCommand Buffer Labels - " + String::num_int64(p_callback_data->cmdBufLabelCount);
+		for (uint32_t cmd_buf_label = 0; cmd_buf_label < p_callback_data->cmdBufLabelCount; ++cmd_buf_label) {
+			labels_string +=
+					"\n\t\tLabel[" + String::num_int64(cmd_buf_label) + "]" +
+					" - " + p_callback_data->pCmdBufLabels[cmd_buf_label].pLabelName +
+					"{ ";
+
+			for (int color_idx = 0; color_idx < 4; ++color_idx) {
+				labels_string += String::num(p_callback_data->pCmdBufLabels[cmd_buf_label].color[color_idx]);
+				if (color_idx < 3) {
+					labels_string += ", ";
+				}
+			}
+
+			labels_string += " }";
+		}
+	}
+
+	String error_message(type_string +
+			" - Message Id Number: " + String::num_int64(p_callback_data->messageIdNumber) +
+			" | Message Id Name: " + p_callback_data->pMessageIdName +
+			"\n\t" + p_callback_data->pMessage +
+			objects_string + labels_string);
+
+	// Convert VK severity to our own log macros.
+	switch (p_message_severity) {
+		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
+			print_verbose(error_message);
+			break;
+		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
+			print_line(error_message);
+			break;
+		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
+			WARN_PRINT(error_message);
+			break;
+		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
+			ERR_PRINT(error_message);
+			CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(), "Crashing, because abort on GPU errors is enabled.");
+			break;
+		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT:
+			break; // Shouldn't happen, only handling to make compilers happy.
+	}
+
+	return VK_FALSE;
+}
+
+VKAPI_ATTR VkBool32 VKAPI_CALL RenderingContextDriverVulkan::_debug_report_callback(VkDebugReportFlagsEXT p_flags, VkDebugReportObjectTypeEXT p_object_type, uint64_t p_object, size_t p_location, int32_t p_message_code, const char *p_layer_prefix, const char *p_message, void *p_user_data) {
+	String debug_message = String("Vulkan Debug Report: object - ") + String::num_int64(p_object) + "\n" + p_message;
+
+	switch (p_flags) {
+		case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
+		case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
+			print_line(debug_message);
+			break;
+		case VK_DEBUG_REPORT_WARNING_BIT_EXT:
+		case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
+			WARN_PRINT(debug_message);
+			break;
+		case VK_DEBUG_REPORT_ERROR_BIT_EXT:
+			ERR_PRINT(debug_message);
+			break;
+	}
+
+	return VK_FALSE;
+}
+
+Error RenderingContextDriverVulkan::_initialize_instance() {
+	Error err;
+	TightLocalVector<const char *> enabled_extension_names;
+	enabled_extension_names.reserve(enabled_instance_extension_names.size());
+	for (const CharString &extension_name : enabled_instance_extension_names) {
+		enabled_extension_names.push_back(extension_name.ptr());
+	}
+
+	// We'll set application version to the Vulkan version we're developing against, even if our instance is based on an older Vulkan
+	// version, devices can still support newer versions of Vulkan. The exception is when we're on Vulkan 1.0, we should not set this
+	// to anything but 1.0. Note that this value is only used by validation layers to warn us about version issues.
+	uint32_t application_api_version = instance_api_version == VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : VK_API_VERSION_1_2;
+
+	CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
+	VkApplicationInfo app_info = {};
+	app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+	app_info.pApplicationName = cs.get_data();
+	app_info.pEngineName = VERSION_NAME;
+	app_info.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
+	app_info.apiVersion = application_api_version;
+
+	TightLocalVector<const char *> enabled_layer_names;
+	if (_use_validation_layers()) {
+		err = _find_validation_layers(enabled_layer_names);
+		ERR_FAIL_COND_V(err != OK, err);
+	}
+
+	VkInstanceCreateInfo instance_info = {};
+	instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+	instance_info.pApplicationInfo = &app_info;
+	instance_info.enabledExtensionCount = enabled_extension_names.size();
+	instance_info.ppEnabledExtensionNames = enabled_extension_names.ptr();
+	instance_info.enabledLayerCount = enabled_layer_names.size();
+	instance_info.ppEnabledLayerNames = enabled_layer_names.ptr();
+
+	// This is info for a temp callback to use during CreateInstance. After the instance is created, we use the instance-based function to register the final callback.
+	VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = {};
+	VkDebugReportCallbackCreateInfoEXT debug_report_callback_create_info = {};
+	const bool has_debug_utils_extension = enabled_instance_extension_names.has(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+	const bool has_debug_report_extension = enabled_instance_extension_names.has(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+	if (has_debug_utils_extension) {
+		debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+		debug_messenger_create_info.pNext = nullptr;
+		debug_messenger_create_info.flags = 0;
+		debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+		debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
+		debug_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
+		debug_messenger_create_info.pUserData = this;
+		instance_info.pNext = &debug_messenger_create_info;
+	} else if (has_debug_report_extension) {
+		debug_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
+		debug_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+		debug_report_callback_create_info.pfnCallback = _debug_report_callback;
+		debug_report_callback_create_info.pUserData = this;
+		instance_info.pNext = &debug_report_callback_create_info;
+	}
+
+	err = _create_vulkan_instance(&instance_info, &instance);
+	ERR_FAIL_COND_V(err != OK, err);
+
+#ifdef USE_VOLK
+	volkLoadInstance(instance);
+#endif
+
+	// Physical device.
+	if (enabled_instance_extension_names.has(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+		functions.GetPhysicalDeviceFeatures2 = PFN_vkGetPhysicalDeviceFeatures2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+		functions.GetPhysicalDeviceProperties2 = PFN_vkGetPhysicalDeviceProperties2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+
+		// In Vulkan 1.0, the functions might be accessible under their original extension names.
+		if (functions.GetPhysicalDeviceFeatures2 == nullptr) {
+			functions.GetPhysicalDeviceFeatures2 = PFN_vkGetPhysicalDeviceFeatures2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
+		}
+
+		if (functions.GetPhysicalDeviceProperties2 == nullptr) {
+			functions.GetPhysicalDeviceProperties2 = PFN_vkGetPhysicalDeviceProperties2(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
+		}
+	}
+
+	// Device.
+	functions.GetDeviceProcAddr = PFN_vkGetDeviceProcAddr(vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
+
+	// Surfaces.
+	functions.GetPhysicalDeviceSurfaceSupportKHR = PFN_vkGetPhysicalDeviceSurfaceSupportKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
+	functions.GetPhysicalDeviceSurfaceFormatsKHR = PFN_vkGetPhysicalDeviceSurfaceFormatsKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
+	functions.GetPhysicalDeviceSurfaceCapabilitiesKHR = PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
+	functions.GetPhysicalDeviceSurfacePresentModesKHR = PFN_vkGetPhysicalDeviceSurfacePresentModesKHR(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
+
+	// Debug utils and report.
+	if (has_debug_utils_extension) {
+		// Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
+		functions.CreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
+		functions.DestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
+		functions.CmdBeginDebugUtilsLabelEXT = (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT");
+		functions.CmdEndDebugUtilsLabelEXT = (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT");
+		functions.SetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT");
+
+		if (!functions.debug_util_functions_available()) {
+			ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_utils\nGetProcAddr: Failure");
+		}
+
+		VkResult res = functions.CreateDebugUtilsMessengerEXT(instance, &debug_messenger_create_info, nullptr, &debug_messenger);
+		switch (res) {
+			case VK_SUCCESS:
+				break;
+			case VK_ERROR_OUT_OF_HOST_MEMORY:
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugUtilsMessengerEXT: out of host memory\nCreateDebugUtilsMessengerEXT Failure");
+				break;
+			default:
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugUtilsMessengerEXT: unknown failure\nCreateDebugUtilsMessengerEXT Failure");
+				break;
+		}
+	} else if (has_debug_report_extension) {
+		functions.CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
+		functions.DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT");
+		functions.DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
+
+		if (!functions.debug_report_functions_available()) {
+			ERR_FAIL_V_MSG(ERR_CANT_CREATE, "GetProcAddr: Failed to init VK_EXT_debug_report\nGetProcAddr: Failure");
+		}
+
+		VkResult res = functions.CreateDebugReportCallbackEXT(instance, &debug_report_callback_create_info, nullptr, &debug_report);
+		switch (res) {
+			case VK_SUCCESS:
+				break;
+			case VK_ERROR_OUT_OF_HOST_MEMORY:
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugReportCallbackEXT: out of host memory\nCreateDebugReportCallbackEXT Failure");
+				break;
+			default:
+				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CreateDebugReportCallbackEXT: unknown failure\nCreateDebugReportCallbackEXT Failure");
+				break;
+		}
+	}
+
+	return OK;
+}
+
+Error RenderingContextDriverVulkan::_initialize_devices() {
+	if (VulkanHooks::get_singleton() != nullptr) {
+		VkPhysicalDevice physical_device;
+		bool device_retrieved = VulkanHooks::get_singleton()->get_physical_device(&physical_device);
+		ERR_FAIL_COND_V(!device_retrieved, ERR_CANT_CREATE);
+
+		// When a hook is active, pretend the device returned by the hook is the only device available.
+		driver_devices.resize(1);
+		physical_devices.resize(1);
+		device_queue_families.resize(1);
+		physical_devices[0] = physical_device;
+
+	} else {
+		uint32_t physical_device_count = 0;
+		VkResult err = vkEnumeratePhysicalDevices(instance, &physical_device_count, nullptr);
+		ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+		ERR_FAIL_COND_V_MSG(physical_device_count == 0, ERR_CANT_CREATE, "vkEnumeratePhysicalDevices reported zero accessible devices.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkEnumeratePhysicalDevices Failure.");
+
+		driver_devices.resize(physical_device_count);
+		physical_devices.resize(physical_device_count);
+		device_queue_families.resize(physical_device_count);
+		err = vkEnumeratePhysicalDevices(instance, &physical_device_count, physical_devices.ptr());
+		ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE);
+	}
+
+	// Fill the list of driver devices with the properties from the physical devices.
+	for (uint32_t i = 0; i < physical_devices.size(); i++) {
+		VkPhysicalDeviceProperties props;
+		vkGetPhysicalDeviceProperties(physical_devices[i], &props);
+
+		Device &driver_device = driver_devices[i];
+		driver_device.name = String::utf8(props.deviceName);
+		driver_device.vendor = Vendor(props.vendorID);
+		driver_device.type = DeviceType(props.deviceType);
+
+		uint32_t queue_family_properties_count = 0;
+		vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, nullptr);
+
+		if (queue_family_properties_count > 0) {
+			device_queue_families[i].properties.resize(queue_family_properties_count);
+			vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, device_queue_families[i].properties.ptr());
+		}
+	}
+
+	return OK;
+}
+
+bool RenderingContextDriverVulkan::_use_validation_layers() const {
+	return Engine::get_singleton()->is_validation_layers_enabled();
+}
+
+Error RenderingContextDriverVulkan::_create_vulkan_instance(const VkInstanceCreateInfo *p_create_info, VkInstance *r_instance) {
+	if (VulkanHooks::get_singleton() != nullptr) {
+		return VulkanHooks::get_singleton()->create_vulkan_instance(p_create_info, r_instance) ? OK : ERR_CANT_CREATE;
+	} else {
+		VkResult err = vkCreateInstance(p_create_info, nullptr, r_instance);
+		ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
+				"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
+				"vkCreateInstance Failure");
+		ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
+				"Cannot find a specified extension library.\n"
+				"Make sure your layers path is set appropriately.\n"
+				"vkCreateInstance Failure");
+		ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
+				"vkCreateInstance failed.\n\n"
+				"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
+				"Please look at the Getting Started guide for additional information.\n"
+				"vkCreateInstance Failure");
+	}
+
+	return OK;
+}
+
+Error RenderingContextDriverVulkan::initialize() {
+	Error err;
+
+#ifdef USE_VOLK
+	if (volkInitialize() != VK_SUCCESS) {
+		return FAILED;
+	}
+#endif
+
+	err = _initialize_vulkan_version();
+	ERR_FAIL_COND_V(err != OK, err);
+
+	err = _initialize_instance_extensions();
+	ERR_FAIL_COND_V(err != OK, err);
+
+	err = _initialize_instance();
+	ERR_FAIL_COND_V(err != OK, err);
+
+	err = _initialize_devices();
+	ERR_FAIL_COND_V(err != OK, err);
+
+	return OK;
+}
+
+const RenderingContextDriver::Device &RenderingContextDriverVulkan::device_get(uint32_t p_device_index) const {
+	DEV_ASSERT(p_device_index < driver_devices.size());
+	return driver_devices[p_device_index];
+}
+
+uint32_t RenderingContextDriverVulkan::device_get_count() const {
+	return driver_devices.size();
+}
+
+bool RenderingContextDriverVulkan::device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const {
+	DEV_ASSERT(p_device_index < physical_devices.size());
+
+	// Check if any of the queues supported by the device supports presenting to the window's surface.
+	const VkPhysicalDevice physical_device = physical_devices[p_device_index];
+	const DeviceQueueFamilies &queue_families = device_queue_families[p_device_index];
+	for (uint32_t i = 0; i < queue_families.properties.size(); i++) {
+		if ((queue_families.properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && queue_family_supports_present(physical_device, i, p_surface)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+RenderingDeviceDriver *RenderingContextDriverVulkan::driver_create() {
+	return memnew(RenderingDeviceDriverVulkan(this));
+}
+
+void RenderingContextDriverVulkan::driver_free(RenderingDeviceDriver *p_driver) {
+	memdelete(p_driver);
+}
+
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkan::surface_create(const void *p_platform_data) {
+	DEV_ASSERT(false && "Surface creation should not be called on the platform-agnostic version of the driver.");
+	return SurfaceID();
+}
+
+void RenderingContextDriverVulkan::surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->width = p_width;
+	surface->height = p_height;
+	surface->needs_resize = true;
+}
+
+void RenderingContextDriverVulkan::surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->vsync_mode = p_vsync_mode;
+	surface->needs_resize = true;
+}
+
+DisplayServer::VSyncMode RenderingContextDriverVulkan::surface_get_vsync_mode(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->vsync_mode;
+}
+
+uint32_t RenderingContextDriverVulkan::surface_get_width(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->width;
+}
+
+uint32_t RenderingContextDriverVulkan::surface_get_height(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->height;
+}
+
+void RenderingContextDriverVulkan::surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) {
+	Surface *surface = (Surface *)(p_surface);
+	surface->needs_resize = p_needs_resize;
+}
+
+bool RenderingContextDriverVulkan::surface_get_needs_resize(SurfaceID p_surface) const {
+	Surface *surface = (Surface *)(p_surface);
+	return surface->needs_resize;
+}
+
+void RenderingContextDriverVulkan::surface_destroy(SurfaceID p_surface) {
+	Surface *surface = (Surface *)(p_surface);
+	vkDestroySurfaceKHR(instance, surface->vk_surface, nullptr);
+	memdelete(surface);
+}
+
+bool RenderingContextDriverVulkan::is_debug_utils_enabled() const {
+	return enabled_instance_extension_names.has(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+}
+
+VkInstance RenderingContextDriverVulkan::instance_get() const {
+	return instance;
+}
+
+VkPhysicalDevice RenderingContextDriverVulkan::physical_device_get(uint32_t p_device_index) const {
+	DEV_ASSERT(p_device_index < physical_devices.size());
+	return physical_devices[p_device_index];
+}
+
+uint32_t RenderingContextDriverVulkan::queue_family_get_count(uint32_t p_device_index) const {
+	DEV_ASSERT(p_device_index < physical_devices.size());
+	return device_queue_families[p_device_index].properties.size();
+}
+
+VkQueueFamilyProperties RenderingContextDriverVulkan::queue_family_get(uint32_t p_device_index, uint32_t p_queue_family_index) const {
+	DEV_ASSERT(p_device_index < physical_devices.size());
+	DEV_ASSERT(p_queue_family_index < queue_family_get_count(p_device_index));
+	return device_queue_families[p_device_index].properties[p_queue_family_index];
+}
+
+bool RenderingContextDriverVulkan::queue_family_supports_present(VkPhysicalDevice p_physical_device, uint32_t p_queue_family_index, SurfaceID p_surface) const {
+	DEV_ASSERT(p_physical_device != VK_NULL_HANDLE);
+	DEV_ASSERT(p_surface != 0);
+	Surface *surface = (Surface *)(p_surface);
+	VkBool32 present_supported = false;
+	VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(p_physical_device, p_queue_family_index, surface->vk_surface, &present_supported);
+	return err == VK_SUCCESS && present_supported;
+}
+
+const RenderingContextDriverVulkan::Functions &RenderingContextDriverVulkan::functions_get() const {
+	return functions;
+}
+
+#endif // VULKAN_ENABLED

+ 161 - 0
drivers/vulkan/rendering_context_driver_vulkan.h

@@ -0,0 +1,161 @@
+/**************************************************************************/
+/*  rendering_context_driver_vulkan.h                                     */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_H
+
+#ifdef VULKAN_ENABLED
+
+#include "servers/rendering/rendering_context_driver.h"
+
+#ifdef USE_VOLK
+#include <volk.h>
+#else
+#include <vulkan/vulkan.h>
+#endif
+
+class RenderingContextDriverVulkan : public RenderingContextDriver {
+public:
+	struct Functions {
+		// Physical device.
+		PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2 = nullptr;
+		PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2 = nullptr;
+
+		// Device.
+		PFN_vkGetDeviceProcAddr GetDeviceProcAddr = nullptr;
+
+		// Surfaces.
+		PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR = nullptr;
+		PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR = nullptr;
+		PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
+		PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR = nullptr;
+
+		// Debug utils.
+		PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
+		PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
+		PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
+		PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
+		PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
+
+		bool debug_util_functions_available() const {
+			return CreateDebugUtilsMessengerEXT != nullptr &&
+					DestroyDebugUtilsMessengerEXT != nullptr &&
+					CmdBeginDebugUtilsLabelEXT != nullptr &&
+					CmdEndDebugUtilsLabelEXT != nullptr &&
+					SetDebugUtilsObjectNameEXT != nullptr;
+		}
+
+		// Debug report.
+		PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
+		PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
+		PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
+
+		bool debug_report_functions_available() const {
+			return CreateDebugReportCallbackEXT != nullptr &&
+					DebugReportMessageEXT != nullptr &&
+					DestroyDebugReportCallbackEXT != nullptr;
+		}
+	};
+
+private:
+	struct DeviceQueueFamilies {
+		TightLocalVector<VkQueueFamilyProperties> properties;
+	};
+
+	VkInstance instance = VK_NULL_HANDLE;
+	uint32_t instance_api_version = VK_API_VERSION_1_0;
+	HashMap<CharString, bool> requested_instance_extensions;
+	HashSet<CharString> enabled_instance_extension_names;
+	TightLocalVector<Device> driver_devices;
+	TightLocalVector<VkPhysicalDevice> physical_devices;
+	TightLocalVector<DeviceQueueFamilies> device_queue_families;
+	VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
+	VkDebugReportCallbackEXT debug_report = VK_NULL_HANDLE;
+	Functions functions;
+
+	Error _initialize_vulkan_version();
+	void _register_requested_instance_extension(const CharString &p_extension_name, bool p_required);
+	Error _initialize_instance_extensions();
+	Error _initialize_instance();
+	Error _initialize_devices();
+
+	// Static callbacks.
+	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data);
+	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(VkDebugReportFlagsEXT p_flags, VkDebugReportObjectTypeEXT p_object_type, uint64_t p_object, size_t p_location, int32_t p_message_code, const char *p_layer_prefix, const char *p_message, void *p_user_data);
+
+protected:
+	Error _find_validation_layers(TightLocalVector<const char *> &r_layer_names) const;
+
+	// Can be overridden by platform-specific drivers.
+	virtual const char *_get_platform_surface_extension() const { return nullptr; }
+	virtual bool _use_validation_layers() const;
+	virtual Error _create_vulkan_instance(const VkInstanceCreateInfo *p_create_info, VkInstance *r_instance);
+
+public:
+	virtual Error initialize() override;
+	virtual const Device &device_get(uint32_t p_device_index) const override;
+	virtual uint32_t device_get_count() const override;
+	virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const override;
+	virtual RenderingDeviceDriver *driver_create() override;
+	virtual void driver_free(RenderingDeviceDriver *p_driver) override;
+	virtual SurfaceID surface_create(const void *p_platform_data) override;
+	virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) override;
+	virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) override;
+	virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const override;
+	virtual uint32_t surface_get_width(SurfaceID p_surface) const override;
+	virtual uint32_t surface_get_height(SurfaceID p_surface) const override;
+	virtual void surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) override;
+	virtual bool surface_get_needs_resize(SurfaceID p_surface) const override;
+	virtual void surface_destroy(SurfaceID p_surface) override;
+	virtual bool is_debug_utils_enabled() const override;
+
+	// Vulkan-only methods.
+	struct Surface {
+		VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+		uint32_t width = 0;
+		uint32_t height = 0;
+		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
+		bool needs_resize = false;
+	};
+
+	VkInstance instance_get() const;
+	VkPhysicalDevice physical_device_get(uint32_t p_device_index) const;
+	uint32_t queue_family_get_count(uint32_t p_device_index) const;
+	VkQueueFamilyProperties queue_family_get(uint32_t p_device_index, uint32_t p_queue_family_index) const;
+	bool queue_family_supports_present(VkPhysicalDevice p_physical_device, uint32_t p_queue_family_index, SurfaceID p_surface) const;
+	const Functions &functions_get() const;
+
+	RenderingContextDriverVulkan();
+	virtual ~RenderingContextDriverVulkan() override;
+};
+
+#endif // VULKAN_ENABLED
+
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_H

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1207 - 51
drivers/vulkan/rendering_device_driver_vulkan.cpp


+ 183 - 25
drivers/vulkan/rendering_device_driver_vulkan.h

@@ -33,6 +33,7 @@
 
 #include "core/templates/hash_map.h"
 #include "core/templates/paged_allocator.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 #include "servers/rendering/rendering_device_driver.h"
 
 #ifdef DEBUG_ENABLED
@@ -48,8 +49,6 @@
 #include <vulkan/vulkan.h>
 #endif
 
-class VulkanContext;
-
 // Design principles:
 // - Vulkan structs are zero-initialized and fields not requiring a non-zero value are omitted (except in cases where expresivity reasons apply).
 class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
@@ -57,9 +56,99 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
 	/**** GENERIC ****/
 	/*****************/
 
-	VulkanContext *context = nullptr;
-	VkDevice vk_device = VK_NULL_HANDLE; // Owned by the context.
+	struct CommandQueue;
+	struct SwapChain;
+
+	struct Queue {
+		VkQueue queue = VK_NULL_HANDLE;
+		uint32_t virtual_count = 0;
+		BinaryMutex submit_mutex;
+	};
+
+	struct SubgroupCapabilities {
+		uint32_t size = 0;
+		uint32_t min_size = 0;
+		uint32_t max_size = 0;
+		VkShaderStageFlags supported_stages = 0;
+		VkSubgroupFeatureFlags supported_operations = 0;
+		VkBool32 quad_operations_in_all_stages = false;
+		bool size_control_is_supported = false;
+
+		uint32_t supported_stages_flags_rd() const;
+		String supported_stages_desc() const;
+		uint32_t supported_operations_flags_rd() const;
+		String supported_operations_desc() const;
+	};
+
+	struct VRSCapabilities {
+		bool pipeline_vrs_supported = false; // We can specify our fragment rate on a pipeline level.
+		bool primitive_vrs_supported = false; // We can specify our fragment rate on each drawcall.
+		bool attachment_vrs_supported = false; // We can provide a density map attachment on our framebuffer.
+
+		Size2i min_texel_size;
+		Size2i max_texel_size;
+
+		Size2i texel_size; // The texel size we'll use
+	};
+
+	struct ShaderCapabilities {
+		bool shader_float16_is_supported = false;
+		bool shader_int8_is_supported = false;
+	};
+
+	struct StorageBufferCapabilities {
+		bool storage_buffer_16_bit_access_is_supported = false;
+		bool uniform_and_storage_buffer_16_bit_access_is_supported = false;
+		bool storage_push_constant_16_is_supported = false;
+		bool storage_input_output_16 = false;
+	};
+
+	struct DeviceFunctions {
+		PFN_vkCreateSwapchainKHR CreateSwapchainKHR = nullptr;
+		PFN_vkDestroySwapchainKHR DestroySwapchainKHR = nullptr;
+		PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR = nullptr;
+		PFN_vkAcquireNextImageKHR AcquireNextImageKHR = nullptr;
+		PFN_vkQueuePresentKHR QueuePresentKHR = nullptr;
+		PFN_vkCreateRenderPass2KHR CreateRenderPass2KHR = nullptr;
+	};
 
+	VkDevice vk_device = VK_NULL_HANDLE;
+	RenderingContextDriverVulkan *context_driver = nullptr;
+	RenderingContextDriver::Device context_device = {};
+	VkPhysicalDevice physical_device = VK_NULL_HANDLE;
+	VkPhysicalDeviceProperties physical_device_properties = {};
+	VkPhysicalDeviceFeatures physical_device_features = {};
+	VkPhysicalDeviceFeatures requested_device_features = {};
+	HashMap<CharString, bool> requested_device_extensions;
+	HashSet<CharString> enabled_device_extension_names;
+	TightLocalVector<TightLocalVector<Queue>> queue_families;
+	TightLocalVector<VkQueueFamilyProperties> queue_family_properties;
+	RDD::Capabilities device_capabilities;
+	SubgroupCapabilities subgroup_capabilities;
+	MultiviewCapabilities multiview_capabilities;
+	VRSCapabilities vrs_capabilities;
+	ShaderCapabilities shader_capabilities;
+	StorageBufferCapabilities storage_buffer_capabilities;
+	bool pipeline_cache_control_support = false;
+	DeviceFunctions device_functions;
+
+	void _register_requested_device_extension(const CharString &p_extension_name, bool p_required);
+	Error _initialize_device_extensions();
+	Error _check_device_features();
+	Error _check_device_capabilities();
+	Error _add_queue_create_info(LocalVector<VkDeviceQueueCreateInfo> &r_queue_create_info);
+	Error _initialize_device(const LocalVector<VkDeviceQueueCreateInfo> &p_queue_create_info);
+	Error _initialize_allocator();
+	Error _initialize_pipeline_cache();
+	VkResult _create_render_pass(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
+	bool _release_image_semaphore(CommandQueue *p_command_queue, uint32_t p_semaphore_index, bool p_release_on_swap_chain);
+	bool _recreate_image_semaphore(CommandQueue *p_command_queue, uint32_t p_semaphore_index, bool p_release_on_swap_chain);
+	void _set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
+
+public:
+	Error initialize(uint32_t p_device_index, uint32_t p_frame_count) override final;
+
+private:
 	/****************/
 	/**** MEMORY ****/
 	/****************/
@@ -154,32 +243,104 @@ public:
 			VectorView<BufferBarrier> p_buffer_barriers,
 			VectorView<TextureBarrier> p_texture_barriers) override final;
 
-	/*************************/
-	/**** COMMAND BUFFERS ****/
-	/*************************/
+	/****************/
+	/**** FENCES ****/
+	/****************/
+
 private:
-#ifdef DEBUG_ENABLED
-	// Vulkan doesn't need to know if the command buffers created in a pool
-	// will be primary or secondary, but RDD works like that, so we will enforce.
+	struct Fence {
+		VkFence vk_fence = VK_NULL_HANDLE;
+		CommandQueue *queue_signaled_from = nullptr;
+	};
 
-	HashSet<CommandPoolID> secondary_cmd_pools;
-	HashSet<CommandBufferID> secondary_cmd_buffers;
-#endif
+public:
+	virtual FenceID fence_create() override final;
+	virtual Error fence_wait(FenceID p_fence) override final;
+	virtual void fence_free(FenceID p_fence) override final;
+
+	/********************/
+	/**** SEMAPHORES ****/
+	/********************/
+
+	virtual SemaphoreID semaphore_create() override final;
+	virtual void semaphore_free(SemaphoreID p_semaphore) override final;
+
+	/******************/
+	/**** COMMANDS ****/
+	/******************/
+
+	// ----- QUEUE FAMILY -----
+
+	virtual CommandQueueFamilyID command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface = 0) override final;
+
+	// ----- QUEUE -----
+private:
+	struct CommandQueue {
+		LocalVector<VkSemaphore> image_semaphores;
+		LocalVector<SwapChain *> image_semaphores_swap_chains;
+		LocalVector<uint32_t> pending_semaphores_for_execute;
+		LocalVector<uint32_t> pending_semaphores_for_fence;
+		LocalVector<uint32_t> free_image_semaphores;
+		LocalVector<Pair<Fence *, uint32_t>> image_semaphores_for_fences;
+		uint32_t queue_family = 0;
+		uint32_t queue_index = 0;
+	};
 
 public:
+	virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override final;
+	virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override final;
+	virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override final;
+	virtual void command_queue_free(CommandQueueID p_cmd_queue) override final;
+
+private:
 	// ----- POOL -----
 
-	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) override final;
+	struct CommandPool {
+		VkCommandPool vk_command_pool = VK_NULL_HANDLE;
+		CommandBufferType buffer_type = COMMAND_BUFFER_TYPE_PRIMARY;
+	};
+
+public:
+	virtual CommandPoolID command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) override final;
 	virtual void command_pool_free(CommandPoolID p_cmd_pool) override final;
 
 	// ----- BUFFER -----
 
-	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) override final;
+	virtual CommandBufferID command_buffer_create(CommandPoolID p_cmd_pool) override final;
 	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) override final;
 	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) override final;
 	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) override final;
 	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) override final;
 
+	/********************/
+	/**** SWAP CHAIN ****/
+	/********************/
+
+private:
+	struct SwapChain {
+		VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
+		RenderingContextDriver::SurfaceID surface = RenderingContextDriver::SurfaceID();
+		VkFormat format = VK_FORMAT_UNDEFINED;
+		VkColorSpaceKHR color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+		TightLocalVector<VkImage> images;
+		TightLocalVector<VkImageView> image_views;
+		TightLocalVector<FramebufferID> framebuffers;
+		LocalVector<CommandQueue *> command_queues_acquired;
+		LocalVector<uint32_t> command_queues_acquired_semaphores;
+		RenderPassID render_pass;
+		uint32_t image_index = 0;
+	};
+
+	void _swap_chain_release(SwapChain *p_swap_chain);
+
+public:
+	virtual SwapChainID swap_chain_create(RenderingContextDriver::SurfaceID p_surface) override final;
+	virtual Error swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) override final;
+	virtual FramebufferID swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) override final;
+	virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) override final;
+	virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override final;
+	virtual void swap_chain_free(SwapChainID p_swap_chain) override final;
+
 	/*********************/
 	/**** FRAMEBUFFER ****/
 	/*********************/
@@ -329,6 +490,7 @@ private:
 
 	static int caching_instance_count;
 	PipelineCache pipelines_cache;
+	String pipeline_cache_id;
 
 public:
 	virtual void pipeline_free(PipelineID p_pipeline) override final;
@@ -439,25 +601,17 @@ public:
 	virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) override final;
 	virtual void command_end_label(CommandBufferID p_cmd_buffer) override final;
 
-	/****************/
-	/**** SCREEN ****/
-	/****************/
-
-	virtual DataFormat screen_get_format() override final;
-
 	/********************/
 	/**** SUBMISSION ****/
 	/********************/
 
-	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
+	virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) override final;
 	virtual void end_segment() override final;
 
 	/**************/
 	/**** MISC ****/
 	/**************/
 
-	VkPhysicalDeviceLimits limits = {};
-
 	virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) override final;
 	virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) override final;
 	virtual uint64_t get_total_memory_used() override final;
@@ -465,6 +619,10 @@ public:
 	virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
 	virtual bool has_feature(Features p_feature) override final;
 	virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
+	virtual String get_api_name() const override final;
+	virtual String get_api_version() const override final;
+	virtual String get_pipeline_cache_uuid() const override final;
+	virtual const Capabilities &get_capabilities() const override final;
 
 private:
 	/*********************/
@@ -482,7 +640,7 @@ private:
 	/******************/
 
 public:
-	RenderingDeviceDriverVulkan(VulkanContext *p_context, VkDevice p_vk_device);
+	RenderingDeviceDriverVulkan(RenderingContextDriverVulkan *p_context_driver);
 	virtual ~RenderingDeviceDriverVulkan();
 };
 

+ 0 - 2915
drivers/vulkan/vulkan_context.cpp

@@ -1,2915 +0,0 @@
-/**************************************************************************/
-/*  vulkan_context.cpp                                                    */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "vulkan_context.h"
-
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
-#include "core/string/ustring.h"
-#include "core/templates/local_vector.h"
-#include "core/version.h"
-#include "servers/rendering/rendering_device.h"
-
-#include "vk_enum_string_helper.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-#define APP_SHORT_NAME "GodotEngine"
-
-VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
-
-Vector<VkAttachmentReference> VulkanContext::_convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs) {
-	Vector<VkAttachmentReference> att_refs;
-
-	if (p_refs != nullptr) {
-		for (uint32_t i = 0; i < p_count; i++) {
-			// We lose aspectMask in this conversion but we don't use it currently.
-
-			VkAttachmentReference ref = {
-				p_refs[i].attachment, /* attachment */
-				p_refs[i].layout /* layout */
-			};
-
-			att_refs.push_back(ref);
-		}
-	}
-
-	return att_refs;
-}
-
-VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass) {
-	if (is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
-		if (fpCreateRenderPass2KHR == nullptr) {
-			fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(p_device, "vkCreateRenderPass2KHR");
-		}
-
-		if (fpCreateRenderPass2KHR == nullptr) {
-			return VK_ERROR_EXTENSION_NOT_PRESENT;
-		} else {
-			return (fpCreateRenderPass2KHR)(p_device, p_create_info, p_allocator, p_render_pass);
-		}
-	} else {
-		// need to fall back on vkCreateRenderPass
-
-		const void *next = p_create_info->pNext; // ATM we only support multiview which should work if supported.
-
-		Vector<VkAttachmentDescription> attachments;
-		for (uint32_t i = 0; i < p_create_info->attachmentCount; i++) {
-			// Basically the old layout just misses type and next.
-			VkAttachmentDescription att = {
-				p_create_info->pAttachments[i].flags, /* flags */
-				p_create_info->pAttachments[i].format, /* format */
-				p_create_info->pAttachments[i].samples, /* samples */
-				p_create_info->pAttachments[i].loadOp, /* loadOp */
-				p_create_info->pAttachments[i].storeOp, /* storeOp */
-				p_create_info->pAttachments[i].stencilLoadOp, /* stencilLoadOp */
-				p_create_info->pAttachments[i].stencilStoreOp, /* stencilStoreOp */
-				p_create_info->pAttachments[i].initialLayout, /* initialLayout */
-				p_create_info->pAttachments[i].finalLayout /* finalLayout */
-			};
-
-			attachments.push_back(att);
-		}
-
-		Vector<Vector<VkAttachmentReference>> attachment_references;
-		Vector<VkSubpassDescription> subpasses;
-		for (uint32_t i = 0; i < p_create_info->subpassCount; i++) {
-			// Here we need to do more, again it's just stripping out type and next
-			// but we have VkAttachmentReference2 to convert to VkAttachmentReference.
-			// Also viewmask is not supported but we don't use it outside of multiview.
-
-			Vector<VkAttachmentReference> input_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].inputAttachmentCount, p_create_info->pSubpasses[i].pInputAttachments);
-			Vector<VkAttachmentReference> color_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pColorAttachments);
-			Vector<VkAttachmentReference> resolve_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pResolveAttachments);
-			Vector<VkAttachmentReference> depth_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pDepthStencilAttachment);
-
-			VkSubpassDescription subpass = {
-				p_create_info->pSubpasses[i].flags, /* flags */
-				p_create_info->pSubpasses[i].pipelineBindPoint, /* pipelineBindPoint */
-				p_create_info->pSubpasses[i].inputAttachmentCount, /* inputAttachmentCount */
-				input_attachments.size() == 0 ? nullptr : input_attachments.ptr(), /* pInputAttachments */
-				p_create_info->pSubpasses[i].colorAttachmentCount, /* colorAttachmentCount */
-				color_attachments.size() == 0 ? nullptr : color_attachments.ptr(), /* pColorAttachments */
-				resolve_attachments.size() == 0 ? nullptr : resolve_attachments.ptr(), /* pResolveAttachments */
-				depth_attachments.size() == 0 ? nullptr : depth_attachments.ptr(), /* pDepthStencilAttachment */
-				p_create_info->pSubpasses[i].preserveAttachmentCount, /* preserveAttachmentCount */
-				p_create_info->pSubpasses[i].pPreserveAttachments /* pPreserveAttachments */
-			};
-			attachment_references.push_back(input_attachments);
-			attachment_references.push_back(color_attachments);
-			attachment_references.push_back(resolve_attachments);
-			attachment_references.push_back(depth_attachments);
-
-			subpasses.push_back(subpass);
-		}
-
-		Vector<VkSubpassDependency> dependencies;
-		for (uint32_t i = 0; i < p_create_info->dependencyCount; i++) {
-			// We lose viewOffset here but again I don't believe we use this anywhere.
-			VkSubpassDependency dep = {
-				p_create_info->pDependencies[i].srcSubpass, /* srcSubpass */
-				p_create_info->pDependencies[i].dstSubpass, /* dstSubpass */
-				p_create_info->pDependencies[i].srcStageMask, /* srcStageMask */
-				p_create_info->pDependencies[i].dstStageMask, /* dstStageMask */
-				p_create_info->pDependencies[i].srcAccessMask, /* srcAccessMask */
-				p_create_info->pDependencies[i].dstAccessMask, /* dstAccessMask */
-				p_create_info->pDependencies[i].dependencyFlags, /* dependencyFlags */
-			};
-
-			dependencies.push_back(dep);
-		}
-
-		// CorrelatedViewMask is not supported in vkCreateRenderPass but we
-		// currently only use this for multiview.
-		// We'll need to look into this.
-
-		VkRenderPassCreateInfo create_info = {
-			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* sType */
-			next, /* pNext*/
-			p_create_info->flags, /* flags */
-			(uint32_t)attachments.size(), /* attachmentCount */
-			attachments.ptr(), /* pAttachments */
-			(uint32_t)subpasses.size(), /* subpassCount */
-			subpasses.ptr(), /* pSubpasses */
-			(uint32_t)dependencies.size(), /* */
-			dependencies.ptr(), /* */
-		};
-
-		return vkCreateRenderPass(device, &create_info, p_allocator, p_render_pass);
-	}
-}
-
-VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
-		VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-		VkDebugUtilsMessageTypeFlagsEXT messageType,
-		const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
-		void *pUserData) {
-	// This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors.
-	if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != nullptr &&
-			strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) {
-		return VK_FALSE;
-	}
-	// This needs to be ignored because Validator is wrong here.
-	if (strstr(pCallbackData->pMessage, "Invalid SPIR-V binary version 1.3") != nullptr) {
-		return VK_FALSE;
-	}
-	// This needs to be ignored because Validator is wrong here.
-	if (strstr(pCallbackData->pMessage, "Shader requires flag") != nullptr) {
-		return VK_FALSE;
-	}
-
-	// This needs to be ignored because Validator is wrong here.
-	if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != nullptr &&
-			strstr(pCallbackData->pMessage, "must be a memory object") != nullptr) {
-		return VK_FALSE;
-	}
-
-	if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
-		return VK_FALSE;
-	}
-
-	String type_string;
-	switch (messageType) {
-		case (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT):
-			type_string = "GENERAL";
-			break;
-		case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT):
-			type_string = "VALIDATION";
-			break;
-		case (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
-			type_string = "PERFORMANCE";
-			break;
-		case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
-			type_string = "VALIDATION|PERFORMANCE";
-			break;
-	}
-
-	String objects_string;
-	if (pCallbackData->objectCount > 0) {
-		objects_string = "\n\tObjects - " + String::num_int64(pCallbackData->objectCount);
-		for (uint32_t object = 0; object < pCallbackData->objectCount; ++object) {
-			objects_string +=
-					"\n\t\tObject[" + String::num_int64(object) + "]" +
-					" - " + string_VkObjectType(pCallbackData->pObjects[object].objectType) +
-					", Handle " + String::num_int64(pCallbackData->pObjects[object].objectHandle);
-			if (nullptr != pCallbackData->pObjects[object].pObjectName && strlen(pCallbackData->pObjects[object].pObjectName) > 0) {
-				objects_string += ", Name \"" + String(pCallbackData->pObjects[object].pObjectName) + "\"";
-			}
-		}
-	}
-
-	String labels_string;
-	if (pCallbackData->cmdBufLabelCount > 0) {
-		labels_string = "\n\tCommand Buffer Labels - " + String::num_int64(pCallbackData->cmdBufLabelCount);
-		for (uint32_t cmd_buf_label = 0; cmd_buf_label < pCallbackData->cmdBufLabelCount; ++cmd_buf_label) {
-			labels_string +=
-					"\n\t\tLabel[" + String::num_int64(cmd_buf_label) + "]" +
-					" - " + pCallbackData->pCmdBufLabels[cmd_buf_label].pLabelName +
-					"{ ";
-			for (int color_idx = 0; color_idx < 4; ++color_idx) {
-				labels_string += String::num(pCallbackData->pCmdBufLabels[cmd_buf_label].color[color_idx]);
-				if (color_idx < 3) {
-					labels_string += ", ";
-				}
-			}
-			labels_string += " }";
-		}
-	}
-
-	String error_message(type_string +
-			" - Message Id Number: " + String::num_int64(pCallbackData->messageIdNumber) +
-			" | Message Id Name: " + pCallbackData->pMessageIdName +
-			"\n\t" + pCallbackData->pMessage +
-			objects_string + labels_string);
-
-	// Convert VK severity to our own log macros.
-	switch (messageSeverity) {
-		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
-			print_verbose(error_message);
-			break;
-		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
-			print_line(error_message);
-			break;
-		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
-			WARN_PRINT(error_message);
-			break;
-		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
-			ERR_PRINT(error_message);
-			CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),
-					"Crashing, because abort on GPU errors is enabled.");
-			break;
-		case VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT:
-			break; // Shouldn't happen, only handling to make compilers happy.
-	}
-
-	return VK_FALSE;
-}
-
-VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_report_callback(
-		VkDebugReportFlagsEXT flags,
-		VkDebugReportObjectTypeEXT objectType,
-		uint64_t object,
-		size_t location,
-		int32_t messageCode,
-		const char *pLayerPrefix,
-		const char *pMessage,
-		void *pUserData) {
-	String debugMessage = String("Vulkan Debug Report: object - ") +
-			String::num_int64(object) + "\n" + pMessage;
-
-	switch (flags) {
-		case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
-		case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
-			print_line(debugMessage);
-			break;
-		case VK_DEBUG_REPORT_WARNING_BIT_EXT:
-		case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
-			WARN_PRINT(debugMessage);
-			break;
-		case VK_DEBUG_REPORT_ERROR_BIT_EXT:
-			ERR_PRINT(debugMessage);
-			break;
-	}
-
-	return VK_FALSE;
-}
-
-VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers) {
-	for (uint32_t i = 0; i < check_count; i++) {
-		VkBool32 found = 0;
-		for (uint32_t j = 0; j < layer_count; j++) {
-			if (!strcmp(check_names[i], layers[j].layerName)) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found) {
-			WARN_PRINT("Can't find layer: " + String(check_names[i]));
-			return 0;
-		}
-	}
-	return 1;
-}
-
-Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
-	static const LocalVector<LocalVector<const char *>> instance_validation_layers_alt{
-		// Preferred set of validation layers.
-		{ "VK_LAYER_KHRONOS_validation" },
-
-		// Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers.
-		{ "VK_LAYER_LUNARG_standard_validation" },
-
-		// Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers.
-		{ "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
-	};
-
-	// Clear out-arguments.
-	*count = 0;
-	if (names != nullptr) {
-		*names = nullptr;
-	}
-
-	VkResult err;
-	uint32_t instance_layer_count;
-
-	err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
-	if (err) {
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	if (instance_layer_count < 1) {
-		return OK;
-	}
-
-	VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
-	err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
-	if (err) {
-		free(instance_layers);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	for (const LocalVector<const char *> &layer : instance_validation_layers_alt) {
-		if (_check_layers(layer.size(), layer.ptr(), instance_layer_count, instance_layers)) {
-			*count = layer.size();
-			if (names != nullptr) {
-				*names = layer.ptr();
-			}
-			break;
-		}
-	}
-
-	free(instance_layers);
-
-	return OK;
-}
-
-typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);
-
-Error VulkanContext::_obtain_vulkan_version() {
-	// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
-	// For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
-	_vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
-	if (func != nullptr) {
-		uint32_t api_version;
-		VkResult res = func(&api_version);
-		if (res == VK_SUCCESS) {
-			instance_api_version = api_version;
-		} else {
-			// According to the documentation this shouldn't fail with anything except a memory allocation error
-			// in which case we're in deep trouble anyway.
-			ERR_FAIL_V(ERR_CANT_CREATE);
-		}
-	} else {
-		print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
-		instance_api_version = VK_API_VERSION_1_0;
-	}
-
-	return OK;
-}
-
-bool VulkanContext::instance_extensions_initialized = false;
-HashMap<CharString, bool> VulkanContext::requested_instance_extensions;
-
-void VulkanContext::register_requested_instance_extension(const CharString &extension_name, bool p_required) {
-	ERR_FAIL_COND_MSG(instance_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
-	ERR_FAIL_COND(requested_instance_extensions.has(extension_name));
-
-	requested_instance_extensions[extension_name] = p_required;
-}
-
-Error VulkanContext::_initialize_instance_extensions() {
-	enabled_instance_extension_names.clear();
-
-	// Make sure our core extensions are here
-	register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
-	if (_get_platform_surface_extension()) {
-		register_requested_instance_extension(_get_platform_surface_extension(), true);
-	}
-
-	if (_use_validation_layers()) {
-		register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
-	}
-
-	// This extension allows us to use the properties2 features to query additional device capabilities
-	register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
-
-	// Only enable debug utils in verbose mode or DEV_ENABLED.
-	// End users would get spammed with messages of varying verbosity due to the
-	// mess that thirdparty layers/extensions and drivers seem to leave in their
-	// wake, making the Windows registry a bottomless pit of broken layer JSON.
-#ifdef DEV_ENABLED
-	bool want_debug_utils = true;
-#else
-	bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
-#endif
-	if (want_debug_utils) {
-		register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false);
-	}
-
-	// Load instance extensions that are available...
-	uint32_t instance_extension_count = 0;
-	VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
-	ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
-	ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions found, is a driver installed?");
-
-	VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count);
-	err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions);
-	if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
-		free(instance_extensions);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-#ifdef DEV_ENABLED
-	for (uint32_t i = 0; i < instance_extension_count; i++) {
-		print_verbose(String("VULKAN: Found instance extension ") + String::utf8(instance_extensions[i].extensionName));
-	}
-#endif
-
-	// Enable all extensions that are supported and requested
-	for (uint32_t i = 0; i < instance_extension_count; i++) {
-		CharString extension_name(instance_extensions[i].extensionName);
-		if (requested_instance_extensions.has(extension_name)) {
-			enabled_instance_extension_names.insert(extension_name);
-		}
-	}
-
-	// Now check our requested extensions
-	for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) {
-		if (!enabled_instance_extension_names.has(requested_extension.key)) {
-			if (requested_extension.value) {
-				free(instance_extensions);
-				ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String::utf8(requested_extension.key) + String(" not found, is a driver installed?"));
-			} else {
-				print_verbose(String("Optional extension ") + String::utf8(requested_extension.key) + String(" not found"));
-			}
-		}
-	}
-
-	free(instance_extensions);
-
-	instance_extensions_initialized = true;
-	return OK;
-}
-
-bool VulkanContext::device_extensions_initialized = false;
-HashMap<CharString, bool> VulkanContext::requested_device_extensions;
-
-void VulkanContext::register_requested_device_extension(const CharString &extension_name, bool p_required) {
-	ERR_FAIL_COND_MSG(device_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
-	ERR_FAIL_COND(requested_device_extensions.has(extension_name));
-
-	requested_device_extensions[extension_name] = p_required;
-}
-
-Error VulkanContext::_initialize_device_extensions() {
-	// Look for device extensions.
-	enabled_device_extension_names.clear();
-
-	// Make sure our core extensions are here
-	register_requested_device_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true);
-
-	register_requested_device_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, false);
-	register_requested_device_extension(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
-
-	if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
-		register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true);
-	}
-
-	// TODO consider the following extensions:
-	// - VK_KHR_spirv_1_4
-	// - VK_KHR_swapchain_mutable_format
-	// - VK_EXT_full_screen_exclusive
-	// - VK_EXT_hdr_metadata
-	// - VK_KHR_depth_stencil_resolve
-
-	// Even though the user "enabled" the extension via the command
-	// line, we must make sure that it's enumerated for use with the
-	// device.  Therefore, disable it here, and re-enable it again if
-	// enumerated.
-	if (VK_KHR_incremental_present_enabled) {
-		register_requested_device_extension(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, false);
-	}
-	if (VK_GOOGLE_display_timing_enabled) {
-		register_requested_device_extension(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, false);
-	}
-
-	// obtain available device extensions
-	uint32_t device_extension_count = 0;
-	VkResult err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	ERR_FAIL_COND_V_MSG(device_extension_count == 0, ERR_CANT_CREATE,
-			"vkEnumerateDeviceExtensionProperties failed to find any extensions\n\n"
-			"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
-			"vkCreateInstance Failure");
-
-	VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count);
-	err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions);
-	if (err) {
-		free(device_extensions);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-#ifdef DEV_ENABLED
-	for (uint32_t i = 0; i < device_extension_count; i++) {
-		print_verbose(String("VULKAN: Found device extension ") + String::utf8(device_extensions[i].extensionName));
-	}
-#endif
-
-	// Enable all extensions that are supported and requested
-	for (uint32_t i = 0; i < device_extension_count; i++) {
-		CharString extension_name(device_extensions[i].extensionName);
-		if (requested_device_extensions.has(extension_name)) {
-			enabled_device_extension_names.insert(extension_name);
-		}
-	}
-
-	// Now check our requested extensions
-	for (KeyValue<CharString, bool> &requested_extension : requested_device_extensions) {
-		if (!enabled_device_extension_names.has(requested_extension.key)) {
-			if (requested_extension.value) {
-				free(device_extensions);
-				ERR_FAIL_V_MSG(ERR_BUG,
-						String("vkEnumerateDeviceExtensionProperties failed to find the ") + String::utf8(requested_extension.key) + String(" extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkCreateInstance Failure"));
-			} else {
-				print_verbose(String("Optional extension ") + String::utf8(requested_extension.key) + String(" not found"));
-			}
-		}
-	}
-
-	free(device_extensions);
-
-	device_extensions_initialized = true;
-	return OK;
-}
-
-uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
-	uint32_t flags = 0;
-
-	if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
-		flags += RenderingDevice::ShaderStage::SHADER_STAGE_VERTEX_BIT;
-	}
-	if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
-		flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_CONTROL_BIT;
-	}
-	if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
-		flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_EVALUATION_BIT;
-	}
-	// if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
-	// 	flags += RenderingDevice::ShaderStage::SHADER_STAGE_GEOMETRY_BIT;
-	// }
-	if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
-		flags += RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT;
-	}
-	if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
-		flags += RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT;
-	}
-
-	return flags;
-}
-
-String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
-	String res;
-
-	if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
-		res += ", STAGE_VERTEX";
-	}
-	if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
-		res += ", STAGE_TESSELLATION_CONTROL";
-	}
-	if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
-		res += ", STAGE_TESSELLATION_EVALUATION";
-	}
-	if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
-		res += ", STAGE_GEOMETRY";
-	}
-	if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
-		res += ", STAGE_FRAGMENT";
-	}
-	if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
-		res += ", STAGE_COMPUTE";
-	}
-
-	// These are not defined on Android GRMBL.
-	if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
-		res += ", STAGE_RAYGEN_KHR";
-	}
-	if (supportedStages & 0x00000200 /* VK_SHADER_STAGE_ANY_HIT_BIT_KHR */) {
-		res += ", STAGE_ANY_HIT_KHR";
-	}
-	if (supportedStages & 0x00000400 /* VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR */) {
-		res += ", STAGE_CLOSEST_HIT_KHR";
-	}
-	if (supportedStages & 0x00000800 /* VK_SHADER_STAGE_MISS_BIT_KHR */) {
-		res += ", STAGE_MISS_KHR";
-	}
-	if (supportedStages & 0x00001000 /* VK_SHADER_STAGE_INTERSECTION_BIT_KHR */) {
-		res += ", STAGE_INTERSECTION_KHR";
-	}
-	if (supportedStages & 0x00002000 /* VK_SHADER_STAGE_CALLABLE_BIT_KHR */) {
-		res += ", STAGE_CALLABLE_KHR";
-	}
-	if (supportedStages & 0x00000040 /* VK_SHADER_STAGE_TASK_BIT_NV */) {
-		res += ", STAGE_TASK_NV";
-	}
-	if (supportedStages & 0x00000080 /* VK_SHADER_STAGE_MESH_BIT_NV */) {
-		res += ", STAGE_MESH_NV";
-	}
-
-	return res.substr(2); // Remove first ", ".
-}
-
-uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
-	uint32_t flags = 0;
-
-	if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT;
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
-		flags += RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT;
-	}
-
-	return flags;
-}
-
-String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
-	String res;
-
-	if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
-		res += ", FEATURE_BASIC";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
-		res += ", FEATURE_VOTE";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
-		res += ", FEATURE_ARITHMETIC";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
-		res += ", FEATURE_BALLOT";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
-		res += ", FEATURE_SHUFFLE";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
-		res += ", FEATURE_SHUFFLE_RELATIVE";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
-		res += ", FEATURE_CLUSTERED";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
-		res += ", FEATURE_QUAD";
-	}
-	if (supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) {
-		res += ", FEATURE_PARTITIONED_NV";
-	}
-
-	return res.substr(2); // Remove first ", ".
-}
-
-Error VulkanContext::_check_capabilities() {
-	// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html
-	// https://www.khronos.org/blog/vulkan-subgroup-tutorial
-
-	// For Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
-
-	// So we check if the functions are accessible by getting their function pointers and skipping if not
-	// (note that the desktop loader does a better job here but the android loader doesn't.)
-
-	// Assume not supported until proven otherwise.
-	vrs_capabilities.pipeline_vrs_supported = false;
-	vrs_capabilities.primitive_vrs_supported = false;
-	vrs_capabilities.attachment_vrs_supported = false;
-	vrs_capabilities.min_texel_size = Size2i();
-	vrs_capabilities.max_texel_size = Size2i();
-	vrs_capabilities.texel_size = Size2i();
-	multiview_capabilities.is_supported = false;
-	multiview_capabilities.geometry_shader_is_supported = false;
-	multiview_capabilities.tessellation_shader_is_supported = false;
-	multiview_capabilities.max_view_count = 0;
-	multiview_capabilities.max_instance_count = 0;
-	subgroup_capabilities.size = 0;
-	subgroup_capabilities.min_size = 0;
-	subgroup_capabilities.max_size = 0;
-	subgroup_capabilities.supportedStages = 0;
-	subgroup_capabilities.supportedOperations = 0;
-	subgroup_capabilities.quadOperationsInAllStages = false;
-	subgroup_capabilities.size_control_is_supported = false;
-	shader_capabilities.shader_float16_is_supported = false;
-	shader_capabilities.shader_int8_is_supported = false;
-	storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false;
-	storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = false;
-	storage_buffer_capabilities.storage_push_constant_16_is_supported = false;
-	storage_buffer_capabilities.storage_input_output_16 = false;
-
-	if (is_instance_extension_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
-		// Check for extended features.
-		PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
-		if (vkGetPhysicalDeviceFeatures2_func == nullptr) {
-			// In Vulkan 1.0 might be accessible under its original extension name.
-			vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
-		}
-		if (vkGetPhysicalDeviceFeatures2_func != nullptr) {
-			// Check our extended features.
-			void *next = nullptr;
-
-			// We must check that the relative extension is present before assuming a
-			// feature as enabled.
-			// See also: https://github.com/godotengine/godot/issues/65409
-
-			VkPhysicalDeviceVulkan12Features device_features_vk12 = {};
-			VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {};
-			VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
-			VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
-			VkPhysicalDeviceMultiviewFeatures multiview_features = {};
-			VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_cache_control_features = {};
-
-			if (device_api_version >= VK_API_VERSION_1_2) {
-				device_features_vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
-				device_features_vk12.pNext = next;
-				next = &device_features_vk12;
-			} else {
-				if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
-					shader_features = {
-						/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
-						/*pNext*/ next,
-						/*shaderFloat16*/ false,
-						/*shaderInt8*/ false,
-					};
-					next = &shader_features;
-				}
-			}
-
-			if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
-				vrs_features = {
-					/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR,
-					/*pNext*/ next,
-					/*pipelineFragmentShadingRate*/ false,
-					/*primitiveFragmentShadingRate*/ false,
-					/*attachmentFragmentShadingRate*/ false,
-				};
-				next = &vrs_features;
-			}
-
-			if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
-				storage_feature = {
-					/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
-					/*pNext*/ next,
-					/*storageBuffer16BitAccess*/ false,
-					/*uniformAndStorageBuffer16BitAccess*/ false,
-					/*storagePushConstant16*/ false,
-					/*storageInputOutput16*/ false,
-				};
-				next = &storage_feature;
-			}
-
-			if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
-				multiview_features = {
-					/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
-					/*pNext*/ next,
-					/*multiview*/ false,
-					/*multiviewGeometryShader*/ false,
-					/*multiviewTessellationShader*/ false,
-				};
-				next = &multiview_features;
-			}
-
-			if (is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) {
-				pipeline_cache_control_features = {
-					/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
-					/*pNext*/ next,
-					/*pipelineCreationCacheControl*/ false,
-				};
-				next = &pipeline_cache_control_features;
-			}
-
-			VkPhysicalDeviceFeatures2 device_features;
-			device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-			device_features.pNext = next;
-
-			vkGetPhysicalDeviceFeatures2_func(gpu, &device_features);
-
-			if (device_api_version >= VK_API_VERSION_1_2) {
-#ifdef MACOS_ENABLED
-				ERR_FAIL_COND_V_MSG(!device_features_vk12.shaderSampledImageArrayNonUniformIndexing, ERR_CANT_CREATE, "Your GPU doesn't support shaderSampledImageArrayNonUniformIndexing which is required to use the Vulkan-based renderers in Godot.");
-#endif
-
-				if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
-					shader_capabilities.shader_float16_is_supported = device_features_vk12.shaderFloat16;
-					shader_capabilities.shader_int8_is_supported = device_features_vk12.shaderInt8;
-				}
-			} else {
-				if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
-					shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
-					shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
-				}
-			}
-
-			if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
-				vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
-				vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
-				vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
-			}
-
-			if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
-				multiview_capabilities.is_supported = multiview_features.multiview;
-				multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
-				multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
-			}
-
-			if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
-				storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
-				storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess;
-				storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
-				storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
-			}
-
-			if (is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) {
-				pipeline_cache_control_support = pipeline_cache_control_features.pipelineCreationCacheControl;
-			}
-		}
-
-		// Check extended properties.
-		PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
-		if (device_properties_func == nullptr) {
-			// In Vulkan 1.0 might be accessible under its original extension name.
-			device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
-		}
-		if (device_properties_func != nullptr) {
-			VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties{};
-			VkPhysicalDeviceMultiviewProperties multiviewProperties{};
-			VkPhysicalDeviceSubgroupProperties subgroupProperties{};
-			VkPhysicalDeviceSubgroupSizeControlProperties subgroupSizeControlProperties = {};
-			VkPhysicalDeviceProperties2 physicalDeviceProperties{};
-			void *nextptr = nullptr;
-
-			if (device_api_version >= VK_API_VERSION_1_1) { // Vulkan 1.1 or higher
-				subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
-				subgroupProperties.pNext = nextptr;
-
-				nextptr = &subgroupProperties;
-
-				subgroup_capabilities.size_control_is_supported = is_device_extension_enabled(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
-
-				if (subgroup_capabilities.size_control_is_supported) {
-					subgroupSizeControlProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
-					subgroupSizeControlProperties.pNext = nextptr;
-
-					nextptr = &subgroupSizeControlProperties;
-				}
-			}
-
-			if (multiview_capabilities.is_supported) {
-				multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
-				multiviewProperties.pNext = nextptr;
-
-				nextptr = &multiviewProperties;
-			}
-
-			if (vrs_capabilities.attachment_vrs_supported) {
-				vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
-				vrsProperties.pNext = nextptr;
-
-				nextptr = &vrsProperties;
-			}
-
-			physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-			physicalDeviceProperties.pNext = nextptr;
-
-			device_properties_func(gpu, &physicalDeviceProperties);
-
-			subgroup_capabilities.size = subgroupProperties.subgroupSize;
-			subgroup_capabilities.min_size = subgroupProperties.subgroupSize;
-			subgroup_capabilities.max_size = subgroupProperties.subgroupSize;
-			subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
-			subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
-			// Note: quadOperationsInAllStages will be true if:
-			// - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT.
-			// - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT.
-			subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
-
-			if (subgroup_capabilities.size_control_is_supported && (subgroupSizeControlProperties.requiredSubgroupSizeStages & VK_SHADER_STAGE_COMPUTE_BIT)) {
-				subgroup_capabilities.min_size = subgroupSizeControlProperties.minSubgroupSize;
-				subgroup_capabilities.max_size = subgroupSizeControlProperties.maxSubgroupSize;
-			}
-
-			if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
-				print_verbose("- Vulkan Variable Rate Shading supported:");
-				if (vrs_capabilities.pipeline_vrs_supported) {
-					print_verbose("  Pipeline fragment shading rate");
-				}
-				if (vrs_capabilities.primitive_vrs_supported) {
-					print_verbose("  Primitive fragment shading rate");
-				}
-				if (vrs_capabilities.attachment_vrs_supported) {
-					// TODO expose these somehow to the end user.
-					vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width;
-					vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height;
-					vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
-					vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height;
-
-					// We'll attempt to default to a texel size of 16x16
-					vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x);
-					vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y);
-
-					print_verbose(String("  Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")"));
-				}
-
-			} else {
-				print_verbose("- Vulkan Variable Rate Shading not supported");
-			}
-
-			if (multiview_capabilities.is_supported) {
-				multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
-				multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
-
-				print_verbose("- Vulkan multiview supported:");
-				print_verbose("  max view count: " + itos(multiview_capabilities.max_view_count));
-				print_verbose("  max instances: " + itos(multiview_capabilities.max_instance_count));
-			} else {
-				print_verbose("- Vulkan multiview not supported");
-			}
-
-			print_verbose("- Vulkan subgroup:");
-			print_verbose("  size: " + itos(subgroup_capabilities.size));
-			print_verbose("  min size: " + itos(subgroup_capabilities.min_size));
-			print_verbose("  max size: " + itos(subgroup_capabilities.max_size));
-			print_verbose("  stages: " + subgroup_capabilities.supported_stages_desc());
-			print_verbose("  supported ops: " + subgroup_capabilities.supported_operations_desc());
-			if (subgroup_capabilities.quadOperationsInAllStages) {
-				print_verbose("  quad operations in all stages");
-			}
-		} else {
-			print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2");
-		}
-	}
-
-	return OK;
-}
-
-Error VulkanContext::_create_instance() {
-	// Obtain Vulkan version.
-	_obtain_vulkan_version();
-
-	// Initialize extensions.
-	{
-		Error err = _initialize_instance_extensions();
-		if (err != OK) {
-			return err;
-		}
-	}
-
-	int enabled_extension_count = 0;
-	const char *enabled_extension_names[MAX_EXTENSIONS];
-	ERR_FAIL_COND_V(enabled_instance_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
-	for (const CharString &extension_name : enabled_instance_extension_names) {
-		enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
-	}
-
-	// We'll set application version to the Vulkan version we're developing against, even if our instance is based on
-	// an older Vulkan version, devices can still support newer versions of Vulkan.
-	// The exception is when we're on Vulkan 1.0, we should not set this to anything but 1.0.
-	// Note that this value is only used by validation layers to warn us about version issues.
-	uint32_t application_api_version = instance_api_version == VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : VK_API_VERSION_1_2;
-
-	CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
-	const VkApplicationInfo app = {
-		/*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
-		/*pNext*/ nullptr,
-		/*pApplicationName*/ cs.get_data(),
-		/*applicationVersion*/ 0, // It would be really nice if we store a version number in project settings, say "application/config/version"
-		/*pEngineName*/ VERSION_NAME,
-		/*engineVersion*/ VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH),
-		/*apiVersion*/ application_api_version
-	};
-	VkInstanceCreateInfo inst_info{};
-	inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
-	inst_info.pApplicationInfo = &app;
-	inst_info.enabledExtensionCount = enabled_extension_count;
-	inst_info.ppEnabledExtensionNames = (const char *const *)enabled_extension_names;
-	if (_use_validation_layers()) {
-		_get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames);
-	}
-
-	/*
-	 * This is info for a temp callback to use during CreateInstance.
-	 * After the instance is created, we use the instance-based
-	 * function to register the final callback.
-	 */
-	VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info = {};
-	VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info = {};
-	if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
-		// VK_EXT_debug_utils style.
-		dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
-		dbg_messenger_create_info.pNext = nullptr;
-		dbg_messenger_create_info.flags = 0;
-		dbg_messenger_create_info.messageSeverity =
-				VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
-		dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
-				VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
-				VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
-		dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
-		dbg_messenger_create_info.pUserData = this;
-		inst_info.pNext = &dbg_messenger_create_info;
-	} else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-		dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
-		dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
-				VK_DEBUG_REPORT_WARNING_BIT_EXT |
-				VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
-				VK_DEBUG_REPORT_ERROR_BIT_EXT |
-				VK_DEBUG_REPORT_DEBUG_BIT_EXT;
-		dbg_report_callback_create_info.pfnCallback = _debug_report_callback;
-		dbg_report_callback_create_info.pUserData = this;
-		inst_info.pNext = &dbg_report_callback_create_info;
-	}
-
-	VkResult err;
-
-	if (vulkan_hooks) {
-		if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) {
-			return ERR_CANT_CREATE;
-		}
-	} else {
-		err = vkCreateInstance(&inst_info, nullptr, &inst);
-		ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
-				"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
-				"vkCreateInstance Failure");
-		ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
-				"Cannot find a specified extension library.\n"
-				"Make sure your layers path is set appropriately.\n"
-				"vkCreateInstance Failure");
-		ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
-				"vkCreateInstance failed.\n\n"
-				"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
-				"Please look at the Getting Started guide for additional information.\n"
-				"vkCreateInstance Failure");
-	}
-
-	inst_initialized = true;
-
-#ifdef USE_VOLK
-	volkLoadInstance(inst);
-#endif
-
-	if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
-		// Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
-		CreateDebugUtilsMessengerEXT =
-				(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT");
-		DestroyDebugUtilsMessengerEXT =
-				(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugUtilsMessengerEXT");
-		SubmitDebugUtilsMessageEXT =
-				(PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(inst, "vkSubmitDebugUtilsMessageEXT");
-		CmdBeginDebugUtilsLabelEXT =
-				(PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdBeginDebugUtilsLabelEXT");
-		CmdEndDebugUtilsLabelEXT =
-				(PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdEndDebugUtilsLabelEXT");
-		CmdInsertDebugUtilsLabelEXT =
-				(PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT");
-		SetDebugUtilsObjectNameEXT =
-				(PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT");
-		if (nullptr == CreateDebugUtilsMessengerEXT || nullptr == DestroyDebugUtilsMessengerEXT ||
-				nullptr == SubmitDebugUtilsMessageEXT || nullptr == CmdBeginDebugUtilsLabelEXT ||
-				nullptr == CmdEndDebugUtilsLabelEXT || nullptr == CmdInsertDebugUtilsLabelEXT ||
-				nullptr == SetDebugUtilsObjectNameEXT) {
-			ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-					"GetProcAddr: Failed to init VK_EXT_debug_utils\n"
-					"GetProcAddr: Failure");
-		}
-
-		err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, nullptr, &dbg_messenger);
-		switch (err) {
-			case VK_SUCCESS:
-				break;
-			case VK_ERROR_OUT_OF_HOST_MEMORY:
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-						"CreateDebugUtilsMessengerEXT: out of host memory\n"
-						"CreateDebugUtilsMessengerEXT Failure");
-				break;
-			default:
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-						"CreateDebugUtilsMessengerEXT: unknown failure\n"
-						"CreateDebugUtilsMessengerEXT Failure");
-				ERR_FAIL_V(ERR_CANT_CREATE);
-				break;
-		}
-	} else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
-		CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT");
-		DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT");
-		DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT");
-
-		if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) {
-			ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-					"GetProcAddr: Failed to init VK_EXT_debug_report\n"
-					"GetProcAddr: Failure");
-		}
-
-		err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report);
-		switch (err) {
-			case VK_SUCCESS:
-				break;
-			case VK_ERROR_OUT_OF_HOST_MEMORY:
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-						"CreateDebugReportCallbackEXT: out of host memory\n"
-						"CreateDebugReportCallbackEXT Failure");
-				break;
-			default:
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE,
-						"CreateDebugReportCallbackEXT: unknown failure\n"
-						"CreateDebugReportCallbackEXT Failure");
-				ERR_FAIL_V(ERR_CANT_CREATE);
-				break;
-		}
-	}
-
-	return OK;
-}
-
-Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
-	// Make initial call to query gpu_count, then second call for gpu info.
-	uint32_t gpu_count = 0;
-	VkResult err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	ERR_FAIL_COND_V_MSG(gpu_count == 0, ERR_CANT_CREATE,
-			"vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
-			"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
-			"vkEnumeratePhysicalDevices Failure");
-
-	VkPhysicalDevice *physical_devices = (VkPhysicalDevice *)malloc(sizeof(VkPhysicalDevice) * gpu_count);
-	err = vkEnumeratePhysicalDevices(inst, &gpu_count, physical_devices);
-	if (err) {
-		free(physical_devices);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	static const struct {
-		uint32_t id;
-		const char *name;
-	} vendor_names[] = {
-		{ 0x1002, "AMD" },
-		{ 0x1010, "ImgTec" },
-		{ 0x106B, "Apple" },
-		{ 0x10DE, "NVIDIA" },
-		{ 0x13B5, "ARM" },
-		{ 0x5143, "Qualcomm" },
-		{ 0x8086, "Intel" },
-		{ 0, nullptr },
-	};
-
-	int32_t device_index = -1;
-	if (vulkan_hooks) {
-		if (!vulkan_hooks->get_physical_device(&gpu)) {
-			return ERR_CANT_CREATE;
-		}
-
-		// Not really needed but nice to print the correct entry.
-		for (uint32_t i = 0; i < gpu_count; ++i) {
-			if (physical_devices[i] == gpu) {
-				device_index = i;
-				break;
-			}
-		}
-	} else {
-		// TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
-		// The device should really be a preference, but for now choosing a discrete GPU over the
-		// integrated one is better than the default.
-
-		int type_selected = -1;
-		print_verbose("Vulkan devices:");
-		for (uint32_t i = 0; i < gpu_count; ++i) {
-			VkPhysicalDeviceProperties props;
-			vkGetPhysicalDeviceProperties(physical_devices[i], &props);
-
-			bool present_supported = false;
-
-			if (p_surface) {
-				uint32_t device_queue_family_count = 0;
-				vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
-				VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
-				vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
-				for (uint32_t j = 0; j < device_queue_family_count; j++) {
-					if ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
-						VkBool32 supports;
-						err = vkGetPhysicalDeviceSurfaceSupportKHR(
-								physical_devices[i], j, p_surface, &supports);
-						if (err == VK_SUCCESS && supports) {
-							present_supported = true;
-						} else {
-							continue;
-						}
-					}
-				}
-				free(device_queue_props);
-			}
-			String name = String::utf8(props.deviceName);
-			String vendor = "Unknown";
-			String dev_type;
-			switch (props.deviceType) {
-				case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
-					dev_type = "Discrete";
-				} break;
-				case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
-					dev_type = "Integrated";
-				} break;
-				case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
-					dev_type = "Virtual";
-				} break;
-				case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
-					dev_type = "CPU";
-				} break;
-				default: {
-					dev_type = "Other";
-				} break;
-			}
-			uint32_t vendor_idx = 0;
-			while (vendor_names[vendor_idx].name != nullptr) {
-				if (props.vendorID == vendor_names[vendor_idx].id) {
-					vendor = vendor_names[vendor_idx].name;
-					break;
-				}
-				vendor_idx++;
-			}
-			print_verbose("  #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
-
-			if (present_supported || !p_surface) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
-				switch (props.deviceType) {
-					case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
-						if (type_selected < 4) {
-							type_selected = 4;
-							device_index = i;
-						}
-					} break;
-					case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
-						if (type_selected < 3) {
-							type_selected = 3;
-							device_index = i;
-						}
-					} break;
-					case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
-						if (type_selected < 2) {
-							type_selected = 2;
-							device_index = i;
-						}
-					} break;
-					case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
-						if (type_selected < 1) {
-							type_selected = 1;
-							device_index = i;
-						}
-					} break;
-					default: {
-						if (type_selected < 0) {
-							type_selected = 0;
-							device_index = i;
-						}
-					} break;
-				}
-			}
-		}
-
-		int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
-		if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
-			device_index = user_device_index;
-		}
-
-		ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
-
-		gpu = physical_devices[device_index];
-	}
-
-	free(physical_devices);
-
-	// Get identifier properties.
-	vkGetPhysicalDeviceProperties(gpu, &gpu_props);
-
-	device_name = String::utf8(gpu_props.deviceName);
-	device_type = gpu_props.deviceType;
-	pipeline_cache_id = String::hex_encode_buffer(gpu_props.pipelineCacheUUID, VK_UUID_SIZE);
-	pipeline_cache_id += "-driver-" + itos(gpu_props.driverVersion);
-	{
-		device_vendor = "Unknown";
-		uint32_t vendor_idx = 0;
-		while (vendor_names[vendor_idx].name != nullptr) {
-			if (gpu_props.vendorID == vendor_names[vendor_idx].id) {
-				device_vendor = vendor_names[vendor_idx].name;
-				break;
-			}
-			vendor_idx++;
-		}
-	}
-
-	// Get device version
-	device_api_version = gpu_props.apiVersion;
-
-	String rendering_method;
-	if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
-		rendering_method = "Forward Mobile";
-	} else {
-		rendering_method = "Forward+";
-	}
-
-	// Output our device version
-	print_line(vformat("Vulkan API %s - %s - Using Vulkan Device #%d: %s - %s", get_device_api_version(), rendering_method, device_index, device_vendor, device_name));
-
-	{
-		Error _err = _initialize_device_extensions();
-		if (_err != OK) {
-			return _err;
-		}
-	}
-
-	// Call with nullptr data to get count.
-	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
-	ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
-
-	queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties));
-	vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props);
-	// Query fine-grained feature support for this device.
-	//  If app has specific feature requirements it should check supported
-	//  features based on this query
-	VkPhysicalDeviceFeatures features = {};
-	vkGetPhysicalDeviceFeatures(gpu, &features);
-
-	// Check required features and abort if any of them is missing.
-	if (!features.imageCubeArray || !features.independentBlend) {
-		String error_string = vformat("Your GPU (%s) does not support the following features which are required to use Vulkan-based renderers in Godot:\n\n", device_name);
-		if (!features.imageCubeArray) {
-			error_string += "- No support for image cube arrays.\n";
-		}
-		if (!features.independentBlend) {
-			error_string += "- No support for independentBlend.\n";
-		}
-		error_string += "\nThis is usually a hardware limitation, so updating graphics drivers won't help in most cases.";
-
-#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
-		// Android/iOS platform ports currently don't exit themselves when this method returns `ERR_CANT_CREATE`.
-		OS::get_singleton()->alert(error_string + "\nClick OK to exit (black screen will be visible).");
-#else
-		OS::get_singleton()->alert(error_string + "\nClick OK to exit.");
-#endif
-
-		return ERR_CANT_CREATE;
-	}
-
-	memset(&physical_device_features, 0, sizeof(physical_device_features));
-#define VK_DEVICEFEATURE_ENABLE_IF(x)            \
-	if (features.x) {                            \
-		physical_device_features.x = features.x; \
-	} else                                       \
-		((void)0)
-
-	//
-	// Opt-in to the features we actually need/use. These can be changed in the future.
-	// We do this for multiple reasons:
-	//
-	//	1. Certain features (like sparse* stuff) cause unnecessary internal driver allocations.
-	//	2. Others like shaderStorageImageMultisample are a huge red flag
-	//	   (MSAA + Storage is rarely needed).
-	//	3. Most features when turned off aren't actually off (we just promise the driver not to use them)
-	//	   and it is validation what will complain. This allows us to target a minimum baseline.
-	//
-	// TODO: Allow the user to override these settings (i.e. turn off more stuff) using profiles
-	// so they can target a broad range of HW. For example Mali HW does not have
-	// shaderClipDistance/shaderCullDistance; thus validation would complain if such feature is used;
-	// allowing them to fix the problem without even owning Mali HW to test on.
-	//
-
-	// Turn off robust buffer access, which can hamper performance on some hardware.
-	//VK_DEVICEFEATURE_ENABLE_IF(robustBufferAccess);
-	VK_DEVICEFEATURE_ENABLE_IF(fullDrawIndexUint32);
-	VK_DEVICEFEATURE_ENABLE_IF(imageCubeArray);
-	VK_DEVICEFEATURE_ENABLE_IF(independentBlend);
-	VK_DEVICEFEATURE_ENABLE_IF(geometryShader);
-	VK_DEVICEFEATURE_ENABLE_IF(tessellationShader);
-	VK_DEVICEFEATURE_ENABLE_IF(sampleRateShading);
-	VK_DEVICEFEATURE_ENABLE_IF(dualSrcBlend);
-	VK_DEVICEFEATURE_ENABLE_IF(logicOp);
-	VK_DEVICEFEATURE_ENABLE_IF(multiDrawIndirect);
-	VK_DEVICEFEATURE_ENABLE_IF(drawIndirectFirstInstance);
-	VK_DEVICEFEATURE_ENABLE_IF(depthClamp);
-	VK_DEVICEFEATURE_ENABLE_IF(depthBiasClamp);
-	VK_DEVICEFEATURE_ENABLE_IF(fillModeNonSolid);
-	VK_DEVICEFEATURE_ENABLE_IF(depthBounds);
-	VK_DEVICEFEATURE_ENABLE_IF(wideLines);
-	VK_DEVICEFEATURE_ENABLE_IF(largePoints);
-	VK_DEVICEFEATURE_ENABLE_IF(alphaToOne);
-	VK_DEVICEFEATURE_ENABLE_IF(multiViewport);
-	VK_DEVICEFEATURE_ENABLE_IF(samplerAnisotropy);
-	VK_DEVICEFEATURE_ENABLE_IF(textureCompressionETC2);
-	VK_DEVICEFEATURE_ENABLE_IF(textureCompressionASTC_LDR);
-	VK_DEVICEFEATURE_ENABLE_IF(textureCompressionBC);
-	//VK_DEVICEFEATURE_ENABLE_IF(occlusionQueryPrecise);
-	//VK_DEVICEFEATURE_ENABLE_IF(pipelineStatisticsQuery);
-	VK_DEVICEFEATURE_ENABLE_IF(vertexPipelineStoresAndAtomics);
-	VK_DEVICEFEATURE_ENABLE_IF(fragmentStoresAndAtomics);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderTessellationAndGeometryPointSize);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderImageGatherExtended);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderStorageImageExtendedFormats);
-	// Intel Arc doesn't support shaderStorageImageMultisample (yet? could be a driver thing), so it's
-	// better for Validation to scream at us if we use it. Furthermore MSAA Storage is a huge red flag
-	// for performance.
-	//VK_DEVICEFEATURE_ENABLE_IF(shaderStorageImageMultisample);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderStorageImageReadWithoutFormat);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderStorageImageWriteWithoutFormat);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderUniformBufferArrayDynamicIndexing);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderSampledImageArrayDynamicIndexing);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderStorageBufferArrayDynamicIndexing);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderStorageImageArrayDynamicIndexing);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderClipDistance);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderCullDistance);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderFloat64);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderInt64);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderInt16);
-	//VK_DEVICEFEATURE_ENABLE_IF(shaderResourceResidency);
-	VK_DEVICEFEATURE_ENABLE_IF(shaderResourceMinLod);
-	// We don't use sparse features and enabling them cause extra internal
-	// allocations inside the Vulkan driver we don't need.
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseBinding);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidencyBuffer);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidencyImage2D);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidencyImage3D);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidency2Samples);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidency4Samples);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidency8Samples);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidency16Samples);
-	//VK_DEVICEFEATURE_ENABLE_IF(sparseResidencyAliased);
-	VK_DEVICEFEATURE_ENABLE_IF(variableMultisampleRate);
-	//VK_DEVICEFEATURE_ENABLE_IF(inheritedQueries);
-
-#define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                                            \
-	{                                                                                       \
-		fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
-		ERR_FAIL_NULL_V_MSG(fp##entrypoint, ERR_CANT_CREATE,                                \
-				"vkGetInstanceProcAddr failed to find vk" #entrypoint);                     \
-	}
-
-	GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceSupportKHR);
-	GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
-	GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceFormatsKHR);
-	GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
-	GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
-
-	// Gets capability info for current Vulkan driver.
-	{
-		Error res = _check_capabilities();
-		if (res != OK) {
-			return res;
-		}
-	}
-
-	device_initialized = true;
-	return OK;
-}
-
-Error VulkanContext::_create_device(VkDevice &r_vk_device) {
-	VkResult err;
-	float queue_priorities[1] = { 0.0 };
-	VkDeviceQueueCreateInfo queues[2];
-	queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
-	queues[0].pNext = nullptr;
-	queues[0].queueFamilyIndex = graphics_queue_family_index;
-	queues[0].queueCount = 1;
-	queues[0].pQueuePriorities = queue_priorities;
-	queues[0].flags = 0;
-
-	// Before we retrieved what is supported, here we tell Vulkan we want to enable these features using the same structs.
-	void *nextptr = nullptr;
-
-	VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
-		/*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
-		/*pNext*/ nextptr,
-		/*shaderFloat16*/ shader_capabilities.shader_float16_is_supported,
-		/*shaderInt8*/ shader_capabilities.shader_int8_is_supported,
-	};
-	nextptr = &shader_features;
-
-	VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
-	if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
-		// Insert into our chain to enable these features if they are available.
-		vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
-		vrs_features.pNext = nextptr;
-		vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported;
-		vrs_features.primitiveFragmentShadingRate = vrs_capabilities.primitive_vrs_supported;
-		vrs_features.attachmentFragmentShadingRate = vrs_capabilities.attachment_vrs_supported;
-
-		nextptr = &vrs_features;
-	}
-
-	VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_cache_control_features = {};
-	if (pipeline_cache_control_support) {
-		pipeline_cache_control_features.sType =
-				VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES;
-		pipeline_cache_control_features.pNext = nextptr;
-		pipeline_cache_control_features.pipelineCreationCacheControl = pipeline_cache_control_support;
-
-		nextptr = &pipeline_cache_control_features;
-	}
-
-	VkPhysicalDeviceVulkan11Features vulkan11features = {};
-	VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
-	VkPhysicalDeviceMultiviewFeatures multiview_features = {};
-	if (device_api_version >= VK_API_VERSION_1_2) {
-		// In Vulkan 1.2 and newer we use a newer struct to enable various features.
-
-		vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
-		vulkan11features.pNext = nextptr;
-		vulkan11features.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
-		vulkan11features.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
-		vulkan11features.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
-		vulkan11features.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
-		vulkan11features.multiview = multiview_capabilities.is_supported;
-		vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
-		vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
-		vulkan11features.variablePointersStorageBuffer = 0;
-		vulkan11features.variablePointers = 0;
-		vulkan11features.protectedMemory = 0;
-		vulkan11features.samplerYcbcrConversion = 0;
-		vulkan11features.shaderDrawParameters = 0;
-		nextptr = &vulkan11features;
-	} else {
-		// On Vulkan 1.0 and 1.1 we use our older structs to initialize these features.
-		storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
-		storage_feature.pNext = nextptr;
-		storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
-		storage_feature.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
-		storage_feature.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
-		storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
-		nextptr = &storage_feature;
-
-		if (device_api_version >= VK_API_VERSION_1_1) { // any Vulkan 1.1.x version
-			multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
-			multiview_features.pNext = nextptr;
-			multiview_features.multiview = multiview_capabilities.is_supported;
-			multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
-			multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
-			nextptr = &multiview_features;
-		}
-	}
-
-	uint32_t enabled_extension_count = 0;
-	const char *enabled_extension_names[MAX_EXTENSIONS];
-	ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
-	for (const CharString &extension_name : enabled_device_extension_names) {
-		enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
-	}
-
-	VkDeviceCreateInfo sdevice = {
-		/*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-		/*pNext*/ nextptr,
-		/*flags*/ 0,
-		/*queueCreateInfoCount*/ 1,
-		/*pQueueCreateInfos*/ queues,
-		/*enabledLayerCount*/ 0,
-		/*ppEnabledLayerNames*/ nullptr,
-		/*enabledExtensionCount*/ enabled_extension_count,
-		/*ppEnabledExtensionNames*/ (const char *const *)enabled_extension_names,
-		/*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here.
-	};
-	if (separate_present_queue) {
-		queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
-		queues[1].pNext = nullptr;
-		queues[1].queueFamilyIndex = present_queue_family_index;
-		queues[1].queueCount = 1;
-		queues[1].pQueuePriorities = queue_priorities;
-		queues[1].flags = 0;
-		sdevice.queueCreateInfoCount = 2;
-	}
-
-	if (vulkan_hooks) {
-		if (!vulkan_hooks->create_vulkan_device(&sdevice, &r_vk_device)) {
-			return ERR_CANT_CREATE;
-		}
-	} else {
-		err = vkCreateDevice(gpu, &sdevice, nullptr, &r_vk_device);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	}
-
-	return OK;
-}
-
-Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
-	// Iterate over each queue to learn whether it supports presenting:
-	VkBool32 *supportsPresent = nullptr;
-
-	if (p_surface) {
-		supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32));
-		for (uint32_t i = 0; i < queue_family_count; i++) {
-			fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supportsPresent[i]);
-		}
-	}
-
-	// Search for a graphics and a present queue in the array of queue
-	// families, try to find one that supports both.
-	uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
-	uint32_t presentQueueFamilyIndex = UINT32_MAX;
-	for (uint32_t i = 0; i < queue_family_count; i++) {
-		if ((queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
-			if (graphicsQueueFamilyIndex == UINT32_MAX) {
-				graphicsQueueFamilyIndex = i;
-			}
-
-			if (p_surface && supportsPresent[i] == VK_TRUE) {
-				graphicsQueueFamilyIndex = i;
-				presentQueueFamilyIndex = i;
-				break;
-			}
-		}
-	}
-
-	if (p_surface && presentQueueFamilyIndex == UINT32_MAX) {
-		// If didn't find a queue that supports both graphics and present, then
-		// find a separate present queue.
-		for (uint32_t i = 0; i < queue_family_count; ++i) {
-			if (supportsPresent[i] == VK_TRUE) {
-				presentQueueFamilyIndex = i;
-				break;
-			}
-		}
-	}
-
-	if (p_surface) {
-		free(supportsPresent);
-
-		// Generate error if could not find both a graphics and a present queue.
-		ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE,
-				"Could not find both graphics and present queues\n");
-
-		graphics_queue_family_index = graphicsQueueFamilyIndex;
-		present_queue_family_index = presentQueueFamilyIndex;
-		separate_present_queue = (graphics_queue_family_index != present_queue_family_index);
-	} else {
-		graphics_queue_family_index = graphicsQueueFamilyIndex;
-	}
-
-	_create_device(device);
-	driver = memnew(RenderingDeviceDriverVulkan(this, device));
-
-	static PFN_vkGetDeviceProcAddr g_gdpa = nullptr;
-#define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                                     \
-	{                                                                                             \
-		if (!g_gdpa)                                                                              \
-			g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \
-		fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint);                       \
-		ERR_FAIL_NULL_V_MSG(fp##entrypoint, ERR_CANT_CREATE,                                      \
-				"vkGetDeviceProcAddr failed to find vk" #entrypoint);                             \
-	}
-
-	GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
-	GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
-	GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
-	GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
-	GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
-	if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
-		GET_DEVICE_PROC_ADDR(device, GetRefreshCycleDurationGOOGLE);
-		GET_DEVICE_PROC_ADDR(device, GetPastPresentationTimingGOOGLE);
-	}
-
-	vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue);
-
-	if (p_surface) {
-		if (!separate_present_queue) {
-			present_queue = graphics_queue;
-		} else {
-			vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue);
-		}
-
-		// Get the list of VkFormat's that are supported:
-		uint32_t formatCount;
-		VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, nullptr);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-		VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
-		err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, surfFormats);
-		if (err) {
-			free(surfFormats);
-			ERR_FAIL_V(ERR_CANT_CREATE);
-		}
-		// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
-		// the surface has no preferred format.  Otherwise, at least one
-		// supported format will be returned.
-		if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
-			format = VK_FORMAT_B8G8R8A8_UNORM;
-			color_space = surfFormats[0].colorSpace;
-		} else {
-			// These should be ordered with the ones we want to use on top and fallback modes further down
-			// we want a 32bit RGBA unsigned normalized buffer or similar.
-			const VkFormat allowed_formats[] = {
-				VK_FORMAT_B8G8R8A8_UNORM,
-				VK_FORMAT_R8G8B8A8_UNORM
-			};
-			uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
-
-			if (formatCount < 1) {
-				free(surfFormats);
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
-			}
-
-			// Find the first format that we support.
-			format = VK_FORMAT_UNDEFINED;
-			for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
-				for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
-					if (surfFormats[sf].format == allowed_formats[af]) {
-						format = surfFormats[sf].format;
-						color_space = surfFormats[sf].colorSpace;
-					}
-				}
-			}
-
-			if (format == VK_FORMAT_UNDEFINED) {
-				free(surfFormats);
-				ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
-			}
-		}
-
-		free(surfFormats);
-	}
-
-	Error serr = _create_semaphores();
-	if (serr) {
-		return serr;
-	}
-
-	queues_initialized = true;
-	return OK;
-}
-
-Error VulkanContext::_create_semaphores() {
-	VkResult err;
-
-	// Create semaphores to synchronize acquiring presentable buffers before
-	// rendering and waiting for drawing to be complete before presenting.
-	VkSemaphoreCreateInfo semaphoreCreateInfo = {
-		/*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
-		/*pNext*/ nullptr,
-		/*flags*/ 0,
-	};
-
-	// Create fences that we can use to throttle if we get too far
-	// ahead of the image presents.
-	VkFenceCreateInfo fence_ci = {
-		/*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
-		/*pNext*/ nullptr,
-		/*flags*/ VK_FENCE_CREATE_SIGNALED_BIT
-	};
-	for (uint32_t i = 0; i < FRAME_LAG; i++) {
-		err = vkCreateFence(device, &fence_ci, nullptr, &fences[i]);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-		err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &draw_complete_semaphores[i]);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-		if (separate_present_queue) {
-			err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &image_ownership_semaphores[i]);
-			ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-		}
-	}
-	frame_index = 0;
-
-	// Get Memory information and properties.
-	vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties);
-
-	return OK;
-}
-
-bool VulkanContext::_use_validation_layers() {
-	return Engine::get_singleton()->is_validation_layers_enabled();
-}
-
-VkExtent2D VulkanContext::_compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const {
-	// Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
-	if (p_surf_capabilities.currentExtent.width == 0xFFFFFFFF) {
-		// If the surface size is undefined, the size is set to the size
-		// of the images requested, which must fit within the minimum and
-		// maximum values.
-		VkExtent2D extent = {};
-		extent.width = CLAMP((uint32_t)(*p_window_width), p_surf_capabilities.minImageExtent.width, p_surf_capabilities.maxImageExtent.width);
-		extent.height = CLAMP((uint32_t)(*p_window_height), p_surf_capabilities.minImageExtent.height, p_surf_capabilities.maxImageExtent.height);
-		return extent;
-	} else {
-		// If the surface size is defined, the swap chain size must match.
-		*p_window_width = p_surf_capabilities.currentExtent.width;
-		*p_window_height = p_surf_capabilities.currentExtent.height;
-		return p_surf_capabilities.currentExtent;
-	}
-}
-
-Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) {
-	ERR_FAIL_NULL_V_MSG(_get_platform_surface_extension(), ERR_UNAVAILABLE, "This Vulkan context is headless.");
-
-	ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
-
-	if (!device_initialized) {
-		Error err = _create_physical_device(p_surface);
-		ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-	}
-
-	if (!queues_initialized) {
-		// We use a single GPU, but we need a surface to initialize the
-		// queues, so this process must be deferred until a surface
-		// is created.
-		Error err = _initialize_queues(p_surface);
-		ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-	}
-
-	Window window;
-	window.surface = p_surface;
-	window.width = p_width;
-	window.height = p_height;
-	window.vsync_mode = p_vsync_mode;
-	Error err = _update_swap_chain(&window);
-	ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
-
-	windows[p_window_id] = window;
-	return OK;
-}
-
-void VulkanContext::window_resize(DisplayServer::WindowID p_window, int p_width, int p_height) {
-	ERR_FAIL_COND(!windows.has(p_window));
-	windows[p_window].width = p_width;
-	windows[p_window].height = p_height;
-	_update_swap_chain(&windows[p_window]);
-}
-
-int VulkanContext::window_get_width(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), -1);
-	return windows[p_window].width;
-}
-
-int VulkanContext::window_get_height(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), -1);
-	return windows[p_window].height;
-}
-
-bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), false);
-	Window *w = &windows[p_window];
-	return w->swapchain_image_resources != VK_NULL_HANDLE;
-}
-
-RDD::RenderPassID VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), RDD::RenderPassID());
-	Window *w = &windows[p_window];
-	return (RDD::RenderPassID)w->render_pass;
-}
-
-RDD::FramebufferID VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_window) {
-	ERR_FAIL_COND_V(!windows.has(p_window), RDD::FramebufferID());
-	ERR_FAIL_COND_V(!buffers_prepared, RDD::FramebufferID());
-	Window *w = &windows[p_window];
-	if (w->swapchain_image_resources != VK_NULL_HANDLE) {
-		return (RDD::FramebufferID)w->swapchain_image_resources[w->current_buffer].framebuffer;
-	} else {
-		return RDD::FramebufferID();
-	}
-}
-
-void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) {
-	ERR_FAIL_COND(!windows.has(p_window_id));
-	_clean_up_swap_chain(&windows[p_window_id]);
-
-	vkDestroySurfaceKHR(inst, windows[p_window_id].surface, nullptr);
-	windows.erase(p_window_id);
-}
-
-Error VulkanContext::_clean_up_swap_chain(Window *window) {
-	if (!window->swapchain) {
-		return OK;
-	}
-	vkDeviceWaitIdle(device);
-
-	// This destroys images associated it seems.
-	fpDestroySwapchainKHR(device, window->swapchain, nullptr);
-	window->swapchain = VK_NULL_HANDLE;
-	vkDestroyRenderPass(device, window->render_pass, nullptr);
-	window->render_pass = VK_NULL_HANDLE;
-	if (window->swapchain_image_resources) {
-		for (uint32_t i = 0; i < swapchainImageCount; i++) {
-			vkDestroyImageView(device, window->swapchain_image_resources[i].view, nullptr);
-			vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, nullptr);
-		}
-
-		free(window->swapchain_image_resources);
-		window->swapchain_image_resources = nullptr;
-		swapchainImageCount = 0;
-	}
-	if (separate_present_queue) {
-		vkDestroyCommandPool(device, window->present_cmd_pool, nullptr);
-	}
-
-	for (uint32_t i = 0; i < FRAME_LAG; i++) {
-		// Destroy the semaphores now (we'll re-create it later if we have to).
-		// We must do this because the semaphore cannot be reused if it's in a signaled state
-		// (which happens if vkAcquireNextImageKHR returned VK_ERROR_OUT_OF_DATE_KHR or VK_SUBOPTIMAL_KHR)
-		// The only way to reset it would be to present the swapchain... the one we just destroyed.
-		// And the API has no way to "unsignal" the semaphore.
-		vkDestroySemaphore(device, window->image_acquired_semaphores[i], nullptr);
-		window->image_acquired_semaphores[i] = 0;
-	}
-
-	return OK;
-}
-
-Error VulkanContext::_update_swap_chain(Window *window) {
-	VkResult err;
-
-	if (window->swapchain) {
-		_clean_up_swap_chain(window);
-	}
-
-	// Check the surface capabilities and formats.
-	VkSurfaceCapabilitiesKHR surfCapabilities;
-	err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	{
-		VkBool32 supports = VK_FALSE;
-		err = vkGetPhysicalDeviceSurfaceSupportKHR(
-				gpu, present_queue_family_index, window->surface, &supports);
-		ERR_FAIL_COND_V_MSG(err != VK_SUCCESS || supports == false, ERR_CANT_CREATE,
-				"Window's surface is not supported by device. Did the GPU go offline? Was the window "
-				"created on another monitor? Check previous errors & try launching with "
-				"--gpu-validation.");
-	}
-
-	uint32_t presentModeCount;
-	err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, nullptr);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
-	ERR_FAIL_NULL_V(presentModes, ERR_CANT_CREATE);
-	err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, presentModes);
-	if (err) {
-		free(presentModes);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	VkExtent2D swapchainExtent = _compute_swapchain_extent(surfCapabilities, &window->width, &window->height);
-
-	if (window->width == 0 || window->height == 0) {
-		free(presentModes);
-		// Likely window minimized, no swapchain created.
-		return ERR_SKIP;
-	}
-	// The FIFO present mode is guaranteed by the spec to be supported
-	// and to have no tearing.  It's a great default present mode to use.
-
-	// There are times when you may wish to use another present mode.  The
-	// following code shows how to select them, and the comments provide some
-	// reasons you may wish to use them.
-	//
-	// It should be noted that Vulkan 1.0 doesn't provide a method for
-	// synchronizing rendering with the presentation engine's display. There
-	// is a method provided for throttling rendering with the display, but
-	// there are some presentation engines for which this method will not work.
-	// If an application doesn't throttle its rendering, and if it renders much
-	// faster than the refresh rate of the display, this can waste power on
-	// mobile devices. That is because power is being spent rendering images
-	// that may never be seen.
-
-	// VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
-	// tearing, or have some way of synchronizing their rendering with the
-	// display.
-	// VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
-	// generally render a new presentable image every refresh cycle, but are
-	// occasionally early.  In this case, the application wants the new image
-	// to be displayed instead of the previously-queued-for-presentation image
-	// that has not yet been displayed.
-	// VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
-	// render a new presentable image every refresh cycle, but are occasionally
-	// late.  In this case (perhaps because of stuttering/latency concerns),
-	// the application wants the late image to be immediately displayed, even
-	// though that may mean some tearing.
-
-	VkPresentModeKHR requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
-	switch (window->vsync_mode) {
-		case DisplayServer::VSYNC_MAILBOX:
-			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR;
-			break;
-		case DisplayServer::VSYNC_ADAPTIVE:
-			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR;
-			break;
-		case DisplayServer::VSYNC_ENABLED:
-			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
-			break;
-		case DisplayServer::VSYNC_DISABLED:
-			requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR;
-			break;
-	}
-
-	// Check if the requested mode is available.
-	bool present_mode_available = false;
-	for (uint32_t i = 0; i < presentModeCount; i++) {
-		if (presentModes[i] == requested_present_mode) {
-			present_mode_available = true;
-		}
-	}
-
-	// Set the windows present mode if it is available, otherwise FIFO is used (guaranteed supported).
-	if (present_mode_available) {
-		if (window->presentMode != requested_present_mode) {
-			window->presentMode = requested_present_mode;
-			print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode)));
-		}
-	} else {
-		String present_mode_string;
-		switch (window->vsync_mode) {
-			case DisplayServer::VSYNC_MAILBOX:
-				present_mode_string = "Mailbox";
-				break;
-			case DisplayServer::VSYNC_ADAPTIVE:
-				present_mode_string = "Adaptive";
-				break;
-			case DisplayServer::VSYNC_ENABLED:
-				present_mode_string = "Enabled";
-				break;
-			case DisplayServer::VSYNC_DISABLED:
-				present_mode_string = "Disabled";
-				break;
-		}
-		WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
-		window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
-	}
-
-	free(presentModes);
-
-	// Determine the number of VkImages to use in the swap chain.
-	// Application desires to acquire 3 images at a time for triple
-	// buffering.
-	uint32_t desiredNumOfSwapchainImages = 3;
-	if (desiredNumOfSwapchainImages < surfCapabilities.minImageCount) {
-		desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
-	}
-	// If maxImageCount is 0, we can ask for as many images as we want;
-	// otherwise we're limited to maxImageCount.
-	if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
-		// Application must settle for fewer images than desired.
-		desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
-	}
-
-	VkSurfaceTransformFlagsKHR preTransform;
-	if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
-		preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-	} else {
-		preTransform = surfCapabilities.currentTransform;
-	}
-
-	VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
-	if (OS::get_singleton()->is_layered_allowed() || !(surfCapabilities.supportedCompositeAlpha & compositeAlpha)) {
-		// Find a supported composite alpha mode - one of these is guaranteed to be set.
-		VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
-			VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
-			VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
-			VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
-			VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
-		};
-
-		for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
-			if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
-				compositeAlpha = compositeAlphaFlags[i];
-				break;
-			}
-		}
-	}
-
-	VkSwapchainCreateInfoKHR swapchain_ci = {
-		/*sType*/ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
-		/*pNext*/ nullptr,
-		/*flags*/ 0,
-		/*surface*/ window->surface,
-		/*minImageCount*/ desiredNumOfSwapchainImages,
-		/*imageFormat*/ format,
-		/*imageColorSpace*/ color_space,
-		/*imageExtent*/ {
-				/*width*/ swapchainExtent.width,
-				/*height*/ swapchainExtent.height,
-		},
-		/*imageArrayLayers*/ 1,
-		/*imageUsage*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
-		/*imageSharingMode*/ VK_SHARING_MODE_EXCLUSIVE,
-		/*queueFamilyIndexCount*/ 0,
-		/*pQueueFamilyIndices*/ nullptr,
-		/*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
-		/*compositeAlpha*/ compositeAlpha,
-		/*presentMode*/ window->presentMode,
-		/*clipped*/ true,
-		/*oldSwapchain*/ VK_NULL_HANDLE,
-	};
-
-	err = fpCreateSwapchainKHR(device, &swapchain_ci, nullptr, &window->swapchain);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	uint32_t sp_image_count;
-	err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, nullptr);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-	if (swapchainImageCount == 0) {
-		// Assign here for the first time.
-		swapchainImageCount = sp_image_count;
-	} else {
-		ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG);
-	}
-
-	VkImage *swapchainImages = (VkImage *)malloc(swapchainImageCount * sizeof(VkImage));
-	ERR_FAIL_NULL_V(swapchainImages, ERR_CANT_CREATE);
-	err = fpGetSwapchainImagesKHR(device, window->swapchain, &swapchainImageCount, swapchainImages);
-	if (err) {
-		free(swapchainImages);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	window->swapchain_image_resources =
-			(SwapchainImageResources *)malloc(sizeof(SwapchainImageResources) * swapchainImageCount);
-	if (!window->swapchain_image_resources) {
-		free(swapchainImages);
-		ERR_FAIL_V(ERR_CANT_CREATE);
-	}
-
-	for (uint32_t i = 0; i < swapchainImageCount; i++) {
-		VkImageViewCreateInfo color_image_view = {
-			/*sType*/ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-			/*pNext*/ nullptr,
-			/*flags*/ 0,
-			/*image*/ swapchainImages[i],
-			/*viewType*/ VK_IMAGE_VIEW_TYPE_2D,
-			/*format*/ format,
-			/*components*/ {
-					/*r*/ VK_COMPONENT_SWIZZLE_R,
-					/*g*/ VK_COMPONENT_SWIZZLE_G,
-					/*b*/ VK_COMPONENT_SWIZZLE_B,
-					/*a*/ VK_COMPONENT_SWIZZLE_A,
-			},
-			/*subresourceRange*/ { /*aspectMask*/ VK_IMAGE_ASPECT_COLOR_BIT,
-					/*baseMipLevel*/ 0,
-					/*levelCount*/ 1,
-					/*baseArrayLayer*/ 0,
-					/*layerCount*/ 1 },
-		};
-
-		window->swapchain_image_resources[i].image = swapchainImages[i];
-
-		color_image_view.image = window->swapchain_image_resources[i].image;
-
-		err = vkCreateImageView(device, &color_image_view, nullptr, &window->swapchain_image_resources[i].view);
-		if (err) {
-			free(swapchainImages);
-			ERR_FAIL_V(ERR_CANT_CREATE);
-		}
-	}
-
-	free(swapchainImages);
-
-	/******** FRAMEBUFFER ************/
-
-	{
-		const VkAttachmentDescription2KHR attachment = {
-			/*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR,
-			/*pNext*/ nullptr,
-			/*flags*/ 0,
-			/*format*/ format,
-			/*samples*/ VK_SAMPLE_COUNT_1_BIT,
-			/*loadOp*/ VK_ATTACHMENT_LOAD_OP_CLEAR,
-			/*storeOp*/ VK_ATTACHMENT_STORE_OP_STORE,
-			/*stencilLoadOp*/ VK_ATTACHMENT_LOAD_OP_DONT_CARE,
-			/*stencilStoreOp*/ VK_ATTACHMENT_STORE_OP_DONT_CARE,
-			/*initialLayout*/ VK_IMAGE_LAYOUT_UNDEFINED,
-			/*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-
-		};
-		const VkAttachmentReference2KHR color_reference = {
-			/*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR,
-			/*pNext*/ nullptr,
-			/*attachment*/ 0,
-			/*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-			/*aspectMask*/ 0,
-		};
-
-		const VkSubpassDescription2KHR subpass = {
-			/*sType*/ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR,
-			/*pNext*/ nullptr,
-			/*flags*/ 0,
-			/*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS,
-			/*viewMask*/ 0,
-			/*inputAttachmentCount*/ 0,
-			/*pInputAttachments*/ nullptr,
-			/*colorAttachmentCount*/ 1,
-			/*pColorAttachments*/ &color_reference,
-			/*pResolveAttachments*/ nullptr,
-			/*pDepthStencilAttachment*/ nullptr,
-			/*preserveAttachmentCount*/ 0,
-			/*pPreserveAttachments*/ nullptr,
-		};
-
-		const VkRenderPassCreateInfo2KHR pass_info = {
-			/*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR,
-			/*pNext*/ nullptr,
-			/*flags*/ 0,
-			/*attachmentCount*/ 1,
-			/*pAttachments*/ &attachment,
-			/*subpassCount*/ 1,
-			/*pSubpasses*/ &subpass,
-			/*dependencyCount*/ 0,
-			/*pDependencies*/ nullptr,
-			/*correlatedViewMaskCount*/ 0,
-			/*pCorrelatedViewMasks*/ nullptr,
-		};
-
-		err = vkCreateRenderPass2KHR(device, &pass_info, nullptr, &window->render_pass);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-		for (uint32_t i = 0; i < swapchainImageCount; i++) {
-			const VkFramebufferCreateInfo fb_info = {
-				/*sType*/ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-				/*pNext*/ nullptr,
-				/*flags*/ 0,
-				/*renderPass*/ window->render_pass,
-				/*attachmentCount*/ 1,
-				/*pAttachments*/ &window->swapchain_image_resources[i].view,
-				/*width*/ (uint32_t)window->width,
-				/*height*/ (uint32_t)window->height,
-				/*layers*/ 1,
-			};
-
-			err = vkCreateFramebuffer(device, &fb_info, nullptr, &window->swapchain_image_resources[i].framebuffer);
-			ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-		}
-	}
-
-	/******** SEPARATE PRESENT QUEUE ************/
-
-	if (separate_present_queue) {
-		const VkCommandPoolCreateInfo present_cmd_pool_info = {
-			/*sType*/ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
-			/*pNext*/ nullptr,
-			/*flags*/ 0,
-			/*queueFamilyIndex*/ present_queue_family_index,
-		};
-		err = vkCreateCommandPool(device, &present_cmd_pool_info, nullptr, &window->present_cmd_pool);
-		ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-		const VkCommandBufferAllocateInfo present_cmd_info = {
-			/*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-			/*pNext*/ nullptr,
-			/*commandPool*/ window->present_cmd_pool,
-			/*level*/ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-			/*commandBufferCount*/ 1,
-		};
-		for (uint32_t i = 0; i < swapchainImageCount; i++) {
-			err = vkAllocateCommandBuffers(device, &present_cmd_info,
-					&window->swapchain_image_resources[i].graphics_to_present_cmd);
-			ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-			const VkCommandBufferBeginInfo cmd_buf_info = {
-				/*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-				/*pNext*/ nullptr,
-				/*flags*/ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
-				/*pInheritanceInfo*/ nullptr,
-			};
-			err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info);
-			ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-
-			VkImageMemoryBarrier image_ownership_barrier = {
-				/*sType*/ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-				/*pNext*/ nullptr,
-				/*srcAccessMask*/ 0,
-				/*dstAccessMask*/ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
-				/*oldLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-				/*newLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-				/*srcQueueFamilyIndex*/ graphics_queue_family_index,
-				/*dstQueueFamilyIndex*/ present_queue_family_index,
-				/*image*/ window->swapchain_image_resources[i].image,
-				/*subresourceRange*/ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
-			};
-
-			vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
-					VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_ownership_barrier);
-			err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd);
-			ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-		}
-	}
-
-	// Reset current buffer.
-	window->current_buffer = 0;
-
-	VkSemaphoreCreateInfo semaphoreCreateInfo = {
-		/*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
-		/*pNext*/ nullptr,
-		/*flags*/ 0,
-	};
-
-	for (uint32_t i = 0; i < FRAME_LAG; i++) {
-		VkResult vkerr = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &window->image_acquired_semaphores[i]);
-		ERR_FAIL_COND_V(vkerr, ERR_CANT_CREATE);
-	}
-
-	return OK;
-}
-
-Error VulkanContext::initialize() {
-#ifdef USE_VOLK
-	if (volkInitialize() != VK_SUCCESS) {
-		return FAILED;
-	}
-#endif
-
-	Error err = _create_instance();
-	if (err != OK) {
-		return err;
-	}
-
-	// Headless? Complete setup now.
-	if (!_get_platform_surface_extension()) {
-		err = _create_physical_device(VK_NULL_HANDLE);
-		if (err != OK) {
-			return err;
-		}
-
-		err = _initialize_queues(VK_NULL_HANDLE);
-		if (err != OK) {
-			return err;
-		}
-	}
-
-	return OK;
-}
-
-void VulkanContext::set_setup_buffer(RDD::CommandBufferID p_command_buffer) {
-	command_buffer_queue[0] = (VkCommandBuffer)p_command_buffer.id;
-}
-
-void VulkanContext::append_command_buffer(RDD::CommandBufferID p_command_buffer) {
-	if (command_buffer_queue.size() <= command_buffer_count) {
-		command_buffer_queue.resize(command_buffer_count + 1);
-	}
-
-	command_buffer_queue[command_buffer_count] = (VkCommandBuffer)p_command_buffer.id;
-	command_buffer_count++;
-}
-
-void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) {
-	// Ensure everything else pending is executed.
-	if (p_sync) {
-		vkDeviceWaitIdle(device);
-	}
-
-	// Flush the pending setup buffer.
-
-	bool setup_flushable = p_flush_setup && command_buffer_queue[0];
-	bool pending_flushable = p_flush_pending && command_buffer_count > 1;
-
-	if (setup_flushable) {
-		// Use a fence to wait for everything done.
-		VkSubmitInfo submit_info;
-		submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-		submit_info.pNext = nullptr;
-		submit_info.pWaitDstStageMask = nullptr;
-		submit_info.waitSemaphoreCount = 0;
-		submit_info.pWaitSemaphores = nullptr;
-		submit_info.commandBufferCount = 1;
-		submit_info.pCommandBuffers = command_buffer_queue.ptr();
-		submit_info.signalSemaphoreCount = pending_flushable ? 1 : 0;
-		submit_info.pSignalSemaphores = pending_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
-		VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
-		command_buffer_queue[0] = nullptr;
-		ERR_FAIL_COND(err);
-	}
-
-	if (pending_flushable) {
-		// Use a fence to wait for everything to finish.
-
-		VkSubmitInfo submit_info;
-		submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-		submit_info.pNext = nullptr;
-		VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-		submit_info.pWaitDstStageMask = setup_flushable ? &wait_stage_mask : nullptr;
-		submit_info.waitSemaphoreCount = setup_flushable ? 1 : 0;
-		submit_info.pWaitSemaphores = setup_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
-		submit_info.commandBufferCount = command_buffer_count - 1;
-		submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1;
-		submit_info.signalSemaphoreCount = 0;
-		submit_info.pSignalSemaphores = nullptr;
-		VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
-		command_buffer_count = 1;
-		ERR_FAIL_COND(err);
-	}
-
-	if (p_sync) {
-		vkDeviceWaitIdle(device);
-	}
-}
-
-Error VulkanContext::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
-	if (!queues_initialized) {
-		return OK;
-	}
-
-	VkResult err;
-
-	// Ensure no more than FRAME_LAG renderings are outstanding.
-	vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
-	vkResetFences(device, 1, &fences[frame_index]);
-
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-
-		w->semaphore_acquired = false;
-
-		if (w->swapchain == VK_NULL_HANDLE) {
-			continue;
-		}
-
-		do {
-			// Get the index of the next available swapchain image.
-			err =
-					fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX,
-							w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer);
-
-			if (err == VK_ERROR_OUT_OF_DATE_KHR) {
-				// Swapchain is out of date (e.g. the window was resized) and
-				// must be recreated.
-				print_verbose("Vulkan: Early out of date swapchain, recreating.");
-				// resize_notify();
-				_update_swap_chain(w);
-			} else if (err == VK_SUBOPTIMAL_KHR) {
-				// Swapchain is not as optimal as it could be, but the platform's
-				// presentation engine will still present the image correctly.
-				print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
-				Error swap_chain_err = _update_swap_chain(w);
-				if (swap_chain_err == ERR_SKIP) {
-					break;
-				}
-			} else if (err != VK_SUCCESS) {
-				ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
-			} else {
-				w->semaphore_acquired = true;
-			}
-		} while (err != VK_SUCCESS);
-	}
-
-	buffers_prepared = true;
-
-	return OK;
-}
-
-void VulkanContext::postpare_buffers(RDD::CommandBufferID p_command_buffer) {
-}
-
-Error VulkanContext::swap_buffers() {
-	if (!queues_initialized) {
-		return OK;
-	}
-
-	//print_line("swap_buffers");
-	VkResult err;
-
-#if 0
-	if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
-		// Look at what happened to previous presents, and make appropriate
-		// adjustments in timing.
-		DemoUpdateTargetIPD(demo);
-
-		// Note: a real application would position its geometry to that it's in
-		// the correct location for when the next image is presented.  It might
-		// also wait, so that there's less latency between any input and when
-		// the next image is rendered/presented.  This demo program is so
-		// simple that it doesn't do either of those.
-	}
-#endif
-	// Wait for the image acquired semaphore to be signaled to ensure
-	// that the image won't be rendered to until the presentation
-	// engine has fully released ownership to the application, and it is
-	// okay to render to the image.
-
-	const VkCommandBuffer *commands_ptr = nullptr;
-	uint32_t commands_to_submit = 0;
-
-	if (command_buffer_queue[0] == nullptr) {
-		// No setup command, but commands to submit, submit from the first and skip command.
-		if (command_buffer_count > 1) {
-			commands_ptr = command_buffer_queue.ptr() + 1;
-			commands_to_submit = command_buffer_count - 1;
-		}
-	} else {
-		commands_ptr = command_buffer_queue.ptr();
-		commands_to_submit = command_buffer_count;
-	}
-
-	VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore));
-	VkPipelineStageFlags *pipe_stage_flags = (VkPipelineStageFlags *)alloca(windows.size() * sizeof(VkPipelineStageFlags));
-	uint32_t semaphores_to_acquire_count = 0;
-
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-
-		if (w->semaphore_acquired) {
-			semaphores_to_acquire[semaphores_to_acquire_count] = w->image_acquired_semaphores[frame_index];
-			pipe_stage_flags[semaphores_to_acquire_count] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-			semaphores_to_acquire_count++;
-		}
-	}
-
-	VkSubmitInfo submit_info;
-	submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-	submit_info.pNext = nullptr;
-	submit_info.waitSemaphoreCount = semaphores_to_acquire_count;
-	submit_info.pWaitSemaphores = semaphores_to_acquire;
-	submit_info.pWaitDstStageMask = pipe_stage_flags;
-	submit_info.commandBufferCount = commands_to_submit;
-	submit_info.pCommandBuffers = commands_ptr;
-	submit_info.signalSemaphoreCount = 1;
-	submit_info.pSignalSemaphores = &draw_complete_semaphores[frame_index];
-	err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
-	ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit graphics queue. Error code: " + String(string_VkResult(err)));
-
-	command_buffer_queue[0] = nullptr;
-	command_buffer_count = 1;
-
-	if (separate_present_queue) {
-		// If we are using separate queues, change image ownership to the
-		// present queue before presenting, waiting for the draw complete
-		// semaphore and signaling the ownership released semaphore when finished.
-		VkFence nullFence = VK_NULL_HANDLE;
-		pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-		submit_info.waitSemaphoreCount = 1;
-		submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
-		submit_info.commandBufferCount = 0;
-
-		VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size());
-		submit_info.pCommandBuffers = cmdbufptr;
-
-		for (KeyValue<int, Window> &E : windows) {
-			Window *w = &E.value;
-
-			if (w->swapchain == VK_NULL_HANDLE) {
-				continue;
-			}
-			cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd;
-			submit_info.commandBufferCount++;
-		}
-
-		submit_info.signalSemaphoreCount = 1;
-		submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index];
-		err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence);
-		ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit present queue. Error code: " + String(string_VkResult(err)));
-	}
-
-	// If we are using separate queues, we have to wait for image ownership,
-	// otherwise wait for draw complete.
-	VkPresentInfoKHR present = {
-		/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
-		/*pNext*/ nullptr,
-		/*waitSemaphoreCount*/ 1,
-		/*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
-		/*swapchainCount*/ 0,
-		/*pSwapchain*/ nullptr,
-		/*pImageIndices*/ nullptr,
-		/*pResults*/ nullptr,
-	};
-
-	VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
-	uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size());
-
-	present.pSwapchains = pSwapchains;
-	present.pImageIndices = pImageIndices;
-
-	for (KeyValue<int, Window> &E : windows) {
-		Window *w = &E.value;
-
-		if (w->swapchain == VK_NULL_HANDLE) {
-			continue;
-		}
-		pSwapchains[present.swapchainCount] = w->swapchain;
-		pImageIndices[present.swapchainCount] = w->current_buffer;
-		present.swapchainCount++;
-	}
-
-#if 0
-	if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) {
-		// If using VK_KHR_incremental_present, we provide a hint of the region
-		// that contains changed content relative to the previously-presented
-		// image.  The implementation can use this hint in order to save
-		// work/power (by only copying the region in the hint).  The
-		// implementation is free to ignore the hint though, and so we must
-		// ensure that the entire image has the correctly-drawn content.
-		uint32_t eighthOfWidth = width / 8;
-		uint32_t eighthOfHeight = height / 8;
-		VkRectLayerKHR rect = {
-			/*offset.x*/ eighthOfWidth,
-			/*offset.y*/ eighthOfHeight,
-			/*extent.width*/ eighthOfWidth * 6,
-			/*extent.height*/ eighthOfHeight * 6,
-			/*layer*/ 0,
-		};
-		VkPresentRegionKHR region = {
-			/*rectangleCount*/ 1,
-			/*pRectangles*/ &rect,
-		};
-		VkPresentRegionsKHR regions = {
-			/*sType*/ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
-			/*pNext*/ present.pNext,
-			/*swapchainCount*/ present.swapchainCount,
-			/*pRegions*/ &region,
-		};
-		present.pNext = &regions;
-	}
-#endif
-
-#if 0
-	if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
-		VkPresentTimeGOOGLE ptime;
-		if (prev_desired_present_time == 0) {
-			// This must be the first present for this swapchain.
-			//
-			// We don't know where we are relative to the presentation engine's
-			// display's refresh cycle.  We also don't know how long rendering
-			// takes.  Let's make a grossly-simplified assumption that the
-			// desiredPresentTime should be half way between now and
-			// now+target_IPD.  We will adjust over time.
-			uint64_t curtime = getTimeInNanoseconds();
-			if (curtime == 0) {
-				// Since we didn't find out the current time, don't give a
-				// desiredPresentTime.
-				ptime.desiredPresentTime = 0;
-			} else {
-				ptime.desiredPresentTime = curtime + (target_IPD >> 1);
-			}
-		} else {
-			ptime.desiredPresentTime = (prev_desired_present_time + target_IPD);
-		}
-		ptime.presentID = next_present_id++;
-		prev_desired_present_time = ptime.desiredPresentTime;
-
-		VkPresentTimesInfoGOOGLE present_time = {
-			/*sType*/ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
-			/*pNext*/ present.pNext,
-			/*swapchainCount*/ present.swapchainCount,
-			/*pTimes*/ &ptime,
-		};
-		if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
-			present.pNext = &present_time;
-		}
-	}
-#endif
-	//	print_line("current buffer:  " + itos(current_buffer));
-	err = fpQueuePresentKHR(present_queue, &present);
-
-	frame_index += 1;
-	frame_index %= FRAME_LAG;
-
-	if (err == VK_ERROR_OUT_OF_DATE_KHR) {
-		// Swapchain is out of date (e.g. the window was resized) and
-		// must be recreated.
-		print_verbose("Vulkan queue submit: Swapchain is out of date, recreating.");
-		resize_notify();
-	} else if (err == VK_SUBOPTIMAL_KHR) {
-		// Swapchain is not as optimal as it could be, but the platform's
-		// presentation engine will still present the image correctly.
-		print_verbose("Vulkan queue submit: Swapchain is suboptimal.");
-	} else {
-		ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Error code: " + String(string_VkResult(err)));
-	}
-
-	buffers_prepared = false;
-	return OK;
-}
-
-void VulkanContext::resize_notify() {
-}
-
-RenderingDevice::Capabilities VulkanContext::get_device_capabilities() const {
-	RenderingDevice::Capabilities c;
-	c.device_family = RenderingDevice::DEVICE_VULKAN;
-	c.version_major = VK_API_VERSION_MAJOR(device_api_version);
-	c.version_minor = VK_API_VERSION_MINOR(device_api_version);
-	return c;
-}
-
-VkDevice VulkanContext::get_device() {
-	return device;
-}
-
-VkPhysicalDevice VulkanContext::get_physical_device() {
-	return gpu;
-}
-
-int VulkanContext::get_swapchain_image_count() const {
-	return swapchainImageCount;
-}
-
-VkQueue VulkanContext::get_graphics_queue() const {
-	return graphics_queue;
-}
-
-uint32_t VulkanContext::get_graphics_queue_family_index() const {
-	return graphics_queue_family_index;
-}
-
-VkFormat VulkanContext::get_screen_format() const {
-	return format;
-}
-
-const VkPhysicalDeviceLimits &VulkanContext::get_device_limits() const {
-	return gpu_props.limits;
-}
-
-RID VulkanContext::local_device_create() {
-	LocalDevice ld;
-
-	Error err = _create_device(ld.device);
-	ERR_FAIL_COND_V(err, RID());
-
-	{ // Create graphics queue.
-
-		vkGetDeviceQueue(ld.device, graphics_queue_family_index, 0, &ld.queue);
-	}
-
-	ld.driver = memnew(RenderingDeviceDriverVulkan(this, ld.device));
-
-	return local_device_owner.make_rid(ld);
-}
-
-void VulkanContext::local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	ERR_FAIL_COND(ld->waiting);
-
-	VkSubmitInfo submit_info;
-	submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-	submit_info.pNext = nullptr;
-	submit_info.pWaitDstStageMask = nullptr;
-	submit_info.waitSemaphoreCount = 0;
-	submit_info.pWaitSemaphores = nullptr;
-	submit_info.commandBufferCount = p_count;
-	submit_info.pCommandBuffers = (const VkCommandBuffer *)p_buffers;
-	submit_info.signalSemaphoreCount = 0;
-	submit_info.pSignalSemaphores = nullptr;
-
-	VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE);
-	if (err == VK_ERROR_OUT_OF_HOST_MEMORY) {
-		print_line("Vulkan: Out of host memory!");
-	}
-	if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
-		print_line("Vulkan: Out of device memory!");
-	}
-	if (err == VK_ERROR_DEVICE_LOST) {
-		print_line("Vulkan: Device lost!");
-	}
-	ERR_FAIL_COND(err);
-
-	ld->waiting = true;
-}
-
-void VulkanContext::local_device_sync(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	ERR_FAIL_COND(!ld->waiting);
-
-	vkDeviceWaitIdle(ld->device);
-	ld->waiting = false;
-}
-
-void VulkanContext::local_device_free(RID p_local_device) {
-	LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-	memdelete(ld->driver);
-	vkDestroyDevice(ld->device, nullptr);
-	local_device_owner.free(p_local_device);
-}
-
-void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) {
-	if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
-		return;
-	}
-	CharString obj_data = p_object_name.utf8();
-	VkDebugUtilsObjectNameInfoEXT name_info;
-	name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
-	name_info.pNext = nullptr;
-	name_info.objectType = p_object_type;
-	name_info.objectHandle = p_object_handle;
-	name_info.pObjectName = obj_data.get_data();
-	SetDebugUtilsObjectNameEXT(device, &name_info);
-}
-
-String VulkanContext::get_device_vendor_name() const {
-	return device_vendor;
-}
-
-String VulkanContext::get_device_name() const {
-	return device_name;
-}
-
-RenderingDevice::DeviceType VulkanContext::get_device_type() const {
-	return RenderingDevice::DeviceType(device_type);
-}
-
-String VulkanContext::get_device_api_version() const {
-	return vformat("%d.%d.%d", VK_API_VERSION_MAJOR(device_api_version), VK_API_VERSION_MINOR(device_api_version), VK_API_VERSION_PATCH(device_api_version));
-}
-
-String VulkanContext::get_device_pipeline_cache_uuid() const {
-	return pipeline_cache_id;
-}
-
-DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const {
-	ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
-	return windows[p_window].vsync_mode;
-}
-
-void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
-	ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
-	windows[p_window].vsync_mode = p_mode;
-	_update_swap_chain(&windows[p_window]);
-}
-
-RenderingDeviceDriver *VulkanContext::get_driver(RID p_local_device) {
-	if (p_local_device.is_valid()) {
-		LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
-		ERR_FAIL_NULL_V(ld, nullptr);
-		return ld->driver;
-	} else {
-		return driver;
-	}
-}
-
-bool VulkanContext::is_debug_utils_enabled() const {
-	return is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
-}
-
-VulkanContext::VulkanContext() {
-	command_buffer_queue.resize(1); // First one is always the setup command.
-	command_buffer_queue[0] = nullptr;
-}
-
-VulkanContext::~VulkanContext() {
-	if (driver) {
-		memdelete(driver);
-	}
-	if (queue_props) {
-		free(queue_props);
-	}
-	if (device_initialized) {
-		for (uint32_t i = 0; i < FRAME_LAG; i++) {
-			vkDestroyFence(device, fences[i], nullptr);
-			vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr);
-			if (separate_present_queue) {
-				vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr);
-			}
-		}
-		if (inst_initialized && is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
-			DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
-		}
-		if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) {
-			DestroyDebugReportCallbackEXT(inst, dbg_debug_report, nullptr);
-		}
-		vkDestroyDevice(device, nullptr);
-	}
-	if (inst_initialized) {
-		vkDestroyInstance(inst, nullptr);
-	}
-}

+ 0 - 348
drivers/vulkan/vulkan_context.h

@@ -1,348 +0,0 @@
-/**************************************************************************/
-/*  vulkan_context.h                                                      */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#ifndef VULKAN_CONTEXT_H
-#define VULKAN_CONTEXT_H
-
-#include "core/error/error_list.h"
-#include "core/os/mutex.h"
-#include "core/string/ustring.h"
-#include "core/templates/hash_map.h"
-#include "core/templates/rb_map.h"
-#include "core/templates/rid_owner.h"
-#include "rendering_device_driver_vulkan.h"
-#include "servers/display_server.h"
-#include "servers/rendering/renderer_rd/api_context_rd.h"
-
-#ifdef USE_VOLK
-#include <volk.h>
-#else
-#include <vulkan/vulkan.h>
-#endif
-
-#include "vulkan_hooks.h"
-
-class VulkanContext : public ApiContextRD {
-public:
-	struct SubgroupCapabilities {
-		uint32_t size;
-		uint32_t min_size;
-		uint32_t max_size;
-		VkShaderStageFlags supportedStages;
-		VkSubgroupFeatureFlags supportedOperations;
-		VkBool32 quadOperationsInAllStages;
-		bool size_control_is_supported;
-
-		uint32_t supported_stages_flags_rd() const;
-		String supported_stages_desc() const;
-		uint32_t supported_operations_flags_rd() const;
-		String supported_operations_desc() const;
-	};
-
-	struct VRSCapabilities {
-		bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level.
-		bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall.
-		bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer.
-
-		Size2i min_texel_size;
-		Size2i max_texel_size;
-
-		Size2i texel_size; // The texel size we'll use
-	};
-
-	struct ShaderCapabilities {
-		bool shader_float16_is_supported;
-		bool shader_int8_is_supported;
-	};
-
-	struct StorageBufferCapabilities {
-		bool storage_buffer_16_bit_access_is_supported;
-		bool uniform_and_storage_buffer_16_bit_access_is_supported;
-		bool storage_push_constant_16_is_supported;
-		bool storage_input_output_16;
-	};
-
-private:
-	enum {
-		MAX_EXTENSIONS = 128,
-		MAX_LAYERS = 64,
-		FRAME_LAG = 2
-	};
-
-	static VulkanHooks *vulkan_hooks;
-	VkInstance inst = VK_NULL_HANDLE;
-	VkPhysicalDevice gpu = VK_NULL_HANDLE;
-	VkPhysicalDeviceProperties gpu_props;
-	uint32_t queue_family_count = 0;
-	VkQueueFamilyProperties *queue_props = nullptr;
-	VkDevice device = VK_NULL_HANDLE;
-	bool device_initialized = false;
-	bool inst_initialized = false;
-
-	uint32_t instance_api_version = VK_API_VERSION_1_0;
-	SubgroupCapabilities subgroup_capabilities;
-	RDD::MultiviewCapabilities multiview_capabilities;
-	VRSCapabilities vrs_capabilities;
-	ShaderCapabilities shader_capabilities;
-	StorageBufferCapabilities storage_buffer_capabilities;
-	bool pipeline_cache_control_support = false;
-
-	String device_vendor;
-	String device_name;
-	VkPhysicalDeviceType device_type;
-	String pipeline_cache_id;
-	uint32_t device_api_version = 0;
-
-	bool buffers_prepared = false;
-
-	// Present queue.
-	bool queues_initialized = false;
-	uint32_t graphics_queue_family_index = UINT32_MAX;
-	uint32_t present_queue_family_index = UINT32_MAX;
-	bool separate_present_queue = false;
-	VkQueue graphics_queue = VK_NULL_HANDLE;
-	VkQueue present_queue = VK_NULL_HANDLE;
-	VkColorSpaceKHR color_space;
-	VkFormat format;
-	VkSemaphore draw_complete_semaphores[FRAME_LAG];
-	VkSemaphore image_ownership_semaphores[FRAME_LAG];
-	int frame_index = 0;
-	VkFence fences[FRAME_LAG];
-	VkPhysicalDeviceMemoryProperties memory_properties;
-	VkPhysicalDeviceFeatures physical_device_features;
-
-	typedef struct {
-		VkImage image;
-		VkCommandBuffer graphics_to_present_cmd;
-		VkImageView view;
-		VkFramebuffer framebuffer;
-	} SwapchainImageResources;
-
-	struct Window {
-		VkSurfaceKHR surface = VK_NULL_HANDLE;
-		VkSwapchainKHR swapchain = VK_NULL_HANDLE;
-		SwapchainImageResources *swapchain_image_resources = VK_NULL_HANDLE;
-		VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
-		VkSemaphore image_acquired_semaphores[FRAME_LAG];
-		bool semaphore_acquired = false;
-		uint32_t current_buffer = 0;
-		int width = 0;
-		int height = 0;
-		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
-		VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
-		VkRenderPass render_pass = VK_NULL_HANDLE;
-	};
-
-	struct LocalDevice {
-		bool waiting = false;
-		VkDevice device = VK_NULL_HANDLE;
-		VkQueue queue = VK_NULL_HANDLE;
-		RenderingDeviceDriverVulkan *driver = nullptr;
-	};
-
-	RID_Owner<LocalDevice, true> local_device_owner;
-
-	RenderingDeviceDriverVulkan *driver = nullptr;
-
-	HashMap<DisplayServer::WindowID, Window> windows;
-	uint32_t swapchainImageCount = 0;
-
-	// Commands.
-
-	bool prepared = false;
-
-	LocalVector<VkCommandBuffer> command_buffer_queue;
-	uint32_t command_buffer_count = 1;
-
-	// Extensions.
-	static bool instance_extensions_initialized;
-	static HashMap<CharString, bool> requested_instance_extensions;
-	HashSet<CharString> enabled_instance_extension_names;
-
-	static bool device_extensions_initialized;
-	static HashMap<CharString, bool> requested_device_extensions;
-	HashSet<CharString> enabled_device_extension_names;
-	bool VK_KHR_incremental_present_enabled = true;
-	bool VK_GOOGLE_display_timing_enabled = true;
-
-	PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
-	PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
-	PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT = nullptr;
-	PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
-	PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
-	PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr;
-	PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
-	PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
-	PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
-	PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
-	PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR = nullptr;
-	PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
-	PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
-	PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
-	PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR = nullptr;
-	PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR = nullptr;
-	PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR = nullptr;
-	PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR = nullptr;
-	PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr;
-	PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr;
-	PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr;
-	PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr;
-
-	VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
-	VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
-
-	Error _obtain_vulkan_version();
-	Error _initialize_instance_extensions();
-	Error _initialize_device_extensions();
-	Error _check_capabilities();
-
-	VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
-	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
-			VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
-			VkDebugUtilsMessageTypeFlagsEXT messageType,
-			const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
-			void *pUserData);
-
-	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(
-			VkDebugReportFlagsEXT flags,
-			VkDebugReportObjectTypeEXT objectType,
-			uint64_t object,
-			size_t location,
-			int32_t messageCode,
-			const char *pLayerPrefix,
-			const char *pMessage,
-			void *pUserData);
-
-	Error _create_instance();
-
-	Error _create_physical_device(VkSurfaceKHR p_surface);
-
-	Error _initialize_queues(VkSurfaceKHR p_surface);
-
-	Error _create_device(VkDevice &r_vk_device);
-
-	Error _clean_up_swap_chain(Window *window);
-
-	Error _update_swap_chain(Window *window);
-
-	Error _create_swap_chain();
-	Error _create_semaphores();
-
-	Vector<VkAttachmentReference> _convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs);
-
-protected:
-	virtual const char *_get_platform_surface_extension() const { return nullptr; }
-
-	virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height);
-
-	virtual bool _use_validation_layers();
-
-	Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
-
-	virtual VkExtent2D _compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const;
-
-public:
-	// Extension calls.
-	bool supports_renderpass2() const { return is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); }
-	VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
-
-	virtual const char *get_api_name() const override final { return "Vulkan"; };
-	virtual RenderingDevice::Capabilities get_device_capabilities() const override final;
-	const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
-	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const override final { return multiview_capabilities; };
-	const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
-	const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
-	const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
-	const VkPhysicalDeviceFeatures &get_physical_device_features() const { return physical_device_features; };
-	bool get_pipeline_cache_control_support() const { return pipeline_cache_control_support; };
-
-	VkDevice get_device();
-	VkPhysicalDevice get_physical_device();
-	VkInstance get_instance() { return inst; }
-	virtual int get_swapchain_image_count() const override final;
-	VkQueue get_graphics_queue() const;
-	uint32_t get_graphics_queue_family_index() const;
-
-	static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };
-
-	static void register_requested_instance_extension(const CharString &extension_name, bool p_required);
-	bool is_instance_extension_enabled(const CharString &extension_name) const {
-		return enabled_instance_extension_names.has(extension_name);
-	}
-
-	static void register_requested_device_extension(const CharString &extension_name, bool p_required);
-	bool is_device_extension_enabled(const CharString &extension_name) const {
-		return enabled_device_extension_names.has(extension_name);
-	}
-
-	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) override final;
-	virtual int window_get_width(DisplayServer::WindowID p_window = 0) override final;
-	virtual int window_get_height(DisplayServer::WindowID p_window = 0) override final;
-	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) override final;
-	virtual void window_destroy(DisplayServer::WindowID p_window_id) override final;
-	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) override final;
-	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) override final;
-
-	virtual RID local_device_create() override final;
-	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) override final;
-	virtual void local_device_sync(RID p_local_device) override final;
-	virtual void local_device_free(RID p_local_device) override final;
-
-	VkFormat get_screen_format() const;
-	const VkPhysicalDeviceLimits &get_device_limits() const;
-
-	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) override final;
-	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) override final;
-	void resize_notify();
-	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) override final;
-	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) override final;
-	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) override final;
-	virtual Error swap_buffers() override final;
-	virtual Error initialize() override final;
-
-	void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
-
-	virtual String get_device_vendor_name() const override final;
-	virtual String get_device_name() const override final;
-	virtual RDD::DeviceType get_device_type() const override final;
-	virtual String get_device_api_version() const override final;
-	virtual String get_device_pipeline_cache_uuid() const override final;
-
-	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) override final;
-	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const override final;
-
-	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) override final;
-	virtual bool is_debug_utils_enabled() const override final;
-
-	VulkanContext();
-	virtual ~VulkanContext();
-};
-
-#endif // VULKAN_CONTEXT_H

+ 15 - 3
servers/rendering/renderer_rd/api_context_rd.cpp → drivers/vulkan/vulkan_hooks.cpp

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  api_context_rd.cpp                                                    */
+/*  vulkan_hooks.cpp                                                      */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,6 +28,18 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#include "api_context_rd.h"
+#include "vulkan_hooks.h"
 
-ApiContextRD::~ApiContextRD() {}
+VulkanHooks *VulkanHooks::singleton = nullptr;
+
+VulkanHooks::VulkanHooks() {
+	if (singleton == nullptr) {
+		singleton = this;
+	}
+}
+
+VulkanHooks::~VulkanHooks() {
+	if (singleton == this) {
+		singleton = nullptr;
+	}
+}

+ 10 - 4
drivers/vulkan/vulkan_hooks.h

@@ -38,11 +38,17 @@
 #endif
 
 class VulkanHooks {
+private:
+	static VulkanHooks *singleton;
+
 public:
-	virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { return false; };
-	virtual bool get_physical_device(VkPhysicalDevice *r_device) { return false; };
-	virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { return false; };
-	virtual ~VulkanHooks(){};
+	VulkanHooks();
+	virtual ~VulkanHooks();
+	virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) = 0;
+	virtual bool get_physical_device(VkPhysicalDevice *r_device) = 0;
+	virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) = 0;
+	virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) = 0;
+	static VulkanHooks *get_singleton() { return singleton; }
 };
 
 #endif // VULKAN_HOOKS_H

+ 7 - 0
misc/extension_api_validation/4.2-stable.expected

@@ -113,3 +113,10 @@ Validate extension JSON: API was removed: classes/TileMap/methods/set_tileset
 Validate extension JSON: API was removed: classes/TileMap/properties/tile_set
 
 Moved to the parent TileMapLayerGroup class. No change should be necessary.
+
+
+GH-87340
+--------
+Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/RenderingDevice/methods/screen_get_framebuffer_format': arguments
+
+screen_get_framebuffer_format can now specify the screen it should get the format from. The argument defaults to the main window to emulate the behavior of the old function.

+ 7 - 7
modules/glslang/register_types.cpp

@@ -39,7 +39,7 @@
 #include <glslang/SPIRV/GlslangToSpv.h>
 
 static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device) {
-	const RD::Capabilities *capabilities = p_render_device->get_device_capabilities();
+	const RDD::Capabilities &capabilities = p_render_device->get_device_capabilities();
 	Vector<uint8_t> ret;
 
 	ERR_FAIL_COND_V(p_language == RenderingDevice::SHADER_LANGUAGE_HLSL, ret);
@@ -57,17 +57,17 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
 	glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2;
 	glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
 
-	if (capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
-		if (capabilities->version_major == 1 && capabilities->version_minor == 0) {
+	if (capabilities.device_family == RDD::DEVICE_VULKAN) {
+		if (capabilities.version_major == 1 && capabilities.version_minor == 0) {
 			ClientVersion = glslang::EShTargetVulkan_1_0;
 			TargetVersion = glslang::EShTargetSpv_1_0;
-		} else if (capabilities->version_major == 1 && capabilities->version_minor == 1) {
+		} else if (capabilities.version_major == 1 && capabilities.version_minor == 1) {
 			ClientVersion = glslang::EShTargetVulkan_1_1;
 			TargetVersion = glslang::EShTargetSpv_1_3;
 		} else {
 			// use defaults
 		}
-	} else if (capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_DIRECTX) {
+	} else if (capabilities.device_family == RDD::DEVICE_DIRECTX) {
 		// NIR-DXIL is Vulkan 1.1-conformant.
 		ClientVersion = glslang::EShTargetVulkan_1_1;
 		// The SPIR-V part of Mesa supports 1.6, but:
@@ -186,9 +186,9 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
 }
 
 static String _get_cache_key_function_glsl(const RenderingDevice *p_render_device) {
-	const RD::Capabilities *capabilities = p_render_device->get_device_capabilities();
+	const RenderingDeviceDriver::Capabilities &capabilities = p_render_device->get_device_capabilities();
 	String version;
-	version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(capabilities->version_major) + ", minor=" + itos(capabilities->version_minor) + " , subgroup_size=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_SIZE)) + " , subgroup_ops=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS)) + " , subgroup_in_shaders=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS)) + " , debug=" + itos(Engine::get_singleton()->is_generate_spirv_debug_info_enabled());
+	version = "SpirVGen=" + itos(glslang::GetSpirvGeneratorVersion()) + ", major=" + itos(capabilities.version_major) + ", minor=" + itos(capabilities.version_minor) + " , subgroup_size=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_SIZE)) + " , subgroup_ops=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_OPERATIONS)) + " , subgroup_in_shaders=" + itos(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS)) + " , debug=" + itos(Engine::get_singleton()->is_generate_spirv_debug_info_enabled());
 	return version;
 }
 

+ 52 - 2
modules/lightmapper_rd/lightmapper_rd.cpp

@@ -41,6 +41,10 @@
 #include "editor/editor_settings.h"
 #include "servers/rendering/rendering_device_binds.h"
 
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
+#endif
+
 //uncomment this if you want to see textures from all the process saved
 //#define DEBUG_TEXTURES
 
@@ -1017,7 +1021,35 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 	}
 #endif
 
-	RenderingDevice *rd = RenderingDevice::get_singleton()->create_local_device();
+	// Attempt to create a local device by requesting it from rendering server first.
+	// If that fails because the current renderer is not implemented on top of RD, we fall back to creating
+	// a local rendering device manually depending on the current platform.
+	Error err;
+	RenderingContextDriver *rcd = nullptr;
+	RenderingDevice *rd = RenderingServer::get_singleton()->create_local_rendering_device();
+	if (rd == nullptr) {
+#if defined(RD_ENABLED)
+#if defined(VULKAN_ENABLED)
+		rcd = memnew(RenderingContextDriverVulkan);
+		rd = memnew(RenderingDevice);
+#endif
+#endif
+		if (rcd != nullptr && rd != nullptr) {
+			err = rcd->initialize();
+			if (err == OK) {
+				err = rd->initialize(rcd);
+			}
+
+			if (err != OK) {
+				memdelete(rd);
+				memdelete(rcd);
+				rd = nullptr;
+				rcd = nullptr;
+			}
+		}
+	}
+
+	ERR_FAIL_NULL_V(rd, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
 
 	RID albedo_array_tex;
 	RID emission_array_tex;
@@ -1187,7 +1219,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 	//shaders
 	Ref<RDShaderFile> raster_shader;
 	raster_shader.instantiate();
-	Error err = raster_shader->parse_versions_from_text(lm_raster_shader_glsl);
+	err = raster_shader->parse_versions_from_text(lm_raster_shader_glsl);
 	if (err != OK) {
 		raster_shader->print_errors("raster_shader");
 
@@ -1195,6 +1227,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 		FREE_BUFFERS
 
 		memdelete(rd);
+
+		if (rcd != nullptr) {
+			memdelete(rcd);
+		}
 	}
 	ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
 
@@ -1367,6 +1403,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 		FREE_BUFFERS
 		FREE_RASTER_RESOURCES
 		memdelete(rd);
+
+		if (rcd != nullptr) {
+			memdelete(rcd);
+		}
+
 		compute_shader->print_errors("compute_shader");
 	}
 	ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
@@ -1789,6 +1830,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 		FREE_RASTER_RESOURCES
 		FREE_COMPUTE_RESOURCES
 		memdelete(rd);
+
+		if (rcd != nullptr) {
+			memdelete(rcd);
+		}
+
 		blendseams_shader->print_errors("blendseams_shader");
 	}
 	ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
@@ -1964,6 +2010,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 
 	memdelete(rd);
 
+	if (rcd != nullptr) {
+		memdelete(rcd);
+	}
+
 	return BAKE_OK;
 }
 

+ 8 - 12
modules/openxr/extensions/platform/openxr_vulkan_extension.cpp

@@ -38,14 +38,6 @@
 #include "servers/rendering/rendering_server_globals.h"
 #include "servers/rendering_server.h"
 
-OpenXRVulkanExtension::OpenXRVulkanExtension() {
-	VulkanContext::set_vulkan_hooks(this);
-}
-
-OpenXRVulkanExtension::~OpenXRVulkanExtension() {
-	VulkanContext::set_vulkan_hooks(nullptr);
-}
-
 HashMap<String, bool *> OpenXRVulkanExtension::get_requested_extensions() {
 	HashMap<String, bool *> request_extensions;
 
@@ -178,10 +170,6 @@ bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
 bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) {
 	ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), false);
 
-	// the first entry in our queue list should be the one we need to remember...
-	vulkan_queue_family_index = p_device_create_info->pQueueCreateInfos[0].queueFamilyIndex;
-	vulkan_queue_index = 0; // ??
-
 	XrVulkanDeviceCreateInfoKHR create_info = {
 		XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, // type
 		nullptr, // next
@@ -209,9 +197,17 @@ bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_dev
 	return true;
 }
 
+void OpenXRVulkanExtension::set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) {
+	vulkan_queue_family_index = p_queue_family_index;
+	vulkan_queue_index = p_queue_index;
+}
+
 XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan;
 
 void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
+	DEV_ASSERT(vulkan_queue_family_index < UINT32_MAX && "Direct queue family index was not specified yet.");
+	DEV_ASSERT(vulkan_queue_index < UINT32_MAX && "Direct queue index was not specified yet.");
+
 	graphics_binding_vulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
 	graphics_binding_vulkan.next = p_next_pointer;
 	graphics_binding_vulkan.instance = vulkan_instance;

+ 9 - 7
modules/openxr/extensions/platform/openxr_vulkan_extension.h

@@ -36,23 +36,25 @@
 #include "../openxr_extension_wrapper.h"
 
 #include "core/templates/vector.h"
+#include "drivers/vulkan/vulkan_hooks.h"
 
 // Always include this as late as possible.
 #include "../../openxr_platform_inc.h"
 
 class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
 public:
-	OpenXRVulkanExtension();
-	virtual ~OpenXRVulkanExtension() override;
+	OpenXRVulkanExtension() = default;
+	virtual ~OpenXRVulkanExtension() override = default;
 
 	virtual HashMap<String, bool *> get_requested_extensions() override;
 
 	virtual void on_instance_created(const XrInstance p_instance) override;
 	virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
 
-	virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) override;
-	virtual bool get_physical_device(VkPhysicalDevice *r_device) override;
-	virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override;
+	virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) override final;
+	virtual bool get_physical_device(VkPhysicalDevice *r_device) override final;
+	virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override final;
+	virtual void set_direct_queue_family_and_index(uint32_t p_queue_family_index, uint32_t p_queue_index) override final;
 
 	virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
 	virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
@@ -76,8 +78,8 @@ private:
 	VkInstance vulkan_instance = nullptr;
 	VkPhysicalDevice vulkan_physical_device = nullptr;
 	VkDevice vulkan_device = nullptr;
-	uint32_t vulkan_queue_family_index = 0;
-	uint32_t vulkan_queue_index = 0;
+	uint32_t vulkan_queue_family_index = UINT32_MAX;
+	uint32_t vulkan_queue_index = UINT32_MAX;
 
 	EXT_PROTO_XRRESULT_FUNC3(xrGetVulkanGraphicsRequirements2KHR, (XrInstance), p_instance, (XrSystemId), p_system_id, (XrGraphicsRequirementsVulkanKHR *), p_graphics_requirements)
 	EXT_PROTO_XRRESULT_FUNC4(xrCreateVulkanInstanceKHR, (XrInstance), p_instance, (const XrVulkanInstanceCreateInfoKHR *), p_create_info, (VkInstance *), r_vulkan_instance, (VkResult *), r_vulkan_result)

+ 1 - 1
modules/openxr/openxr_platform_inc.h

@@ -36,7 +36,7 @@
 
 #ifdef VULKAN_ENABLED
 #define XR_USE_GRAPHICS_API_VULKAN
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 #endif // VULKAN_ENABLED
 
 #if defined(GLES3_ENABLED) && !defined(MACOS_ENABLED)

+ 1 - 1
platform/android/SCsub

@@ -23,7 +23,7 @@ android_files = [
     "android_keys_utils.cpp",
     "display_server_android.cpp",
     "plugin/godot_plugin_jni.cpp",
-    "vulkan_context_android.cpp",
+    "rendering_context_driver_vulkan_android.cpp",
 ]
 
 env_android = env.Clone()

+ 44 - 32
platform/android/display_server_android.cpp

@@ -42,7 +42,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #if defined(VULKAN_ENABLED)
-#include "vulkan_context_android.h"
+#include "rendering_context_driver_vulkan_android.h"
 #endif
 #endif
 
@@ -518,15 +518,17 @@ void DisplayServerAndroid::register_android_driver() {
 
 void DisplayServerAndroid::reset_window() {
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		VSyncMode last_vsync_mode = context_rd->get_vsync_mode(MAIN_WINDOW_ID);
-		context_rd->window_destroy(MAIN_WINDOW_ID);
+	if (rendering_context) {
+		if (rendering_device) {
+			rendering_device->screen_free(MAIN_WINDOW_ID);
+		}
 
-		Size2i display_size = OS_Android::get_singleton()->get_display_size();
+		VSyncMode last_vsync_mode = rendering_context->window_get_vsync_mode(MAIN_WINDOW_ID);
+		rendering_context->window_destroy(MAIN_WINDOW_ID);
 
 		union {
 #ifdef VULKAN_ENABLED
-			VulkanContextAndroid::WindowPlatformData vulkan;
+			RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
 #endif
 		} wpd;
 #ifdef VULKAN_ENABLED
@@ -537,12 +539,20 @@ void DisplayServerAndroid::reset_window() {
 		}
 #endif
 
-		if (context_rd->window_create(MAIN_WINDOW_ID, last_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
-			ERR_PRINT(vformat("Failed to reset %s window.", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+		if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+			ERR_PRINT(vformat("Failed to reset %s window.", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			return;
 		}
+
+		Size2i display_size = OS_Android::get_singleton()->get_display_size();
+		rendering_context->window_set_size(MAIN_WINDOW_ID, display_size.width, display_size.height);
+		rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, last_vsync_mode);
+
+		if (rendering_device) {
+			rendering_device->screen_create(MAIN_WINDOW_ID);
+		}
 	}
 #endif
 }
@@ -565,28 +575,26 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 #endif
 
 #if defined(RD_ENABLED)
-	context_rd = nullptr;
+	rendering_context = nullptr;
 	rendering_device = nullptr;
 
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_rd = memnew(VulkanContextAndroid);
+		rendering_context = memnew(RenderingContextDriverVulkanAndroid);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			ERR_PRINT(vformat("Failed to initialize %s context", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			return;
 		}
 
-		Size2i display_size = OS_Android::get_singleton()->get_display_size();
-
 		union {
 #ifdef VULKAN_ENABLED
-			VulkanContextAndroid::WindowPlatformData vulkan;
+			RenderingContextDriverVulkanAndroid::WindowPlatformData vulkan;
 #endif
 		} wpd;
 #ifdef VULKAN_ENABLED
@@ -597,15 +605,20 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 		}
 #endif
 
-		if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, display_size.width, display_size.height, &wpd) != OK) {
-			ERR_PRINT(vformat("Failed to create %s window.", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+		if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+			ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			return;
 		}
 
+		Size2i display_size = OS_Android::get_singleton()->get_display_size();
+		rendering_context->window_set_size(MAIN_WINDOW_ID, display_size.width, display_size.height);
+		rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
+
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -620,11 +633,10 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 DisplayServerAndroid::~DisplayServerAndroid() {
 #if defined(RD_ENABLED)
 	if (rendering_device) {
-		rendering_device->finalize();
 		memdelete(rendering_device);
 	}
-	if (context_rd) {
-		memdelete(context_rd);
+	if (rendering_context) {
+		memdelete(rendering_context);
 	}
 #endif
 }
@@ -716,16 +728,16 @@ void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor
 
 void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
 
 DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_window) const {
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;

+ 2 - 2
platform/android/display_server_android.h

@@ -34,7 +34,7 @@
 #include "servers/display_server.h"
 
 #if defined(RD_ENABLED)
-class ApiContextRD;
+class RenderingContextDriver;
 class RenderingDevice;
 #endif
 
@@ -73,7 +73,7 @@ class DisplayServerAndroid : public DisplayServer {
 	CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
 
 #if defined(RD_ENABLED)
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 

+ 18 - 18
platform/android/vulkan_context_android.cpp → platform/android/rendering_context_driver_vulkan_android.cpp

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_android.cpp                                            */
+/*  rendering_context_driver_vulkan_android.cpp                           */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#include "vulkan_context_android.h"
+#include "rendering_context_driver_vulkan_android.h"
 
 #ifdef VULKAN_ENABLED
 
@@ -38,32 +38,32 @@
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextAndroid::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanAndroid::_get_platform_surface_extension() const {
 	return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextAndroid::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanAndroid::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
 
-	VkAndroidSurfaceCreateInfoKHR createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
-	createInfo.window = wpd->window;
+	VkAndroidSurfaceCreateInfoKHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+	create_info.window = wpd->window;
 
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateAndroidSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
-	if (err != VK_SUCCESS) {
-		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
-	}
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateAndroidSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
 
-	return _window_create(DisplayServer::MAIN_WINDOW_ID, p_vsync_mode, surface, p_width, p_height);
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
 }
 
-bool VulkanContextAndroid::_use_validation_layers() {
-	uint32_t count = 0;
-	_get_preferred_validation_layers(&count, nullptr);
+bool RenderingContextDriverVulkanAndroid::_use_validation_layers() const {
+	TightLocalVector<const char *> layer_names;
+	Error err = _find_validation_layers(layer_names);
 
 	// On Android, we use validation layers automatically if they were explicitly linked with the app.
-	return count > 0;
+	return (err == OK) && !layer_names.is_empty();
 }
 
 #endif // VULKAN_ENABLED

+ 13 - 12
platform/android/vulkan_context_android.h → platform/android/rendering_context_driver_vulkan_android.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_android.h                                              */
+/*  rendering_context_driver_vulkan_android.h                             */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,31 +28,32 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_ANDROID_H
-#define VULKAN_CONTEXT_ANDROID_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
 struct ANativeWindow;
 
-class VulkanContextAndroid : public VulkanContext {
+class RenderingContextDriverVulkanAndroid : public RenderingContextDriverVulkan {
+private:
 	virtual const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+	bool _use_validation_layers() const override final;
+
 public:
 	struct WindowPlatformData {
 		ANativeWindow *window;
 	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
-	VulkanContextAndroid() = default;
-	~VulkanContextAndroid() override = default;
-
-protected:
-	bool _use_validation_layers() override;
+	RenderingContextDriverVulkanAndroid() = default;
+	~RenderingContextDriverVulkanAndroid() override = default;
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_ANDROID_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_ANDROID_H

+ 1 - 1
platform/ios/SCsub

@@ -9,7 +9,7 @@ ios_lib = [
     "app_delegate.mm",
     "view_controller.mm",
     "ios.mm",
-    "vulkan_context_ios.mm",
+    "rendering_context_driver_vulkan_ios.mm",
     "display_server_ios.mm",
     "joypad_ios.mm",
     "godot_view.mm",

+ 2 - 2
platform/ios/display_server_ios.h

@@ -39,7 +39,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #if defined(VULKAN_ENABLED)
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
 
 #ifdef USE_VOLK
 #include <volk.h>
@@ -62,7 +62,7 @@ class DisplayServerIOS : public DisplayServer {
 	_THREAD_SAFE_CLASS_
 
 #if defined(RD_ENABLED)
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 

+ 29 - 25
platform/ios/display_server_ios.mm

@@ -63,14 +63,14 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
 	}
 
 #if defined(RD_ENABLED)
-	context_rd = nullptr;
+	rendering_context = nullptr;
 	rendering_device = nullptr;
 
 	CALayer *layer = nullptr;
 
 	union {
 #ifdef VULKAN_ENABLED
-		VulkanContextIOS::WindowPlatformData vulkan;
+		RenderingContextDriverVulkanIOS::WindowPlatformData vulkan;
 #endif
 	} wpd;
 
@@ -81,29 +81,33 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
 			ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
 		}
 		wpd.vulkan.layer_ptr = &layer;
-		context_rd = memnew(VulkanContextIOS);
+		rendering_context = memnew(RenderingContextDriverVulkanIOS);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			ERR_PRINT(vformat("Failed to initialize %s context", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			return;
 		}
 
-		Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
-		if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, size.width, size.height, &wpd) != OK) {
-			ERR_PRINT(vformat("Failed to create %s window.", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+		if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+			ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			r_error = ERR_UNAVAILABLE;
 			return;
 		}
 
+		Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
+		rendering_context->window_set_size(MAIN_WINDOW_ID, size.width, size.height);
+		rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
+
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -132,15 +136,15 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
 DisplayServerIOS::~DisplayServerIOS() {
 #if defined(RD_ENABLED)
 	if (rendering_device) {
-		rendering_device->finalize();
+		rendering_device->screen_free(MAIN_WINDOW_ID);
 		memdelete(rendering_device);
 		rendering_device = nullptr;
 	}
 
-	if (context_rd) {
-		context_rd->window_destroy(MAIN_WINDOW_ID);
-		memdelete(context_rd);
-		context_rd = nullptr;
+	if (rendering_context) {
+		rendering_context->window_destroy(MAIN_WINDOW_ID);
+		memdelete(rendering_context);
+		rendering_context = nullptr;
 	}
 #endif
 }
@@ -714,8 +718,8 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
 	Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(MAIN_WINDOW_ID, size.x, size.y);
+	if (rendering_context) {
+		rendering_context->window_set_size(MAIN_WINDOW_ID, size.x, size.y);
 	}
 #endif
 
@@ -726,8 +730,8 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
 void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
@@ -735,8 +739,8 @@ void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
 DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;

+ 1 - 1
platform/ios/os_ios.h

@@ -45,7 +45,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #if defined(VULKAN_ENABLED)
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
 #endif
 #endif
 

+ 12 - 9
platform/ios/vulkan_context_ios.h → platform/ios/rendering_context_driver_vulkan_ios.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_ios.h                                                  */
+/*  rendering_context_driver_vulkan_ios.h                                 */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,28 +28,31 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_IOS_H
-#define VULKAN_CONTEXT_IOS_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
 #import <UIKit/UIKit.h>
 
-class VulkanContextIOS : public VulkanContext {
+class RenderingContextDriverVulkanIOS : public RenderingContextDriverVulkan {
+private:
 	virtual const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+
 public:
 	struct WindowPlatformData {
 		CALayer *const *layer_ptr;
 	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
-	VulkanContextIOS();
-	~VulkanContextIOS();
+	RenderingContextDriverVulkanIOS();
+	~RenderingContextDriverVulkanIOS();
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_IOS_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H

+ 20 - 14
platform/ios/vulkan_context_ios.mm → platform/ios/rendering_context_driver_vulkan_ios.mm

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_ios.mm                                                 */
+/*  rendering_context_driver_vulkan_ios.mm                                */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
 
 #ifdef VULKAN_ENABLED
 
@@ -38,26 +38,32 @@
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextIOS::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanIOS::_get_platform_surface_extension() const {
 	return VK_MVK_IOS_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanIOS::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
 
-	VkIOSSurfaceCreateInfoMVK createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
-	createInfo.pView = (__bridge const void *)(*wpd->layer_ptr);
+	VkIOSSurfaceCreateInfoMVK create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
+	create_info.pView = (__bridge const void *)(*wpd->layer_ptr);
 
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateIOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateIOSSurfaceMVK(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
 
-	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
 }
 
-VulkanContextIOS::VulkanContextIOS() {}
+RenderingContextDriverVulkanIOS::RenderingContextDriverVulkanIOS() {
+	// Does nothing.
+}
 
-VulkanContextIOS::~VulkanContextIOS() {}
+RenderingContextDriverVulkanIOS::~RenderingContextDriverVulkanIOS() {
+	// Does nothing.
+}
 
 #endif // VULKAN_ENABLED

+ 1 - 1
platform/linuxbsd/wayland/SCsub

@@ -195,7 +195,7 @@ if env["use_sowrap"]:
 
 
 if env["vulkan"]:
-    source_files.append("vulkan_context_wayland.cpp")
+    source_files.append("rendering_context_driver_vulkan_wayland.cpp")
 
 if env["opengl3"]:
     source_files.append("egl_manager_wayland.cpp")

+ 34 - 27
platform/linuxbsd/wayland/display_server_wayland.cpp

@@ -100,8 +100,8 @@ void DisplayServerWayland::_resize_window(const Size2i &p_size) {
 	wd.rect.size = p_size;
 
 #ifdef RD_ENABLED
-	if (wd.visible && context_rd) {
-		context_rd->window_resize(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height);
+	if (wd.visible && rendering_context) {
+		rendering_context->window_set_size(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height);
 	}
 #endif
 
@@ -140,10 +140,10 @@ void DisplayServerWayland::_show_window() {
 		// the only acceptable way of implementing window showing is to move the
 		// graphics context window creation logic here.
 #ifdef RD_ENABLED
-		if (context_rd) {
+		if (rendering_context) {
 			union {
 #ifdef VULKAN_ENABLED
-				VulkanContextWayland::WindowPlatformData vulkan;
+				RenderingContextDriverVulkanWayland::WindowPlatformData vulkan;
 #endif
 			} wpd;
 #ifdef VULKAN_ENABLED
@@ -152,14 +152,17 @@ void DisplayServerWayland::_show_window() {
 				wpd.vulkan.display = wayland_thread.get_wl_display();
 			}
 #endif
-			Error err = context_rd->window_create(wd.id, wd.vsync_mode, wd.rect.size.width, wd.rect.size.height, &wpd);
-			ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s window", context_rd->get_api_name()));
+			Error err = rendering_context->window_create(wd.id, &wpd);
+			ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s window", rendering_driver));
 
-			emulate_vsync = (context_rd->get_vsync_mode(wd.id) == DisplayServer::VSYNC_ENABLED);
+			rendering_context->window_set_size(wd.id, wd.rect.size.width, wd.rect.size.height);
+			rendering_context->window_set_vsync_mode(wd.id, wd.vsync_mode);
+
+			emulate_vsync = (rendering_context->window_get_vsync_mode(wd.id) == DisplayServer::VSYNC_ENABLED);
 
 			if (emulate_vsync) {
 				print_verbose("VSYNC: manually throttling frames using MAILBOX.");
-				context_rd->set_vsync_mode(wd.id, DisplayServer::VSYNC_MAILBOX);
+				rendering_context->window_set_vsync_mode(wd.id, DisplayServer::VSYNC_MAILBOX);
 			}
 		}
 #endif
@@ -885,14 +888,14 @@ void DisplayServerWayland::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
 	MutexLock mutex_lock(wayland_thread.mutex);
 
 #ifdef RD_ENABLED
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window_id, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window_id, p_vsync_mode);
 
-		emulate_vsync = (context_rd->get_vsync_mode(p_window_id) == DisplayServer::VSYNC_ENABLED);
+		emulate_vsync = (rendering_context->window_get_vsync_mode(p_window_id) == DisplayServer::VSYNC_ENABLED);
 
 		if (emulate_vsync) {
 			print_verbose("VSYNC: manually throttling frames using MAILBOX.");
-			context_rd->set_vsync_mode(p_window_id, DisplayServer::VSYNC_MAILBOX);
+			rendering_context->window_set_vsync_mode(p_window_id, DisplayServer::VSYNC_MAILBOX);
 		}
 	}
 #endif // VULKAN_ENABLED
@@ -917,8 +920,8 @@ DisplayServer::VSyncMode DisplayServerWayland::window_get_vsync_mode(DisplayServ
 	}
 
 #ifdef VULKAN_ENABLED
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window_id);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window_id);
 	}
 #endif // VULKAN_ENABLED
 
@@ -1236,15 +1239,15 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
 #ifdef RD_ENABLED
 #ifdef VULKAN_ENABLED
 	if (p_rendering_driver == "vulkan") {
-		context_rd = memnew(VulkanContextWayland);
+		rendering_context = memnew(RenderingContextDriverVulkanWayland);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			ERR_PRINT(vformat("Could not initialize %s", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			ERR_PRINT(vformat("Could not initialize %s", p_rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			r_error = ERR_CANT_CREATE;
 			return;
 		}
@@ -1329,9 +1332,10 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
 	_show_window();
 
 #ifdef RD_ENABLED
-	if (context_rd) {
+	if (rendering_context) {
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -1351,8 +1355,12 @@ DisplayServerWayland::~DisplayServerWayland() {
 	// TODO: Multiwindow support.
 	if (main_window.visible) {
 #ifdef VULKAN_ENABLED
-		if (context_rd) {
-			context_rd->window_destroy(MAIN_WINDOW_ID);
+		if (rendering_device) {
+			rendering_device->screen_free(MAIN_WINDOW_ID);
+		}
+
+		if (rendering_context) {
+			rendering_context->window_destroy(MAIN_WINDOW_ID);
 		}
 #endif
 
@@ -1374,12 +1382,11 @@ DisplayServerWayland::~DisplayServerWayland() {
 	// Destroy all drivers.
 #ifdef RD_ENABLED
 	if (rendering_device) {
-		rendering_device->finalize();
 		memdelete(rendering_device);
 	}
 
-	if (context_rd) {
-		memdelete(context_rd);
+	if (rendering_context) {
+		memdelete(rendering_context);
 	}
 #endif
 

+ 2 - 2
platform/linuxbsd/wayland/display_server_wayland.h

@@ -39,7 +39,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #ifdef VULKAN_ENABLED
-#include "wayland/vulkan_context_wayland.h"
+#include "wayland/rendering_context_driver_vulkan_wayland.h"
 #endif
 
 #endif //RD_ENABLED
@@ -123,7 +123,7 @@ class DisplayServerWayland : public DisplayServer {
 	String rendering_driver;
 
 #ifdef RD_ENABLED
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 

+ 25 - 14
platform/linuxbsd/wayland/vulkan_context_wayland.cpp → platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_wayland.cpp                                            */
+/*  rendering_context_driver_vulkan_wayland.cpp                           */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,32 +28,43 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#include "vulkan_context_wayland.h"
-
 #ifdef VULKAN_ENABLED
 
+#include "rendering_context_driver_vulkan_wayland.h"
+
 #ifdef USE_VOLK
 #include <volk.h>
 #else
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextWayland::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanWayland::_get_platform_surface_extension() const {
 	return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextWayland::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
+
+	VkWaylandSurfaceCreateInfoKHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+	create_info.display = wpd->display;
+	create_info.surface = wpd->surface;
+
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
 
-	VkWaylandSurfaceCreateInfoKHR createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
-	createInfo.display = wpd->display;
-	createInfo.surface = wpd->surface;
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
+}
+
+RenderingContextDriverVulkanWayland::RenderingContextDriverVulkanWayland() {
+	// Does nothing.
+}
 
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateWaylandSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+RenderingContextDriverVulkanWayland::~RenderingContextDriverVulkanWayland() {
+	// Does nothing.
 }
 
 #endif // VULKAN_ENABLED

+ 14 - 14
platform/windows/vulkan_context_win.h → platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_win.h                                                  */
+/*  rendering_context_driver_vulkan_wayland.h                             */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,30 +28,30 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_WIN_H
-#define VULKAN_CONTEXT_WIN_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-class VulkanContextWindows : public VulkanContext {
+class RenderingContextDriverVulkanWayland : public RenderingContextDriverVulkan {
+private:
 	virtual const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+
 public:
 	struct WindowPlatformData {
-		HWND window;
-		HINSTANCE instance;
+		struct wl_display *display;
+		struct wl_surface *surface;
 	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
-	VulkanContextWindows();
-	~VulkanContextWindows();
+	RenderingContextDriverVulkanWayland();
+	~RenderingContextDriverVulkanWayland();
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_WIN_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H

+ 1 - 1
platform/linuxbsd/x11/SCsub

@@ -21,7 +21,7 @@ if env["use_sowrap"]:
     )
 
 if env["vulkan"]:
-    source_files.append("vulkan_context_x11.cpp")
+    source_files.append("rendering_context_driver_vulkan_x11.cpp")
 
 if env["opengl3"]:
     env.Append(CPPDEFINES=["GLAD_GLX_NO_X11"])

+ 44 - 29
platform/linuxbsd/x11/display_server_x11.cpp

@@ -1670,7 +1670,11 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, V
 			window_set_flag(WindowFlags(i), true, id);
 		}
 	}
-
+#ifdef RD_ENABLED
+	if (rendering_device) {
+		rendering_device->screen_create(id);
+	}
+#endif
 	return id;
 }
 
@@ -1719,8 +1723,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
 	}
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_destroy(p_id);
+	if (rendering_device) {
+		rendering_device->screen_free(p_id);
+	}
+
+	if (rendering_context) {
+		rendering_context->window_destroy(p_id);
 	}
 #endif
 #ifdef GLES3_ENABLED
@@ -2245,8 +2253,8 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
 
 	// Keep rendering context window size in sync
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(p_window, xwa.width, xwa.height);
+	if (rendering_context) {
+		rendering_context->window_set_size(p_window, xwa.width, xwa.height);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -3970,8 +3978,8 @@ void DisplayServerX11::_window_changed(XEvent *event) {
 	wd.size = new_rect.size;
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(window_id, wd.size.width, wd.size.height);
+	if (rendering_context) {
+		rendering_context->window_set_size(window_id, wd.size.width, wd.size.height);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -5300,8 +5308,8 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
 void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 
@@ -5318,8 +5326,8 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
 DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -5662,10 +5670,10 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
 		_update_size_hints(id);
 
 #if defined(RD_ENABLED)
-		if (context_rd) {
+		if (rendering_context) {
 			union {
 #ifdef VULKAN_ENABLED
-				VulkanContextX11::WindowPlatformData vulkan;
+				RenderingContextDriverVulkanX11::WindowPlatformData vulkan;
 #endif
 			} wpd;
 #ifdef VULKAN_ENABLED
@@ -5674,8 +5682,11 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
 				wpd.vulkan.display = x11_display;
 			}
 #endif
-			Error err = context_rd->window_create(id, p_vsync_mode, win_rect.size.width, win_rect.size.height, &wpd);
-			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", context_rd->get_api_name()));
+			Error err = rendering_context->window_create(id, &wpd);
+			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", rendering_driver));
+
+			rendering_context->window_set_size(id, win_rect.size.width, win_rect.size.height);
+			rendering_context->window_set_vsync_mode(id, p_vsync_mode);
 		}
 #endif
 #ifdef GLES3_ENABLED
@@ -6077,15 +6088,15 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 #if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_rd = memnew(VulkanContextX11);
+		rendering_context = memnew(RenderingContextDriverVulkanX11);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			ERR_PRINT(vformat("Could not initialize %s", context_rd->get_api_name()));
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			ERR_PRINT(vformat("Could not initialize %s", rendering_driver));
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			r_error = ERR_CANT_CREATE;
 			return;
 		}
@@ -6197,9 +6208,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	show_window(main_window);
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
+	if (rendering_context) {
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -6374,8 +6386,12 @@ DisplayServerX11::~DisplayServerX11() {
 	//destroy all windows
 	for (KeyValue<WindowID, WindowData> &E : windows) {
 #if defined(RD_ENABLED)
-		if (context_rd) {
-			context_rd->window_destroy(E.key);
+		if (rendering_device) {
+			rendering_device->screen_free(E.key);
+		}
+
+		if (rendering_context) {
+			rendering_context->window_destroy(E.key);
 		}
 #endif
 #ifdef GLES3_ENABLED
@@ -6419,14 +6435,13 @@ DisplayServerX11::~DisplayServerX11() {
 	//destroy drivers
 #if defined(RD_ENABLED)
 	if (rendering_device) {
-		rendering_device->finalize();
 		memdelete(rendering_device);
 		rendering_device = nullptr;
 	}
 
-	if (context_rd) {
-		memdelete(context_rd);
-		context_rd = nullptr;
+	if (rendering_context) {
+		memdelete(rendering_context);
+		rendering_context = nullptr;
 	}
 #endif
 

+ 2 - 2
platform/linuxbsd/x11/display_server_x11.h

@@ -61,7 +61,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #if defined(VULKAN_ENABLED)
-#include "x11/vulkan_context_x11.h"
+#include "x11/rendering_context_driver_vulkan_x11.h"
 #endif
 #endif
 
@@ -144,7 +144,7 @@ class DisplayServerX11 : public DisplayServer {
 	GLManagerEGL_X11 *gl_manager_egl = nullptr;
 #endif
 #if defined(RD_ENABLED)
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 

+ 20 - 15
platform/linuxbsd/x11/vulkan_context_x11.cpp → platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_x11.cpp                                                */
+/*  rendering_context_driver_vulkan_x11.cpp                               */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -30,7 +30,7 @@
 
 #ifdef VULKAN_ENABLED
 
-#include "vulkan_context_x11.h"
+#include "rendering_context_driver_vulkan_x11.h"
 
 #ifdef USE_VOLK
 #include <volk.h>
@@ -38,28 +38,33 @@
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextX11::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanX11::_get_platform_surface_extension() const {
 	return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
 
-	VkXlibSurfaceCreateInfoKHR createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
-	createInfo.dpy = wpd->display;
-	createInfo.window = wpd->window;
+	VkXlibSurfaceCreateInfoKHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+	create_info.dpy = wpd->display;
+	create_info.window = wpd->window;
 
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateXlibSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
 }
 
-VulkanContextX11::VulkanContextX11() {
+RenderingContextDriverVulkanX11::RenderingContextDriverVulkanX11() {
+	// Does nothing.
 }
 
-VulkanContextX11::~VulkanContextX11() {
+RenderingContextDriverVulkanX11::~RenderingContextDriverVulkanX11() {
+	// Does nothing.
 }
 
 #endif // VULKAN_ENABLED

+ 12 - 9
platform/linuxbsd/x11/vulkan_context_x11.h → platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_x11.h                                                  */
+/*  rendering_context_driver_vulkan_x11.h                                 */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,29 +28,32 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_X11_H
-#define VULKAN_CONTEXT_X11_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
 #include <X11/Xlib.h>
 
-class VulkanContextX11 : public VulkanContext {
+class RenderingContextDriverVulkanX11 : public RenderingContextDriverVulkan {
+private:
 	virtual const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+
 public:
 	struct WindowPlatformData {
 		::Window window;
 		Display *display;
 	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
-	VulkanContextX11();
-	~VulkanContextX11();
+	RenderingContextDriverVulkanX11();
+	~RenderingContextDriverVulkanX11();
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_X11_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_X11_H

+ 1 - 1
platform/macos/SCsub

@@ -24,7 +24,7 @@ files = [
     "dir_access_macos.mm",
     "tts_macos.mm",
     "joypad_macos.cpp",
-    "vulkan_context_macos.mm",
+    "rendering_context_driver_vulkan_macos.mm",
     "gl_manager_macos_angle.mm",
     "gl_manager_macos_legacy.mm",
 ]

+ 2 - 2
platform/macos/display_server_macos.h

@@ -43,7 +43,7 @@
 #include "servers/rendering/rendering_device.h"
 
 #if defined(VULKAN_ENABLED)
-#include "vulkan_context_macos.h"
+#include "rendering_context_driver_vulkan_macos.h"
 #endif // VULKAN_ENABLED
 #endif // RD_ENABLED
 
@@ -137,7 +137,7 @@ private:
 	GLManagerANGLE_MacOS *gl_manager_angle = nullptr;
 #endif
 #if defined(RD_ENABLED)
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 	String rendering_driver;

+ 39 - 33
platform/macos/display_server_macos.mm

@@ -195,10 +195,10 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 		}
 
 #if defined(RD_ENABLED)
-		if (context_rd) {
+		if (rendering_context) {
 			union {
 #ifdef VULKAN_ENABLED
-				VulkanContextMacOS::WindowPlatformData vulkan;
+				RenderingContextDriverVulkanMacOS::WindowPlatformData vulkan;
 #endif
 			} wpd;
 #ifdef VULKAN_ENABLED
@@ -206,8 +206,11 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 				wpd.vulkan.view_ptr = &wd.window_view;
 			}
 #endif
-			Error err = context_rd->window_create(window_id_counter, p_vsync_mode, p_rect.size.width, p_rect.size.height, &wpd);
-			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s context", context_rd->get_api_name()));
+			Error err = rendering_context->window_create(window_id_counter, &wpd);
+			ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s context", rendering_driver));
+
+			rendering_context->window_set_size(window_id_counter, p_rect.size.width, p_rect.size.height);
+			rendering_context->window_set_vsync_mode(window_id_counter, p_vsync_mode);
 		}
 #endif
 #if defined(GLES3_ENABLED)
@@ -257,11 +260,6 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
 		gl_manager_angle->window_resize(id, wd.size.width, wd.size.height);
 	}
 #endif
-#if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(id, wd.size.width, wd.size.height);
-	}
-#endif
 
 	return id;
 }
@@ -791,8 +789,12 @@ void DisplayServerMacOS::window_destroy(WindowID p_window) {
 	}
 #endif
 #ifdef RD_ENABLED
-	if (context_rd) {
-		context_rd->window_destroy(p_window);
+	if (rendering_device) {
+		rendering_device->screen_free(p_window);
+	}
+
+	if (rendering_context) {
+		rendering_context->window_destroy(p_window);
 	}
 #endif
 	windows.erase(p_window);
@@ -800,6 +802,11 @@ void DisplayServerMacOS::window_destroy(WindowID p_window) {
 }
 
 void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_height) {
+#if defined(RD_ENABLED)
+	if (rendering_context) {
+		rendering_context->window_set_size(p_window, p_width, p_height);
+	}
+#endif
 #if defined(GLES3_ENABLED)
 	if (gl_manager_legacy) {
 		gl_manager_legacy->window_resize(p_window, p_width, p_height);
@@ -808,11 +815,6 @@ void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_hei
 		gl_manager_angle->window_resize(p_window, p_width, p_height);
 	}
 #endif
-#if defined(VULKAN_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(p_window, p_width, p_height);
-	}
-#endif
 }
 
 bool DisplayServerMacOS::has_feature(Feature p_feature) const {
@@ -2850,7 +2852,11 @@ DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode,
 			window_set_flag(WindowFlags(i), true, id);
 		}
 	}
-
+#ifdef RD_ENABLED
+	if (rendering_device) {
+		rendering_device->screen_create(id);
+	}
+#endif
 	return id;
 }
 
@@ -3811,8 +3817,8 @@ void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_
 	}
 #endif
 #if defined(VULKAN_ENABLED)
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 }
@@ -3828,8 +3834,8 @@ DisplayServer::VSyncMode DisplayServerMacOS::window_get_vsync_mode(WindowID p_wi
 	}
 #endif
 #if defined(VULKAN_ENABLED)
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window);
 	}
 #endif
 	return DisplayServer::VSYNC_ENABLED;
@@ -4632,16 +4638,16 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
 #if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_rd = memnew(VulkanContextMacOS);
+		rendering_context = memnew(RenderingContextDriverVulkanMacOS);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			r_error = ERR_CANT_CREATE;
-			ERR_FAIL_MSG("Could not initialize Vulkan");
+			ERR_FAIL_MSG("Could not initialize " + rendering_driver);
 		}
 	}
 #endif
@@ -4676,9 +4682,10 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
 	}
 #endif
 #if defined(RD_ENABLED)
-	if (context_rd) {
+	if (rendering_context) {
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -4714,14 +4721,13 @@ DisplayServerMacOS::~DisplayServerMacOS() {
 #endif
 #if defined(RD_ENABLED)
 	if (rendering_device) {
-		rendering_device->finalize();
 		memdelete(rendering_device);
 		rendering_device = nullptr;
 	}
 
-	if (context_rd) {
-		memdelete(context_rd);
-		context_rd = nullptr;
+	if (rendering_context) {
+		memdelete(rendering_context);
+		rendering_context = nullptr;
 	}
 #endif
 

+ 12 - 9
platform/macos/vulkan_context_macos.h → platform/macos/rendering_context_driver_vulkan_macos.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_macos.h                                                */
+/*  rendering_context_driver_vulkan_macos.h                               */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,28 +28,31 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_MACOS_H
-#define VULKAN_CONTEXT_MACOS_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
 #import <AppKit/AppKit.h>
 
-class VulkanContextMacOS : public VulkanContext {
+class RenderingContextDriverVulkanMacOS : public RenderingContextDriverVulkan {
+private:
 	virtual const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+
 public:
 	struct WindowPlatformData {
 		const id *view_ptr;
 	};
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
 
-	VulkanContextMacOS();
-	~VulkanContextMacOS();
+	RenderingContextDriverVulkanMacOS();
+	~RenderingContextDriverVulkanMacOS();
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_MACOS_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_MACOS_H

+ 19 - 14
platform/macos/vulkan_context_macos.mm → platform/macos/rendering_context_driver_vulkan_macos.mm

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_macos.mm                                               */
+/*  rendering_context_driver_vulkan_macos.mm                              */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#include "vulkan_context_macos.h"
+#include "rendering_context_driver_vulkan_macos.h"
 
 #ifdef VULKAN_ENABLED
 
@@ -38,27 +38,32 @@
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextMacOS::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanMacOS::_get_platform_surface_extension() const {
 	return VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextMacOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanMacOS::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
 
-	VkMacOSSurfaceCreateInfoMVK createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
-	createInfo.pView = (__bridge const void *)(*wpd->view_ptr);
+	VkMacOSSurfaceCreateInfoMVK create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
+	create_info.pView = (__bridge const void *)(*wpd->view_ptr);
 
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateMacOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateMacOSSurfaceMVK(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
 }
 
-VulkanContextMacOS::VulkanContextMacOS() {
+RenderingContextDriverVulkanMacOS::RenderingContextDriverVulkanMacOS() {
+	// Does nothing.
 }
 
-VulkanContextMacOS::~VulkanContextMacOS() {
+RenderingContextDriverVulkanMacOS::~RenderingContextDriverVulkanMacOS() {
+	// Does nothing.
 }
 
 #endif // VULKAN_ENABLED

+ 1 - 1
platform/windows/SCsub

@@ -18,10 +18,10 @@ common_win = [
     "joypad_windows.cpp",
     "tts_windows.cpp",
     "windows_terminal_logger.cpp",
-    "vulkan_context_win.cpp",
     "gl_manager_windows_native.cpp",
     "gl_manager_windows_angle.cpp",
     "wgl_detect_version.cpp",
+    "rendering_context_driver_vulkan_windows.cpp",
 ]
 
 common_win_wrap = [

+ 53 - 31
platform/windows/display_server_windows.cpp

@@ -39,6 +39,12 @@
 #include "main/main.h"
 #include "scene/resources/atlas_texture.h"
 
+#if defined(VULKAN_ENABLED)
+#include "rendering_context_driver_vulkan_windows.h"
+#endif
+#if defined(D3D12_ENABLED)
+#include "drivers/d3d12/rendering_context_driver_d3d12.h"
+#endif
 #if defined(GLES3_ENABLED)
 #include "drivers/gles3/rasterizer_gles3.h"
 #endif
@@ -1290,6 +1296,11 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
 	if (mainwindow_icon) {
 		SendMessage(windows[window_id].hWnd, WM_SETICON, ICON_BIG, (LPARAM)mainwindow_icon);
 	}
+#ifdef RD_ENABLED
+	if (rendering_device) {
+		rendering_device->screen_create(window_id);
+	}
+#endif
 	return window_id;
 }
 
@@ -1344,8 +1355,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
 	}
 
 #ifdef RD_ENABLED
-	if (context_rd) {
-		context_rd->window_destroy(p_window);
+	if (rendering_device) {
+		rendering_device->screen_free(p_window);
+	}
+
+	if (rendering_context) {
+		rendering_context->window_destroy(p_window);
 	}
 #endif
 #ifdef GLES3_ENABLED
@@ -1776,8 +1791,8 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
 	wd.height = h;
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->window_resize(p_window, w, h);
+	if (rendering_context) {
+		rendering_context->window_set_size(p_window, w, h);
 	}
 #endif
 #if defined(GLES3_ENABLED)
@@ -2830,8 +2845,8 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
 void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		context_rd->set_vsync_mode(p_window, p_vsync_mode);
+	if (rendering_context) {
+		rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
 	}
 #endif
 
@@ -2848,8 +2863,8 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
 DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
 	_THREAD_SAFE_METHOD_
 #if defined(RD_ENABLED)
-	if (context_rd) {
-		return context_rd->get_vsync_mode(p_window);
+	if (rendering_context) {
+		return rendering_context->window_get_vsync_mode(p_window);
 	}
 #endif
 
@@ -4054,9 +4069,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
 					rect_changed = true;
 				}
 #if defined(RD_ENABLED)
-				if (context_rd && window.context_created) {
+				if (rendering_context && window.context_created) {
 					// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
-					context_rd->window_resize(window_id, window.width, window.height);
+					rendering_context->window_set_size(window_id, window.width, window.height);
 				}
 #endif
 			}
@@ -4612,13 +4627,13 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 		}
 
 #ifdef RD_ENABLED
-		if (context_rd) {
+		if (rendering_context) {
 			union {
 #ifdef VULKAN_ENABLED
-				VulkanContextWindows::WindowPlatformData vulkan;
+				RenderingContextDriverVulkanWindows::WindowPlatformData vulkan;
 #endif
 #ifdef D3D12_ENABLED
-				D3D12Context::WindowPlatformData d3d12;
+				RenderingContextDriverD3D12::WindowPlatformData d3d12;
 #endif
 			} wpd;
 #ifdef VULKAN_ENABLED
@@ -4632,13 +4647,16 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
 				wpd.d3d12.window = wd.hWnd;
 			}
 #endif
-			if (context_rd->window_create(id, p_vsync_mode, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, &wpd) != OK) {
-				ERR_PRINT(vformat("Failed to create %s Window.", context_rd->get_api_name()));
-				memdelete(context_rd);
-				context_rd = nullptr;
+			if (rendering_context->window_create(id, &wpd) != OK) {
+				ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+				memdelete(rendering_context);
+				rendering_context = nullptr;
 				windows.erase(id);
 				return INVALID_WINDOW_ID;
 			}
+
+			rendering_context->window_set_size(id, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
+			rendering_context->window_set_vsync_mode(id, p_vsync_mode);
 			wd.context_created = true;
 		}
 #endif
@@ -4949,19 +4967,19 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 #if defined(RD_ENABLED)
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
-		context_rd = memnew(VulkanContextWindows);
+		rendering_context = memnew(RenderingContextDriverVulkanWindows);
 	}
 #endif
 #if defined(D3D12_ENABLED)
 	if (rendering_driver == "d3d12") {
-		context_rd = memnew(D3D12Context);
+		rendering_context = memnew(RenderingContextDriverD3D12);
 	}
 #endif
 
-	if (context_rd) {
-		if (context_rd->initialize() != OK) {
-			memdelete(context_rd);
-			context_rd = nullptr;
+	if (rendering_context) {
+		if (rendering_context->initialize() != OK) {
+			memdelete(rendering_context);
+			rendering_context = nullptr;
 			r_error = ERR_UNAVAILABLE;
 			return;
 		}
@@ -5051,9 +5069,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
 	show_window(MAIN_WINDOW_ID);
 
 #if defined(RD_ENABLED)
-	if (context_rd) {
+	if (rendering_context) {
 		rendering_device = memnew(RenderingDevice);
-		rendering_device->initialize(context_rd);
+		rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+		rendering_device->screen_create(MAIN_WINDOW_ID);
 
 		RendererCompositorRD::make_current();
 	}
@@ -5165,8 +5184,12 @@ DisplayServerWindows::~DisplayServerWindows() {
 
 	if (windows.has(MAIN_WINDOW_ID)) {
 #ifdef RD_ENABLED
-		if (context_rd) {
-			context_rd->window_destroy(MAIN_WINDOW_ID);
+		if (rendering_device) {
+			rendering_device->screen_free(MAIN_WINDOW_ID);
+		}
+
+		if (rendering_context) {
+			rendering_context->window_destroy(MAIN_WINDOW_ID);
 		}
 #endif
 		if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
@@ -5178,14 +5201,13 @@ DisplayServerWindows::~DisplayServerWindows() {
 
 #ifdef RD_ENABLED
 	if (rendering_device) {
-		rendering_device->finalize();
 		memdelete(rendering_device);
 		rendering_device = nullptr;
 	}
 
-	if (context_rd) {
-		memdelete(context_rd);
-		context_rd = nullptr;
+	if (rendering_context) {
+		memdelete(rendering_context);
+		rendering_context = nullptr;
 	}
 #endif
 

+ 1 - 8
platform/windows/display_server_windows.h

@@ -54,13 +54,6 @@
 
 #if defined(RD_ENABLED)
 #include "servers/rendering/rendering_device.h"
-
-#if defined(VULKAN_ENABLED)
-#include "vulkan_context_win.h"
-#endif
-#if defined(D3D12_ENABLED)
-#include "drivers/d3d12/d3d12_context.h"
-#endif
 #endif
 
 #if defined(GLES3_ENABLED)
@@ -349,7 +342,7 @@ class DisplayServerWindows : public DisplayServer {
 #endif
 
 #if defined(RD_ENABLED)
-	ApiContextRD *context_rd = nullptr;
+	RenderingContextDriver *rendering_context = nullptr;
 	RenderingDevice *rendering_device = nullptr;
 #endif
 

+ 0 - 7
platform/windows/os_windows.h

@@ -48,13 +48,6 @@
 
 #if defined(RD_ENABLED)
 #include "servers/rendering/rendering_device.h"
-
-#if defined(VULKAN_ENABLED)
-#include "vulkan_context_win.h"
-#endif
-#if defined(D3D12_ENABLED)
-#include "drivers/d3d12/d3d12_context.h"
-#endif
 #endif
 
 #include <io.h>

+ 25 - 19
platform/windows/vulkan_context_win.cpp → platform/windows/rendering_context_driver_vulkan_windows.cpp

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_win.cpp                                                */
+/*  rendering_context_driver_vulkan_windows.cpp                           */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -30,7 +30,9 @@
 
 #if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
 
-#include "vulkan_context_win.h"
+#include "core/os/os.h"
+
+#include "rendering_context_driver_vulkan_windows.h"
 
 #ifdef USE_VOLK
 #include <volk.h>
@@ -38,32 +40,36 @@
 #include <vulkan/vulkan.h>
 #endif
 
-const char *VulkanContextWindows::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanWindows::_get_platform_surface_extension() const {
 	return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
 }
 
-Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
-	const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
-
-	VkWin32SurfaceCreateInfoKHR createInfo = {};
-	createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
-	createInfo.hinstance = wpd->instance;
-	createInfo.hwnd = wpd->window;
-
-	VkSurfaceKHR surface = VK_NULL_HANDLE;
-	VkResult err = vkCreateWin32SurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
-	ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
-	return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
-}
-
-VulkanContextWindows::VulkanContextWindows() {
+RenderingContextDriverVulkanWindows::RenderingContextDriverVulkanWindows() {
 	// Workaround for Vulkan not working on setups with AMD integrated graphics + NVIDIA dedicated GPU (GH-57708).
 	// This prevents using AMD integrated graphics with Vulkan entirely, but it allows the engine to start
 	// even on outdated/broken driver setups.
 	OS::get_singleton()->set_environment("DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1", "1");
 }
 
-VulkanContextWindows::~VulkanContextWindows() {
+RenderingContextDriverVulkanWindows::~RenderingContextDriverVulkanWindows() {
+	// Does nothing.
+}
+
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_create(const void *p_platform_data) {
+	const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
+
+	VkWin32SurfaceCreateInfoKHR create_info = {};
+	create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+	create_info.hinstance = wpd->instance;
+	create_info.hwnd = wpd->window;
+
+	VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+	VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+	ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+	Surface *surface = memnew(Surface);
+	surface->vk_surface = vk_surface;
+	return SurfaceID(surface);
 }
 
 #endif // WINDOWS_ENABLED && VULKAN_ENABLED

+ 17 - 9
platform/linuxbsd/wayland/vulkan_context_wayland.h → platform/windows/rendering_context_driver_vulkan_windows.h

@@ -1,5 +1,5 @@
 /**************************************************************************/
-/*  vulkan_context_wayland.h                                              */
+/*  rendering_context_driver_vulkan_windows.h                             */
 /**************************************************************************/
 /*                         This file is part of:                          */
 /*                             GODOT ENGINE                               */
@@ -28,25 +28,33 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 /**************************************************************************/
 
-#ifndef VULKAN_CONTEXT_WAYLAND_H
-#define VULKAN_CONTEXT_WAYLAND_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H
 
 #ifdef VULKAN_ENABLED
 
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
 
-class VulkanContextWayland : public VulkanContext {
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+class RenderingContextDriverVulkanWindows : public RenderingContextDriverVulkan {
+private:
 	const char *_get_platform_surface_extension() const override final;
 
+protected:
+	SurfaceID surface_create(const void *p_platform_data) override final;
+
 public:
 	struct WindowPlatformData {
-		struct wl_display *display;
-		struct wl_surface *surface;
+		HWND window;
+		HINSTANCE instance;
 	};
 
-	Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
+	RenderingContextDriverVulkanWindows();
+	~RenderingContextDriverVulkanWindows() override final;
 };
 
 #endif // VULKAN_ENABLED
 
-#endif // VULKAN_CONTEXT_WAYLAND_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H

+ 0 - 1
servers/rendering/dummy/rasterizer_dummy.h

@@ -86,7 +86,6 @@ public:
 		time += frame_step;
 	}
 
-	void prepare_for_blitting_render_targets() override {}
 	void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}
 
 	void end_viewport(bool p_swap_buffers) override {}

+ 0 - 1
servers/rendering/renderer_compositor.h

@@ -96,7 +96,6 @@ public:
 	virtual void initialize() = 0;
 	virtual void begin_frame(double frame_step) = 0;
 
-	virtual void prepare_for_blitting_render_targets() = 0;
 	virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
 
 	virtual void end_viewport(bool p_swap_buffers) = 0;

+ 0 - 82
servers/rendering/renderer_rd/api_context_rd.h

@@ -1,82 +0,0 @@
-/**************************************************************************/
-/*  api_context_rd.h                                                      */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#ifndef API_CONTEXT_RD_H
-#define API_CONTEXT_RD_H
-
-#include "servers/rendering/rendering_device.h"
-#include "servers/rendering/rendering_device_driver.h"
-
-class ApiContextRD {
-public:
-	virtual const char *get_api_name() const = 0;
-	virtual RenderingDevice::Capabilities get_device_capabilities() const = 0;
-	virtual const RDD::MultiviewCapabilities &get_multiview_capabilities() const = 0;
-
-	virtual int get_swapchain_image_count() const = 0;
-
-	virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) = 0;
-	virtual void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) = 0;
-	virtual int window_get_width(DisplayServer::WindowID p_window = 0) = 0;
-	virtual int window_get_height(DisplayServer::WindowID p_window = 0) = 0;
-	virtual bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0) = 0;
-	virtual void window_destroy(DisplayServer::WindowID p_window_id) = 0;
-	virtual RDD::RenderPassID window_get_render_pass(DisplayServer::WindowID p_window = 0) = 0;
-	virtual RDD::FramebufferID window_get_framebuffer(DisplayServer::WindowID p_window = 0) = 0;
-
-	virtual RID local_device_create() = 0;
-	virtual void local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) = 0;
-	virtual void local_device_sync(RID p_local_device) = 0;
-	virtual void local_device_free(RID p_local_device) = 0;
-
-	virtual void set_setup_buffer(RDD::CommandBufferID p_command_buffer) = 0;
-	virtual void append_command_buffer(RDD::CommandBufferID p_command_buffer) = 0;
-	virtual void flush(bool p_flush_setup = false, bool p_flush_pending = false, bool p_sync = true) = 0;
-	virtual Error prepare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
-	virtual void postpare_buffers(RDD::CommandBufferID p_command_buffer) = 0;
-	virtual Error swap_buffers() = 0;
-	virtual Error initialize() = 0;
-
-	virtual String get_device_vendor_name() const = 0;
-	virtual String get_device_name() const = 0;
-	virtual RDD::DeviceType get_device_type() const = 0;
-	virtual String get_device_api_version() const = 0;
-	virtual String get_device_pipeline_cache_uuid() const = 0;
-
-	virtual void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) = 0;
-	virtual DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const = 0;
-
-	virtual RenderingDeviceDriver *get_driver(RID p_local_device = RID()) = 0;
-	virtual bool is_debug_utils_enabled() const = 0;
-
-	virtual ~ApiContextRD();
-};
-
-#endif // API_CONTEXT_RD_H

+ 9 - 9
servers/rendering/renderer_rd/renderer_compositor_rd.cpp

@@ -33,16 +33,16 @@
 #include "core/config/project_settings.h"
 #include "core/io/dir_access.h"
 
-void RendererCompositorRD::prepare_for_blitting_render_targets() {
-	RD::get_singleton()->prepare_screen_for_drawing();
-}
-
 void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);
-	if (draw_list == RD::INVALID_ID) {
-		return; // Window is minimized and does not have valid swapchain, skip drawing without printing errors.
+	Error err = RD::get_singleton()->screen_prepare_for_drawing(p_screen);
+	if (err != OK) {
+		// Window is minimized and does not have valid swapchain, skip drawing without printing errors.
+		return;
 	}
 
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);
+	ERR_FAIL_COND(draw_list == RD::INVALID_ID);
+
 	for (int i = 0; i < p_amount; i++) {
 		RID rd_texture = texture_storage->render_target_get_rd_texture(p_render_targets[i].render_target);
 		ERR_CONTINUE(rd_texture.is_null());
@@ -122,7 +122,7 @@ void RendererCompositorRD::initialize() {
 		blit.shader_version = blit.shader.version_create();
 
 		for (int i = 0; i < BLIT_MODE_MAX; i++) {
-			blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), i == BLIT_MODE_NORMAL_ALPHA ? RenderingDevice::PipelineColorBlendState::create_blend() : RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
+			blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(DisplayServer::MAIN_WINDOW_ID), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), i == BLIT_MODE_NORMAL_ALPHA ? RenderingDevice::PipelineColorBlendState::create_blend() : RenderingDevice::PipelineColorBlendState::create_disabled(), 0);
 		}
 
 		//create index array for copy shader
@@ -169,7 +169,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color
 		return;
 	}
 
-	RD::get_singleton()->prepare_screen_for_drawing();
+	RD::get_singleton()->screen_prepare_for_drawing(DisplayServer::MAIN_WINDOW_ID);
 
 	RID texture = texture_storage->texture_allocate();
 	texture_storage->texture_2d_initialize(texture, p_image);

+ 0 - 1
servers/rendering/renderer_rd/renderer_compositor_rd.h

@@ -120,7 +120,6 @@ public:
 
 	void initialize();
 	void begin_frame(double frame_step);
-	void prepare_for_blitting_render_targets();
 	void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);
 
 	void end_viewport(bool p_swap_buffers) {}

+ 1 - 2
servers/rendering/renderer_rd/shader_rd.cpp

@@ -36,7 +36,6 @@
 #include "core/object/worker_thread_pool.h"
 #include "core/version.h"
 #include "renderer_compositor_rd.h"
-#include "servers/rendering/renderer_rd/api_context_rd.h"
 #include "servers/rendering/rendering_device.h"
 #include "thirdparty/misc/smolv.h"
 
@@ -398,7 +397,7 @@ static const uint32_t cache_file_version = 3;
 
 String ShaderRD::_get_cache_file_path(Version *p_version, int p_group) {
 	const String &sha1 = _version_get_sha1(p_version);
-	const String &api_safe_name = String(RD::get_singleton()->get_context()->get_api_name()).validate_filename().to_lower();
+	const String &api_safe_name = String(RD::get_singleton()->get_device_api_name()).validate_filename().to_lower();
 	const String &path = shader_cache_dir.path_join(name).path_join(group_sha256[p_group]).path_join(sha1) + "." + api_safe_name + ".cache";
 	return path;
 }

+ 0 - 3
servers/rendering/renderer_viewport.cpp

@@ -824,9 +824,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
 	RENDER_TIMESTAMP("< Render Viewports");
 
 	if (p_swap_buffers && !blit_to_screen_list.is_empty()) {
-		// This needs to be called to make screen swapping more efficient.
-		RSG::rasterizer->prepare_for_blitting_render_targets();
-
 		for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
 			RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size());
 		}

+ 85 - 0
servers/rendering/rendering_context_driver.cpp

@@ -0,0 +1,85 @@
+/**************************************************************************/
+/*  rendering_context_driver.cpp                                          */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "rendering_context_driver.h"
+
+RenderingContextDriver::~RenderingContextDriver() {
+}
+
+RenderingContextDriver::SurfaceID RenderingContextDriver::surface_get_from_window(DisplayServer::WindowID p_window) const {
+	HashMap<DisplayServer::WindowID, SurfaceID>::ConstIterator it = window_surface_map.find(p_window);
+	if (it != window_surface_map.end()) {
+		return it->value;
+	} else {
+		return SurfaceID();
+	}
+}
+
+Error RenderingContextDriver::window_create(DisplayServer::WindowID p_window, const void *p_platform_data) {
+	SurfaceID surface = surface_create(p_platform_data);
+	if (surface != 0) {
+		window_surface_map[p_window] = surface;
+		return OK;
+	} else {
+		return ERR_CANT_CREATE;
+	}
+}
+
+void RenderingContextDriver::window_set_size(DisplayServer::WindowID p_window, uint32_t p_width, uint32_t p_height) {
+	SurfaceID surface = surface_get_from_window(p_window);
+	if (surface) {
+		surface_set_size(surface, p_width, p_height);
+	}
+}
+
+void RenderingContextDriver::window_set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_vsync_mode) {
+	SurfaceID surface = surface_get_from_window(p_window);
+	if (surface) {
+		surface_set_vsync_mode(surface, p_vsync_mode);
+	}
+}
+
+DisplayServer::VSyncMode RenderingContextDriver::window_get_vsync_mode(DisplayServer::WindowID p_window) const {
+	SurfaceID surface = surface_get_from_window(p_window);
+	if (surface) {
+		return surface_get_vsync_mode(surface);
+	} else {
+		return DisplayServer::VSYNC_DISABLED;
+	}
+}
+
+void RenderingContextDriver::window_destroy(DisplayServer::WindowID p_window) {
+	SurfaceID surface = surface_get_from_window(p_window);
+	if (surface) {
+		surface_destroy(surface);
+	}
+
+	window_surface_map.erase(p_window);
+}

+ 101 - 0
servers/rendering/rendering_context_driver.h

@@ -0,0 +1,101 @@
+/**************************************************************************/
+/*  rendering_context_driver.h                                            */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef RENDERING_CONTEXT_DRIVER_H
+#define RENDERING_CONTEXT_DRIVER_H
+
+#include "core/object/object.h"
+#include "servers/display_server.h"
+
+class RenderingDeviceDriver;
+
+class RenderingContextDriver {
+public:
+	typedef uint64_t SurfaceID;
+
+private:
+	HashMap<DisplayServer::WindowID, SurfaceID> window_surface_map;
+
+public:
+	SurfaceID surface_get_from_window(DisplayServer::WindowID p_window) const;
+	Error window_create(DisplayServer::WindowID p_window, const void *p_platform_data);
+	void window_set_size(DisplayServer::WindowID p_window, uint32_t p_width, uint32_t p_height);
+	void window_set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_vsync_mode);
+	DisplayServer::VSyncMode window_get_vsync_mode(DisplayServer::WindowID p_window) const;
+	void window_destroy(DisplayServer::WindowID p_window);
+
+public:
+	enum Vendor {
+		VENDOR_UNKNOWN = 0x0,
+		VENDOR_AMD = 0x1002,
+		VENDOR_IMGTEC = 0x1010,
+		VENDOR_APPLE = 0x106B,
+		VENDOR_NVIDIA = 0x10DE,
+		VENDOR_ARM = 0x13B5,
+		VENDOR_MICROSOFT = 0x1414,
+		VENDOR_QUALCOMM = 0x5143,
+		VENDOR_INTEL = 0x8086
+	};
+
+	enum DeviceType {
+		DEVICE_TYPE_OTHER = 0x0,
+		DEVICE_TYPE_INTEGRATED_GPU = 0x1,
+		DEVICE_TYPE_DISCRETE_GPU = 0x2,
+		DEVICE_TYPE_VIRTUAL_GPU = 0x3,
+		DEVICE_TYPE_CPU = 0x4,
+		DEVICE_TYPE_MAX = 0x5
+	};
+
+	struct Device {
+		String name = "Unknown";
+		Vendor vendor = VENDOR_UNKNOWN;
+		DeviceType type = DEVICE_TYPE_OTHER;
+	};
+
+	virtual ~RenderingContextDriver();
+	virtual Error initialize() = 0;
+	virtual const Device &device_get(uint32_t p_device_index) const = 0;
+	virtual uint32_t device_get_count() const = 0;
+	virtual bool device_supports_present(uint32_t p_device_index, SurfaceID p_surface) const = 0;
+	virtual RenderingDeviceDriver *driver_create() = 0;
+	virtual void driver_free(RenderingDeviceDriver *p_driver) = 0;
+	virtual SurfaceID surface_create(const void *p_platform_data) = 0;
+	virtual void surface_set_size(SurfaceID p_surface, uint32_t p_width, uint32_t p_height) = 0;
+	virtual void surface_set_vsync_mode(SurfaceID p_surface, DisplayServer::VSyncMode p_vsync_mode) = 0;
+	virtual DisplayServer::VSyncMode surface_get_vsync_mode(SurfaceID p_surface) const = 0;
+	virtual uint32_t surface_get_width(SurfaceID p_surface) const = 0;
+	virtual uint32_t surface_get_height(SurfaceID p_surface) const = 0;
+	virtual void surface_set_needs_resize(SurfaceID p_surface, bool p_needs_resize) = 0;
+	virtual bool surface_get_needs_resize(SurfaceID p_surface) const = 0;
+	virtual void surface_destroy(SurfaceID p_surface) = 0;
+	virtual bool is_debug_utils_enabled() const = 0;
+};
+
+#endif // RENDERING_CONTEXT_DRIVER_H

+ 5 - 0
servers/rendering/rendering_device.compat.inc

@@ -117,6 +117,10 @@ Error RenderingDevice::_texture_resolve_multisample_bind_compat_84976(RID p_from
 	return texture_resolve_multisample(p_from_texture, p_to_texture);
 }
 
+RenderingDevice::FramebufferFormatID RenderingDevice::_screen_get_framebuffer_format_bind_compat_87340() const {
+	return screen_get_framebuffer_format(DisplayServer::MAIN_WINDOW_ID);
+}
+
 void RenderingDevice::_bind_compatibility_methods() {
 	ClassDB::bind_compatibility_method(D_METHOD("shader_create_from_bytecode", "binary_data"), &RenderingDevice::_shader_create_from_bytecode_bind_compat_79606);
 	ClassDB::bind_compatibility_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::_draw_list_end_bind_compat_81356, DEFVAL(7));
@@ -132,6 +136,7 @@ void RenderingDevice::_bind_compatibility_methods() {
 	ClassDB::bind_compatibility_method(D_METHOD("texture_copy", "from_texture", "to_texture", "from_pos", "to_pos", "size", "src_mipmap", "dst_mipmap", "src_layer", "dst_layer", "post_barrier"), &RenderingDevice::_texture_copy_bind_compat_84976, DEFVAL(0x7FFF));
 	ClassDB::bind_compatibility_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::_texture_clear_bind_compat_84976, DEFVAL(0x7FFF));
 	ClassDB::bind_compatibility_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::_texture_resolve_multisample_bind_compat_84976, DEFVAL(0x7FFF));
+	ClassDB::bind_compatibility_method(D_METHOD("screen_get_framebuffer_format"), &RenderingDevice::_screen_get_framebuffer_format_bind_compat_87340);
 }
 
 #endif

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 475 - 242
servers/rendering/rendering_device.cpp


+ 63 - 63
servers/rendering/rendering_device.h

@@ -64,36 +64,11 @@ class RenderingDevice : public RenderingDeviceCommons {
 
 	_THREAD_SAFE_CLASS_
 public:
-	enum DeviceFamily {
-		DEVICE_UNKNOWN,
-		DEVICE_OPENGL,
-		DEVICE_VULKAN,
-		DEVICE_DIRECTX,
-	};
-
 	enum ShaderLanguage {
 		SHADER_LANGUAGE_GLSL,
 		SHADER_LANGUAGE_HLSL
 	};
 
-	enum SubgroupOperations {
-		SUBGROUP_BASIC_BIT = 1,
-		SUBGROUP_VOTE_BIT = 2,
-		SUBGROUP_ARITHMETIC_BIT = 4,
-		SUBGROUP_BALLOT_BIT = 8,
-		SUBGROUP_SHUFFLE_BIT = 16,
-		SUBGROUP_SHUFFLE_RELATIVE_BIT = 32,
-		SUBGROUP_CLUSTERED_BIT = 64,
-		SUBGROUP_QUAD_BIT = 128,
-	};
-
-	struct Capabilities {
-		// main device info
-		DeviceFamily device_family = DEVICE_UNKNOWN;
-		uint32_t version_major = 1;
-		uint32_t version_minor = 0;
-	};
-
 	typedef int64_t DrawListID;
 	typedef int64_t ComputeListID;
 
@@ -110,9 +85,9 @@ private:
 
 	static RenderingDevice *singleton;
 
-	Capabilities device_capabilities;
-
-	RenderingDeviceDriver *driver = nullptr; // Owned by the context.
+	RenderingContextDriver *context = nullptr;
+	RenderingDeviceDriver *driver = nullptr;
+	RenderingContextDriver::Device device;
 
 protected:
 	static void _bind_methods();
@@ -188,8 +163,8 @@ private:
 
 	enum StagingRequiredAction {
 		STAGING_REQUIRED_ACTION_NONE,
-		STAGING_REQUIRED_ACTION_FLUSH_CURRENT,
-		STAGING_REQUIRED_ACTION_FLUSH_OLDER
+		STAGING_REQUIRED_ACTION_FLUSH_AND_STALL_ALL,
+		STAGING_REQUIRED_ACTION_STALL_PREVIOUS
 	};
 
 	Error _staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, StagingRequiredAction &r_required_action, bool p_can_segment = true);
@@ -819,12 +794,11 @@ private:
 	Error _texture_copy_bind_compat_84976(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, BitField<BarrierMask> p_post_barrier);
 	Error _texture_clear_bind_compat_84976(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, BitField<BarrierMask> p_post_barrier);
 	Error _texture_resolve_multisample_bind_compat_84976(RID p_from_texture, RID p_to_texture, BitField<BarrierMask> p_post_barrier);
+	FramebufferFormatID _screen_get_framebuffer_format_bind_compat_87340() const;
 #endif
 
 public:
-	ApiContextRD *get_context() const { return context; }
-
-	const Capabilities *get_device_capabilities() const { return &device_capabilities; };
+	const RDD::Capabilities &get_device_capabilities() const { return driver->get_capabilities(); }
 
 	bool has_feature(const Features p_feature) const;
 
@@ -996,10 +970,10 @@ private:
 
 	RID_Owner<RenderPipeline> render_pipeline_owner;
 
-	bool pipelines_cache_enabled = false;
-	size_t pipelines_cache_size = 0;
-	String pipelines_cache_file_path;
-	WorkerThreadPool::TaskID pipelines_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;
+	bool pipeline_cache_enabled = false;
+	size_t pipeline_cache_size = 0;
+	String pipeline_cache_file_path;
+	WorkerThreadPool::TaskID pipeline_cache_save_task = WorkerThreadPool::INVALID_TASK_ID;
 
 	Vector<uint8_t> _load_pipeline_cache();
 	void _update_pipeline_cache(bool p_closing = false);
@@ -1024,13 +998,22 @@ public:
 	RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
 	bool compute_pipeline_is_valid(RID p_pipeline);
 
+private:
 	/****************/
 	/**** SCREEN ****/
 	/****************/
+	HashMap<DisplayServer::WindowID, RDD::SwapChainID> screen_swap_chains;
+	HashMap<DisplayServer::WindowID, RDD::FramebufferID> screen_framebuffers;
 
-	int screen_get_width(DisplayServer::WindowID p_screen = 0) const;
-	int screen_get_height(DisplayServer::WindowID p_screen = 0) const;
-	FramebufferFormatID screen_get_framebuffer_format() const;
+	uint32_t _get_swap_chain_desired_count() const;
+
+public:
+	Error screen_create(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
+	Error screen_prepare_for_drawing(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
+	int screen_get_width(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
+	int screen_get_height(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
+	FramebufferFormatID screen_get_framebuffer_format(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
+	Error screen_free(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
 
 	/*************************/
 	/**** DRAW LISTS (II) ****/
@@ -1101,7 +1084,6 @@ private:
 
 	DrawList *draw_list = nullptr;
 	uint32_t draw_list_subpass_count = 0;
-	uint32_t draw_list_count = 0;
 	RDD::RenderPassID draw_list_render_pass;
 	RDD::FramebufferID draw_list_vkframebuffer;
 #ifdef DEBUG_ENABLED
@@ -1214,6 +1196,15 @@ private:
 
 	RenderingDeviceGraph draw_graph;
 
+	/**************************/
+	/**** QUEUE MANAGEMENT ****/
+	/**************************/
+
+	RDD::CommandQueueFamilyID main_queue_family;
+	RDD::CommandQueueFamilyID present_queue_family;
+	RDD::CommandQueueID main_queue;
+	RDD::CommandQueueID present_queue;
+
 	/**************************/
 	/**** FRAME MANAGEMENT ****/
 	/**************************/
@@ -1232,7 +1223,6 @@ private:
 	// nature of the GPU. They will get deleted
 	// when the frame is cycled.
 
-private:
 	struct Frame {
 		// List in usage order, from last to free to first to free.
 		List<Buffer> buffers_to_dispose_of;
@@ -1245,13 +1235,30 @@ private:
 		List<ComputePipeline> compute_pipelines_to_dispose_of;
 
 		RDD::CommandPoolID command_pool;
+
+		// Used at the beginning of every frame for set-up.
 		// Used for filling up newly created buffers with data provided on creation.
 		// Primarily intended to be accessed by worker threads.
-		// Ideally this cmd buffer should use an async transfer queue.
-		RDD::CommandBufferID setup_command_buffer; // Used at the beginning of every frame for set-up.
-		// The main cmd buffer for drawing and compute.
+		// Ideally this command buffer should use an async transfer queue.
+		RDD::CommandBufferID setup_command_buffer;
+
+		// The main command buffer for drawing and compute.
 		// Primarily intended to be used by the main thread to do most stuff.
-		RDD::CommandBufferID draw_command_buffer; // Used at the beginning of every frame for set-up.
+		RDD::CommandBufferID draw_command_buffer;
+
+		// Signaled by the setup submission. Draw must wait on this semaphore.
+		RDD::SemaphoreID setup_semaphore;
+
+		// Signaled by the draw submission. Present must wait on this semaphore.
+		RDD::SemaphoreID draw_semaphore;
+
+		// Signaled by the draw submission. Must wait on this fence before beginning
+		// command recording for the frame.
+		RDD::FenceID draw_fence;
+		bool draw_fence_signaled = false;
+
+		// Swap chains prepared for drawing during the frame that must be presented.
+		LocalVector<RDD::SwapChainID> swap_chains_to_present;
 
 		struct Timestamp {
 			String description;
@@ -1272,37 +1279,32 @@ private:
 
 	uint32_t max_timestamp_query_elements = 0;
 
-	TightLocalVector<Frame> frames; // Frames available, for main device they are cycled (usually 3), for local devices only 1.
-	int frame = 0; // Current frame.
-	int frame_count = 0; // Total amount of frames.
+	int frame = 0;
+	TightLocalVector<Frame> frames;
 	uint64_t frames_drawn = 0;
-	RID local_device;
-	bool local_device_processing = false;
 
 	void _free_pending_resources(int p_frame);
 
-	ApiContextRD *context = nullptr;
-
 	uint64_t texture_memory = 0;
 	uint64_t buffer_memory = 0;
 
 	void _free_internal(RID p_id);
-	void _flush(bool p_current_frame);
-
-	bool screen_prepared = false;
+	void _begin_frame();
+	void _end_frame();
+	void _execute_frame(bool p_signal_for_present);
+	void _present_frame();
+	void _stall_for_previous_frames();
+	void _flush_and_stall_for_all_frames();
 
 	template <class T>
 	void _free_rids(T &p_owner, const char *p_type);
 
-	void _finalize_command_buffers(bool p_postpare);
-	void _begin_frame();
-
 #ifdef DEV_ENABLED
 	HashMap<RID, String> resource_names;
 #endif
 
 public:
-	void initialize(ApiContextRD *p_context, bool p_local_device = false);
+	Error initialize(RenderingContextDriver *p_context, DisplayServer::WindowID p_main_window = DisplayServer::INVALID_WINDOW_ID);
 	void finalize();
 
 	void free(RID p_id);
@@ -1324,9 +1326,6 @@ public:
 
 	uint64_t limit_get(Limit p_limit) const;
 
-	//methods below not exposed, used by RenderingDeviceRD
-	void prepare_screen_for_drawing();
-
 	void swap_buffers();
 
 	uint32_t get_frame_delay() const;
@@ -1352,6 +1351,7 @@ public:
 	String get_device_vendor_name() const;
 	String get_device_name() const;
 	DeviceType get_device_type() const;
+	String get_device_api_name() const;
 	String get_device_api_version() const;
 	String get_device_pipeline_cache_uuid() const;
 

+ 11 - 0
servers/rendering/rendering_device_commons.h

@@ -820,6 +820,17 @@ public:
 		SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS,
 	};
 
+	enum SubgroupOperations {
+		SUBGROUP_BASIC_BIT = 1,
+		SUBGROUP_VOTE_BIT = 2,
+		SUBGROUP_ARITHMETIC_BIT = 4,
+		SUBGROUP_BALLOT_BIT = 8,
+		SUBGROUP_SHUFFLE_BIT = 16,
+		SUBGROUP_SHUFFLE_RELATIVE_BIT = 32,
+		SUBGROUP_CLUSTERED_BIT = 64,
+		SUBGROUP_QUAD_BIT = 128,
+	};
+
 	////////////////////////////////////////////
 	// PROTECTED STUFF
 	// Not exposed by RenderingDevice, but shared

+ 105 - 25
servers/rendering/rendering_device_driver.h

@@ -49,12 +49,11 @@
 #include "core/object/object.h"
 #include "core/variant/type_info.h"
 #include "servers/display_server.h"
+#include "servers/rendering/rendering_context_driver.h"
 #include "servers/rendering/rendering_device_commons.h"
 
 #include <algorithm>
 
-class ApiContextRD;
-
 // This may one day be used in Godot for interoperability between C arrays, Vector and LocalVector.
 // (See https://github.com/godotengine/godot-proposals/issues/5144.)
 template <class T>
@@ -127,20 +126,22 @@ public:
 				id(p_id) {}
 	};
 
-#define DEFINE_ID(m_name)                                                                           \
-	struct m_name##ID : public ID {                                                                 \
-		_ALWAYS_INLINE_ operator bool() const { return id != 0; }                                   \
-		_ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) {                                 \
-			id = p_other.id;                                                                        \
-			return *this;                                                                           \
-		}                                                                                           \
-		_ALWAYS_INLINE_ bool operator<(const m_name##ID &p_other) const { return id < p_other.id; } \
-		_ALWAYS_INLINE_ m_name##ID(const m_name##ID &p_other) : ID(p_other.id) {}                   \
-		_ALWAYS_INLINE_ explicit m_name##ID(uint64_t p_int) : ID(p_int) {}                          \
-		_ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((size_t)p_ptr) {}                     \
-		_ALWAYS_INLINE_ m_name##ID() = default;                                                     \
-	};                                                                                              \
-	/* Ensure type-punnable to pointer. Makes some things easier.*/                                 \
+#define DEFINE_ID(m_name)                                                                             \
+	struct m_name##ID : public ID {                                                                   \
+		_ALWAYS_INLINE_ operator bool() const { return id != 0; }                                     \
+		_ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) {                                   \
+			id = p_other.id;                                                                          \
+			return *this;                                                                             \
+		}                                                                                             \
+		_ALWAYS_INLINE_ bool operator<(const m_name##ID &p_other) const { return id < p_other.id; }   \
+		_ALWAYS_INLINE_ bool operator==(const m_name##ID &p_other) const { return id == p_other.id; } \
+		_ALWAYS_INLINE_ bool operator!=(const m_name##ID &p_other) const { return id != p_other.id; } \
+		_ALWAYS_INLINE_ m_name##ID(const m_name##ID &p_other) : ID(p_other.id) {}                     \
+		_ALWAYS_INLINE_ explicit m_name##ID(uint64_t p_int) : ID(p_int) {}                            \
+		_ALWAYS_INLINE_ explicit m_name##ID(void *p_ptr) : ID((size_t)p_ptr) {}                       \
+		_ALWAYS_INLINE_ m_name##ID() = default;                                                       \
+	};                                                                                                \
+	/* Ensure type-punnable to pointer. Makes some things easier.*/                                   \
 	static_assert(sizeof(m_name##ID) == sizeof(void *));
 
 	// Id types declared before anything else to prevent cyclic dependencies between the different concerns.
@@ -148,14 +149,26 @@ public:
 	DEFINE_ID(Texture);
 	DEFINE_ID(Sampler);
 	DEFINE_ID(VertexFormat);
+	DEFINE_ID(CommandQueue);
+	DEFINE_ID(CommandQueueFamily);
 	DEFINE_ID(CommandPool);
 	DEFINE_ID(CommandBuffer);
+	DEFINE_ID(SwapChain);
 	DEFINE_ID(Framebuffer);
 	DEFINE_ID(Shader);
 	DEFINE_ID(UniformSet);
 	DEFINE_ID(Pipeline);
 	DEFINE_ID(RenderPass);
 	DEFINE_ID(QueryPool);
+	DEFINE_ID(Fence);
+	DEFINE_ID(Semaphore);
+
+public:
+	/*****************/
+	/**** GENERIC ****/
+	/*****************/
+
+	virtual Error initialize(uint32_t p_device_index, uint32_t p_frame_count) = 0;
 
 	/****************/
 	/**** MEMORY ****/
@@ -361,10 +374,44 @@ public:
 			VectorView<BufferBarrier> p_buffer_barriers,
 			VectorView<TextureBarrier> p_texture_barriers) = 0;
 
+	/****************/
+	/**** FENCES ****/
+	/****************/
+
+	virtual FenceID fence_create() = 0;
+	virtual Error fence_wait(FenceID p_fence) = 0;
+	virtual void fence_free(FenceID p_fence) = 0;
+
+	/********************/
+	/**** SEMAPHORES ****/
+	/********************/
+
+	virtual SemaphoreID semaphore_create() = 0;
+	virtual void semaphore_free(SemaphoreID p_semaphore) = 0;
+
 	/*************************/
 	/**** COMMAND BUFFERS ****/
 	/*************************/
 
+	// ----- QUEUE FAMILY -----
+
+	enum CommandQueueFamilyBits {
+		COMMAND_QUEUE_FAMILY_GRAPHICS_BIT = 0x1,
+		COMMAND_QUEUE_FAMILY_COMPUTE_BIT = 0x2,
+		COMMAND_QUEUE_FAMILY_TRANSFER_BIT = 0x4
+	};
+
+	// The requested command queue family must support all specified bits or it'll fail to return a valid family otherwise. If a valid surface is specified, the queue must support presenting to it.
+	// It is valid to specify no bits and a valid surface: in this case, the dedicated presentation queue family will be the preferred option.
+	virtual CommandQueueFamilyID command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface = 0) = 0;
+
+	// ----- QUEUE -----
+
+	virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) = 0;
+	virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) = 0;
+	virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) = 0;
+	virtual void command_queue_free(CommandQueueID p_cmd_queue) = 0;
+
 	// ----- POOL -----
 
 	enum CommandBufferType {
@@ -372,17 +419,39 @@ public:
 		COMMAND_BUFFER_TYPE_SECONDARY,
 	};
 
-	virtual CommandPoolID command_pool_create(CommandBufferType p_cmd_buffer_type) = 0;
+	virtual CommandPoolID command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) = 0;
 	virtual void command_pool_free(CommandPoolID p_cmd_pool) = 0;
 
 	// ----- BUFFER -----
 
-	virtual CommandBufferID command_buffer_create(CommandBufferType p_cmd_buffer_type, CommandPoolID p_cmd_pool) = 0;
+	virtual CommandBufferID command_buffer_create(CommandPoolID p_cmd_pool) = 0;
 	virtual bool command_buffer_begin(CommandBufferID p_cmd_buffer) = 0;
 	virtual bool command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) = 0;
 	virtual void command_buffer_end(CommandBufferID p_cmd_buffer) = 0;
 	virtual void command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) = 0;
 
+	/********************/
+	/**** SWAP CHAIN ****/
+	/********************/
+
+	// The swap chain won't be valid for use until it is resized at least once.
+	virtual SwapChainID swap_chain_create(RenderingContextDriver::SurfaceID p_surface) = 0;
+
+	// The swap chain must not be in use when a resize is requested. Wait until all rendering associated to the swap chain is finished before resizing it.
+	virtual Error swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) = 0;
+
+	// Acquire the framebuffer that can be used for drawing. This must be called only once every time a new frame will be rendered.
+	virtual FramebufferID swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) = 0;
+
+	// Retrieve the render pass that can be used to draw on the swap chain's framebuffers.
+	virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) = 0;
+
+	// Retrieve the format used by the swap chain's framebuffers.
+	virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) = 0;
+
+	// Wait until all rendering associated to the swap chain is finished before deleting it.
+	virtual void swap_chain_free(SwapChainID p_swap_chain) = 0;
+
 	/*********************/
 	/**** FRAMEBUFFER ****/
 	/*********************/
@@ -633,17 +702,11 @@ public:
 	virtual void command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) = 0;
 	virtual void command_end_label(CommandBufferID p_cmd_buffer) = 0;
 
-	/****************/
-	/**** SCREEN ****/
-	/****************/
-
-	virtual DataFormat screen_get_format() = 0;
-
 	/********************/
 	/**** SUBMISSION ****/
 	/********************/
 
-	virtual void begin_segment(CommandBufferID p_cmd_buffer, uint32_t p_frame_index, uint32_t p_frames_drawn) = 0;
+	virtual void begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) = 0;
 	virtual void end_segment() = 0;
 
 	/**************/
@@ -682,6 +745,19 @@ public:
 		SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH,
 	};
 
+	enum DeviceFamily {
+		DEVICE_UNKNOWN,
+		DEVICE_OPENGL,
+		DEVICE_VULKAN,
+		DEVICE_DIRECTX,
+	};
+
+	struct Capabilities {
+		DeviceFamily device_family = DEVICE_UNKNOWN;
+		uint32_t version_major = 1;
+		uint32_t version_minor = 0;
+	};
+
 	virtual void set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) = 0;
 	virtual uint64_t get_resource_native_handle(DriverResource p_type, ID p_driver_id) = 0;
 	virtual uint64_t get_total_memory_used() = 0;
@@ -689,6 +765,10 @@ public:
 	virtual uint64_t api_trait_get(ApiTrait p_trait);
 	virtual bool has_feature(Features p_feature) = 0;
 	virtual const MultiviewCapabilities &get_multiview_capabilities() = 0;
+	virtual String get_api_name() const = 0;
+	virtual String get_api_version() const = 0;
+	virtual String get_pipeline_cache_uuid() const = 0;
+	virtual const Capabilities &get_capabilities() const = 0;
 
 	/******************/
 

+ 17 - 12
servers/rendering/rendering_device_graph.cpp

@@ -40,15 +40,6 @@ RenderingDeviceGraph::RenderingDeviceGraph() {
 }
 
 RenderingDeviceGraph::~RenderingDeviceGraph() {
-	_wait_for_secondary_command_buffer_tasks();
-
-	for (Frame &f : frames) {
-		for (SecondaryCommandBuffer &secondary : f.secondary_command_buffers) {
-			if (secondary.command_pool.id != 0) {
-				driver->command_pool_free(secondary.command_pool);
-			}
-		}
-	}
 }
 
 bool RenderingDeviceGraph::_is_write_usage(ResourceUsage p_usage) {
@@ -1246,7 +1237,7 @@ void RenderingDeviceGraph::_print_compute_list(const uint8_t *p_instruction_data
 	}
 }
 
-void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame) {
+void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame) {
 	driver = p_driver;
 	frames.resize(p_frame_count);
 
@@ -1255,8 +1246,8 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, uin
 
 		for (uint32_t j = 0; j < p_secondary_command_buffers_per_frame; j++) {
 			SecondaryCommandBuffer &secondary = frames[i].secondary_command_buffers[j];
-			secondary.command_pool = driver->command_pool_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY);
-			secondary.command_buffer = driver->command_buffer_create(RDD::COMMAND_BUFFER_TYPE_SECONDARY, secondary.command_pool);
+			secondary.command_pool = driver->command_pool_create(p_secondary_command_queue_family, RDD::COMMAND_BUFFER_TYPE_SECONDARY);
+			secondary.command_buffer = driver->command_buffer_create(secondary.command_pool);
 			secondary.task = WorkerThreadPool::INVALID_TASK_ID;
 		}
 	}
@@ -1264,6 +1255,20 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, uint32_t p_frame_count, uin
 	driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
 }
 
+void RenderingDeviceGraph::finalize() {
+	_wait_for_secondary_command_buffer_tasks();
+
+	for (Frame &f : frames) {
+		for (SecondaryCommandBuffer &secondary : f.secondary_command_buffers) {
+			if (secondary.command_pool.id != 0) {
+				driver->command_pool_free(secondary.command_pool);
+			}
+		}
+	}
+
+	frames.clear();
+}
+
 void RenderingDeviceGraph::begin() {
 	command_data.clear();
 	command_data_offsets.clear();

+ 2 - 1
servers/rendering/rendering_device_graph.h

@@ -619,7 +619,8 @@ private:
 public:
 	RenderingDeviceGraph();
 	~RenderingDeviceGraph();
-	void initialize(RDD *p_driver, uint32_t p_frame_count, uint32_t p_secondary_command_buffers_per_frame);
+	void initialize(RDD *p_driver, uint32_t p_frame_count, RDD::CommandQueueFamilyID p_secondary_command_queue_family, uint32_t p_secondary_command_buffers_per_frame);
+	void finalize();
 	void begin();
 	void add_buffer_clear(RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, uint32_t p_offset, uint32_t p_size);
 	void add_buffer_copy(RDD::BufferID p_src, ResourceTracker *p_src_tracker, RDD::BufferID p_dst, ResourceTracker *p_dst_tracker, RDD::BufferCopyRegion p_region);

Vissa filer visades inte eftersom för många filer har ändrats