From 31194f5b1c84638267958c8efa9212f362e57ae0 Mon Sep 17 00:00:00 2001
From: Hugo Locurcio <hugo.locurcio@hugo.pro>
Date: Sat, 31 Jul 2021 15:39:46 +0200
Subject: [PATCH] Add `get_video_adapter_api_version()` to RenderingServer

This method can be used to get the graphics API version currently in
use (such as Vulkan). It can be used by projects for troubleshooting
or statistical purposes.
---
 doc/classes/RenderingServer.xml                       | 7 +++++++
 drivers/gles3/rasterizer_storage_gles3.cpp            | 4 ++++
 drivers/gles3/rasterizer_storage_gles3.h              | 1 +
 drivers/vulkan/rendering_device_vulkan.cpp            | 5 +++++
 drivers/vulkan/rendering_device_vulkan.h              | 1 +
 drivers/vulkan/vulkan_context.cpp                     | 5 +++++
 drivers/vulkan/vulkan_context.h                       | 1 +
 servers/rendering/dummy/rasterizer_storage_dummy.h    | 1 +
 servers/rendering/renderer_rd/renderer_storage_rd.cpp | 4 ++++
 servers/rendering/renderer_rd/renderer_storage_rd.h   | 1 +
 servers/rendering/renderer_storage.h                  | 1 +
 servers/rendering/rendering_device.h                  | 1 +
 servers/rendering/rendering_server_default.cpp        | 4 ++++
 servers/rendering/rendering_server_default.h          | 1 +
 servers/rendering_server.cpp                          | 1 +
 servers/rendering_server.h                            | 1 +
 16 files changed, 39 insertions(+)

diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index d21e2b5bca6..b8f26f75c91 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1252,6 +1252,13 @@
 				Returns the id of the test texture. Creates one if none exists.
 			</description>
 		</method>
+		<method name="get_video_adapter_api_version" qualifiers="const">
+			<return type="String" />
+			<description>
+				Returns the version of the graphics video adapter [i]currently in use[/i] (e.g. "1.2.189" for Vulkan, "3.3.0 NVIDIA 510.60.02" for OpenGL). This version may be different from the actual latest version supported by the hardware, as Godot may not always request the latest version.
+				[b]Note:[/b] When running a headless or server binary, this function returns an empty string.
+			</description>
+		</method>
 		<method name="get_video_adapter_name" qualifiers="const">
 			<return type="String" />
 			<description>
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 0049e74a7cb..cca445bf00e 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -627,6 +627,10 @@ RenderingDevice::DeviceType RasterizerStorageGLES3::get_video_adapter_type() con
 	return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER;
 }
 
+String RasterizerStorageGLES3::get_video_adapter_api_version() const {
+	return (const char *)glGetString(GL_VERSION);
+}
+
 void RasterizerStorageGLES3::initialize() {
 	config = GLES3::Config::get_singleton();
 
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 3858f2bbd09..6401771abb9 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -234,6 +234,7 @@ public:
 	String get_video_adapter_name() const override;
 	String get_video_adapter_vendor() const override;
 	RenderingDevice::DeviceType get_video_adapter_type() const override;
+	String get_video_adapter_api_version() const override;
 
 	void capture_timestamps_begin() override {}
 	void capture_timestamp(const String &p_name) override {}
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 59b4c34c3f1..5102eab9797 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -8649,6 +8649,7 @@ void RenderingDeviceVulkan::draw_command_end_label() {
 String RenderingDeviceVulkan::get_device_vendor_name() const {
 	return context->get_device_vendor_name();
 }
+
 String RenderingDeviceVulkan::get_device_name() const {
 	return context->get_device_name();
 }
@@ -8657,6 +8658,10 @@ RenderingDevice::DeviceType RenderingDeviceVulkan::get_device_type() const {
 	return context->get_device_type();
 }
 
+String RenderingDeviceVulkan::get_device_api_version() const {
+	return context->get_device_api_version();
+}
+
 String RenderingDeviceVulkan::get_device_pipeline_cache_uuid() const {
 	return context->get_device_pipeline_cache_uuid();
 }
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 219d48a9f57..236742c15db 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -1229,6 +1229,7 @@ public:
 	virtual String get_device_vendor_name() const;
 	virtual String get_device_name() const;
 	virtual RenderingDevice::DeviceType get_device_type() const;
+	virtual String get_device_api_version() const;
 	virtual String get_device_pipeline_cache_uuid() const;
 
 	virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index a09a757842f..7944057041d 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -2364,6 +2364,7 @@ void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_objec
 String VulkanContext::get_device_vendor_name() const {
 	return device_vendor;
 }
+
 String VulkanContext::get_device_name() const {
 	return device_name;
 }
@@ -2372,6 +2373,10 @@ RenderingDevice::DeviceType VulkanContext::get_device_type() const {
 	return RenderingDevice::DeviceType(device_type);
 }
 
+String VulkanContext::get_device_api_version() const {
+	return vformat("%d.%d.%d", vulkan_major, vulkan_minor, vulkan_patch);
+}
+
 String VulkanContext::get_device_pipeline_cache_uuid() const {
 	return pipeline_cache_id;
 }
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 365ee3c9b05..6858eb75249 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -305,6 +305,7 @@ public:
 	String get_device_vendor_name() const;
 	String get_device_name() const;
 	RenderingDevice::DeviceType get_device_type() const;
+	String get_device_api_version() const;
 	String get_device_pipeline_cache_uuid() const;
 
 	void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
diff --git a/servers/rendering/dummy/rasterizer_storage_dummy.h b/servers/rendering/dummy/rasterizer_storage_dummy.h
index ac6085cdec8..596960786a5 100644
--- a/servers/rendering/dummy/rasterizer_storage_dummy.h
+++ b/servers/rendering/dummy/rasterizer_storage_dummy.h
@@ -128,6 +128,7 @@ public:
 	String get_video_adapter_name() const override { return String(); }
 	String get_video_adapter_vendor() const override { return String(); }
 	RenderingDevice::DeviceType get_video_adapter_type() const override { return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; }
+	String get_video_adapter_api_version() const override { return String(); }
 
 	static RendererStorage *base_singleton;
 
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index fa9f87abbe2..cf642c38c9c 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -727,6 +727,10 @@ RenderingDevice::DeviceType RendererStorageRD::get_video_adapter_type() const {
 	return RenderingDevice::get_singleton()->get_device_type();
 }
 
+String RendererStorageRD::get_video_adapter_api_version() const {
+	return RenderingDevice::get_singleton()->get_device_api_version();
+}
+
 RendererStorageRD *RendererStorageRD::base_singleton = nullptr;
 
 RendererStorageRD::RendererStorageRD() {
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 37c76f9c629..718fa9bf3e7 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -284,6 +284,7 @@ public:
 	String get_video_adapter_name() const;
 	String get_video_adapter_vendor() const;
 	RenderingDevice::DeviceType get_video_adapter_type() const;
+	String get_video_adapter_api_version() const;
 
 	virtual void capture_timestamps_begin();
 	virtual void capture_timestamp(const String &p_name);
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index ab7dbb87a30..7cf4fd0aff6 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -199,6 +199,7 @@ public:
 	virtual String get_video_adapter_name() const = 0;
 	virtual String get_video_adapter_vendor() const = 0;
 	virtual RenderingDevice::DeviceType get_video_adapter_type() const = 0;
+	virtual String get_video_adapter_api_version() const = 0;
 
 	static RendererStorage *base_singleton;
 
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 1902b5f74a9..0973e299740 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -1254,6 +1254,7 @@ public:
 	virtual String get_device_vendor_name() const = 0;
 	virtual String get_device_name() const = 0;
 	virtual RenderingDevice::DeviceType get_device_type() const = 0;
+	virtual String get_device_api_version() const = 0;
 	virtual String get_device_pipeline_cache_uuid() const = 0;
 
 	virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0) = 0;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index e42034dbb9a..000b253e8a6 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -265,6 +265,10 @@ RenderingDevice::DeviceType RenderingServerDefault::get_video_adapter_type() con
 	return RSG::storage->get_video_adapter_type();
 }
 
+String RenderingServerDefault::get_video_adapter_api_version() const {
+	return RSG::storage->get_video_adapter_api_version();
+}
+
 void RenderingServerDefault::set_frame_profiling_enabled(bool p_enable) {
 	RSG::storage->capturing_timestamps = p_enable;
 }
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 8dfb5985f8f..de4f8d9194f 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -939,6 +939,7 @@ public:
 	virtual String get_video_adapter_name() const override;
 	virtual String get_video_adapter_vendor() const override;
 	virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
+	virtual String get_video_adapter_api_version() const override;
 
 	virtual void set_frame_profiling_enabled(bool p_enable) override;
 	virtual Vector<FrameProfileArea> get_frame_profile() override;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index c2a6b83485e..136664e3334 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2726,6 +2726,7 @@ void RenderingServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &RenderingServer::get_video_adapter_name);
 	ClassDB::bind_method(D_METHOD("get_video_adapter_vendor"), &RenderingServer::get_video_adapter_vendor);
 	ClassDB::bind_method(D_METHOD("get_video_adapter_type"), &RenderingServer::get_video_adapter_type);
+	ClassDB::bind_method(D_METHOD("get_video_adapter_api_version"), &RenderingServer::get_video_adapter_api_version);
 
 	ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &RenderingServer::make_sphere_mesh);
 	ClassDB::bind_method(D_METHOD("get_test_cube"), &RenderingServer::get_test_cube);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 2db384f7df1..d622571a478 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1487,6 +1487,7 @@ public:
 	virtual String get_video_adapter_name() const = 0;
 	virtual String get_video_adapter_vendor() const = 0;
 	virtual RenderingDevice::DeviceType get_video_adapter_type() const = 0;
+	virtual String get_video_adapter_api_version() const = 0;
 
 	struct FrameProfileArea {
 		String name;