Add basic Vulkan support

Added GLFW_INCLUDE_VULKAN.  Added glfwVulkanSupported,
glfwGetRequiredInstanceExtensions, glfwGetInstanceProcAddress,
glfwGetPhysicalDevicePresentationSupport and glfwCreateWindowSurface.
Added port of LunarG SDK tri example.
This commit is contained in:
Camilla Berglund 2015-08-10 20:19:04 +02:00
parent c2efe87cff
commit 9b75bffc88
35 changed files with 7823 additions and 51 deletions

1
.gitignore vendored
View File

@ -71,5 +71,6 @@ tests/tearing
tests/threads
tests/title
tests/version
tests/vulkan
tests/windows

View File

@ -0,0 +1,23 @@
# Find Vulkan
#
# VULKAN_INCLUDE_DIR
# VULKAN_LIBRARY
# VULKAN_FOUND
if (WIN32)
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS
"$ENV{VK_SDK_PATH}/Include")
find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS
"$ENV{VK_SDK_PATH}/Bin")
else()
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS
"$ENV{VULKAN_SDK}/include")
find_library(VULKAN_LIBRARY NAMES vulkan HINTS
"$ENV{VULKAN_SDK}/lib")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Vulkan DEFAULT_MSG VULKAN_LIBRARY VULKAN_INCLUDE_DIR)
mark_as_advanced(VULKAN_INCLUDE_DIR VULKAN_LIBRARY)

View File

@ -66,6 +66,7 @@ endif()
set(CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
find_package(Threads REQUIRED)
find_package(Vulkan)
if (GLFW_BUILD_DOCS)
set(DOXYGEN_SKIP_DOT TRUE)

View File

@ -5,9 +5,9 @@
## Introduction
GLFW is a free, Open Source, multi-platform library for OpenGL and OpenGL ES
application development. It provides a simple, platform-independent API for
creating windows and contexts, reading input, handling events, etc.
GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and
Vulkan application development. It provides a simple, platform-independent API
for creating windows, contexts and surfaces, reading input, handling events, etc.
Version 3.2 is _not yet described_.
@ -50,7 +50,7 @@ This will help both us and other people experiencing the same bug.
GLFW itself needs only the headers and libraries for your window system. It
does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or
client API (OpenGL, OpenGL ES) to enable support for them.
rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them.
GLFW bundles a number of dependencies in the `deps/` directory. These are only
used by the tests and examples and are not required to build the library.
@ -64,15 +64,22 @@ used by the tests and examples and are not required to build the library.
- [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in
examples
The Vulkan example additionally requires the Vulkan SDK to be installed, or it
will not be included in the build.
## Changelog
- Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`,
`glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and
`glfwCreateWindowSurface` for platform independent Vulkan support
- Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting
absolute and relative window size limits
- Added `glfwGetKeyName` for querying the layout-specific name of printable
keys
- Added `GLFW_NO_API` for creating window without contexts
- Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support
- Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header
- Added `GLFW_TRUE` and `GLFW_FALSE` as client API independent boolean values
- Added `glfwGetGLXWindow` to query the `GLXWindow` of a window
- Added icons to examples on Windows and OS X
@ -168,6 +175,7 @@ skills.
- Osman Keskin
- Cameron King
- Peter Knut
- Christoph Kubisch
- Eric Larson
- Robin Leffmann
- Glenn Lewis

127
deps/vulkan/vk_platform.h vendored Normal file
View File

@ -0,0 +1,127 @@
//
// File: vk_platform.h
//
/*
** Copyright (c) 2014-2015 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are 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 Materials.
**
** THE MATERIALS ARE 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
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
#ifndef __VK_PLATFORM_H__
#define __VK_PLATFORM_H__
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
/*
***************************************************************************************************
* Platform-specific directives and type declarations
***************************************************************************************************
*/
/* Platform-specific calling convention macros.
*
* Platforms should define these so that Vulkan clients call Vulkan commands
* with the same calling conventions that the Vulkan implementation expects.
*
* VKAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* VKAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
*/
#if defined(_WIN32)
// On Windows, Vulkan commands use the stdcall convention
#define VKAPI_ATTR
#define VKAPI_CALL __stdcall
#define VKAPI_PTR VKAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__)
// Android does not support Vulkan in native code using the "armeabi" ABI.
#error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs"
#elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
// On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling
// convention, even if the application's native code is compiled with the
// armeabi-v7a calling convention.
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define VKAPI_CALL
#define VKAPI_PTR VKAPI_ATTR
#else
// On other platforms, use the default calling convention
#define VKAPI_ATTR
#define VKAPI_CALL
#define VKAPI_PTR
#endif
#include <stddef.h>
#if !defined(VK_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined(VK_NO_STDINT_H)
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
// Platform-specific headers required by platform window system extensions.
// These are enabled prior to #including "vulkan.h". The same enable then
// controls inclusion of the extension interfaces in vulkan.h.
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include <android/native_window.h>
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
#include <mir_toolkit/client_types.h>
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#include <wayland-client.h>
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
#include <windows.h>
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
#include <X11/Xlib.h>
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#include <xcb/xcb.h>
#endif
#endif // __VK_PLATFORM_H__

3775
deps/vulkan/vulkan.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -674,6 +674,7 @@ INPUT = @GLFW_INTERNAL_DOCS@ \
@GLFW_SOURCE_DIR@/docs/monitor.dox \
@GLFW_SOURCE_DIR@/docs/window.dox \
@GLFW_SOURCE_DIR@/docs/input.dox \
@GLFW_SOURCE_DIR@/docs/vulkan.dox \
@GLFW_SOURCE_DIR@/docs/rift.dox \
@GLFW_SOURCE_DIR@/docs/compat.dox
@ -1590,7 +1591,8 @@ PREDEFINED = GLFWAPI= \
GLFW_EXPOSE_NATIVE_GLX \
GLFW_EXPOSE_NATIVE_COCOA \
GLFW_EXPOSE_NATIVE_NSGL \
GLFW_EXPOSE_NATIVE_EGL
GLFW_EXPOSE_NATIVE_EGL \
VK_VERSION_1_0
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.

View File

@ -80,6 +80,9 @@ header instead of the regular OpenGL header.
`GLFW_INCLUDE_ES31` makes the GLFW header include the OpenGL ES 3.1 `GLES3/gl31.h`
header instead of the regular OpenGL header.
`GLFW_INCLUDE_VULKAN` makes the GLFW header include the Vulkan `vulkan/vulkan.h`
header instead of the regular OpenGL header.
`GLFW_INCLUDE_NONE` makes the GLFW header not include any OpenGL or OpenGL ES API
header. This is useful in combination with an extension loading library.

View File

@ -186,4 +186,43 @@ setting the `GLFW_OPENGL_PROFILE` or `GLFW_OPENGL_FORWARD_COMPAT` hints to
a non-default value will cause @ref glfwCreateWindow to fail and the
`GLFW_OPENGL_DEBUG_CONTEXT` hint is ignored.
@section compat_vulkan Vulkan loader and API
GLFW uses the standard system-wside Vulkan loader to access the Vulkan API.
This should be installed by graphics drivers and Vulkan SDKs. If this is not
available, @ref glfwVulkanSupported will return `GLFW_FALSE` and all other
Vulkan-related functions will fail with an @ref GLFW_API_UNAVAILABLE error.
@section compat_wsi Vulkan WSI extensions
The Vulkan WSI extensions are used to create Vulkan surfaces for GLFW windows on
all supported platforms.
GLFW uses the `VK_KHR_surface` and `VK_KHR_win32_surface` extensions to create
surfaces on Microsoft Windows. If any of these extensions are not available,
@ref glfwGetRequiredInstanceExtensions will return an empty list and window
surface creation will fail.
GLFW uses the `VK_KHR_surface` and either the `VK_KHR_xlib_surface` or
`VK_KHR_xcb_surface` extensions to create surfaces on X11. If `VK_KHR_surface`
or both `VK_KHR_xlib_surface` and `VK_KHR_xcb_surface` are not available, @ref
glfwGetRequiredInstanceExtensions will return an empty list and window surface
creation will fail.
GLFW uses the `VK_KHR_surface` and `VK_KHR_wayland_surface` extensions to create
surfaces on Wayland. If any of these extensions are not available, @ref
glfwGetRequiredInstanceExtensions will return an empty list and window surface
creation will fail.
GLFW uses the `VK_KHR_surface` and `VK_KHR_mir_surface` extensions to create
surfaces on Mir. If any of these extensions are not available, @ref
glfwGetRequiredInstanceExtensions will return an empty list and window surface
creation will fail.
GLFW does not support any extensions for window surface creation on OS X,
meaning@ref glfwGetRequiredInstanceExtensions will return an empty list and
window surface creation will fail.
*/

View File

@ -26,6 +26,11 @@ as the context handle.
To test the creation of various kinds of contexts and see their properties, run
the `glfwinfo` test program.
@note Vulkan does not have a context and the Vulkan instance is created via the
Vulkan API itself. If you will be using Vulkan to render to a window, disable
context creation by setting the [GLFW_CLIENT_API](@ref window_hints_ctx) hint to
`GLFW_NO_API`. For more information, see the @ref vulkan.
@subsection context_hints Context creation hints

View File

@ -4,9 +4,9 @@
@section main_intro Introduction
__GLFW__ is a free, Open Source, multi-platform library for creating windows
with OpenGL or OpenGL ES contexts and receiving many kinds of input. It is easy
to integrate into existing applications and does not lay claim to the main loop.
GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and
Vulkan application development. It provides a simple, platform-independent API
for creating windows, contexts and surfaces, reading input, handling events, etc.
See @ref news_32 for release highlights or the
[version history](http://www.glfw.org/changelog.html) for details.
@ -32,6 +32,8 @@ about specific functions.
There is a section on @ref guarantees_limitations for pointer lifetimes,
reentrancy, thread safety, event order and backward and forward compatibility.
The @ref vulkan guide fills in the gaps for how to use Vulkan with GLFW.
The @ref rift fills in the gaps for how to use LibOVR with GLFW.
The [FAQ](http://www.glfw.org/faq.html) answers many common questions about the

View File

@ -17,6 +17,15 @@ GLFW now supports querying the localized name of printable keys with @ref
glfwGetKeyName, either by key token or by scancode.
@subsection news_32_vulkan Support for Vulkan
GLFW now supports basic integration with Vulkan with @ref glfwVulkanSupported,
@ref glfwGetRequiredInstanceExtensions, @ref glfwGetInstanceProcAddress, @ref
glfwGetPhysicalDevicePresentationSupport and @ref glfwCreateWindowSurface.
Vulkan header inclusion can be selected with
[GLFW_INCLUDE_VULKAN](@ref build_macros).
@section news_31 New features in 3.1
These are the release highlights. For a full list of changes see the

185
docs/vulkan.dox Normal file
View File

@ -0,0 +1,185 @@
/*!
@page vulkan Vulkan guide
@tableofcontents
This guide is intended to fill the gaps between the Vulkan documentation and the
rest of the GLFW documentation and is not a replacement for either.
To develop for Vulkan you should install an SDK for your platform, for example
the [LunarG Vulkan SDK](http://lunarg.com/vulkan-sdk/). Apart from the headers
and libraries, it also provides the validation layers necessary for development.
GLFW itself does not need a Vulkan SDK to enable support for Vulkan. However,
any Vulkan-specific test and example programs are built only if the CMake files
find the LunarG SDK.
@section vulkan_include Including the Vulkan and GLFW header files
To include the Vulkan header, define `GLFW_INCLUDE_VULKAN` before including the
GLFW header.
@code
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
@endcode
If you want to include the Vulkan header from a custom location or use your own
custom Vulkan header then you need to include them before the GLFW header.
@code
#include <custom/path/vulkan.h>
#include <GLFW/glfw3.h>
@endcode
Unless a Vulkan header is included, either by the GLFW header or above it, any
GLFW functions that use Vulkan types will not be declared.
The `VK_USE_PLATFORM_*_KHR` macros do not need to be defined for the Vulkan part
of GLFW to work.
@section vulkan_support Querying for Vulkan support
If you are loading the Vulkan loader dynamically instead of linking directly
against it, you can check for the availability of a loader with @ref
glfwVulkanSupported.
@code
if (glfwVulkanSupported())
{
// Vulkan is available, at least for compute
}
@endcode
This function returns `GLFW_TRUE` if the Vulkan loader was found. This check is
performed by @ref glfwInit.
If no loader was found, calling any other Vulkan related GLFW function will
generate a @ref GLFW_API_UNAVAILABLE error.
@subsection vulkan_proc Querying Vulkan function pointers
To load any Vulkan core or extension function from the found loader, call @ref
glfwGetInstanceProcAddress.
@code
PFN_vkCreateDevice pfnCreateDevice = (PFN_vkCreateDevice)
glfwGetInstanceProcAddress(instance, "vkCreateDevice");
@endcode
This is equivalent to calling `vkGetInstanceProcAddr`. If that fails, the
function falls back to a platform-specific query of the Vulkan loader (i.e.
`dlsym` or `GetProcAddress`). If that also fails, the function returns `NULL`.
For more information about `vkGetInstanceProcAddr`, see the Vulkan
documentation.
Vulkan also provides `vkGetDeviceProcAddr` for loading device-specific versions
of Vulkan function. This function can be retrieved from an instance with @ref
glfwGetInstanceProcAddress.
@code
PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)
glfwGetInstanceProcAddress(instance, "vkGetDeviceProcAddr");
@endcode
Device-specific functions may execute a little bit faster, due to not having to
dispatch internally based on the device passed to them. For more information
about `vkGetDeviceProcAddr`, see the Vulkan documentation.
@section vulkan_ext Querying required Vulkan extensions
To do anything useful with Vulkan you need to create an instance. If you want
to use Vulkan to render to a window, you must enable the instance extensions
GLFW requires to create Vulkan surfaces.
To query the instance extensions required, call @ref
glfwGetRequiredInstanceExtensions.
@code
int count;
const char** extensions = glfwGetRequiredInstanceExtensions(&count);
@endcode
These extensions must all be enabled when creating instances that are going to
be passed to @ref glfwGetPhysicalDevicePresentationSupport and @ref
glfwCreateWindowSurface. The set of extensions will vary depending on platform
and may also vary depending on graphics drivers and other factors.
If it fails it will return `NULL` and Vulkan window surface creation will not be
possible. You may still use Vulkan for off-screen rendering and compute work.
The returned array will always contain `VK_KHR_surface`, so if you don't
require any additional extensions you can pass this list directly to the
`VkInstanceCreateInfo` struct.
@code
VkInstanceCreateInfo ici;
memset(&ici, 0, sizeof(ici));
ici.enabledExtensionCount = count;
ici.ppEnabledExtensionNames = extensions;
...
@endcode
Additional extensions may be required by future versions of GLFW. You should
check whether any extensions you wish to enable are already in the returned
array, as it is an error to specify an extension more than once in the
`VkInstanceCreateInfo` struct.
@section vulkan_present Querying for Vulkan presentation support
Not every Vulkan queue family of every device can present images to surfaces.
To check whether a specific queue family of a physical device supports image
presentation without first having to create a window and surface, call @ref
glfwGetPhysicalDevicePresentationSupport.
@code
if (glfwGetPhysicalDevicePresentationSupport(instance, physical_device, queue_family_index))
{
// Queue family supports image presentation
}
@endcode
The `VK_KHR_surface` extension also provides the
`vkGetPhysicalDeviceSurfaceSupportKHR` function, which performs the same test on
an existing Vulkan surface.
@section vulkan_window Creating the window
Unless you will be using OpenGL or OpenGL ES in addition to Vulkan, there is no
need to create a context for that window. You can disable context creation by
setting the [GLFW_CLIENT_API](@ref window_hints_ctx) hint to `GLFW_NO_API`.
@code
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(640, 480, "Window Title", NULL, NULL);
@endcode
See @ref context_less for more information.
@section vulkan_surface Creating a Vulkan window surface
You can create a Vulkan surface (as defined by the `VK_KHR_surface` extension)
for a GLFW window with @ref glfwCreateWindowSurface.
@code
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(instance, window, NULL, &surface);
if (err)
{
// Window surface creation failed
}
@endcode
It is your responsibility to destroy the surface. GLFW does not destroy it for
you. Call `vkDestroySurfaceKHR` function from the same extension to destroy it.
*/

View File

@ -1,6 +1,8 @@
link_libraries(glfw)
include_directories(${glfw_INCLUDE_DIRS})
if (BUILD_SHARED_LIBS)
link_libraries("${MATH_LIBRARY}")
endif()

View File

@ -51,6 +51,11 @@ extern "C" {
* This is the reference documentation for context related functions. For more
* information, see the @ref context.
*/
/*! @defgroup vulkan Vulkan support
*
* This is the reference documentation for Vulkan related functions. For more
* information, see the @ref vulkan.
*/
/*! @defgroup init Initialization, version and errors
*
* This is the reference documentation for initialization and termination of
@ -157,6 +162,8 @@ extern "C" {
#if defined(GLFW_INCLUDE_GLEXT)
#include <GLES2/gl2ext.h>
#endif
#elif defined(GLFW_INCLUDE_VULKAN)
#include <vulkan/vulkan.h>
#elif !defined(GLFW_INCLUDE_NONE)
#include <GL/gl.h>
#if defined(GLFW_INCLUDE_GLEXT)
@ -539,15 +546,12 @@ extern "C" {
* to our [issue tracker](https://github.com/glfw/glfw/issues).
*/
#define GLFW_OUT_OF_MEMORY 0x00010005
/*! @brief GLFW could not find support for the requested client API on the
* system.
/*! @brief GLFW could not find support for the requested API on the system.
*
* GLFW could not find support for the requested client API on the system. If
* emitted by functions other than @ref glfwCreateWindow, no supported client
* API was found.
* GLFW could not find support for the requested API on the system.
*
* @analysis The installed graphics driver does not support the requested
* client API, or does not support it via the chosen context creation backend.
* API, or does not support it via the chosen context creation backend.
* Below are a few examples.
*
* @par
@ -555,7 +559,7 @@ extern "C" {
* supports OpenGL ES via EGL, while Nvidia and Intel only support it via
* a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa
* EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
* driver.
* driver. Older graphics drivers do not support Vulkan.
*/
#define GLFW_API_UNAVAILABLE 0x00010006
/*! @brief The requested OpenGL or OpenGL ES version is not available.
@ -738,6 +742,20 @@ extern "C" {
*/
typedef void (*GLFWglproc)(void);
/*! @brief Vulkan API function pointer type.
*
* Generic function pointer used for returning Vulkan API function pointers
* without forcing a cast from a regular pointer.
*
* @sa @ref vulkan_proc
* @sa glfwGetInstanceProcAddress
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
typedef void (*GLFWvkproc)(void);
/*! @brief Opaque monitor object.
*
* Opaque monitor object.
@ -3656,6 +3674,204 @@ GLFWAPI int glfwExtensionSupported(const char* extension);
*/
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname);
/*! @brief Returns whether the Vulkan loader has been found.
*
* This function returns whether the Vulkan loader has been found. This check
* is performed by @ref glfwInit.
*
* The availability of a Vulkan loader does not by itself guarantee that window
* surface creation or even device creation is possible. Call @ref
* glfwGetRequiredInstanceExtensions to check whether the extensions necessary
* for Vulkan surface creation are available and @ref
* glfwGetPhysicalDevicePresentationSupport to check whether a queue family of
* a physical device supports image presentation.
*
* @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread.
*
* @sa @ref vulkan_support
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
GLFWAPI int glfwVulkanSupported(void);
/*! @brief Returns the Vulkan instance extensions required by GLFW.
*
* This function returns an array of names of Vulkan instance extensions required
* by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the
* list will always contains `VK_KHR_surface`, so if you don't require any
* additional extensions you can pass this list directly to the
* `VkInstanceCreateInfo` struct.
*
* If Vulkan is not available on the machine, this function returns `NULL` and
* generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
* to check whether Vulkan is available.
*
* If Vulkan is available but no set of extensions allowing window surface
* creation was found, this function returns `NULL`. You may still use Vulkan
* for off-screen rendering and compute work.
*
* @param[out] count Where to store the number of extensions in the returned
* array. This is set to zero if an error occurred.
* @return An array of ASCII encoded extension names, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_API_UNAVAILABLE.
*
* @remarks Additional extensions may be required by future versions of GLFW.
* You should check if any extensions you wish to enable are already in the
* returned array, as it is an error to specify an extension more than once in
* the `VkInstanceCreateInfo` struct.
*
* @pointer_lifetime The returned array is allocated and freed by GLFW. You
* should not free it yourself. It is guaranteed to be valid only until the
* library is terminated.
*
* @thread_safety This function may be called from any thread.
*
* @sa @ref vulkan_ext
* @sa glfwCreateWindowSurface
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
GLFWAPI const char** glfwGetRequiredInstanceExtensions(int* count);
#if defined(VK_VERSION_1_0)
/*! @brief Returns the address of the specified Vulkan instance function.
*
* This function returns the address of the specified Vulkan core or extension
* function for the specified instance. If instance is set to `NULL` it can
* return any function exported from the Vulkan loader, including at least the
* following functions:
*
* - `vkEnumerateInstanceExtensionProperties`
* - `vkEnumerateInstanceLayerProperties`
* - `vkCreateInstance`
* - `vkGetInstanceProcAddr`
*
* If Vulkan is not available on the machine, this function returns `NULL` and
* generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
* to check whether Vulkan is available.
*
* This function is equivalent to calling `vkGetInstanceProcAddr` with
* a platform-specific query of the Vulkan loader as a fallback.
*
* @param[in] instance The Vulkan instance to query, or `NULL` to retrieve
* functions related to instance creation.
* @param[in] procname The ASCII encoded name of the function.
* @return The address of the function, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_API_UNAVAILABLE.
*
* @pointer_lifetime The returned function pointer is valid until the library
* is terminated.
*
* @thread_safety This function may be called from any thread.
*
* @sa @ref vulkan_proc
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname);
/*! @brief Returns whether the specified queue family can present images.
*
* This function returns whether the specified queue family of the specified
* physical device supports presentation to the platform GLFW was built for.
*
* If Vulkan or the required window surface creation instance extensions are
* not available on the machine, or if the specified instance was not created
* with the required extensions, this function returns `GLFW_FALSE` and
* generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported
* to check whether Vulkan is available and @ref
* glfwGetRequiredInstanceExtensions to check what instance extensions are
* required.
*
* @param[in] instance The instance that the physical device belongs to.
* @param[in] device The physical device that the queue family belongs to.
* @param[in] queuefamily The index of the queue family to query.
* @return `GLFW_TRUE` if the queue family supports presentation, or
* `GLFW_FALSE` otherwise.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function may be called from any thread. For
* synchronization details of Vulkan objects, see the Vulkan specification.
*
* @sa @ref vulkan_present
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
/*! @brief Creates a Vulkan surface for the specified window.
*
* This function creates a Vulkan surface for the specified window.
*
* If the Vulkan loader was not found at initialization, this function returns
* `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE
* error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was
* found.
*
* If the required window surface creation instance extensions are not
* available or if the specified instance was not created with these extensions
* enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and
* generates a @ref GLFW_API_UNAVAILABLE error. Call @ref
* glfwGetRequiredInstanceExtensions to check what instance extensions are
* required.
*
* The window surface must be destroyed before the specified Vulkan instance.
* It is the responsibility of the caller to destroy the window surface. GLFW
* does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the
* surface.
*
* @param[in] instance The Vulkan instance to create the surface in.
* @param[in] window The window to create the surface for.
* @param[in] allocator The allocator to use, or `NULL` to use the default
* allocator.
* @param[out] surface Where to store the handle of the surface. This is set
* to `VK_NULL_HANDLE` if an error occurred.
* @return `VK_SUCCESS` if successful, or a Vulkan error code if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
*
* @remarks If an error occurs before the creation call is made, GLFW returns
* the Vulkan error code most appropriate for the error. Appropriate use of
* @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should
* elminiate almost all occurences of these errors.
*
* @thread_safety This function may be called from any thread. For
* synchronization details of Vulkan objects, see the Vulkan specification.
*
* @sa @ref vulkan_surface
* @sa glfwGetRequiredInstanceExtensions
*
* @since Added in version 3.2.
*
* @ingroup vulkan
*/
GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
#endif /*VK_VERSION_1_0*/
/*************************************************************************
* Global definition cleanup

View File

@ -3,7 +3,7 @@ set(common_HEADERS internal.h
"${GLFW_BINARY_DIR}/src/glfw_config.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h")
set(common_SOURCES context.c init.c input.c monitor.c window.c)
set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c)
if (_GLFW_COCOA)
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h

View File

@ -28,6 +28,7 @@
#define _glfw3_cocoa_platform_h_
#include <stdint.h>
#include <dlfcn.h>
#if defined(__OBJC__)
#import <Carbon/Carbon.h>
@ -47,6 +48,10 @@ typedef void* id;
#error "The Cocoa backend depends on NSGL platform support"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time

View File

@ -1322,6 +1322,27 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return _glfw.ns.clipboardString;
}
char** _glfwPlatformGetRequiredInstanceExtensions(int* count)
{
*count = 0;
return NULL;
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
unsigned int queuefamily)
{
return GLFW_FALSE;
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -28,17 +28,6 @@
#ifndef _glfw3_egl_context_h_
#define _glfw3_egl_context_h_
#if defined(_GLFW_WIN32)
#define _glfw_dlopen(name) LoadLibraryA(name)
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
#else
#include <dlfcn.h>
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#endif
#if defined(_GLFW_USE_EGLPLATFORM_H)
#include <EGL/eglplatform.h>
#elif defined(_GLFW_WIN32)

View File

@ -30,7 +30,6 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <dlfcn.h>
#ifndef GLXBadProfileARB
#define GLXBadProfileARB 13

View File

@ -130,6 +130,8 @@ GLFWAPI int glfwInit(void)
return GLFW_FALSE;
}
_glfwInitVulkan();
_glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
_glfwInitialized = GLFW_TRUE;
@ -161,6 +163,8 @@ GLFWAPI void glfwTerminate(void)
_glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
}
_glfwTerminateVulkan();
_glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount);
_glfw.monitors = NULL;
_glfw.monitorCount = 0;

View File

@ -47,6 +47,26 @@
#define GLFW_INCLUDE_NONE
#include "../include/GLFW/glfw3.h"
#include <stddef.h>
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef unsigned __int64 GLFWuint64;
#else
#include <stdint.h>
typedef uint64_t GLFWuint64;
#endif
typedef int GLFWbool;
typedef struct _GLFWwndconfig _GLFWwndconfig;
typedef struct _GLFWctxconfig _GLFWctxconfig;
typedef struct _GLFWfbconfig _GLFWfbconfig;
typedef struct _GLFWcontext _GLFWcontext;
typedef struct _GLFWwindow _GLFWwindow;
typedef struct _GLFWlibrary _GLFWlibrary;
typedef struct _GLFWmonitor _GLFWmonitor;
typedef struct _GLFWcursor _GLFWcursor;
#define GL_VERSION 0x1f02
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
@ -76,16 +96,66 @@ typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGIPROC)(GLenum,GLuint);
typedef struct _GLFWwndconfig _GLFWwndconfig;
typedef struct _GLFWctxconfig _GLFWctxconfig;
typedef struct _GLFWfbconfig _GLFWfbconfig;
typedef struct _GLFWcontext _GLFWcontext;
typedef struct _GLFWwindow _GLFWwindow;
typedef struct _GLFWlibrary _GLFWlibrary;
typedef struct _GLFWmonitor _GLFWmonitor;
typedef struct _GLFWcursor _GLFWcursor;
#define VK_NULL_HANDLE 0
typedef int GLFWbool;
typedef GLFWuint64 VkInstance;
typedef GLFWuint64 VkPhysicalDevice;
typedef GLFWuint64 VkSurfaceKHR;
typedef unsigned int VkFlags;
typedef unsigned int VkBool32;
typedef enum VkStructureType
{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
typedef enum VkResult
{
VK_SUCCESS = 0,
VK_NOT_READY = 1,
VK_TIMEOUT = 2,
VK_EVENT_SET = 3,
VK_EVENT_RESET = 4,
VK_INCOMPLETE = 5,
VK_ERROR_OUT_OF_HOST_MEMORY = -1,
VK_ERROR_OUT_OF_DEVICE_MEMORY = -2,
VK_ERROR_INITIALIZATION_FAILED = -3,
VK_ERROR_DEVICE_LOST = -4,
VK_ERROR_MEMORY_MAP_FAILED = -5,
VK_ERROR_LAYER_NOT_PRESENT = -6,
VK_ERROR_EXTENSION_NOT_PRESENT = -7,
VK_ERROR_FEATURE_NOT_PRESENT = -8,
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
VK_SUBOPTIMAL_KHR = 1000001003,
VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_RESULT_MAX_ENUM = 0x7FFFFFFF
} VkResult;
typedef struct VkAllocationCallbacks VkAllocationCallbacks;
typedef struct VkExtensionProperties
{
char extensionName[256];
unsigned int specVersion;
} VkExtensionProperties;
typedef void (APIENTRY * PFN_vkVoidFunction)(void);
typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,unsigned int*,VkExtensionProperties*);
#define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
#if defined(_GLFW_COCOA)
#include "cocoa_platform.h"
@ -363,6 +433,21 @@ struct _GLFWlibrary
_GLFWmonitor** monitors;
int monitorCount;
struct {
GLFWbool available;
void* handle;
char** extensions;
int extensionCount;
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
GLFWbool KHR_surface;
GLFWbool KHR_win32_surface;
GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface;
GLFWbool KHR_wayland_surface;
GLFWbool KHR_mir_surface;
} vk;
struct {
GLFWmonitorfun monitor;
} callbacks;
@ -686,6 +771,18 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
*/
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
/*! @ingroup platform
*/
char** _glfwPlatformGetRequiredInstanceExtensions(int* count);
/*! @ingroup platform
*/
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, unsigned int queuefamily);
/*! @ingroup platform
*/
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
//========================================================================
// Event API functions
@ -920,4 +1017,16 @@ void _glfwFreeMonitors(_GLFWmonitor** monitors, int count);
*/
GLFWbool _glfwIsPrintable(int key);
/*! @ingroup utility
*/
void _glfwInitVulkan(void);
/*! @ingroup utility
*/
void _glfwTerminateVulkan(void);
/*! @ingroup utility
*/
const char* _glfwGetVulkanResultString(VkResult result);
#endif // _glfw3_internal_h_

View File

@ -29,9 +29,24 @@
#include <sys/queue.h>
#include <pthread.h>
#include <dlfcn.h>
#include <mir_toolkit/mir_client_library.h>
typedef VkFlags VkMirSurfaceCreateFlagsKHR;
typedef struct VkMirSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkMirSurfaceCreateFlagsKHR flags;
MirConnection* connection;
MirSurface* mirSurface;
} VkMirSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*);
#include "posix_tls.h"
#include "posix_time.h"
#include "linux_joystick.h"
@ -43,6 +58,10 @@
#error "The Mir backend depends on EGL platform support"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.window)
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display)

View File

@ -706,6 +706,76 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return NULL;
}
char** _glfwPlatformGetRequiredInstanceExtensions(int* count)
{
char** extensions;
*count = 0;
if (!_glfw.vk.KHR_mir_surface)
return NULL;
extensions = calloc(2, sizeof(char*));
extensions[0] = strdup("VK_KHR_surface");
extensions[1] = strdup("VK_KHR_mir_surface");
*count = 2;
return extensions;
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
unsigned int queuefamily)
{
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR =
(PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
return GLFW_FALSE;
}
return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
queuefamily,
_glfw.mir.connection);
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
VkResult err;
VkMirSurfaceCreateInfoKHR sci;
PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)
vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR");
if (!vkCreateMirSurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
sci.display = _glfw.mir.connection;
sci.surface = window->mir.surface;
err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Mir: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

287
src/vulkan.c Normal file
View File

@ -0,0 +1,287 @@
//========================================================================
// GLFW 3.2 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwInitVulkan(void)
{
VkResult err;
VkExtensionProperties* ep;
unsigned int i, count;
#if defined(_GLFW_WIN32)
const char* name = "vulkan-1.dll";
#else
const char* name = "libvulkan.so.1";
#endif
_glfw.vk.handle = _glfw_dlopen(name);
if (!_glfw.vk.handle)
return;
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
if (!_glfw.vk.GetInstanceProcAddr)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Loader does not export vkGetInstanceProcAddr");
return;
}
_glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
vkGetInstanceProcAddr(0, "vkEnumerateInstanceExtensionProperties");
if (!_glfw.vk.EnumerateInstanceExtensionProperties)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
return;
}
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Vulkan: Failed to query instance extension count: %s",
_glfwGetVulkanResultString(err));
return;
}
ep = calloc(count, sizeof(VkExtensionProperties));
err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Vulkan: Failed to query instance extensions: %s",
_glfwGetVulkanResultString(err));
free(ep);
return;
}
for (i = 0; i < count; i++)
{
if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
_glfw.vk.KHR_surface = GLFW_TRUE;
if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
_glfw.vk.KHR_mir_surface = GLFW_TRUE;
}
free(ep);
_glfw.vk.available = GLFW_TRUE;
if (!_glfw.vk.KHR_surface)
return;
_glfw.vk.extensions =
_glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount);
}
void _glfwTerminateVulkan(void)
{
int i;
for (i = 0; i < _glfw.vk.extensionCount; i++)
free(_glfw.vk.extensions[i]);
free(_glfw.vk.extensions);
if (_glfw.vk.handle)
_glfw_dlclose(_glfw.vk.handle);
}
const char* _glfwGetVulkanResultString(VkResult result)
{
switch (result)
{
case VK_SUCCESS:
return "Success";
case VK_NOT_READY:
return "A fence or query has not yet completed";
case VK_TIMEOUT:
return "A wait operation has not completed in the specified time";
case VK_EVENT_SET:
return "An event is signaled";
case VK_EVENT_RESET:
return "An event is unsignaled";
case VK_INCOMPLETE:
return "A return array was too small for the result";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "A host memory allocation has failed";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "A device memory allocation has failed";
case VK_ERROR_INITIALIZATION_FAILED:
return "Initialization of an object could not be completed for implementation-specific reasons";
case VK_ERROR_DEVICE_LOST:
return "The logical or physical device has been lost";
case VK_ERROR_MEMORY_MAP_FAILED:
return "Mapping of a memory object has failed";
case VK_ERROR_LAYER_NOT_PRESENT:
return "A requested layer is not present or could not be loaded";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "A requested extension is not supported";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "A requested feature is not supported";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
case VK_ERROR_TOO_MANY_OBJECTS:
return "Too many objects of the type have already been created";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "A requested format is not supported on this device";
case VK_ERROR_SURFACE_LOST_KHR:
return "A surface is no longer available";
case VK_SUBOPTIMAL_KHR:
return "A swapchain no longer matches the surface properties exactly, but can still be used";
case VK_ERROR_OUT_OF_DATE_KHR:
return "A surface has changed in such a way that it is no longer compatible with the swapchain";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "The display used by a swapchain does not use the same presentable image layout";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "A validation layer found an error";
default:
return "ERROR: UNKNOWN VULKAN ERROR TOKEN";
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwVulkanSupported(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
return _glfw.vk.available;
}
GLFWAPI const char** glfwGetRequiredInstanceExtensions(int* count)
{
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfw.vk.available)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return NULL;
}
*count = _glfw.vk.extensionCount;
return (const char**) _glfw.vk.extensions;
}
GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
const char* procname)
{
GLFWvkproc proc;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfw.vk.available)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return NULL;
}
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
if (!proc)
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
return proc;
}
GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!_glfw.vk.available)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return GLFW_FALSE;
}
if (!_glfw.vk.extensions)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Window surface creation extensions not found");
return GLFW_FALSE;
}
return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
device,
queuefamily);
}
GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
GLFWwindow* handle,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window);
assert(surface);
*surface = VK_NULL_HANDLE;
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
if (!_glfw.vk.available)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return VK_ERROR_INITIALIZATION_FAILED;
}
if (!_glfw.vk.extensions)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Window surface creation extensions not found");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
}

View File

@ -140,6 +140,20 @@ typedef HRESULT (WINAPI * DWMFLUSH_T)(VOID);
typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
typedef struct VkWin32SurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkWin32SurfaceCreateFlagsKHR flags;
HINSTANCE hinstance;
HWND hwnd;
} VkWin32SurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
#include "win32_joystick.h"
#if defined(_GLFW_WGL)
@ -154,6 +168,10 @@ typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
#define _GLFW_WNDCLASSNAME L"GLFW30"
#define _glfw_dlopen(name) LoadLibraryA(name)
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time

View File

@ -1403,6 +1403,74 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return _glfw.win32.clipboardString;
}
char** _glfwPlatformGetRequiredInstanceExtensions(int* count)
{
char** extensions;
*count = 0;
if (!_glfw.vk.KHR_win32_surface)
return NULL;
extensions = calloc(2, sizeof(char*));
extensions[0] = strdup("VK_KHR_surface");
extensions[1] = strdup("VK_KHR_win32_surface");
*count = 2;
return extensions;
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
unsigned int queuefamily)
{
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR =
(PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Win32: Vulkan instance missing VK_KHR_win32_surface extension");
return GLFW_FALSE;
}
return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
VkResult err;
VkWin32SurfaceCreateInfoKHR sci;
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
if (!vkCreateWin32SurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Win32: Vulkan instance missing VK_KHR_win32_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
sci.hinstance = GetModuleHandle(NULL);
sci.hwnd = window->win32.handle;
err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -29,6 +29,21 @@
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <dlfcn.h>
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
typedef struct VkWaylandSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkWaylandSurfaceCreateFlagsKHR flags;
struct wl_display* display;
struct wl_surface* surface;
} VkWaylandSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
#include "posix_tls.h"
#include "posix_time.h"
@ -41,6 +56,10 @@
#error "The Wayland backend depends on EGL platform support"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native)
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display)
@ -75,6 +94,7 @@ typedef struct _GLFWwindowWayland
_GLFWmonitor** monitors;
int monitorsCount;
int monitorsSize;
} _GLFWwindowWayland;

View File

@ -699,6 +699,76 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return NULL;
}
char** _glfwPlatformGetRequiredInstanceExtensions(int* count)
{
char** extensions;
*count = 0;
if (!_glfw.vk.KHR_wayland_surface)
return NULL;
extensions = calloc(2, sizeof(char*));
extensions[0] = strdup("VK_KHR_surface");
extensions[1] = strdup("VK_KHR_wayland_surface");
*count = 2;
return extensions;
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
unsigned int queuefamily)
{
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR =
(PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR");
if (!vkGetPhysicalDeviceWaylandPresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
return VK_NULL_HANDLE;
}
return vkGetPhysicalDeviceWaylandPresentationSupportKHR(device,
queuefamily,
_glfw.wl.display);
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
VkResult err;
VkWaylandSurfaceCreateInfoKHR sci;
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)
vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR");
if (!vkCreateWaylandSurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Wayland: Vulkan instance missing VK_KHR_wayland_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
sci.display = _glfw.wl.display;
sci.surface = window->wl.surface;
err = vkCreateWaylandSurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -581,6 +581,13 @@ static GLFWbool initExtensions(void)
}
}
_glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so", RTLD_LAZY | RTLD_GLOBAL);
if (_glfw.x11.x11xcb.handle)
{
_glfw.x11.x11xcb.XGetXCBConnection = (XGETXCBCONNECTION_T)
dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
}
// Update the key code LUT
// FIXME: We should listen to XkbMapNotify events to track changes to
// the keyboard mapping.
@ -789,6 +796,12 @@ int _glfwPlatformInit(void)
void _glfwPlatformTerminate(void)
{
if (_glfw.x11.x11xcb.handle)
{
dlclose(_glfw.x11.x11xcb.handle);
_glfw.x11.x11xcb.handle = NULL;
}
if (_glfw.x11.cursor)
{
XFreeCursor(_glfw.x11.display, _glfw.x11.cursor);

View File

@ -31,6 +31,7 @@
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <dlfcn.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
@ -56,6 +57,37 @@
#include <X11/extensions/xf86vmode.h>
#endif
typedef XID xcb_window_t;
typedef XID xcb_visualid_t;
typedef struct xcb_connection_t xcb_connection_t;
typedef xcb_connection_t* (* XGETXCBCONNECTION_T)(Display*);
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
typedef struct VkXlibSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkXlibSurfaceCreateFlagsKHR flags;
Display* dpy;
Window window;
} VkXlibSurfaceCreateInfoKHR;
typedef struct VkXcbSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkXcbSurfaceCreateFlagsKHR flags;
xcb_connection_t* connection;
xcb_window_t window;
} VkXcbSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID);
typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
#include "posix_tls.h"
#include "posix_time.h"
#include "linux_joystick.h"
@ -71,6 +103,10 @@
#error "No supported context creation API selected"
#endif
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
#define _glfw_dlclose(handle) dlclose(handle)
#define _glfw_dlsym(handle, name) dlsym(handle, name)
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
@ -207,6 +243,11 @@ typedef struct _GLFWlibraryX11
int minor;
} xinerama;
struct {
void* handle;
XGETXCBCONNECTION_T XGetXCBConnection;
} x11xcb;
#if defined(_GLFW_HAS_XINPUT)
struct {
GLFWbool available;

View File

@ -1470,13 +1470,21 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
Visual* visual;
int depth;
if (ctxconfig->api == GLFW_NO_API)
{
visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen);
depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen);
}
else
{
#if defined(_GLFW_GLX)
if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE;
if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE;
#elif defined(_GLFW_EGL)
if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE;
if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE;
#endif
}
if (!createWindow(window, wndconfig, visual, depth))
return GLFW_FALSE;
@ -2109,6 +2117,158 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return _glfw.x11.clipboardString;
}
char** _glfwPlatformGetRequiredInstanceExtensions(int* count)
{
char** extensions;
*count = 0;
if (!_glfw.vk.KHR_xlib_surface)
{
if (!_glfw.vk.KHR_xcb_surface || !_glfw.x11.x11xcb.handle)
return NULL;
}
extensions = calloc(2, sizeof(char*));
extensions[0] = strdup("VK_KHR_surface");
if (_glfw.vk.KHR_xlib_surface)
extensions[1] = strdup("VK_KHR_xlib_surface");
else
extensions[1] = strdup("VK_KHR_xcb_surface");
*count = 2;
return extensions;
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
unsigned int queuefamily)
{
VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display,
_glfw.x11.screen));
if (_glfw.vk.KHR_xlib_surface)
{
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR =
(PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR");
if (!vkGetPhysicalDeviceXlibPresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"X11: Vulkan instance missing VK_KHR_xlib_surface extension");
return GLFW_FALSE;
}
return vkGetPhysicalDeviceXlibPresentationSupportKHR(device,
queuefamily,
_glfw.x11.display,
visualID);
}
else
{
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR =
(PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
if (!vkGetPhysicalDeviceXcbPresentationSupportKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"X11: Vulkan instance missing VK_KHR_xcb_surface extension");
return GLFW_FALSE;
}
xcb_connection_t* connection =
_glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display);
if (!connection)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to retrieve XCB connection");
return GLFW_FALSE;
}
return vkGetPhysicalDeviceXcbPresentationSupportKHR(device,
queuefamily,
connection,
visualID);
}
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
if (_glfw.vk.KHR_xlib_surface)
{
VkResult err;
VkXlibSurfaceCreateInfoKHR sci;
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR)
vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR");
if (!vkCreateXlibSurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"X11: Vulkan instance missing VK_KHR_xlib_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
sci.dpy = _glfw.x11.display;
sci.window = window->x11.handle;
err = vkCreateXlibSurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create Vulkan X11 surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
else
{
VkResult err;
VkXcbSurfaceCreateInfoKHR sci;
PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
xcb_connection_t* connection =
_glfw.x11.x11xcb.XGetXCBConnection(_glfw.x11.display);
if (!connection)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to retrieve XCB connection");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR)
vkGetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR");
if (!vkCreateXcbSurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"X11: Vulkan instance missing VK_KHR_xcb_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
sci.connection = connection;
sci.window = window->x11.handle;
err = vkCreateXcbSurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create Vulkan XCB surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -43,6 +43,13 @@ set(WINDOWS_BINARIES empty sharing tearing threads title windows)
set(CONSOLE_BINARIES clipboard events msaa gamma glfwinfo
iconify joysticks monitors reopen cursor)
if (VULKAN_FOUND)
add_executable(vulkan WIN32 vulkan.c ${ICON})
target_include_directories(vulkan PRIVATE "${VULKAN_INCLUDE_DIR}")
target_link_libraries(vulkan "${VULKAN_LIBRARY}")
list(APPEND WINDOWS_BINARIES vulkan)
endif()
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
FOLDER "GLFW3/Tests")

View File

@ -24,6 +24,7 @@
//========================================================================
#include <glad/glad.h>
#include <vulkan/vulkan.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
@ -61,7 +62,8 @@ static void usage(void)
printf(" -d, --debug request a debug context\n");
printf(" -f, --forward require a forward-compatible context\n");
printf(" -h, --help show this help\n");
printf(" -l, --list-extensions list all client API extensions\n");
printf(" -l, --list-extensions list all Vulkan and client API extensions\n");
printf(" --list-layers list all Vulkan layers\n");
printf(" -m, --major=MAJOR the major number of the required "
"client API version\n");
printf(" -n, --minor=MINOR the minor number of the required "
@ -96,6 +98,22 @@ static void error_callback(int error, const char* description)
fprintf(stderr, "Error: %s\n", description);
}
static const char* get_device_type_name(VkPhysicalDeviceType type)
{
if (type == VK_PHYSICAL_DEVICE_TYPE_OTHER)
return "other";
else if (type == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
return "integrated GPU";
else if (type == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
return "discrete GPU";
else if (type == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
return "virtual GPU";
else if (type == VK_PHYSICAL_DEVICE_TYPE_CPU)
return "CPU";
return "unknown";
}
static const char* get_api_name(int api)
{
if (api == GLFW_OPENGL_API)
@ -146,13 +164,13 @@ static const char* get_strategy_name_glfw(int strategy)
return "unknown";
}
static void list_extensions(int api, int major, int minor)
static void list_context_extensions(int api, int major, int minor)
{
int i;
GLint count;
const GLubyte* extensions;
printf("%s context supported extensions:\n", get_api_name(api));
printf("%s context extensions:\n", get_api_name(api));
if (api == GLFW_OPENGL_API && major > 2)
{
@ -182,6 +200,124 @@ static void list_extensions(int api, int major, int minor)
}
}
static void list_vulkan_instance_extensions(void)
{
uint32_t i, ep_count = 0;
VkExtensionProperties* ep;
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties =
(PFN_vkEnumerateInstanceExtensionProperties)
glfwGetInstanceProcAddress(NULL, "vkEnumerateInstanceExtensionProperties");
printf("Vulkan instance extensions:\n");
if (vkEnumerateInstanceExtensionProperties(NULL, &ep_count, NULL) != VK_SUCCESS)
return;
ep = calloc(ep_count, sizeof(VkExtensionProperties));
if (vkEnumerateInstanceExtensionProperties(NULL, &ep_count, ep) != VK_SUCCESS)
{
free(ep);
return;
}
for (i = 0; i < ep_count; i++)
printf(" %s (v%u)\n", ep[i].extensionName, ep[i].specVersion);
free(ep);
}
static void list_vulkan_instance_layers(void)
{
uint32_t i, lp_count = 0;
VkLayerProperties* lp;
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties =
(PFN_vkEnumerateInstanceLayerProperties)
glfwGetInstanceProcAddress(NULL, "vkEnumerateInstanceLayerProperties");
printf("Vulkan instance layers:\n");
if (vkEnumerateInstanceLayerProperties(&lp_count, NULL) != VK_SUCCESS)
return;
lp = calloc(lp_count, sizeof(VkLayerProperties));
if (vkEnumerateInstanceLayerProperties(&lp_count, lp) != VK_SUCCESS)
{
free(lp);
return;
}
for (i = 0; i < lp_count; i++)
{
printf(" %s (v%u) \"%s\"\n",
lp[i].layerName,
lp[i].specVersion >> 22,
lp[i].description);
}
free(lp);
}
static void list_vulkan_device_extensions(VkInstance instance, VkPhysicalDevice device)
{
uint32_t i, ep_count;
VkExtensionProperties* ep;
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties =
(PFN_vkEnumerateDeviceExtensionProperties)
glfwGetInstanceProcAddress(instance, "vkEnumerateDeviceExtensionProperties");
printf("Vulkan device extensions:\n");
if (vkEnumerateDeviceExtensionProperties(device, NULL, &ep_count, NULL) != VK_SUCCESS)
return;
ep = calloc(ep_count, sizeof(VkExtensionProperties));
if (vkEnumerateDeviceExtensionProperties(device, NULL, &ep_count, ep) != VK_SUCCESS)
{
free(ep);
return;
}
for (i = 0; i < ep_count; i++)
printf(" %s (v%u)\n", ep[i].extensionName, ep[i].specVersion);
free(ep);
}
static void list_vulkan_device_layers(VkInstance instance, VkPhysicalDevice device)
{
uint32_t i, lp_count;
VkLayerProperties* lp;
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties =
(PFN_vkEnumerateDeviceLayerProperties)
glfwGetInstanceProcAddress(instance, "vkEnumerateDeviceLayerProperties");
printf("Vulkan device layers:\n");
if (vkEnumerateDeviceLayerProperties(device, &lp_count, NULL) != VK_SUCCESS)
return;
lp = calloc(lp_count, sizeof(VkLayerProperties));
if (vkEnumerateDeviceLayerProperties(device, &lp_count, lp) != VK_SUCCESS)
{
free(lp);
return;
}
for (i = 0; i < lp_count; i++)
{
printf(" %s (v%u) \"%s\"\n",
lp[i].layerName,
lp[i].specVersion >> 22,
lp[i].description);
}
free(lp);
}
static int valid_version(void)
{
int major, minor, revision;
@ -216,10 +352,10 @@ int main(int argc, char** argv)
{
int ch, api, major, minor, revision, profile;
GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits;
int list = GLFW_FALSE;
int list_extensions = GLFW_FALSE, list_layers = GLFW_FALSE;
GLFWwindow* window;
enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS,
enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS, LAYERS,
MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION,
REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS,
ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS,
@ -232,6 +368,7 @@ int main(int argc, char** argv)
{ "forward", 0, NULL, FORWARD },
{ "help", 0, NULL, HELP },
{ "list-extensions", 0, NULL, EXTENSIONS },
{ "list-layers", 0, NULL, LAYERS },
{ "major", 1, NULL, MAJOR },
{ "minor", 1, NULL, MINOR },
{ "profile", 1, NULL, PROFILE },
@ -314,7 +451,10 @@ int main(int argc, char** argv)
exit(EXIT_SUCCESS);
case 'l':
case EXTENSIONS:
list = GLFW_TRUE;
list_extensions = GLFW_TRUE;
break;
case LAYERS:
list_layers = GLFW_TRUE;
break;
case 'm':
case MAJOR:
@ -564,7 +704,7 @@ int main(int argc, char** argv)
glGetString(GL_SHADING_LANGUAGE_VERSION));
}
printf("Framebuffer:\n");
printf("%s framebuffer:\n", get_api_name(api));
if (api == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE)
{
@ -632,9 +772,103 @@ int main(int argc, char** argv)
accumredbits, accumgreenbits, accumbluebits, accumalphabits, auxbuffers);
}
// Report client API extensions
if (list)
list_extensions(api, major, minor);
if (list_extensions)
list_context_extensions(api, major, minor);
printf("Vulkan loader: %s\n",
glfwVulkanSupported() ? "available" : "missing");
if (glfwVulkanSupported())
{
uint32_t i, re_count, pd_count;
const char** re;
VkApplicationInfo ai = {0};
VkInstanceCreateInfo ici = {0};
VkInstance instance;
VkPhysicalDevice* pd;
PFN_vkCreateInstance vkCreateInstance = (PFN_vkCreateInstance)
glfwGetInstanceProcAddress(NULL, "vkCreateInstance");
PFN_vkDestroyInstance vkDestroyInstance;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
re = glfwGetRequiredInstanceExtensions((int*) &re_count);
printf("Vulkan required instance extensions:");
for (i = 0; i < re_count; i++)
printf(" %s", re[i]);
putchar('\n');
if (list_extensions)
{
list_vulkan_instance_extensions();
}
if (list_layers)
list_vulkan_instance_layers();
ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
ai.pApplicationName = "glfwinfo";
ai.applicationVersion = GLFW_VERSION_MAJOR;
ai.pEngineName = "GLFW";
ai.engineVersion = GLFW_VERSION_MAJOR;
ai.apiVersion = VK_API_VERSION;
ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
ici.pApplicationInfo = &ai;
ici.enabledExtensionCount = re_count;
ici.ppEnabledExtensionNames = re;
if (vkCreateInstance(&ici, NULL, &instance) != VK_SUCCESS)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
vkDestroyInstance = (PFN_vkDestroyInstance)
glfwGetInstanceProcAddress(instance, "vkDestroyInstance");
vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)
glfwGetInstanceProcAddress(instance, "vkEnumeratePhysicalDevices");
vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)
glfwGetInstanceProcAddress(instance, "vkGetPhysicalDeviceProperties");
if (vkEnumeratePhysicalDevices(instance, &pd_count, NULL) != VK_SUCCESS)
{
vkDestroyInstance(instance, NULL);
glfwTerminate();
exit(EXIT_FAILURE);
}
pd = calloc(pd_count, sizeof(VkPhysicalDevice));
if (vkEnumeratePhysicalDevices(instance, &pd_count, pd) != VK_SUCCESS)
{
free(pd);
vkDestroyInstance(instance, NULL);
glfwTerminate();
exit(EXIT_FAILURE);
}
for (i = 0; i < pd_count; i++)
{
VkPhysicalDeviceProperties pdp;
vkGetPhysicalDeviceProperties(pd[i], &pdp);
printf("Vulkan %s device: \"%s\"\n",
get_device_type_name(pdp.deviceType),
pdp.deviceName);
if (list_extensions)
list_vulkan_device_extensions(instance, pd[i]);
if (list_layers)
list_vulkan_device_layers(instance, pd[i]);
}
free(pd);
vkDestroyInstance(instance, NULL);
}
glfwTerminate();
exit(EXIT_SUCCESS);

2240
tests/vulkan.c Normal file

File diff suppressed because it is too large Load Diff