diff --git a/Makefile.am b/Makefile.am
index 1340be10d31cf4ebe1dbe4006ccac926aa3f205c..3787389b89dcc10283259a0b70c64e4af3346299 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -179,6 +179,7 @@ libvkd3d_common_la_SOURCES = \
 	libs/vkd3d-common/error.c \
 	libs/vkd3d-common/memory.c \
 	libs/vkd3d-common/utf8.c
+libvkd3d_common_la_LIBADD = @PTHREAD_LIBS@
 
 lib_LTLIBRARIES = libvkd3d-shader.la libvkd3d.la libvkd3d-utils.la
 
diff --git a/include/private/vkd3d_debug.h b/include/private/vkd3d_debug.h
index 579c33d3605d9570889445eb37b4d59d93ca0245..4f6d43af12f254ad7e01b6cae5ed75df32037ded 100644
--- a/include/private/vkd3d_debug.h
+++ b/include/private/vkd3d_debug.h
@@ -115,5 +115,6 @@ struct vkd3d_debug_option
 bool vkd3d_debug_list_has_member(const char *string, const char *member);
 uint64_t vkd3d_parse_debug_options(const char *string,
         const struct vkd3d_debug_option *options, unsigned int option_count);
+void vkd3d_set_thread_name(const char *name);
 
 #endif  /* __VKD3D_DEBUG_H */
diff --git a/libs/vkd3d-common/debug.c b/libs/vkd3d-common/debug.c
index 0b9e765acedfa766af20291254703847e3d6addc..e07ed36690d1f9063cb2312984aa1aa9e041172b 100644
--- a/libs/vkd3d-common/debug.c
+++ b/libs/vkd3d-common/debug.c
@@ -16,6 +16,10 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#ifdef _WIN32
+# define _WIN32_WINNT 0x0600    /* For InitOnceExecuteOnce(). */
+#endif
+
 #include "vkd3d_debug.h"
 
 #include <assert.h>
@@ -27,6 +31,11 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#include "vkd3d_memory.h"
 
 #define VKD3D_DEBUG_BUFFER_COUNT 64
 #define VKD3D_DEBUG_BUFFER_SIZE 512
@@ -369,3 +378,49 @@ uint64_t vkd3d_parse_debug_options(const char *string,
 
     return flags;
 }
+
+#ifdef _WIN32
+
+static HRESULT (WINAPI *pfn_SetThreadDescription)(HANDLE, const WCHAR *);
+static BOOL WINAPI resolve_SetThreadDescription(INIT_ONCE *once, void *param, void **context)
+{
+    HMODULE kernelbase;
+
+    if (!(kernelbase = LoadLibraryA("kernelbase.dll")))
+        return TRUE;
+
+    if (!(pfn_SetThreadDescription = (void *)GetProcAddress(kernelbase, "SetThreadDescription")))
+        FreeLibrary(kernelbase);
+
+    return TRUE;
+}
+
+#endif
+
+void vkd3d_set_thread_name(const char *name)
+{
+#ifdef _WIN32
+    static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
+    WCHAR *wname;
+    int ret;
+
+    InitOnceExecuteOnce(&init_once, resolve_SetThreadDescription, NULL, NULL);
+    if (!pfn_SetThreadDescription)
+        return;
+
+    if ((ret = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0)) <= 0)
+        return;
+
+    if (!(wname = vkd3d_malloc(ret * sizeof(*wname))))
+        return;
+
+    if ((ret = MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, ret)) > 0)
+        pfn_SetThreadDescription(GetCurrentThread(), wname);
+
+    vkd3d_free(wname);
+#elif defined(HAVE_PTHREAD_SETNAME_NP_2)
+    pthread_setname_np(pthread_self(), name);
+#elif defined(HAVE_PTHREAD_SETNAME_NP_1)
+    pthread_setname_np(name);
+#endif
+}
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index c9b70d9ce123432e04dd6e3960e16a6fb703a582..2da1ab5df075d8f5af366d028dfc33df235482f0 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -1685,15 +1685,6 @@ extern const char vkd3d_build[];
 
 bool vkd3d_get_program_name(char program_name[PATH_MAX]);
 
-static inline void vkd3d_set_thread_name(const char *name)
-{
-#if defined(HAVE_PTHREAD_SETNAME_NP_2)
-    pthread_setname_np(pthread_self(), name);
-#elif defined(HAVE_PTHREAD_SETNAME_NP_1)
-    pthread_setname_np(name);
-#endif
-}
-
 VkResult vkd3d_set_vk_object_name_utf8(struct d3d12_device *device, uint64_t vk_object,
         VkDebugReportObjectTypeEXT vk_object_type, const char *name);
 HRESULT vkd3d_set_vk_object_name(struct d3d12_device *device, uint64_t vk_object,