summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp22
-rw-r--r--drivers/dummy/rasterizer_dummy.h17
-rw-r--r--drivers/png/image_loader_png.cpp2
-rw-r--r--drivers/png/png_driver_common.cpp4
-rw-r--r--drivers/png/resource_saver_png.cpp2
-rw-r--r--drivers/unix/dir_access_unix.cpp34
-rw-r--r--drivers/unix/dir_access_unix.h2
-rw-r--r--drivers/unix/ip_unix.cpp28
-rw-r--r--drivers/unix/ip_unix.h8
-rw-r--r--drivers/unix/net_socket_posix.cpp99
-rw-r--r--drivers/unix/net_socket_posix.h27
-rw-r--r--drivers/unix/os_unix.cpp2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp43
-rw-r--r--drivers/vulkan/vulkan_context.cpp514
-rw-r--r--drivers/vulkan/vulkan_context.h64
15 files changed, 696 insertions, 172 deletions
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index f40036d628..4139727422 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -70,7 +70,7 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
Error AudioDriverCoreAudio::init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -97,7 +97,7 @@ Error AudioDriverCoreAudio::init() {
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
UInt32 size = sizeof(strdesc);
result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -118,7 +118,7 @@ Error AudioDriverCoreAudio::init() {
mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = channels;
@@ -148,7 +148,7 @@ Error AudioDriverCoreAudio::init() {
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::output_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
@@ -173,7 +173,7 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
if (!ad->active || !ad->try_lock()) {
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
AudioBuffer *abuf = &ioData->mBuffers[i];
- zeromem(abuf->mData, abuf->mDataByteSize);
+ memset(abuf->mData, 0, abuf->mDataByteSize);
};
return 0;
};
@@ -293,7 +293,7 @@ void AudioDriverCoreAudio::finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
@@ -337,7 +337,7 @@ void AudioDriverCoreAudio::finish() {
Error AudioDriverCoreAudio::capture_init() {
AudioComponentDescription desc;
- zeromem(&desc, sizeof(desc));
+ memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
#ifdef OSX_ENABLED
desc.componentSubType = kAudioUnitSubType_HALOutput;
@@ -383,7 +383,7 @@ Error AudioDriverCoreAudio::capture_init() {
#endif
AudioStreamBasicDescription strdesc;
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
size = sizeof(strdesc);
result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -405,7 +405,7 @@ Error AudioDriverCoreAudio::capture_init() {
mix_rate = GLOBAL_GET("audio/driver/mix_rate");
- zeromem(&strdesc, sizeof(strdesc));
+ memset(&strdesc, 0, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = capture_channels;
@@ -419,7 +419,7 @@ Error AudioDriverCoreAudio::capture_init() {
ERR_FAIL_COND_V(result != noErr, FAILED);
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = &AudioDriverCoreAudio::input_callback;
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
@@ -436,7 +436,7 @@ void AudioDriverCoreAudio::capture_finish() {
lock();
AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
+ memset(&callback, 0, sizeof(AURenderCallbackStruct));
OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
if (result != noErr) {
ERR_PRINT("AudioUnitSetProperty failed");
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 9d6be1a802..1a27c54757 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -175,7 +175,7 @@ public:
void gi_probe_set_quality(RS::GIProbeQuality) override {}
- void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {}
+ void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {}
void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {}
void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {}
@@ -199,8 +199,6 @@ public:
void update() override {}
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {}
- bool is_low_end() const override { return true; }
-
RasterizerSceneDummy() {}
~RasterizerSceneDummy() {}
};
@@ -548,6 +546,10 @@ public:
void lightmap_set_probe_capture_update_speed(float p_speed) override {}
float lightmap_get_probe_capture_update_speed() const override { return 0; }
+ /* OCCLUDER */
+
+ void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {}
+
/* PARTICLES */
RID particles_allocate() override { return RID(); }
@@ -565,10 +567,17 @@ public:
void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {}
void particles_set_process_material(RID p_particles, RID p_material) override {}
void particles_set_fixed_fps(RID p_particles, int p_fps) override {}
+ void particles_set_interpolate(RID p_particles, bool p_enable) override {}
void particles_set_fractional_delta(RID p_particles, bool p_enable) override {}
void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override {}
- void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) override {}
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override {}
void particles_set_collision_base_size(RID p_particles, float p_size) override {}
+
+ void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {}
+
+ void particles_set_trails(RID p_particles, bool p_enable, float p_length) override {}
+ void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) override {}
+
void particles_restart(RID p_particles) override {}
void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override {}
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 854c6706e6..ded6bbc53e 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -88,7 +88,7 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) {
{
// must be closed before call to image_to_png
uint8_t *writer = out_buffer.ptrw();
- copymem(writer, "PNG ", 4);
+ memcpy(writer, "PNG ", 4);
}
Error err = PNGDriverCommon::image_to_png(p_image, out_buffer);
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index 9e848a2253..412e17c6b7 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -60,7 +60,7 @@ static bool check_error(const png_image &image) {
Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) {
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
// fetch image properties
@@ -134,7 +134,7 @@ Error image_to_png(const Ref<Image> &p_image, Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(source_image->is_compressed(), FAILED);
png_image png_img;
- zeromem(&png_img, sizeof(png_img));
+ memset(&png_img, 0, sizeof(png_img));
png_img.version = PNG_IMAGE_VERSION;
png_img.width = source_image->get_width();
png_img.height = source_image->get_height();
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index f47fc403cc..b737a287d1 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -41,7 +41,7 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32
ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG.");
ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as PNG.");
- Ref<Image> img = texture->get_data();
+ Ref<Image> img = texture->get_image();
Error err = save_image(p_path, img);
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index eda929850c..22151b60c1 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -102,6 +102,28 @@ bool DirAccessUnix::dir_exists(String p_dir) {
return (success && S_ISDIR(flags.st_mode));
}
+bool DirAccessUnix::is_readable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), R_OK) == 0);
+}
+
+bool DirAccessUnix::is_writable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), W_OK) == 0);
+}
+
uint64_t DirAccessUnix::get_modified_time(String p_file) {
if (p_file.is_rel_path()) {
p_file = current_dir.plus_file(p_file);
@@ -204,8 +226,9 @@ static void _get_drives(List<String> *list) {
while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) {
// Avoid duplicates
- if (!list->find(mnt.mnt_dir)) {
- list->push_back(mnt.mnt_dir);
+ String name = String::utf8(mnt.mnt_dir);
+ if (!list->find(name)) {
+ list->push_back(name);
}
}
}
@@ -218,8 +241,9 @@ static void _get_drives(List<String> *list) {
const char *home = getenv("HOME");
if (home) {
// Only add if it's not a duplicate
- if (!list->find(home)) {
- list->push_back(home);
+ String home_name = String::utf8(home);
+ if (!list->find(home_name)) {
+ list->push_back(home_name);
}
// Check $HOME/.config/gtk-3.0/bookmarks
@@ -232,7 +256,7 @@ static void _get_drives(List<String> *list) {
// Parse only file:// links
if (strncmp(string, "file://", 7) == 0) {
// Strip any unwanted edges on the strings and push_back if it's not a duplicate
- String fpath = String(string + 7).strip_edges().split_spaces()[0].uri_decode();
+ String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode();
if (!list->find(fpath)) {
list->push_back(fpath);
}
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index b70df1ca02..54f4a5c312 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -71,6 +71,8 @@ public:
virtual bool file_exists(String p_file);
virtual bool dir_exists(String p_dir);
+ virtual bool is_readable(String p_dir);
+ virtual bool is_writable(String p_dir);
virtual uint64_t get_modified_time(String p_file);
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 8ec1de4386..053e3fd9d6 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -75,8 +75,8 @@
#include <net/if.h> // Order is important on OpenBSD, leave as last
#endif
-static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
- IP_Address ip;
+static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
+ IPAddress ip;
if (p_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
@@ -89,7 +89,7 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
return ip;
};
-IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
+IPAddress IPUnix::_resolve_hostname(const String &p_hostname, Type p_type) {
struct addrinfo hints;
struct addrinfo *result = nullptr;
@@ -108,7 +108,7 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
- return IP_Address();
+ return IPAddress();
};
if (result == nullptr || result->ai_addr == nullptr) {
@@ -116,10 +116,10 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
if (result) {
freeaddrinfo(result);
}
- return IP_Address();
+ return IPAddress();
};
- IP_Address ip = _sockaddr2ip(result->ai_addr);
+ IPAddress ip = _sockaddr2ip(result->ai_addr);
freeaddrinfo(result);
@@ -130,7 +130,7 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
#if defined(UWP_ENABLED)
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
using namespace Windows::Networking;
using namespace Windows::Networking::Connectivity;
@@ -156,14 +156,14 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
Interface_Info &info = E->get();
- IP_Address ip = IP_Address(hostname->CanonicalName->Data());
+ IPAddress ip = IPAddress(hostname->CanonicalName->Data());
info.ip_addresses.push_front(ip);
}
}
#else
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
@@ -211,7 +211,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
#else // UNIX
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
int family;
@@ -249,15 +249,15 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
}
#endif
-void IP_Unix::make_default() {
+void IPUnix::make_default() {
_create = _create_unix;
}
-IP *IP_Unix::_create_unix() {
- return memnew(IP_Unix);
+IP *IPUnix::_create_unix() {
+ return memnew(IPUnix);
}
-IP_Unix::IP_Unix() {
+IPUnix::IPUnix() {
}
#endif
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index ca2ee17f4e..e6479be6e5 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -35,10 +35,10 @@
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
-class IP_Unix : public IP {
- GDCLASS(IP_Unix, IP);
+class IPUnix : public IP {
+ GDCLASS(IPUnix, IP);
- virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type) override;
+ virtual IPAddress _resolve_hostname(const String &p_hostname, IP::Type p_type) override;
static IP *_create_unix();
@@ -46,7 +46,7 @@ public:
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override;
static void make_default();
- IP_Unix();
+ IPUnix();
};
#endif
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 19753943c8..222aef998c 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -95,7 +95,7 @@
#endif
-size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket
@@ -106,7 +106,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
if (p_ip.is_valid()) {
- copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
+ memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
} else {
addr6->sin6_addr = in6addr_any;
}
@@ -121,7 +121,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr4->sin_port = htons(p_port); // short, network byte order
if (p_ip.is_valid()) {
- copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
+ memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
} else {
addr4->sin_addr.s_addr = INADDR_ANY;
}
@@ -130,18 +130,23 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
}
}
-void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) {
+void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
- r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
-
- r_port = ntohs(addr4->sin_port);
-
+ if (r_ip) {
+ r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
+ }
+ if (r_port) {
+ *r_port = ntohs(addr4->sin_port);
+ }
} else if (p_addr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
- r_ip.set_ipv6(addr6->sin6_addr.s6_addr);
-
- r_port = ntohs(addr6->sin6_port);
+ if (r_ip) {
+ r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
+ }
+ if (r_port) {
+ *r_port = ntohs(addr6->sin6_port);
+ }
};
}
@@ -186,13 +191,21 @@ NetSocketPosix::~NetSocketPosix() {
NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#if defined(WINDOWS_ENABLED)
int err = WSAGetLastError();
-
- if (err == WSAEISCONN)
+ if (err == WSAEISCONN) {
return ERR_NET_IS_CONNECTED;
- if (err == WSAEINPROGRESS || err == WSAEALREADY)
+ }
+ if (err == WSAEINPROGRESS || err == WSAEALREADY) {
return ERR_NET_IN_PROGRESS;
- if (err == WSAEWOULDBLOCK)
+ }
+ if (err == WSAEWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
+ }
+ if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (err == WSAEACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(err));
return ERR_NET_OTHER;
#else
@@ -205,6 +218,12 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK;
}
+ if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (errno == EACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
print_verbose("Socket error: " + itos(errno));
return ERR_NET_OTHER;
#endif
@@ -214,7 +233,7 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#pragma GCC diagnostic pop
#endif
-bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const {
+bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
return false;
} else if (!p_for_bind && !p_ip.is_valid()) {
@@ -225,7 +244,7 @@ bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind)
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
}
-_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) {
+_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
@@ -235,7 +254,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int ret = -1;
- IP_Address if_ip;
+ IPAddress if_ip;
uint32_t if_v6id = 0;
Map<String, IP::Interface_Info> if_info;
IP::get_singleton()->get_local_interfaces(&if_info);
@@ -250,7 +269,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
break; // IPv6 uses index.
}
- for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ for (List<IPAddress>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
if (!F->get().is_ipv4()) {
continue; // Wrong IP type
}
@@ -264,13 +283,13 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
struct ip_mreq greq;
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
- copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
- copymem(&greq.imr_interface, if_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
} else {
struct ipv6_mreq greq;
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
- copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
+ memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
greq.ipv6mr_interface = if_v6id;
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
}
@@ -376,7 +395,7 @@ void NetSocketPosix::close() {
_is_stream = false;
}
-Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
+Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
@@ -384,8 +403,8 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
- _get_socket_error();
- print_verbose("Failed to bind socket.");
+ NetError err = _get_socket_error();
+ print_verbose("Failed to bind socket. Error: " + itos(err));
close();
return ERR_UNAVAILABLE;
}
@@ -406,7 +425,7 @@ Error NetSocketPosix::listen(int p_max_pending) {
return OK;
}
-Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) {
+Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
@@ -446,7 +465,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
FD_ZERO(&wr);
FD_ZERO(&ex);
FD_SET(_sock, &ex);
- struct timeval timeout = { p_timeout, 0 };
+ struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
// For blocking operation, pass nullptr timeout pointer to select.
struct timeval *tp = nullptr;
if (p_timeout >= 0) {
@@ -540,7 +559,7 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
return OK;
}
-Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek) {
+Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage from;
@@ -597,7 +616,7 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
return OK;
}
-Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage addr;
@@ -716,7 +735,21 @@ int NetSocketPosix::get_available_bytes() const {
return len;
}
-Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
+Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
+ ERR_FAIL_COND_V(!is_open(), FAILED);
+
+ struct sockaddr_storage saddr;
+ socklen_t len = sizeof(saddr);
+ if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
+ _get_socket_error();
+ print_verbose("Error when reading local socket address.");
+ return FAILED;
+ }
+ _set_ip_port(&saddr, r_ip, r_port);
+ return OK;
+}
+
+Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out);
@@ -729,7 +762,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return out;
}
- _set_ip_port(&their_addr, r_ip, r_port);
+ _set_ip_port(&their_addr, &r_ip, &r_port);
NetSocketPosix *ns = memnew(NetSocketPosix);
ns->_set_socket(fd, _ip_type, _is_stream);
@@ -737,11 +770,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return Ref<NetSocket>(ns);
}
-Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, true);
}
-Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
#endif
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index cc6af661c8..38c8170a52 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -54,39 +54,42 @@ private:
ERR_NET_WOULD_BLOCK,
ERR_NET_IS_CONNECTED,
ERR_NET_IN_PROGRESS,
- ERR_NET_OTHER
+ ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
+ ERR_NET_UNAUTHORIZED,
+ ERR_NET_OTHER,
};
NetError _get_socket_error() const;
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
- _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add);
+ _FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
_FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled);
protected:
static NetSocket *_create_func();
- bool _can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const;
+ bool _can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const;
public:
static void make_default();
static void cleanup();
- static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port);
- static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type);
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
+ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
virtual Error open(Type p_sock_type, IP::Type &ip_type);
virtual void close();
- virtual Error bind(IP_Address p_addr, uint16_t p_port);
+ virtual Error bind(IPAddress p_addr, uint16_t p_port);
virtual Error listen(int p_max_pending);
- virtual Error connect_to_host(IP_Address p_host, uint16_t p_port);
+ virtual Error connect_to_host(IPAddress p_host, uint16_t p_port);
virtual Error poll(PollType p_type, int timeout) const;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read);
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false);
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false);
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent);
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port);
- virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port);
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port);
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port);
virtual bool is_open() const;
virtual int get_available_bytes() const;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const;
virtual Error set_broadcasting_enabled(bool p_enabled);
virtual void set_blocking_enabled(bool p_enabled);
@@ -94,8 +97,8 @@ public:
virtual void set_tcp_no_delay_enabled(bool p_enabled);
virtual void set_reuse_address_enabled(bool p_enabled);
virtual void set_reuse_port_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
NetSocketPosix();
~NetSocketPosix();
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index b9bd773c2e..15cd7bee92 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -129,7 +129,7 @@ void OS_Unix::initialize_core() {
#ifndef NO_NETWORK
NetSocketPosix::make_default();
- IP_Unix::make_default();
+ IPUnix::make_default();
#endif
_setup_clock();
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 469d80368d..43b2a24172 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1486,7 +1486,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
// possible in a single frame
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
//guess we did.. ok, let's see if we can insert a new block..
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we can, so we are safe
Error err = _insert_staging_block();
if (err) {
@@ -1530,7 +1530,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
} else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) {
//this block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we are still allowed to create a new block, so let's do that and insert it for current pos
Error err = _insert_staging_block();
if (err) {
@@ -1600,7 +1600,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
}
//copy to staging buffer
- copymem(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
+ memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
//unmap
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
@@ -2558,7 +2558,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * line_width;
- copymem(wptr, rptr, line_width);
+ memcpy(wptr, rptr, line_width);
}
} else {
@@ -2566,7 +2566,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
- copymem(wptr, rptr, pixel_size * width);
+ memcpy(wptr, rptr, (uint64_t)pixel_size * width);
}
}
}
@@ -2699,7 +2699,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
{
buffer_data.resize(buffer_size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer_size);
+ memcpy(w, buffer_mem, buffer_size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -5359,7 +5359,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
{
buffer_data.resize(buffer->size);
uint8_t *w = buffer_data.ptrw();
- copymem(w, buffer_mem, buffer->size);
+ memcpy(w, buffer_mem, buffer->size);
}
vmaUnmapMemory(allocator, tmp_buffer.allocation);
@@ -7834,6 +7834,22 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
+ // get our device capabilities
+ {
+ device_capabilities.version_major = p_context->get_vulkan_major();
+ device_capabilities.version_minor = p_context->get_vulkan_minor();
+
+ // get info about subgroups
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
+ device_capabilities.subgroup_size = subgroup_capabilities.size;
+ device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
+ device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
+
+ // get info about further features
+ VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
+ device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
+ }
+
context = p_context;
device = p_context->get_device();
if (p_local_device) {
@@ -7974,7 +7990,11 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
List<RID> owned;
p_owner.get_owned_list(&owned);
if (owned.size()) {
- WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked.");
+ if (owned.size() == 1) {
+ WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
+ }
for (List<RID>::Element *E = owned.front(); E; E = E->next()) {
free(E->get());
}
@@ -8187,7 +8207,11 @@ void RenderingDeviceVulkan::finalize() {
List<RID> owned;
texture_owner.get_owned_list(&owned);
if (owned.size()) {
- WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked.");
+ if (owned.size() == 1) {
+ WARN_PRINT("1 RID of type \"Texture\" was leaked.");
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
+ }
//free shared first
for (List<RID>::Element *E = owned.front(); E;) {
List<RID>::Element *N = E->next();
@@ -8253,6 +8277,7 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
}
RenderingDeviceVulkan::RenderingDeviceVulkan() {
+ device_capabilities.device_family = DEVICE_VULKAN;
}
RenderingDeviceVulkan::~RenderingDeviceVulkan() {
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 69517b17ba..4649cee17f 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -34,12 +34,14 @@
#include "core/config/project_settings.h"
#include "core/string/ustring.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>
+#include <vector>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define APP_SHORT_NAME "GodotEngine"
@@ -163,7 +165,36 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
return VK_FALSE;
}
-VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers) {
+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++) {
@@ -180,55 +211,86 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_n
return 1;
}
-Error VulkanContext::_create_validation_layers() {
+Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
+ static const std::vector<std::vector<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;
- const char *instance_validation_layers_alt1[] = { "VK_LAYER_KHRONOS_validation" };
- const char *instance_validation_layers_alt2[] = { "VK_LAYER_LUNARG_standard_validation" };
- const char *instance_validation_layers_alt3[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" };
+ uint32_t instance_layer_count;
- uint32_t instance_layer_count = 0;
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ if (err) {
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
- VkBool32 validation_found = 0;
- uint32_t validation_layer_count = 0;
- const char **instance_validation_layers = nullptr;
- if (instance_layer_count > 0) {
- 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);
- }
+ if (instance_layer_count < 1) {
+ return OK;
+ }
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
- instance_validation_layers = instance_validation_layers_alt1;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ 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);
+ }
- // use alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
- instance_validation_layers = instance_validation_layers_alt2;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) {
+ if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].data(), instance_layer_count, instance_layers)) {
+ *count = instance_validation_layers_alt[i].size();
+ if (names != nullptr) {
+ *names = instance_validation_layers_alt[i].data();
+ }
+ break;
}
+ }
- // use alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt3);
- instance_validation_layers = instance_validation_layers_alt3;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
- }
+ free(instance_layers);
- free(instance_layers);
- }
+ return OK;
+}
- if (validation_found) {
- enabled_layer_count = validation_layer_count;
- for (uint32_t i = 0; i < validation_layer_count; i++) {
- enabled_layers[i] = instance_validation_layers[i];
+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) {
+ vulkan_major = VK_VERSION_MAJOR(api_version);
+ vulkan_minor = VK_VERSION_MINOR(api_version);
+ uint32_t vulkan_patch = VK_VERSION_PATCH(api_version);
+
+ print_line("Vulkan API " + itos(vulkan_major) + "." + itos(vulkan_minor) + "." + itos(vulkan_patch));
+ } 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 {
- return ERR_CANT_CREATE;
+ print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0");
+ }
+
+ // we don't go above 1.2
+ if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
+ vulkan_major = 1;
+ vulkan_minor = 2;
}
return OK;
@@ -238,8 +300,8 @@ Error VulkanContext::_initialize_extensions() {
uint32_t instance_extension_count = 0;
enabled_extension_count = 0;
- enabled_layer_count = 0;
enabled_debug_utils = false;
+ enabled_debug_report = false;
/* Look for instance extensions */
VkBool32 surfaceExtFound = 0;
VkBool32 platformSurfaceExtFound = 0;
@@ -266,8 +328,9 @@ Error VulkanContext::_initialize_extensions() {
extension_names[enabled_extension_count++] = _get_platform_surface_extension();
}
if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- if (use_validation_layers) {
+ if (_use_validation_layers()) {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
+ enabled_debug_report = true;
}
}
if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) {
@@ -289,12 +352,255 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}
-Error VulkanContext::_create_physical_device() {
- /* Look for validation layers */
- if (use_validation_layers) {
- _create_validation_layers();
+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
+ multiview_capabilities.is_supported = false;
+ multiview_capabilities.max_view_count = 0;
+ multiview_capabilities.max_instance_count = 0;
+ subgroup_capabilities.size = 0;
+ subgroup_capabilities.supportedStages = 0;
+ subgroup_capabilities.supportedOperations = 0;
+ subgroup_capabilities.quadOperationsInAllStages = false;
+
+ // check for extended features
+ PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
+ if (device_features_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name
+ device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
+ }
+ if (device_features_func != nullptr) {
+ // check our extended features
+ VkPhysicalDeviceMultiviewFeatures multiview_features;
+ multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ multiview_features.pNext = NULL;
+
+ VkPhysicalDeviceFeatures2 device_features;
+ device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ device_features.pNext = &multiview_features;
+
+ device_features_func(gpu, &device_features);
+ multiview_capabilities.is_supported = multiview_features.multiview;
+ // For now we ignore if multiview is available in geometry and tesselation as we do not currently support those
+ }
+
+ // 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) {
+ VkPhysicalDeviceMultiviewProperties multiviewProperties;
+ VkPhysicalDeviceSubgroupProperties subgroupProperties;
+ VkPhysicalDeviceProperties2 physicalDeviceProperties;
+
+ subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ subgroupProperties.pNext = nullptr;
+
+ physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+
+ if (multiview_capabilities.is_supported) {
+ multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+ multiviewProperties.pNext = &subgroupProperties;
+
+ physicalDeviceProperties.pNext = &multiviewProperties;
+ } else {
+ physicalDeviceProperties.pNext = &subgroupProperties;
+ }
+
+ device_properties_func(gpu, &physicalDeviceProperties);
+
+ subgroup_capabilities.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 (multiview_capabilities.is_supported) {
+ multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
+ multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan multiview supported:");
+ print_line(" max views: " + itos(multiview_capabilities.max_view_count));
+ print_line(" max instances: " + itos(multiview_capabilities.max_instance_count));
+ } else {
+ print_line("- Vulkan multiview not supported");
+#endif
+ }
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan subgroup:");
+ print_line(" size: " + itos(subgroup_capabilities.size));
+ print_line(" stages: " + subgroup_capabilities.supported_stages_desc());
+ print_line(" supported ops: " + subgroup_capabilities.supported_operations_desc());
+ if (subgroup_capabilities.quadOperationsInAllStages) {
+ print_line(" quad operations in all stages");
+ }
+ } else {
+ print_line("- Couldn't call vkGetPhysicalDeviceProperties2");
+#endif
+ }
+
+ return OK;
+}
+
+Error VulkanContext::_create_physical_device() {
+ /* obtain version */
+ _obtain_vulkan_version();
+ /* initialise extensions */
{
Error err = _initialize_extensions();
if (err != OK) {
@@ -312,18 +618,16 @@ Error VulkanContext::_create_physical_device() {
/*applicationVersion*/ 0,
/*pEngineName*/ namecs.get_data(),
/*engineVersion*/ 0,
- /*apiVersion*/ VK_API_VERSION_1_0,
- };
- VkInstanceCreateInfo inst_info = {
- /*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- /*pNext*/ nullptr,
- /*flags*/ 0,
- /*pApplicationInfo*/ &app,
- /*enabledLayerCount*/ enabled_layer_count,
- /*ppEnabledLayerNames*/ (const char *const *)enabled_layers,
- /*enabledExtensionCount*/ enabled_extension_count,
- /*ppEnabledExtensionNames*/ (const char *const *)extension_names,
+ /*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0)
};
+ 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 *)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.
@@ -331,6 +635,7 @@ Error VulkanContext::_create_physical_device() {
* function to register the final callback.
*/
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
+ VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
if (enabled_debug_utils) {
// VK_EXT_debug_utils style
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
@@ -344,6 +649,16 @@ Error VulkanContext::_create_physical_device() {
dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
dbg_messenger_create_info.pUserData = this;
inst_info.pNext = &dbg_messenger_create_info;
+ } else if (enabled_debug_report) {
+ 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;
}
uint32_t gpu_count;
@@ -532,9 +847,36 @@ Error VulkanContext::_create_physical_device() {
ERR_FAIL_V(ERR_CANT_CREATE);
break;
}
+ } else if (enabled_debug_report) {
+ 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;
+ }
}
- /* Call with NULL data to get count */
+ /* Call with nullptr data to get count */
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
@@ -561,6 +903,14 @@ Error VulkanContext::_create_physical_device() {
GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
+ // get info about what our vulkan driver is capable off
+ {
+ Error res = _check_capabilities();
+ if (res != OK) {
+ return res;
+ }
+ }
+
return OK;
}
@@ -692,16 +1042,39 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
// 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 (true || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
+ 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 an 32bit RGBA unsigned normalised 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");
}
- format = surfFormats[0].format;
+
+ // 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.");
+ }
}
- color_space = surfFormats[0].colorSpace;
free(surfFormats);
@@ -755,6 +1128,10 @@ Error VulkanContext::_create_semaphores() {
return OK;
}
+bool VulkanContext::_use_validation_layers() {
+ return Engine::get_singleton()->is_validation_layers_enabled();
+}
+
Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) {
ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
@@ -1279,13 +1656,13 @@ Error VulkanContext::prepare_buffers() {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// swapchain is out of date (e.g. the window was resized) and
// must be recreated:
- print_line("early out of data");
+ print_verbose("Vulkan: Early out of date swapchain, recreating.");
//resize_notify();
_update_swap_chain(w);
} else if (err == VK_SUBOPTIMAL_KHR) {
- print_line("early suboptimal");
// 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.");
break;
} else {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
@@ -1493,12 +1870,12 @@ Error VulkanContext::swap_buffers() {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// swapchain is out of date (e.g. the window was resized) and
// must be recreated:
- print_line("out of date");
+ print_verbose("Vulkan: 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_line("suboptimal");
+ print_verbose("Vulkan: Swapchain is suboptimal.");
} else {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
@@ -1594,13 +1971,13 @@ void VulkanContext::local_device_push_command_buffers(RID p_local_device, const
VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE);
if (err == VK_ERROR_OUT_OF_HOST_MEMORY) {
- print_line("out of host memory");
+ print_line("Vulkan: Out of host memory!");
}
if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
- print_line("out of device memory");
+ print_line("Vulkan: Out of device memory!");
}
if (err == VK_ERROR_DEVICE_LOST) {
- print_line("device lost");
+ print_line("Vulkan: Device lost!");
}
ERR_FAIL_COND(err);
@@ -1686,8 +2063,6 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
}
VulkanContext::VulkanContext() {
- use_validation_layers = Engine::get_singleton()->is_validation_layers_enabled();
-
command_buffer_queue.resize(1); // First one is always the setup command.
command_buffer_queue.write[0] = nullptr;
}
@@ -1708,6 +2083,9 @@ VulkanContext::~VulkanContext() {
if (inst_initialized && enabled_debug_utils) {
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) {
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index dc6b0410bc..3d9b295c5a 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -41,6 +41,26 @@
#include <vulkan/vulkan.h>
class VulkanContext {
+public:
+ struct SubgroupCapabilities {
+ uint32_t size;
+ VkShaderStageFlags supportedStages;
+ VkSubgroupFeatureFlags supportedOperations;
+ VkBool32 quadOperationsInAllStages;
+
+ 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 MultiviewCapabilities {
+ bool is_supported;
+ int32_t max_view_count;
+ int32_t max_instance_count;
+ };
+
+private:
enum {
MAX_EXTENSIONS = 128,
MAX_LAYERS = 64,
@@ -57,6 +77,12 @@ class VulkanContext {
bool device_initialized = false;
bool inst_initialized = false;
+ // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
+ uint32_t vulkan_major = 1;
+ uint32_t vulkan_minor = 0;
+ SubgroupCapabilities subgroup_capabilities;
+ MultiviewCapabilities multiview_capabilities;
+
String device_vendor;
String device_name;
String pipeline_cache_id;
@@ -126,8 +152,11 @@ class VulkanContext {
const char *extension_names[MAX_EXTENSIONS];
bool enabled_debug_utils = false;
- uint32_t enabled_layer_count = 0;
- const char *enabled_layers[MAX_LAYERS];
+ /**
+ * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
+ * still used if VK_EXT_debug_utils is not available.
+ */
+ bool enabled_debug_report = false;
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
@@ -136,6 +165,9 @@ class VulkanContext {
PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+ PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
@@ -149,17 +181,29 @@ class VulkanContext {
PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE;
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
+ VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
- Error _create_validation_layers();
+ Error _obtain_vulkan_version();
Error _initialize_extensions();
+ Error _check_capabilities();
- VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers);
+ 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_physical_device();
Error _initialize_queues(VkSurfaceKHR surface);
@@ -176,16 +220,22 @@ class VulkanContext {
protected:
virtual const char *_get_platform_surface_extension() const = 0;
- // Enabled via command line argument.
- bool use_validation_layers = false;
-
virtual Error _window_create(DisplayServer::WindowID p_window_id, 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);
+
VkInstance _get_instance() {
return inst;
}
public:
+ uint32_t get_vulkan_major() const { return vulkan_major; };
+ uint32_t get_vulkan_minor() const { return vulkan_minor; };
+ SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
+ MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
+
VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_swapchain_image_count() const;