This commit is contained in:
Jan Ziak 2016-11-15 21:50:49 +01:00
commit a2f66a3966
55 changed files with 3330 additions and 592 deletions

View File

@ -0,0 +1,18 @@
# Try to find OSMesa on a Unix system
#
# This will define:
#
# OSMESA_LIBRARIES - Link these to use OSMesa
# OSMESA_INCLUDE_DIR - Include directory for OSMesa
#
# Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
if (NOT WIN32)
find_package (PkgConfig)
pkg_check_modules (PKG_OSMESA QUIET osmesa)
set (OSMESA_INCLUDE_DIR ${PKG_OSMESA_INCLUDE_DIRS})
set (OSMESA_LIBRARIES ${PKG_OSMESA_LIBRARIES})
endif ()

View File

@ -20,6 +20,13 @@ if (WIN32)
"$ENV{VULKAN_SDK}/Bin32"
"$ENV{VK_SDK_PATH}/Bin32")
endif()
elseif (APPLE)
find_library(VULKAN_LIBRARY MoltenVK)
if (VULKAN_LIBRARY)
set(VULKAN_STATIC_LIBRARY ${VULKAN_LIBRARY})
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS
"${VULKAN_LIBRARY}/Headers")
endif()
else()
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS
"$ENV{VULKAN_SDK}/include")

View File

@ -28,6 +28,10 @@ option(GLFW_INSTALL "Generate installation target" ON)
option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF)
option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF)
if (UNIX)
option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF)
endif()
if (WIN32)
option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF)
endif()
@ -129,26 +133,36 @@ if (MINGW)
endif()
endif()
if (APPLE)
# Dependencies required by the MoltenVK static library
set(GLFW_VULKAN_DEPS
"-lc++"
"-framework Cocoa"
"-framework Metal"
"-framework QuartzCore")
endif()
#--------------------------------------------------------------------
# Detect and select backend APIs
#--------------------------------------------------------------------
if (WIN32)
if (GLFW_USE_WAYLAND)
set(_GLFW_WAYLAND 1)
message(STATUS "Using Wayland for window creation")
elseif (GLFW_USE_MIR)
set(_GLFW_MIR 1)
message(STATUS "Using Mir for window creation")
elseif (GLFW_USE_OSMESA)
set(_GLFW_OSMESA 1)
message(STATUS "Using OSMesa for headless context creation")
elseif (WIN32)
set(_GLFW_WIN32 1)
message(STATUS "Using Win32 for window creation")
elseif (APPLE)
set(_GLFW_COCOA 1)
message(STATUS "Using Cocoa for window creation")
elseif (UNIX)
if (GLFW_USE_WAYLAND)
set(_GLFW_WAYLAND 1)
message(STATUS "Using Wayland for window creation")
elseif (GLFW_USE_MIR)
set(_GLFW_MIR 1)
message(STATUS "Using Mir for window creation")
else()
set(_GLFW_X11 1)
message(STATUS "Using X11 for window creation")
endif()
set(_GLFW_X11 1)
message(STATUS "Using X11 for window creation")
else()
message(FATAL_ERROR "No supported platform was detected")
endif()
@ -158,7 +172,10 @@ endif()
#--------------------------------------------------------------------
if (GLFW_VULKAN_STATIC)
if (VULKAN_FOUND AND VULKAN_STATIC_LIBRARY)
list(APPEND glfw_LIBRARIES ${VULKAN_STATIC_LIBRARY})
list(APPEND glfw_LIBRARIES ${VULKAN_STATIC_LIBRARY} ${GLFW_VULKAN_DEPS})
if (BUILD_SHARED_LIBS)
message(WARNING "Linking Vulkan loader static library into GLFW")
endif()
else()
if (BUILD_SHARED_LIBS OR GLFW_BUILD_EXAMPLES OR GLFW_BUILD_TESTS)
message(FATAL_ERROR "Vulkan loader static library not found")
@ -306,6 +323,14 @@ if (_GLFW_MIR)
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}")
endif()
#--------------------------------------------------------------------
# Use OSMesa for offscreen context creation
#--------------------------------------------------------------------
if (_GLFW_OSMESA)
find_package(OSMesa REQUIRED)
list(APPEND glfw_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
endif()
#--------------------------------------------------------------------
# Use Cocoa for window creation and NSOpenGL for context creation
#--------------------------------------------------------------------
@ -323,19 +348,11 @@ if (_GLFW_COCOA)
set(_GLFW_USE_RETINA 1)
endif()
# Set up library and include paths
find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit)
find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation)
find_library(CORE_VIDEO_FRAMEWORK CoreVideo)
mark_as_advanced(COCOA_FRAMEWORK
IOKIT_FRAMEWORK
CORE_FOUNDATION_FRAMEWORK
CORE_VIDEO_FRAMEWORK)
list(APPEND glfw_LIBRARIES "${COCOA_FRAMEWORK}"
"${IOKIT_FRAMEWORK}"
"${CORE_FOUNDATION_FRAMEWORK}"
"${CORE_VIDEO_FRAMEWORK}")
list(APPEND glfw_LIBRARIES
"-framework Cocoa"
"-framework IOKit"
"-framework CoreFoundation"
"-framework CoreVideo")
set(glfw_PKG_DEPS "")
set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo")

View File

@ -36,7 +36,7 @@ does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or
rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them.
GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and
MinGW-w64, on OS X with Clang and on Linux and other Unix-like systems with GCC
MinGW-w64, on macOS with Clang and on Linux and other Unix-like systems with GCC
and Clang. It will likely compile in other environments as well, but this is
not regularly tested.
@ -81,6 +81,7 @@ located in the `deps/` directory.
- [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in
examples
- [Nuklear](https://github.com/vurtun/nuklear) for test and example UI
- [stb\_image\_write](https://github.com/nothings/stb) for writing images to disk
- [Vulkan headers](https://www.khronos.org/registry/vulkan/) for Vulkan tests
The Vulkan example additionally requires the Vulkan SDK to be installed, or it
@ -104,10 +105,17 @@ information on what to include when reporting a bug.
scancodes for keys (#830)
- Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for
receiving window maximization events (#778)
- Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#281,#850)
- Added definition of `GLAPIENTRY` to public header
- Bugfix: Calling `glfwMaximizeWindow` on a full screen window was not ignored
- Bugfix: `GLFW_INCLUDE_VULKAN` could not be combined with the corresponding
OpenGL and OpenGL ES header macros
- Bugfix: `glfwGetInstanceProcAddress` returned `NULL` for
`vkGetInstanceProcAddr` when `_GLFW_VULKAN_STATIC` was enabled
- [Win32] Bugfix: Undecorated windows could not be iconified by the user (#861)
- [Cocoa] Added support for Vulkan window surface creation via MoltenVK (#870)
- [Cocoa] Bugfix: Disabling window aspect ratio would assert (#852)
- [Cocoa] Bugfix: Window creation failed to set first responder (#876,#883)
- [EGL] Added support for `EGL_KHR_get_all_proc_addresses` (#871)
@ -149,6 +157,7 @@ skills.
- Lambert Clara
- Andrew Corrigan
- Noel Cower
- Jason Daly
- Jarrod Davis
- Olivier Delannoy
- Paul R. Deppe
@ -160,6 +169,7 @@ skills.
- Siavash Eliasi
- Michael Fogleman
- Gerald Franz
- Mário Freitas
- GeO4d
- Marcus Geelnard
- Eloi Marín Gratacós

1048
deps/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load Diff

4
deps/tinycthread.h vendored
View File

@ -123,7 +123,9 @@ typedef int _tthread_clockid_t;
/* Emulate clock_gettime */
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts);
#define clock_gettime _tthread_clock_gettime
#define CLOCK_REALTIME 0
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#endif

View File

@ -202,8 +202,9 @@ ALIASES = "thread_safety=@par Thread safety\n" \
"errors=@par Errors\n" \
"glfw3=@par\n__GLFW 3:__" \
"x11=__X11:__" \
"wayland=__Wayland:__" \
"win32=__Windows:__" \
"osx=__OS X:__"
"macos=__macOS:__"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
@ -1576,6 +1577,7 @@ PREDEFINED = GLFWAPI= \
GLFW_EXPOSE_NATIVE_COCOA \
GLFW_EXPOSE_NATIVE_NSGL \
GLFW_EXPOSE_NATIVE_EGL \
GLFW_EXPOSE_NATIVE_OSMESA \
VK_VERSION_1_0
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then

View File

@ -65,7 +65,7 @@ The following macros control which OpenGL or OpenGL ES API header is included.
Only one of these may be defined at a time.
`GLFW_INCLUDE_GLCOREARB` makes the GLFW header include the modern
`GL/glcorearb.h` header (`OpenGL/gl3.h` on OS X) instead of the regular OpenGL
`GL/glcorearb.h` header (`OpenGL/gl3.h` on macOS) instead of the regular OpenGL
header.
`GLFW_INCLUDE_ES1` makes the GLFW header include the OpenGL ES 1.x `GLES/gl.h`
@ -84,7 +84,7 @@ header instead of the regular OpenGL header.
header. This is useful in combination with an extension loading library.
If none of the above inclusion macros are defined, the standard OpenGL `GL/gl.h`
header (`OpenGL/gl.h` on OS X) is included.
header (`OpenGL/gl.h` on macOS) is included.
The following macros control the inclusion of additional API headers. Any
number of these may be defined simultaneously, and/or together with one of the
@ -119,7 +119,7 @@ a shared library / dynamic library / DLL then it takes care of these links.
However, if you are using GLFW as a static library then your executable will
need to link against these libraries.
On Windows and OS X, the list of system libraries is static and can be
On Windows and macOS, the list of system libraries is static and can be
hard-coded into your build environment. See the section for your development
environment below. On Linux and other Unix-like operating systems, the list
varies but can be retrieved in various ways as described below.
@ -289,7 +289,7 @@ env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog my
@endcode
The dependencies do not include OpenGL or GLU, as GLFW loads any OpenGL, OpenGL
ES or Vulkan libraries it needs at runtime and does not use GLU. On OS X, GLU
ES or Vulkan libraries it needs at runtime and does not use GLU. On macOS, GLU
is built into the OpenGL framework, so if you need GLU you don't need to do
anything extra. If you need GLU and are using Linux or BSD, you should add the
`glu` pkg-config package.
@ -309,7 +309,7 @@ cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --static --lib
@endcode
@subsection build_link_xcode With Xcode on OS X
@subsection build_link_xcode With Xcode on macOS
If you are using the dynamic library version of GLFW, simply add it to the
project dependencies.
@ -319,10 +319,10 @@ OpenGL, IOKit and CoreVideo frameworks to the project as dependencies. They can
all be found in `/System/Library/Frameworks`.
@subsection build_link_osx With command-line on OS X
@subsection build_link_osx With command-line on macOS
It is recommended that you use [pkg-config](@ref build_link_pkgconfig) when
building from the command line on OS X. That way you will get any new
building from the command line on macOS. That way you will get any new
dependencies added automatically. If you still wish to build manually, you need
to add the required frameworks and libraries to your command-line yourself using
the `-l` and `-framework` switches.
@ -342,6 +342,6 @@ against it from the command-line.
The OpenGL framework contains both the OpenGL and GLU APIs, so there is nothing
special to do when using GLU. Also note that even though your machine may have
`libGL`-style OpenGL libraries, they are for use with the X Window System and
will _not_ work with the OS X native version of GLFW.
will _not_ work with the macOS native version of GLFW.
*/

View File

@ -160,7 +160,7 @@ extensions to provide support for sRGB framebuffers. Where both of these
extension are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect.
@section compat_osx OpenGL 3.2 and later on OS X
@section compat_osx OpenGL 3.2 and later on macOS
Support for OpenGL 3.2 and above was introduced with OS X 10.7 and even then
only forward-compatible, core profile contexts are supported. Support for
@ -185,10 +185,11 @@ a non-default value will cause @ref glfwCreateWindow to fail and the
@section compat_vulkan Vulkan loader and API
GLFW uses the standard system-wide 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.
By default, GLFW uses the standard system-wide Vulkan loader to access the
Vulkan API on all platforms except macOS. This is installed by both graphics
drivers and Vulkan SDKs. If the loader is not found, @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
@ -201,6 +202,11 @@ 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 `VK_MVK_macos_surface` extensions to create
surfaces on macOS. 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
@ -217,8 +223,4 @@ 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

@ -14,7 +14,8 @@ GLFW uses [CMake](http://www.cmake.org/) to generate project files or makefiles
for a particular development environment. If you are on a Unix-like system such
as Linux or FreeBSD or have a package system like Fink, MacPorts, Cygwin or
Homebrew, you can simply install its CMake package. If not, you can download
installers for Windows and OS X from the [CMake website](http://www.cmake.org/).
installers for Windows and macOS from the
[CMake website](http://www.cmake.org/).
@note CMake only generates project files or makefiles. It does not compile the
actual GLFW library. To compile GLFW, first generate these files for your
@ -76,11 +77,11 @@ the CMake wiki.
Once you have this set up, move on to @ref compile_generate.
@subsubsection compile_deps_xcode Dependencies for Xcode on OS X
@subsubsection compile_deps_xcode Dependencies for Xcode on macOS
Xcode comes with all necessary tools except for CMake. The required headers
and libraries are included in the core OS X frameworks. Xcode can be downloaded
from the Mac App Store or from the ADC Member Center.
and libraries are included in the core macOS frameworks. Xcode can be
downloaded from the Mac App Store or from the ADC Member Center.
Once you have Xcode installed, move on to @ref compile_generate.
@ -96,6 +97,17 @@ Once you have installed the necessary packages, move on to @ref
compile_generate.
@subsection compile_deps_osmesa Dependencies for Linux and OSMesa
To compile GLFW for OSMesa, you need to install the OSMesa library and header
packages. For example, on Ubuntu and other distributions based on Debian
GNU/Linux, you need to install the `libosmesa6-dev` package. The OSMesa library
is required at runtime for context creation and is loaded on demand.
Once you have installed the necessary packages, move on to @ref
compile_generate.
@subsection compile_generate Generating build files with CMake
Once you have all necessary dependencies it is time to generate the project
@ -201,7 +213,7 @@ the library.
statically into the application.
@subsubsection compile_options_osx OS X specific CMake options
@subsubsection compile_options_osx macOS specific CMake options
`GLFW_USE_CHDIR` determines whether `glfwInit` changes the current
directory of bundled applications to the `Contents/Resources` directory.
@ -248,6 +260,7 @@ ramps and clipboard. The options are:
- `_GLFW_X11` to use the X Window System
- `_GLFW_WAYLAND` to use the Wayland API (experimental and incomplete)
- `_GLFW_MIR` to use the Mir API (experimental and incomplete)
- `_GLFW_OSMESA` to use the OSMesa API (headless and non-interactive)
If you are building GLFW as a shared library / dynamic library / DLL then you
must also define `_GLFW_BUILD_DLL`. Otherwise, you must not define it.

View File

@ -84,7 +84,7 @@ objects are recommended for rendering with such contexts.
You should still [process events](@ref events) as long as you have at least one
window, even if none of them are visible.
__OS X:__ The first time a window is created the menu bar is populated with
@macos The first time a window is created the menu bar is populated with
common commands like Hide, Quit and About. This is not desirable for example
when writing a command-line only application. The menu bar setup can be
disabled with a [compile-time option](@ref compile_options_osx).

View File

@ -572,7 +572,7 @@ The callback function receives the ID of the joystick that has been connected
and disconnected and the event that occurred.
@code
void joystick_callback(int joy, int event)
void joystick_callback(int jid, int event)
{
if (event == GLFW_CONNECTED)
{

View File

@ -16,6 +16,18 @@ GLFW now supports querying the platform dependent scancode of any key with
@ref glfwGetKeyScancode.
@subsection news_33_moltenvk Support for Vulkan on macOS via MoltenVK
GLFW now supports the `VK_MVK_macos_surface` window surface creation extension
provided by MoltenVK.
@subsection news_33_osmesa OSMesa backend for headless software rendering
GLFW now supports headless context creation and software rendering via OSMesa,
intended for automated testing. This backend does not provide input.
@section news_32 New features in 3.2
@ -293,11 +305,12 @@ through CMake options.
@subsection news_30_hidpi High-DPI support
GLFW now supports high-DPI monitors on both Windows and OS X, giving windows full
resolution framebuffers where other UI elements are scaled up. To achieve this,
@ref glfwGetFramebufferSize and @ref glfwSetFramebufferSizeCallback have been
added. These work with pixels, while the rest of the GLFW API works with screen
coordinates. This is important as OpenGL uses pixels, not screen coordinates.
GLFW now supports high-DPI monitors on both Windows and macOS, giving windows
full resolution framebuffers where other UI elements are scaled up. To achieve
this, @ref glfwGetFramebufferSize and @ref glfwSetFramebufferSizeCallback have
been added. These work with pixels, while the rest of the GLFW API works with
screen coordinates. This is important as OpenGL uses pixels, not screen
coordinates.
@subsection news_30_error Error callback

View File

@ -340,7 +340,7 @@ The program above can be found in the
[source package](http://www.glfw.org/download.html) as `examples/simple.c`
and is compiled along with all other examples when you build GLFW. If you
built GLFW from the source package then already have this as `simple.exe` on
Windows, `simple` on Linux or `simple.app` on OS X.
Windows, `simple` on Linux or `simple.app` on macOS.
This tutorial used only a few of the many functions GLFW provides. There are
guides for each of the areas covered by GLFW. Each guide will introduce all the

View File

@ -11,8 +11,10 @@ with Vulkan concepts like loaders, devices, queues and surfaces and leaves it to
the Vulkan documentation to explain the details of Vulkan functions.
To develop for Vulkan you should install an SDK for your platform, for example
the [LunarG Vulkan SDK](https://vulkan.lunarg.com/). Apart from the headers and
libraries, it also provides the validation layers necessary for development.
the [LunarG Vulkan SDK](https://vulkan.lunarg.com/) for Windows and Linux or
[MoltenVK](https://moltengl.com/moltenvk/) for macOS. Apart from headers and
link libraries, they should also provide the validation layers necessary for
development.
The GLFW library does not need the Vulkan SDK to enable support for Vulkan.
However, any Vulkan-specific test and example programs are built only if the
@ -28,6 +30,26 @@ are also guides for the other areas of the GLFW API.
- @ref input_guide
@section vulkan_loader Linking against the Vulkan loader
By default, GLFW will look for the Vulkan loader on demand at runtime via its
standard name (`vulkan-1.dll` on Windows, `libvulkan.so.1` on Linux and other
Unix-like systems). This means that GLFW does not need to be linked against the
loader. However, it also means that if you are using the static library form of
the Vulkan loader GLFW will either fail to find it or (worse) use the wrong one.
The [GLFW_VULKAN_STATIC](@ref compile_options_shared) CMake option makes GLFW
link directly against the static form. Not linking against the Vulkan loader
will then be a compile-time error.
@macos MoltenVK only provides the static library form of the Vulkan loader, but
GLFW is able to find it without
[GLFW_VULKAN_STATIC](@ref compile_options_shared) as long as it is linked into
any of the binaries already loaded into the process. As it is a static library,
you must also link against its dependencies: the `Cocoa`, `Metal` and
`QuartzCore` frameworks and the `libc++` library.
@section vulkan_include Including the Vulkan and GLFW header files
To include the Vulkan header, define [GLFW_INCLUDE_VULKAN](@ref build_macros)

View File

@ -258,7 +258,7 @@ create the context. Possible values are `GLFW_NATIVE_CONTEXT_API` and
requested, this hint is ignored.
@par
__OS X:__ The EGL API is not available on this platform and requests to use it
@macos The EGL API is not available on this platform and requests to use it
will fail.
@par

View File

@ -11,6 +11,10 @@ if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
if (GLFW_USE_OSMESA)
add_definitions(-DUSE_NATIVE_OSMESA)
endif()
include_directories("${GLFW_SOURCE_DIR}/deps")
if (WIN32)
@ -31,6 +35,7 @@ set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h"
add_executable(boing WIN32 MACOSX_BUNDLE boing.c ${ICON} ${GLAD})
add_executable(gears WIN32 MACOSX_BUNDLE gears.c ${ICON} ${GLAD})
add_executable(heightmap WIN32 MACOSX_BUNDLE heightmap.c ${ICON} ${GLAD})
add_executable(offscreen offscreen.c ${ICON} ${GLAD})
add_executable(particles WIN32 MACOSX_BUNDLE particles.c ${ICON} ${TINYCTHREAD} ${GETOPT} ${GLAD})
add_executable(simple WIN32 MACOSX_BUNDLE simple.c ${ICON} ${GLAD})
add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD})

171
examples/offscreen.c Normal file
View File

@ -0,0 +1,171 @@
//========================================================================
// Offscreen rendering example
// Copyright (c) Camilla Berglund <elmindreda@glfw.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 <glad/glad.h>
#include <GLFW/glfw3.h>
#if USE_NATIVE_OSMESA
#define GLFW_EXPOSE_NATIVE_OSMESA
#include <GLFW/glfw3native.h>
#endif
#include "linmath.h"
#include <stdlib.h>
#include <stdio.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
static const struct
{
float x, y;
float r, g, b;
} vertices[3] =
{
{ -0.6f, -0.4f, 1.f, 0.f, 0.f },
{ 0.6f, -0.4f, 0.f, 1.f, 0.f },
{ 0.f, 0.6f, 0.f, 0.f, 1.f }
};
static const char* vertex_shader_text =
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
int main(void)
{
GLFWwindow* window;
GLuint vertex_buffer, vertex_shader, fragment_shader, program;
GLint mvp_location, vpos_location, vcol_location;
float ratio;
int width, height;
mat4x4 mvp;
char* buffer;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
// NOTE: OpenGL error checks have been omitted for brevity
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
mvp_location = glGetUniformLocation(program, "MVP");
vpos_location = glGetAttribLocation(program, "vPos");
vcol_location = glGetAttribLocation(program, "vCol");
glEnableVertexAttribArray(vpos_location);
glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
sizeof(vertices[0]), (void*) 0);
glEnableVertexAttribArray(vcol_location);
glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
sizeof(vertices[0]), (void*) (sizeof(float) * 2));
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
mat4x4_ortho(mvp, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
glDrawArrays(GL_TRIANGLES, 0, 3);
#if USE_NATIVE_OSMESA
glfwGetOSMesaColorBuffer(window, &width, &height, NULL, (void**) &buffer);
#else
buffer = calloc(4, width * height);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#endif
// Write image Y-flipped because OpenGL
stbi_write_png("offscreen.png",
width, height, 4,
buffer + (width * 4 * (height - 1)),
-width * 4);
#if USE_NATIVE_OSMESA
// Here is where there's nothing
#else
free(buffer);
#endif
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}

View File

@ -101,6 +101,12 @@ extern "C" {
#endif
#endif /* APIENTRY */
/* Some OpenGL related headers use GLAPIENTRY instead.
*/
#ifndef GLAPIENTRY
#define GLAPIENTRY APIENTRY
#endif /* GLAPIENTRY */
/* Some Windows OpenGL headers need this.
*/
#if !defined(WINGDIAPI) && defined(_WIN32)
@ -116,7 +122,7 @@ extern "C" {
#endif /* CALLBACK */
/* Include because most Windows GLU headers need wchar_t and
* the OS X OpenGL header blocks the definition of ptrdiff_t by glext.h.
* the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h.
* Include it unconditionally to avoid surprising side-effects.
*/
#include <stddef.h>
@ -176,7 +182,11 @@ extern "C" {
#endif
#endif
#if defined(GLFW_INCLUDE_VULKAN)
#include <vulkan/vulkan.h>
#if defined(__APPLE__)
#include <MoltenVK/vulkan/vulkan.h>
#else
#include <vulkan/vulkan.h>
#endif
#endif
#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL)
@ -561,7 +571,7 @@ extern "C" {
* @par
* Some pre-installed Windows graphics drivers do not support OpenGL. AMD only
* 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
* a WGL or GLX extension. macOS does not provide OpenGL ES at all. The Mesa
* EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
* driver. Older graphics drivers do not support Vulkan.
*/
@ -1128,7 +1138,7 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
* This is the function signature for joystick configuration callback
* functions.
*
* @param[in] joy The joystick that was connected or disconnected.
* @param[in] jid The joystick that was connected or disconnected.
* @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
*
* @sa @ref joystick_event
@ -1247,7 +1257,7 @@ typedef struct GLFWimage
*
* @errors Possible errors include @ref GLFW_PLATFORM_ERROR.
*
* @remark @osx This function will change the current directory of the
* @remark @macos This function will change the current directory of the
* application to the `Contents/Resources` subdirectory of the application's
* bundle, if present. This can be disabled with a
* [compile-time option](@ref compile_options_osx).
@ -1621,6 +1631,9 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
*
* @remark @wayland Gamma handling is currently unavailable, this function will
* always emit @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref monitor_gamma
@ -1642,6 +1655,9 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Gamma handling is currently unavailable, this function will
* always return `NULL` and emit @ref GLFW_PLATFORM_ERROR.
*
* @pointer_lifetime The returned structure and its arrays are allocated and
* freed by GLFW. You should not free them yourself. They are valid until the
* specified monitor is disconnected, this function is called again for that
@ -1674,6 +1690,9 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
*
* @remark @win32 The gamma ramp size must be 256.
*
* @remark @wayland Gamma handling is currently unavailable, this function will
* always emit @ref GLFW_PLATFORM_ERROR.
*
* @pointer_lifetime The specified gamma ramp is copied before this function
* returns.
*
@ -1765,8 +1784,8 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* or _borderless full screen_ windows, see @ref window_windowed_full_screen.
*
* Once you have created the window, you can switch it between windowed and
* full screen mode with @ref glfwSetWindowMonitor. If the window has an
* OpenGL or OpenGL ES context, it will be unaffected.
* full screen mode with @ref glfwSetWindowMonitor. This will not affect its
* OpenGL or OpenGL ES context.
*
* By default, newly created windows use the placement recommended by the
* window system. To create the window at a specific position, make it
@ -1812,19 +1831,19 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* @remark @win32 The context to share resources with must not be current on
* any other thread.
*
* @remark @osx The GLFW window has no icon, as it is not a document
* @remark @macos The GLFW window has no icon, as it is not a document
* window, but the dock icon will be the same as the application bundle's icon.
* For more information on bundles, see the
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
* in the Mac Developer Library.
*
* @remark @osx The first time a window is created the menu bar is populated
* @remark @macos The first time a window is created the menu bar is populated
* with common commands like Hide, Quit and About. The About entry opens
* a minimal about dialog with information from the application's bundle. The
* menu bar can be disabled with a
* [compile-time option](@ref compile_options_osx).
*
* @remark @osx On OS X 10.10 and later the window frame will not be rendered
* @remark @macos On OS X 10.10 and later the window frame will not be rendered
* at full resolution on Retina displays unless the `NSHighResolutionCapable`
* key is enabled in the application bundle's `Info.plist`. For more
* information, see
@ -1841,6 +1860,20 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* query the final size, position or other attributes directly after window
* creation.
*
* @remark @wayland The window frame is currently unimplemented, as if
* `GLFW_DECORATED` was always set to `GLFW_FALSE`. A compositor can still
* emit close, resize or maximize events, using for example a keybind
* mechanism.
*
* @remark @wayland A full screen window will not attempt to change the mode,
* no matter what the requested size or refresh rate.
*
* @remark @wayland The wl_shell protocol does not support window
* icons, the window will inherit the one defined in the application's
* desktop file, so this function emits @ref GLFW_PLATFORM_ERROR.
*
* @remark @wayland Screensaver inhibition is currently unimplemented.
*
* @reentrancy This function must not be called from a callback.
*
* @thread_safety This function must only be called from the main thread.
@ -1936,7 +1969,7 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @osx The window title will not be updated until the next time you
* @remark @macos The window title will not be updated until the next time you
* process events.
*
* @thread_safety This function must only be called from the main thread.
@ -1973,12 +2006,16 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
* @pointer_lifetime The specified image data is copied before this function
* returns.
*
* @remark @osx The GLFW window has no icon, as it is not a document
* @remark @macos The GLFW window has no icon, as it is not a document
* window, so this function does nothing. The dock icon will be the same as
* the application bundle's icon. For more information on bundles, see the
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
* in the Mac Developer Library.
*
* @remark @wayland The wl_shell protocol does not support icons, the window
* will inherit the one defined in the application's desktop file, so this
* function emits @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_icon
@ -2006,6 +2043,10 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland There is no way for an application to retrieve the global
* position of its windows, this function will always emit @ref
* GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_pos
@ -2036,6 +2077,10 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland There is no way for an application to set the global
* position of its windows, this function will always emit @ref
* GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_pos
@ -2107,6 +2152,9 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
* @remark If you set size limits and an aspect ratio that conflict, the
* results are undefined.
*
* @remark @wayland The size limits will not be applied until the window is
* actually resized, either by the user or by the compositor.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_sizelimits
@ -2147,6 +2195,9 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe
* @remark If you set size limits and an aspect ratio that conflict, the
* results are undefined.
*
* @remark @wayland The aspect ratio will not be applied until the window is
* actually resized, either by the user or by the compositor.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_sizelimits
@ -2183,6 +2234,9 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland A full screen window will not attempt to change the mode,
* no matter what the requested size.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_size
@ -2252,6 +2306,10 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height)
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland The window frame is currently unimplemented, as if
* `GLFW_DECORATED` was always set to `GLFW_FALSE`, so the returned values
* will always be zero.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_size
@ -2276,6 +2334,9 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland There is no concept of iconification in wl_shell, this
* function will always emit @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_iconify
@ -2403,6 +2464,9 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland It is not possible for an application to bring its windows
* to front, this function will always emit @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_focus
@ -2453,7 +2517,7 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
*
* When a window transitions from full screen to windowed mode, this function
* restores any previous window settings such as whether it is decorated,
* floating, resizable, has size or aspect ratio limits, etc..
* floating, resizable, has size or aspect ratio limits, etc.
*
* @param[in] window The window whose monitor, size or video mode to set.
* @param[in] monitor The desired monitor, or `NULL` to set windowed mode.
@ -2471,6 +2535,16 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark The OpenGL or OpenGL ES context will not be destroyed or otherwise
* affected by any resizing or mode switching, although you may need to update
* your viewport if the framebuffer size has changed.
*
* @remark @wayland The desired window position is ignored, as there is no way
* for an application to set this property.
*
* @remark @wayland Setting the window to full screen will not attempt to
* change the mode, no matter what the requested size or refresh rate.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_monitor
@ -2575,6 +2649,9 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @wayland This callback will never be called, as there is no way for
* an application to know its global position.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_pos
@ -2629,8 +2706,8 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @osx Selecting Quit from the application menu will trigger the close
* callback for all windows.
* @remark @macos Selecting Quit from the application menu will trigger the
* close callback for all windows.
*
* @thread_safety This function must only be called from the main thread.
*
@ -2649,9 +2726,9 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi
* called when the client area of the window needs to be redrawn, for example
* if the window has been exposed after having been covered by another window.
*
* On compositing window systems such as Aero, Compiz or Aqua, where the window
* contents are saved off-screen, this callback may be called only very
* infrequently or never at all.
* On compositing window systems such as Aero, Compiz, Aqua or Wayland, where
* the window contents are saved off-screen, this callback may be called only
* very infrequently or never at all.
*
* @param[in] window The window whose callback to set.
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
@ -2713,6 +2790,9 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @wayland The wl_shell protocol has no concept of iconification,
* this callback will never be called.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_iconify
@ -3205,6 +3285,9 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland This function will only work when the cursor mode is
* `GLFW_CURSOR_DISABLED`, otherwise it will do nothing.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref cursor_pos
@ -3389,7 +3472,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
*
* The character callback behaves as system text input normally does and will
* not be called if modifier keys are held down that would prevent normal text
* input on that platform, for example a Super (Command) key on OS X or Alt key
* input on that platform, for example a Super (Command) key on macOS or Alt key
* on Windows. There is a
* [character with modifiers callback](@ref glfwSetCharModsCallback) that
* receives these events.
@ -3570,6 +3653,8 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @wayland File drop is currently unimplemented.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref path_drop
@ -3584,7 +3669,7 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
*
* This function returns whether the specified joystick is present.
*
* @param[in] joy The [joystick](@ref joysticks) to query.
* @param[in] jid The [joystick](@ref joysticks) to query.
* @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
@ -3598,7 +3683,7 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
*
* @ingroup input
*/
GLFWAPI int glfwJoystickPresent(int joy);
GLFWAPI int glfwJoystickPresent(int jid);
/*! @brief Returns the values of all axes of the specified joystick.
*
@ -3609,7 +3694,7 @@ GLFWAPI int glfwJoystickPresent(int joy);
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
*
* @param[in] joy The [joystick](@ref joysticks) to query.
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of axis values in the returned
* array. This is set to zero if the joystick is not present or an error
* occurred.
@ -3632,7 +3717,7 @@ GLFWAPI int glfwJoystickPresent(int joy);
*
* @ingroup input
*/
GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count);
/*! @brief Returns the state of all buttons of the specified joystick.
*
@ -3643,7 +3728,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
*
* @param[in] joy The [joystick](@ref joysticks) to query.
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of button states in the returned
* array. This is set to zero if the joystick is not present or an error
* occurred.
@ -3667,7 +3752,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
*
* @ingroup input
*/
GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
/*! @brief Returns the name of the specified joystick.
*
@ -3679,7 +3764,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
*
* @param[in] joy The [joystick](@ref joysticks) to query.
* @param[in] jid The [joystick](@ref joysticks) to query.
* @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
* is not present or an [error](@ref error_handling) occurred.
*
@ -3699,7 +3784,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
*
* @ingroup input
*/
GLFWAPI const char* glfwGetJoystickName(int joy);
GLFWAPI const char* glfwGetJoystickName(int jid);
/*! @brief Sets the joystick configuration callback.
*
@ -3735,6 +3820,8 @@ GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Clipboard is currently unimplemented.
*
* @pointer_lifetime The specified string is copied before this function
* returns.
*
@ -3763,6 +3850,8 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Clipboard is currently unimplemented.
*
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
* should not free it yourself. It is valid until the next call to @ref
* glfwGetClipboardString or @ref glfwSetClipboardString, or until the library
@ -4141,11 +4230,14 @@ GLFWAPI int glfwVulkanSupported(void);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_API_UNAVAILABLE.
*
* @remarks Additional extensions may be required by future versions of GLFW.
* @remark 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.
*
* @remark @macos This function currently only supports the
* `VK_MVK_macos_surface` extension from MoltenVK.
*
* @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.
@ -4226,6 +4318,10 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* p
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR.
*
* @remark @macos This function currently always returns `GLFW_TRUE`, as the
* `VK_MVK_macos_surface` extension does not provide
* a `vkGetPhysicalDevice*PresentationSupport` type function.
*
* @thread_safety This function may be called from any thread. For
* synchronization details of Vulkan objects, see the Vulkan specification.
*
@ -4270,11 +4366,17 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhys
* @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
* @remark 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
* eliminate almost all occurrences of these errors.
*
* @remark @macos This function currently only supports the
* `VK_MVK_macos_surface` extension from MoltenVK.
*
* @remark @macos This function creates and sets a `CAMetalLayer` instance for
* the window content view, which is required for MoltenVK to function.
*
* @thread_safety This function may be called from any thread. For
* synchronization details of Vulkan objects, see the Vulkan specification.
*

View File

@ -50,7 +50,7 @@ extern "C" {
* doing and how to fix problems caused by using them. If you don't, you
* shouldn't be using them.**
*
* Before the inclusion of @ref glfw3native.h, you may define exactly one
* Before the inclusion of @ref glfw3native.h, you may define zero or more
* window system API macro and zero or more context creation API macros.
*
* The chosen backends must match those the library was compiled for. Failure
@ -68,6 +68,7 @@ extern "C" {
* * `GLFW_EXPOSE_NATIVE_NSGL`
* * `GLFW_EXPOSE_NATIVE_GLX`
* * `GLFW_EXPOSE_NATIVE_EGL`
* * `GLFW_EXPOSE_NATIVE_OSMESA`
*
* These macros select which of the native access functions that are declared
* and which platform-specific headers to include. It is then up your (by
@ -114,6 +115,9 @@ extern "C" {
#if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
#include <GL/osmesa.h>
#endif
/*************************************************************************
@ -448,6 +452,62 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
/*! @brief Retrieves the color buffer associated with the specified window.
*
* @param[out] width Where to store the width of the color buffer, or `NULL`.
* @param[out] height Where to store the height of the color buffer, or `NULL`.
* @param[out] format Where to store the OSMesa pixel format of the color
* buffer, or `NULL`.
* @param[out] buffer Where to store the address of the color buffer, or
* `NULL`.
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.3.
*
* @ingroup native
*/
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer);
/*! @brief Retrieves the depth buffer associated with the specified window.
*
* @param[out] width Where to store the width of the depth buffer, or `NULL`.
* @param[out] height Where to store the height of the depth buffer, or `NULL`.
* @param[out] bytesPerValue Where to store the number of bytes per depth
* buffer element, or `NULL`.
* @param[out] buffer Where to store the address of the depth buffer, or
* `NULL`.
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.3.
*
* @ingroup native
*/
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer);
/*! @brief Returns the `OSMesaContext` of the specified window.
*
* @return The `OSMesaContext` of the specified window, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.3.
*
* @ingroup native
*/
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -45,6 +45,12 @@ elseif (_GLFW_MIR)
set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c
linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c
egl_context.c)
elseif (_GLFW_OSMESA)
set(glfw_HEADERS ${common_HEADERS} osmesa_platform.h
posix_time.h posix_tls.h osmesa_context.h)
set(glfw_SOURCES ${common_SOURCES} osmesa_init.c osmesa_monitor.c
osmesa_window.c posix_time.c posix_tls.c
osmesa_context.c)
endif()
if (APPLE)

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//

View File

@ -272,24 +272,24 @@ static void matchCallback(void* context,
IOHIDDeviceRef deviceRef)
{
_GLFWjoystickNS* js;
int joy;
int jid;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.ns_js[joy].present && _glfw.ns_js[joy].deviceRef == deviceRef)
if (_glfw.ns_js[jid].present && _glfw.ns_js[jid].deviceRef == deviceRef)
return;
}
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.ns_js[joy].present)
if (!_glfw.ns_js[jid].present)
break;
}
if (joy > GLFW_JOYSTICK_LAST)
if (jid > GLFW_JOYSTICK_LAST)
return;
js = _glfw.ns_js + joy;
js = _glfw.ns_js + jid;
js->present = GLFW_TRUE;
js->deviceRef = deviceRef;
@ -324,7 +324,7 @@ static void matchCallback(void* context,
js->buttons = calloc(CFArrayGetCount(js->buttonElements) +
CFArrayGetCount(js->hatElements) * 4, 1);
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
_glfwInputJoystickChange(jid, GLFW_CONNECTED);
}
// Callback for user-initiated joystick removal
@ -334,13 +334,13 @@ static void removeCallback(void* context,
void* sender,
IOHIDDeviceRef deviceRef)
{
int joy;
int jid;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.ns_js[joy].deviceRef == deviceRef)
if (_glfw.ns_js[jid].deviceRef == deviceRef)
{
removeJoystick(_glfw.ns_js + joy);
removeJoystick(_glfw.ns_js + jid);
break;
}
}
@ -456,11 +456,11 @@ void _glfwInitJoysticksNS(void)
//
void _glfwTerminateJoysticksNS(void)
{
int joy;
int jid;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
_GLFWjoystickNS* js = _glfw.ns_js + jid;
removeJoystick(js);
}
@ -473,15 +473,15 @@ void _glfwTerminateJoysticksNS(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformJoystickPresent(int joy)
int _glfwPlatformJoystickPresent(int jid)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
_GLFWjoystickNS* js = _glfw.ns_js + jid;
return js->present;
}
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
const float* _glfwPlatformGetJoystickAxes(int jid, int* count)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
_GLFWjoystickNS* js = _glfw.ns_js + jid;
if (!pollJoystickAxisEvents(js))
return NULL;
@ -489,9 +489,9 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
return js->axes;
}
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
_GLFWjoystickNS* js = _glfw.ns_js + jid;
if (!pollJoystickButtonEvents(js))
return NULL;
@ -500,9 +500,9 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
return js->buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
const char* _glfwPlatformGetJoystickName(int jid)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
_GLFWjoystickNS* js = _glfw.ns_js + jid;
if (!js->present)
return NULL;

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//
@ -39,6 +39,18 @@
typedef void* id;
#endif
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef struct VkMacOSSurfaceCreateInfoMVK
{
VkStructureType sType;
const void* pNext;
VkMacOSSurfaceCreateFlagsMVK flags;
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
#include "posix_tls.h"
#include "cocoa_joystick.h"
#include "nsgl_context.h"
@ -74,6 +86,7 @@ typedef struct _GLFWwindowNS
id object;
id delegate;
id view;
id layer;
GLFWbool maximized;

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//
@ -32,6 +32,23 @@
// Needed for _NSGetProgname
#include <crt_externs.h>
// HACK: The 10.12 SDK adds new symbols and immediately deprecates the old ones
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskResizable NSResizableWindowMask
#define NSWindowStyleMaskTitled NSTitledWindowMask
#define NSEventModifierFlagCommand NSCommandKeyMask
#define NSEventModifierFlagControl NSControlKeyMask
#define NSEventModifierFlagOption NSAlternateKeyMask
#define NSEventModifierFlagShift NSShiftKeyMask
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
#define NSEventMaskAny NSAnyEventMask
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeKeyUp NSKeyUp
#endif
// Returns the specified standard cursor
//
@ -63,14 +80,15 @@ static NSUInteger getStyleMask(_GLFWwindow* window)
NSUInteger styleMask = 0;
if (window->monitor || !window->decorated)
styleMask |= NSBorderlessWindowMask;
styleMask |= NSWindowStyleMaskBorderless;
else
{
styleMask |= NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask;
styleMask |= NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable;
if (window->resizable)
styleMask |= NSResizableWindowMask;
styleMask |= NSWindowStyleMaskResizable;
}
return styleMask;
@ -144,25 +162,25 @@ static void releaseMonitor(_GLFWwindow* window)
_glfwRestoreVideoModeNS(window->monitor);
}
// Translates OS X key modifiers into GLFW ones
// Translates macOS key modifiers into GLFW ones
//
static int translateFlags(NSUInteger flags)
{
int mods = 0;
if (flags & NSShiftKeyMask)
if (flags & NSEventModifierFlagShift)
mods |= GLFW_MOD_SHIFT;
if (flags & NSControlKeyMask)
if (flags & NSEventModifierFlagControl)
mods |= GLFW_MOD_CONTROL;
if (flags & NSAlternateKeyMask)
if (flags & NSEventModifierFlagOption)
mods |= GLFW_MOD_ALT;
if (flags & NSCommandKeyMask)
if (flags & NSEventModifierFlagCommand)
mods |= GLFW_MOD_SUPER;
return mods;
}
// Translates a OS X keycode to a GLFW keycode
// Translates a macOS keycode to a GLFW keycode
//
static int translateKey(unsigned int key)
{
@ -180,16 +198,16 @@ static NSUInteger translateKeyToModifierFlag(int key)
{
case GLFW_KEY_LEFT_SHIFT:
case GLFW_KEY_RIGHT_SHIFT:
return NSShiftKeyMask;
return NSEventModifierFlagShift;
case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_CONTROL:
return NSControlKeyMask;
return NSEventModifierFlagControl;
case GLFW_KEY_LEFT_ALT:
case GLFW_KEY_RIGHT_ALT:
return NSAlternateKeyMask;
return NSEventModifierFlagOption;
case GLFW_KEY_LEFT_SUPER:
case GLFW_KEY_RIGHT_SUPER:
return NSCommandKeyMask;
return NSEventModifierFlagCommand;
}
return 0;
@ -413,6 +431,16 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
return YES;
}
- (BOOL)wantsUpdateLayer
{
return YES;
}
- (id)makeBackingLayer
{
return window->ns.layer;
}
- (void)cursorUpdate:(NSEvent *)event
{
updateCursorImage(window);
@ -565,7 +593,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
{
int action;
const unsigned int modifierFlags =
[event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
[event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
const int key = translateKey([event keyCode]);
const int mods = translateFlags(modifierFlags);
const NSUInteger keyFlag = translateKeyToModifierFlag(key);
@ -760,7 +788,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (BOOL)canBecomeKeyWindow
{
// Required for NSBorderlessWindowMask windows
// Required for NSWindowStyleMaskBorderless windows
return YES;
}
@ -781,8 +809,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
// down the command key don't get sent to the key window.
- (void)sendEvent:(NSEvent *)event
{
if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask))
if ([event type] == NSEventTypeKeyUp &&
([event modifierFlags] & NSEventModifierFlagCommand))
{
[[self keyWindow] sendEvent:event];
}
else
[super sendEvent:event];
}
@ -866,7 +897,7 @@ static void createMenuBar(void)
[[appMenu addItemWithTitle:@"Hide Others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"]
setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask];
setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
[appMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
@ -898,7 +929,7 @@ static void createMenuBar(void)
[[windowMenu addItemWithTitle:@"Enter Full Screen"
action:@selector(toggleFullScreen:)
keyEquivalent:@"f"]
setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
// Prior to Snow Leopard, we need to use this oddly-named semi-private API
// to get the application menu working properly.
@ -1011,11 +1042,11 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
#endif /*_GLFW_USE_RETINA*/
[window->ns.object setContentView:window->ns.view];
[window->ns.object makeFirstResponder:window->ns.view];
[window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]];
[window->ns.object setDelegate:window->ns.delegate];
[window->ns.object setAcceptsMouseMovedEvents:YES];
[window->ns.object setContentView:window->ns.view];
[window->ns.object setRestorable:NO];
return GLFW_TRUE;
@ -1162,7 +1193,7 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
{
if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
[window->ns.object setContentAspectRatio:NSMakeSize(0, 0)];
[window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)];
else
[window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)];
}
@ -1358,7 +1389,7 @@ void _glfwPlatformPollEvents(void)
{
for (;;)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
@ -1377,7 +1408,7 @@ void _glfwPlatformWaitEvents(void)
// I wanted to pass NO to dequeue:, and rely on PollEvents to
// dequeue and send. For reasons not at all clear to me, passing
// NO to dequeue: causes this method never to return.
NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
@ -1389,7 +1420,7 @@ void _glfwPlatformWaitEvents(void)
void _glfwPlatformWaitEventsTimeout(double timeout)
{
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:date
inMode:NSDefaultRunLoopMode
dequeue:YES];
@ -1402,7 +1433,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
void _glfwPlatformPostEmptyEvent(void)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0
@ -1632,13 +1663,18 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{
if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface)
return;
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_MVK_macos_surface";
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_FALSE;
return GLFW_TRUE;
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
@ -1646,7 +1682,57 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
VkResult err;
VkMacOSSurfaceCreateInfoMVK sci;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
if (!vkCreateMacOSSurfaceMVK)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
// HACK: Dynamically load Core Animation to avoid adding an extra
// dependency for the majority who don't use MoltenVK
NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"];
if (!bundle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find QuartzCore.framework");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
// NOTE: Create the layer here as makeBackingLayer should not return nil
window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer];
if (!window->ns.layer)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to create layer for view");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
[window->ns.view setWantsLayer:YES];
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
sci.pView = window->ns.view;
err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
#else
return VK_ERROR_EXTENSION_NOT_PRESENT;
#endif
}

View File

@ -44,6 +44,8 @@
#cmakedefine _GLFW_WAYLAND
// Define this to 1 if building GLFW for Mir
#cmakedefine _GLFW_MIR
// Define this to 1 if building GLFW for OSMesa
#cmakedefine _GLFW_OSMESA
// Define this to 1 if building as a shared library / dynamic library / DLL
#cmakedefine _GLFW_BUILD_DLL

View File

@ -124,10 +124,10 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
window->callbacks.drop((GLFWwindow*) window, count, paths);
}
void _glfwInputJoystickChange(int joy, int event)
void _glfwInputJoystickChange(int jid, int event)
{
if (_glfw.callbacks.joystick)
_glfw.callbacks.joystick(joy, event);
_glfw.callbacks.joystick(jid, event);
}
@ -553,62 +553,62 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
return cbfun;
}
GLFWAPI int glfwJoystickPresent(int joy)
GLFWAPI int glfwJoystickPresent(int jid)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid);
return 0;
}
return _glfwPlatformJoystickPresent(joy);
return _glfwPlatformJoystickPresent(jid);
}
GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count)
GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
{
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid);
return NULL;
}
return _glfwPlatformGetJoystickAxes(joy, count);
return _glfwPlatformGetJoystickAxes(jid, count);
}
GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count)
GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
{
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid);
return NULL;
}
return _glfwPlatformGetJoystickButtons(joy, count);
return _glfwPlatformGetJoystickButtons(jid, count);
}
GLFWAPI const char* glfwGetJoystickName(int joy)
GLFWAPI const char* glfwGetJoystickName(int jid)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", jid);
return NULL;
}
return _glfwPlatformGetJoystickName(joy);
return _glfwPlatformGetJoystickName(jid);
}
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)

View File

@ -69,6 +69,7 @@ typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
#define GL_VERSION 0x1f02
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_UNSIGNED_BYTE 0x1401
#define GL_EXTENSIONS 0x1f03
#define GL_NUM_EXTENSIONS 0x821d
#define GL_CONTEXT_FLAGS 0x821e
@ -110,6 +111,7 @@ typedef enum VkStructureType
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_MACOS_SURFACE_CREATE_INFO_MVK = 1000053000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
@ -171,6 +173,8 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
#include "wl_platform.h"
#elif defined(_GLFW_MIR)
#include "mir_platform.h"
#elif defined(_GLFW_OSMESA)
#include "osmesa_platform.h"
#else
#error "No supported window creation API selected"
#endif
@ -458,6 +462,8 @@ struct _GLFWlibrary
GLFWbool KHR_surface;
#if defined(_GLFW_WIN32)
GLFWbool KHR_win32_surface;
#elif defined(_GLFW_COCOA)
GLFWbool MVK_macos_surface;
#elif defined(_GLFW_X11)
GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface;
@ -608,22 +614,22 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window);
/*! @copydoc glfwJoystickPresent
* @ingroup platform
*/
int _glfwPlatformJoystickPresent(int joy);
int _glfwPlatformJoystickPresent(int jid);
/*! @copydoc glfwGetJoystickAxes
* @ingroup platform
*/
const float* _glfwPlatformGetJoystickAxes(int joy, int* count);
const float* _glfwPlatformGetJoystickAxes(int jid, int* count);
/*! @copydoc glfwGetJoystickButtons
* @ingroup platform
*/
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count);
const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count);
/*! @copydoc glfwGetJoystickName
* @ingroup platform
*/
const char* _glfwPlatformGetJoystickName(int joy);
const char* _glfwPlatformGetJoystickName(int jid);
/*! @copydoc glfwGetTimerValue
* @ingroup platform
@ -961,11 +967,11 @@ void _glfwInputError(int error, const char* format, ...);
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
/*! @brief Notifies shared code of a joystick connection/disconnection event.
* @param[in] joy The joystick that was connected or disconnected.
* @param[in] jid The joystick that was connected or disconnected.
* @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`.
* @ingroup event
*/
void _glfwInputJoystickChange(int joy, int event);
void _glfwInputJoystickChange(int jid, int event);
//========================================================================
@ -1060,7 +1066,7 @@ GLFWbool _glfwIsPrintable(int key);
/*! @ingroup utility
*/
GLFWbool _glfwInitVulkan(void);
GLFWbool _glfwInitVulkan(int mode);
/*! @ingroup utility
*/

View File

@ -50,25 +50,25 @@ static GLFWbool openJoystickDevice(const char* path)
{
char axisCount, buttonCount;
char name[256] = "";
int joy, fd, version;
int jid, fd, version;
_GLFWjoystickLinux* js;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.linux_js.js[joy].present)
if (!_glfw.linux_js.js[jid].present)
continue;
if (strcmp(_glfw.linux_js.js[joy].path, path) == 0)
if (strcmp(_glfw.linux_js.js[jid].path, path) == 0)
return GLFW_FALSE;
}
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.linux_js.js[joy].present)
if (!_glfw.linux_js.js[jid].present)
break;
}
if (joy > GLFW_JOYSTICK_LAST)
if (jid > GLFW_JOYSTICK_LAST)
return GLFW_FALSE;
fd = open(path, O_RDONLY | O_NONBLOCK);
@ -87,7 +87,7 @@ static GLFWbool openJoystickDevice(const char* path)
if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
js = _glfw.linux_js.js + joy;
js = _glfw.linux_js.js + jid;
js->present = GLFW_TRUE;
js->name = strdup(name);
js->path = strdup(path);
@ -101,7 +101,7 @@ static GLFWbool openJoystickDevice(const char* path)
js->buttonCount = (int) buttonCount;
js->buttons = calloc(buttonCount, 1);
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
_glfwInputJoystickChange(jid, GLFW_CONNECTED);
return GLFW_TRUE;
}
#endif // __linux__
@ -304,15 +304,15 @@ void _glfwPollJoystickEvents(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformJoystickPresent(int joy)
int _glfwPlatformJoystickPresent(int jid)
{
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
_GLFWjoystickLinux* js = _glfw.linux_js.js + jid;
return pollJoystickEvents(js);
}
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
const float* _glfwPlatformGetJoystickAxes(int jid, int* count)
{
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
_GLFWjoystickLinux* js = _glfw.linux_js.js + jid;
if (!pollJoystickEvents(js))
return NULL;
@ -320,9 +320,9 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
return js->axes;
}
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count)
{
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
_GLFWjoystickLinux* js = _glfw.linux_js.js + jid;
if (!pollJoystickEvents(js))
return NULL;
@ -330,9 +330,9 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
return js->buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
const char* _glfwPlatformGetJoystickName(int jid)
{
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
_GLFWjoystickLinux* js = _glfw.linux_js.js + jid;
if (!pollJoystickEvents(js))
return NULL;

View File

@ -175,10 +175,12 @@ void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
{
_GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
monitor->name = strdup(name);
monitor->widthMM = widthMM;
monitor->heightMM = heightMM;
if (name)
monitor->name = strdup(name);
return monitor;
}

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//

View File

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OS X - www.glfw.org
// GLFW 3.3 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
//
@ -124,14 +124,14 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"NSGL: OpenGL ES is not available on OS X");
"NSGL: OpenGL ES is not available on macOS");
return GLFW_FALSE;
}
if (ctxconfig->major == 3 && ctxconfig->minor < 2)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of OS X does not support OpenGL 3.0 or 3.1");
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1");
return GLFW_FALSE;
}
@ -140,23 +140,23 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
if (!ctxconfig->forward)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of OS X only supports forward-compatible contexts for OpenGL 3.2 and above");
"NSGL: The targeted version of macOS only supports forward-compatible contexts for OpenGL 3.2 and above");
return GLFW_FALSE;
}
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of OS X only supports core profile contexts for OpenGL 3.2 and above");
"NSGL: The targeted version of macOS only supports core profile contexts for OpenGL 3.2 and above");
return GLFW_FALSE;
}
}
// Context robustness modes (GL_KHR_robustness) are not yet supported on
// OS X but are not a hard constraint, so ignore and continue
// macOS but are not a hard constraint, so ignore and continue
// Context release behaviors (GL_KHR_context_flush_control) are not yet
// supported on OS X but are not a hard constraint, so ignore and continue
// supported on macOS but are not a hard constraint, so ignore and continue
#define ADD_ATTR(x) { attributes[attributeCount++] = x; }
#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
@ -206,7 +206,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
fbconfig->greenBits +
fbconfig->blueBits;
// OS X needs non-zero color size, so set reasonable values
// macOS needs non-zero color size, so set reasonable values
if (colorBits == 0)
colorBits = 24;
else if (colorBits < 15)
@ -225,7 +225,15 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
if (fbconfig->stereo)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"NSGL: Stereo rendering is deprecated");
return GLFW_FALSE;
#else
ADD_ATTR(NSOpenGLPFAStereo);
#endif
}
if (fbconfig->doublebuffer)
ADD_ATTR(NSOpenGLPFADoubleBuffer);

367
src/osmesa_context.c Normal file
View File

@ -0,0 +1,367 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include "internal.h"
static void makeContextCurrentOSMesa(_GLFWwindow* window)
{
if (window)
{
// Check to see if we need to allocate a new buffer
if ((window->context.osmesa.buffer == NULL) ||
(window->osmesa.width != window->context.osmesa.width) ||
(window->osmesa.height != window->context.osmesa.height))
{
free(window->context.osmesa.buffer);
// Allocate the new buffer (width * height * 8-bit RGBA)
window->context.osmesa.buffer =
calloc(4, window->osmesa.width * window->osmesa.height);
window->context.osmesa.width = window->osmesa.width;
window->context.osmesa.height = window->osmesa.height;
}
if (!OSMesaMakeCurrent(window->context.osmesa.handle,
window->context.osmesa.buffer,
GL_UNSIGNED_BYTE,
window->osmesa.width, window->osmesa.height))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to make context current");
return;
}
}
_glfwPlatformSetCurrentContext(window);
}
static GLFWglproc getProcAddressOSMesa(const char* procname)
{
return (GLFWglproc) OSMesaGetProcAddress(procname);
}
static void destroyContextOSMesa(_GLFWwindow* window)
{
if (window->context.osmesa.handle)
{
OSMesaDestroyContext(window->context.osmesa.handle);
window->context.osmesa.handle = NULL;
}
if (window->context.osmesa.buffer)
{
free(window->context.osmesa.buffer);
window->context.osmesa.width = 0;
window->context.osmesa.height = 0;
}
}
static void swapBuffersOSMesa(_GLFWwindow* window)
{
// No double buffering on OSMesa
}
static void swapIntervalOSMesa(int interval)
{
// No swap interval on OSMesa
}
static int extensionSupportedOSMesa(const char* extension)
{
// OSMesa does not have extensions
return GLFW_FALSE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitOSMesa(void)
{
int i;
const char* sonames[] =
{
#if defined(_WIN32)
"libOSMesa.dll",
"OSMesa.dll",
#elif defined(__APPLE__)
"libOSMesa.8.dylib",
#elif defined(__CYGWIN__)
"libOSMesa-8.so",
#else
"libOSMesa.so.8",
"libOSMesa.so.6",
#endif
NULL
};
if (_glfw.osmesa.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++)
{
_glfw.osmesa.handle = _glfw_dlopen(sonames[i]);
if (_glfw.osmesa.handle)
break;
}
if (!_glfw.osmesa.handle)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
return GLFW_FALSE;
}
_glfw.osmesa.CreateContextExt = (PFNOSMESACREATECONTEXTEXTPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
_glfw.osmesa.CreateContextAttribs = (PFNOSMESACREATECONTEXTATTRIBSPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
_glfw.osmesa.DestroyContext = (PFNOSMESADESTROYCONTEXTPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
_glfw.osmesa.MakeCurrent = (PFNOSMESAMAKECURRENTPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
_glfw.osmesa.GetColorBuffer = (PFNOSMESAGETCOLORBUFFERPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
_glfw.osmesa.GetDepthBuffer = (PFNOSMESAGETDEPTHBUFFERPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
_glfw.osmesa.GetProcAddress = (PFNOSMESAGETPROCADDRESSPROC)
_glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
if (!_glfw.osmesa.CreateContextExt ||
!_glfw.osmesa.DestroyContext ||
!_glfw.osmesa.MakeCurrent ||
!_glfw.osmesa.GetColorBuffer ||
!_glfw.osmesa.GetDepthBuffer ||
!_glfw.osmesa.GetProcAddress)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to load required entry points");
_glfwTerminateOSMesa();
return GLFW_FALSE;
}
return GLFW_TRUE;
}
void _glfwTerminateOSMesa(void)
{
if (_glfw.osmesa.handle)
{
_glfw_dlclose(_glfw.osmesa.handle);
_glfw.osmesa.handle = NULL;
}
}
#define setAttrib(attribName, attribValue) \
{ \
attribs[index++] = attribName; \
attribs[index++] = attribValue; \
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
}
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
OSMesaContext share = NULL;
const int accumBits = fbconfig->accumRedBits +
fbconfig->accumGreenBits +
fbconfig->accumBlueBits +
fbconfig->accumAlphaBits;
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"OSMesa: OpenGL ES is not available on OSMesa");
return GLFW_FALSE;
}
if (ctxconfig->share)
share = ctxconfig->share->context.osmesa.handle;
if (OSMesaCreateContextAttribs)
{
int index = 0, attribs[40];
setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
setAttrib(OSMESA_ACCUM_BITS, accumBits);
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
}
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
}
if (ctxconfig->forward)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Foward-compatible contexts not supported");
return GLFW_FALSE;
}
setAttrib(0, 0);
window->context.osmesa.handle =
OSMesaCreateContextAttribs(attribs, share);
}
else
{
if (ctxconfig->profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: OpenGL profiles unavailable");
return GLFW_FALSE;
}
window->context.osmesa.handle =
OSMesaCreateContextExt(OSMESA_RGBA,
fbconfig->depthBits,
fbconfig->stencilBits,
accumBits,
share);
}
if (window->context.osmesa.handle == NULL)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Failed to create context");
return GLFW_FALSE;
}
window->context.makeCurrent = makeContextCurrentOSMesa;
window->context.swapBuffers = swapBuffersOSMesa;
window->context.swapInterval = swapIntervalOSMesa;
window->context.extensionSupported = extensionSupportedOSMesa;
window->context.getProcAddress = getProcAddressOSMesa;
window->context.destroy = destroyContextOSMesa;
return GLFW_TRUE;
}
#undef setAttrib
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
int* height, int* format, void** buffer)
{
void* mesaBuffer;
GLint mesaWidth, mesaHeight, mesaFormat;
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
&mesaWidth, &mesaHeight,
&mesaFormat, &mesaBuffer))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to retrieve color buffer");
return GLFW_FALSE;
}
if (width)
*width = mesaWidth;
if (height)
*height = mesaHeight;
if (format)
*format = mesaFormat;
if (buffer)
*buffer = mesaBuffer;
return GLFW_TRUE;
}
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
int* width, int* height,
int* bytesPerValue,
void** buffer)
{
void* mesaBuffer;
GLint mesaWidth, mesaHeight, mesaBytes;
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
&mesaWidth, &mesaHeight,
&mesaBytes, &mesaBuffer))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to retrieve depth buffer");
return GLFW_FALSE;
}
if (width)
*width = mesaWidth;
if (height)
*height = mesaHeight;
if (bytesPerValue)
*bytesPerValue = mesaBytes;
if (buffer)
*buffer = mesaBuffer;
return GLFW_TRUE;
}
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
}
return window->context.osmesa.handle;
}

98
src/osmesa_context.h Normal file
View File

@ -0,0 +1,98 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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.
//
//========================================================================
#ifndef _glfw3_osmesa_context_h_
#define _glfw3_osmesa_context_h_
#define OSMESA_RGBA 0x1908
#define OSMESA_FORMAT 0x22
#define OSMESA_DEPTH_BITS 0x30
#define OSMESA_STENCIL_BITS 0x31
#define OSMESA_ACCUM_BITS 0x32
#define OSMESA_PROFILE 0x33
#define OSMESA_CORE_PROFILE 0x34
#define OSMESA_COMPAT_PROFILE 0x35
#define OSMESA_CONTEXT_MAJOR_VERSION 0x36
#define OSMESA_CONTEXT_MINOR_VERSION 0x37
typedef void* OSMesaContext;
typedef void (*OSMESAproc)();
typedef OSMesaContext (* PFNOSMESACREATECONTEXTATTRIBSPROC)(const int*,OSMesaContext);
typedef OSMesaContext (* PFNOSMESACREATECONTEXTEXTPROC)(GLenum,GLint,GLint,GLint,OSMesaContext);
typedef void (* PFNOSMESADESTROYCONTEXTPROC)(OSMesaContext);
typedef int (* PFNOSMESAMAKECURRENTPROC)(OSMesaContext,void*,int,int,int);
typedef int (* PFNOSMESAGETCOLORBUFFERPROC)(OSMesaContext,int*,int*,int*,void**);
typedef int (* PFNOSMESAGETDEPTHBUFFERPROC)(OSMesaContext,int*,int*,int*,void**);
typedef GLFWglproc (* PFNOSMESAGETPROCADDRESSPROC)(const char*);
#define OSMesaCreateContextExt _glfw.osmesa.CreateContextExt
#define OSMesaCreateContextAttribs _glfw.osmesa.CreateContextAttribs
#define OSMesaDestroyContext _glfw.osmesa.DestroyContext
#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent
#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer
#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer
#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextOSMesa osmesa
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryOSMesa osmesa
// OSMesa-specific per-context data
//
typedef struct _GLFWcontextOSMesa
{
OSMesaContext handle;
int width;
int height;
void* buffer;
} _GLFWcontextOSMesa;
// OSMesa-specific global data
//
typedef struct _GLFWlibraryOSMesa
{
void* handle;
PFNOSMESACREATECONTEXTEXTPROC CreateContextExt;
PFNOSMESACREATECONTEXTATTRIBSPROC CreateContextAttribs;
PFNOSMESADESTROYCONTEXTPROC DestroyContext;
PFNOSMESAMAKECURRENTPROC MakeCurrent;
PFNOSMESAGETCOLORBUFFERPROC GetColorBuffer;
PFNOSMESAGETDEPTHBUFFERPROC GetDepthBuffer;
PFNOSMESAGETPROCADDRESSPROC GetProcAddress;
} _GLFWlibraryOSMesa;
GLFWbool _glfwInitOSMesa(void);
void _glfwTerminateOSMesa(void);
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
#endif // _glfw3_osmesa_context_h_

54
src/osmesa_init.c Normal file
View File

@ -0,0 +1,54 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformInit(void)
{
if (!_glfwInitThreadLocalStoragePOSIX())
return GLFW_FALSE;
_glfwInitTimerPOSIX();
return GLFW_TRUE;
}
void _glfwPlatformTerminate(void)
{
_glfwTerminateOSMesa();
_glfwTerminateThreadLocalStoragePOSIX();
}
const char* _glfwPlatformGetVersionString(void)
{
return _GLFW_VERSION_NUMBER " none OSMesa";
}

67
src/osmesa_monitor.c Normal file
View File

@ -0,0 +1,67 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
{
// OSMesa is headless, so no monitors
*count = 0;
return NULL;
}
int _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
{
return GLFW_FALSE;
}
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
}
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
{
return NULL;
}
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
}

65
src/osmesa_platform.h Normal file
View File

@ -0,0 +1,65 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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.
//
//========================================================================
#ifndef _glfw3_osmesa_platform_h_
#define _glfw3_osmesa_platform_h_
#include <dlfcn.h>
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowOSMesa osmesa
#define _GLFW_PLATFORM_MONITOR_STATE
#define _GLFW_PLATFORM_CURSOR_STATE
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
#define _GLFW_EGL_CONTEXT_STATE
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
#include "osmesa_context.h"
#include "posix_time.h"
#include "posix_tls.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
#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
// OSMesa-specific per-window data
//
typedef struct _GLFWwindowOSMesa
{
int width;
int height;
} _GLFWwindowOSMesa;
#endif // _glfw3_osmesa_platform_h_

303
src/osmesa_window.c Normal file
View File

@ -0,0 +1,303 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.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"
static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig)
{
window->osmesa.width = wndconfig->width;
window->osmesa.height = wndconfig->height;
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig))
return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API)
{
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
{
if (!_glfwInitOSMesa())
return GLFW_FALSE;
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
else
{
_glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: EGL not available");
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
{
if (window->context.destroy)
window->context.destroy(window);
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count,
const GLFWimage* images)
{
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
}
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{
}
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
{
}
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->osmesa.width;
if (height)
*height = window->osmesa.height;
}
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{
window->osmesa.width = width;
window->osmesa.height = height;
}
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
}
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d)
{
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->osmesa.width;
if (height)
*height = window->osmesa.height;
}
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
if (right)
*right = window->osmesa.width;
if (bottom)
*top = window->osmesa.height;
}
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
}
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
}
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
{
}
void _glfwPlatformUnhideWindow(_GLFWwindow* window)
{
}
void _glfwPlatformHideWindow(_GLFWwindow* window)
{
}
void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
}
int _glfwPlatformWindowFocused(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformWindowIconified(_GLFWwindow* window)
{
return GLFW_FALSE;
}
int _glfwPlatformWindowVisible(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPlatformPollEvents(void)
{
}
void _glfwPlatformWaitEvents(void)
{
}
void _glfwPlatformWaitEventsTimeout(double timeout)
{
}
void _glfwPlatformPostEmptyEvent(void)
{
}
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
{
}
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{
}
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
}
void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
{
}
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
return GLFW_TRUE;
}
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
return GLFW_TRUE;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{
}
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
}
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
{
}
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
{
return NULL;
}
const char* _glfwPlatformGetKeyName(int key, int scancode)
{
return "";
}
int _glfwPlatformGetKeyScancode(int key)
{
return -1;
}
int _glfwPlatformJoystickPresent(int joy)
{
return GLFW_FALSE;
}
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
return NULL;
}
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
return NULL;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
return NULL;
}
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_FALSE;
}
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
// This seems like the most appropriate error to return here
return VK_ERROR_INITIALIZATION_FAILED;
}

View File

@ -31,37 +31,54 @@
#include <string.h>
#include <stdlib.h>
#define _GLFW_FIND_LOADER 1
#define _GLFW_REQUIRE_LOADER 2
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitVulkan(void)
GLFWbool _glfwInitVulkan(int mode)
{
VkResult err;
VkExtensionProperties* ep;
uint32_t i, count;
#if !defined(_GLFW_VULKAN_STATIC)
#if defined(_GLFW_WIN32)
const char* name = "vulkan-1.dll";
#else
const char* name = "libvulkan.so.1";
#endif
if (_glfw.vk.available)
return GLFW_TRUE;
_glfw.vk.handle = _glfw_dlopen(name);
#if !defined(_GLFW_VULKAN_STATIC)
#if defined(_GLFW_WIN32)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA)
// NULL maps to RTLD_DEFAULT, which searches all loaded binaries
_glfw.vk.handle = _glfw_dlopen(NULL);
#else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif
if (!_glfw.vk.handle)
{
if (mode == _GLFW_REQUIRE_LOADER)
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
return GLFW_FALSE;
}
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
if (!_glfw.vk.GetInstanceProcAddr)
{
#if defined(_GLFW_COCOA)
if (mode == _GLFW_REQUIRE_LOADER)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: vkGetInstanceProcAddr not found in process");
}
#else
_glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Loader does not export vkGetInstanceProcAddr");
#endif
_glfwTerminateVulkan();
return GLFW_FALSE;
@ -111,6 +128,9 @@ GLFWbool _glfwInitVulkan(void)
#if defined(_GLFW_WIN32)
else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
#elif defined(_GLFW_COCOA)
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
_glfw.vk.MVK_macos_surface = GLFW_TRUE;
#elif defined(_GLFW_X11)
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
@ -136,8 +156,10 @@ GLFWbool _glfwInitVulkan(void)
void _glfwTerminateVulkan(void)
{
#if !defined(_GLFW_VULKAN_STATIC)
if (_glfw.vk.handle)
_glfw_dlclose(_glfw.vk.handle);
#endif
}
const char* _glfwGetVulkanResultString(VkResult result)
@ -203,7 +225,7 @@ const char* _glfwGetVulkanResultString(VkResult result)
GLFWAPI int glfwVulkanSupported(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
return _glfwInitVulkan();
return _glfwInitVulkan(_GLFW_FIND_LOADER);
}
GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
@ -212,11 +234,11 @@ GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfwInitVulkan())
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return NULL;
if (!_glfw.vk.extensions[0])
return NULL;
}
*count = 2;
return (const char**) _glfw.vk.extensions;
@ -229,15 +251,20 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfwInitVulkan())
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return NULL;
}
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
#if defined(_GLFW_VULKAN_STATIC)
if (!proc)
{
if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
return (GLFWvkproc) vkGetInstanceProcAddr;
}
#else
if (!proc)
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
#endif
return proc;
}
@ -248,11 +275,8 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
{
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!_glfwInitVulkan())
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return GLFW_FALSE;
}
if (!_glfw.vk.extensions[0])
{
@ -279,11 +303,8 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
if (!_glfwInitVulkan())
{
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
return VK_ERROR_INITIALIZATION_FAILED;
}
if (!_glfw.vk.extensions[0])
{

View File

@ -304,6 +304,7 @@ static void createKeyTables(void)
//
static HWND createHelperWindow(void)
{
MSG msg;
HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
_GLFW_WNDCLASSNAME,
L"GLFW helper window",
@ -336,6 +337,12 @@ static HWND createHelperWindow(void)
DEVICE_NOTIFY_WINDOW_HANDLE);
}
while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return window;
}
@ -423,8 +430,6 @@ int _glfwPlatformInit(void)
if (!_glfw.win32.helperWindowHandle)
return GLFW_FALSE;
_glfwPlatformPollEvents();
_glfwInitTimerWin32();
_glfwInitJoysticksWin32();

View File

@ -332,26 +332,26 @@ static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
//
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
{
int joy = 0;
int jid = 0;
DIDEVCAPS dc;
DIPROPDWORD dipd;
IDirectInputDevice8* device;
_GLFWobjenumWin32 data;
_GLFWjoystickWin32* js;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0)
if (memcmp(&_glfw.win32_js[jid].guid, &di->guidInstance, sizeof(GUID)) == 0)
return DIENUM_CONTINUE;
}
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.win32_js[joy].present)
if (!_glfw.win32_js[jid].present)
break;
}
if (joy > GLFW_JOYSTICK_LAST)
if (jid > GLFW_JOYSTICK_LAST)
return DIENUM_STOP;
if (supportsXInput(&di->guidProduct))
@ -362,14 +362,14 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
&device,
NULL)))
{
_glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device");
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
return DIENUM_CONTINUE;
}
if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"DI: Failed to set device data format");
"Win32: Failed to set device data format");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
@ -381,7 +381,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"DI: Failed to query device capabilities");
"Win32: Failed to query device capabilities");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
@ -398,7 +398,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
&dipd.diph)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"DI: Failed to set device axis mode");
"Win32: Failed to set device axis mode");
IDirectInputDevice8_Release(device);
return DIENUM_CONTINUE;
@ -415,7 +415,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"DI: Failed to enumerate device objects");
"Win32: Failed to enumerate device objects");
IDirectInputDevice8_Release(device);
free(data.objects);
@ -426,7 +426,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
sizeof(_GLFWjoyobjectWin32),
compareJoystickObjects);
js = _glfw.win32_js + joy;
js = _glfw.win32_js + jid;
js->device = device;
js->guid = di->guidInstance;
js->axisCount = data.axisCount + data.sliderCount;
@ -438,7 +438,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName);
js->present = GLFW_TRUE;
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
_glfwInputJoystickChange(jid, GLFW_CONNECTED);
return DIENUM_CONTINUE;
}
@ -447,33 +447,33 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
//
static GLFWbool openXinputDevice(DWORD index)
{
int joy;
int jid;
XINPUT_CAPABILITIES xic;
_GLFWjoystickWin32* js;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.win32_js[joy].present &&
_glfw.win32_js[joy].device == NULL &&
_glfw.win32_js[joy].index == index)
if (_glfw.win32_js[jid].present &&
_glfw.win32_js[jid].device == NULL &&
_glfw.win32_js[jid].index == index)
{
return GLFW_FALSE;
}
}
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.win32_js[joy].present)
if (!_glfw.win32_js[jid].present)
break;
}
if (joy > GLFW_JOYSTICK_LAST)
if (jid > GLFW_JOYSTICK_LAST)
return GLFW_FALSE;
if (_glfw_XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
return GLFW_FALSE;
js = _glfw.win32_js + joy;
js = _glfw.win32_js + jid;
js->axisCount = 6;
js->axes = calloc(js->axisCount, sizeof(float));
js->buttonCount = 14;
@ -482,7 +482,7 @@ static GLFWbool openXinputDevice(DWORD index)
js->name = strdup(getDeviceDescription(&xic));
js->index = index;
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
_glfwInputJoystickChange(jid, GLFW_CONNECTED);
return GLFW_TRUE;
}
@ -664,7 +664,7 @@ void _glfwInitJoysticksWin32(void)
NULL)))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"DI: Failed to create interface");
"Win32: Failed to create interface");
}
}
@ -675,10 +675,10 @@ void _glfwInitJoysticksWin32(void)
//
void _glfwTerminateJoysticksWin32(void)
{
int joy;
int jid;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
closeJoystick(_glfw.win32_js + joy);
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
closeJoystick(_glfw.win32_js + jid);
if (_glfw.win32.dinput8.api)
IDirectInput8_Release(_glfw.win32.dinput8.api);
@ -715,10 +715,10 @@ void _glfwDetectJoystickConnectionWin32(void)
//
void _glfwDetectJoystickDisconnectionWin32(void)
{
int joy;
int jid;
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY);
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
pollJoystickState(_glfw.win32_js + jid, _GLFW_PRESENCE_ONLY);
}
@ -726,15 +726,15 @@ void _glfwDetectJoystickDisconnectionWin32(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformJoystickPresent(int joy)
int _glfwPlatformJoystickPresent(int jid)
{
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
_GLFWjoystickWin32* js = _glfw.win32_js + jid;
return pollJoystickState(js, _GLFW_PRESENCE_ONLY);
}
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
const float* _glfwPlatformGetJoystickAxes(int jid, int* count)
{
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
_GLFWjoystickWin32* js = _glfw.win32_js + jid;
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
return NULL;
@ -742,9 +742,9 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
return js->axes;
}
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
const unsigned char* _glfwPlatformGetJoystickButtons(int jid, int* count)
{
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
_GLFWjoystickWin32* js = _glfw.win32_js + jid;
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
return NULL;
@ -752,9 +752,9 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
return js->buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
const char* _glfwPlatformGetJoystickName(int jid)
{
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
_GLFWjoystickWin32* js = _glfw.win32_js + jid;
if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY))
return NULL;

View File

@ -668,7 +668,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_MOUSEHWHEEL:
{
// This message is only sent on Windows Vista and later
// NOTE: The X-axis is inverted for consistency with OS X and X11.
// NOTE: The X-axis is inverted for consistency with macOS and X11
_glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
return 0;
}

View File

@ -128,7 +128,7 @@ static void pointerHandleAxis(void* data,
wl_fixed_t value)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
double scroll_factor;
double scrollFactor;
double x, y;
if (!window)
@ -137,17 +137,17 @@ static void pointerHandleAxis(void* data,
/* Wayland scroll events are in pointer motion coordinate space (think
* two finger scroll). The factor 10 is commonly used to convert to
* "scroll step means 1.0. */
scroll_factor = 1.0/10.0;
scrollFactor = 1.0/10.0;
switch (axis)
{
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
x = wl_fixed_to_double(value) * scroll_factor;
x = wl_fixed_to_double(value) * scrollFactor;
y = 0.0;
break;
case WL_POINTER_AXIS_VERTICAL_SCROLL:
x = 0.0;
y = wl_fixed_to_double(value) * scroll_factor;
y = wl_fixed_to_double(value) * scrollFactor;
break;
default:
break;
@ -172,7 +172,10 @@ static void keyboardHandleKeymap(void* data,
{
struct xkb_keymap* keymap;
struct xkb_state* state;
struct xkb_compose_table* composeTable;
struct xkb_compose_state* composeState;
char* mapStr;
const char* locale;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
{
@ -186,10 +189,10 @@ static void keyboardHandleKeymap(void* data,
return;
}
keymap = xkb_map_new_from_string(_glfw.wl.xkb.context,
mapStr,
XKB_KEYMAP_FORMAT_TEXT_V1,
0);
keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context,
mapStr,
XKB_KEYMAP_FORMAT_TEXT_V1,
0);
munmap(mapStr, size);
close(fd);
@ -205,23 +208,52 @@ static void keyboardHandleKeymap(void* data,
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB state");
xkb_map_unref(keymap);
xkb_keymap_unref(keymap);
return;
}
// Look up the preferred locale, falling back to "C" as default.
locale = getenv("LC_ALL");
if (!locale)
locale = getenv("LC_CTYPE");
if (!locale)
locale = getenv("LANG");
if (!locale)
locale = "C";
composeTable =
xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
XKB_COMPOSE_COMPILE_NO_FLAGS);
if (composeTable)
{
composeState =
xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
xkb_compose_table_unref(composeTable);
if (composeState)
_glfw.wl.xkb.composeState = composeState;
else
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose state");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose table");
}
xkb_keymap_unref(_glfw.wl.xkb.keymap);
xkb_state_unref(_glfw.wl.xkb.state);
_glfw.wl.xkb.keymap = keymap;
_glfw.wl.xkb.state = state;
_glfw.wl.xkb.control_mask =
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Control");
_glfw.wl.xkb.alt_mask =
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
_glfw.wl.xkb.shift_mask =
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
_glfw.wl.xkb.super_mask =
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
_glfw.wl.xkb.controlMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control");
_glfw.wl.xkb.altMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
_glfw.wl.xkb.shiftMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
_glfw.wl.xkb.superMask =
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
}
static void keyboardHandleEnter(void* data,
@ -258,18 +290,40 @@ static int toGLFWKeyCode(uint32_t key)
return GLFW_KEY_UNKNOWN;
}
static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
{
if (sym == XKB_KEY_NoSymbol)
return sym;
if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
!= XKB_COMPOSE_FEED_ACCEPTED)
return sym;
switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
{
case XKB_COMPOSE_COMPOSED:
return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
case XKB_COMPOSE_COMPOSING:
case XKB_COMPOSE_CANCELLED:
return XKB_KEY_NoSymbol;
case XKB_COMPOSE_NOTHING:
default:
return sym;
}
}
static void inputChar(_GLFWwindow* window, uint32_t key)
{
uint32_t code, num_syms;
uint32_t code, numSyms;
long cp;
const xkb_keysym_t *syms;
xkb_keysym_t sym;
code = key + 8;
num_syms = xkb_key_get_syms(_glfw.wl.xkb.state, code, &syms);
numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms);
if (num_syms == 1)
if (numSyms == 1)
{
cp = _glfwKeySym2Unicode(syms[0]);
sym = composeSymbol(syms[0]);
cp = _glfwKeySym2Unicode(sym);
if (cp != -1)
{
const int mods = _glfw.wl.xkb.modifiers;
@ -327,15 +381,17 @@ static void keyboardHandleModifiers(void* data,
group);
mask = xkb_state_serialize_mods(_glfw.wl.xkb.state,
XKB_STATE_DEPRESSED |
XKB_STATE_LATCHED);
if (mask & _glfw.wl.xkb.control_mask)
XKB_STATE_MODS_DEPRESSED |
XKB_STATE_LAYOUT_DEPRESSED |
XKB_STATE_MODS_LATCHED |
XKB_STATE_LAYOUT_LATCHED);
if (mask & _glfw.wl.xkb.controlMask)
modifiers |= GLFW_MOD_CONTROL;
if (mask & _glfw.wl.xkb.alt_mask)
if (mask & _glfw.wl.xkb.altMask)
modifiers |= GLFW_MOD_ALT;
if (mask & _glfw.wl.xkb.shift_mask)
if (mask & _glfw.wl.xkb.shiftMask)
modifiers |= GLFW_MOD_SHIFT;
if (mask & _glfw.wl.xkb.super_mask)
if (mask & _glfw.wl.xkb.superMask)
modifiers |= GLFW_MOD_SUPER;
_glfw.wl.xkb.modifiers = modifiers;
}
@ -387,10 +443,10 @@ static void registryHandleGlobal(void* data,
{
if (strcmp(interface, "wl_compositor") == 0)
{
_glfw.wl.wl_compositor_version = min(3, version);
_glfw.wl.compositorVersion = min(3, version);
_glfw.wl.compositor =
wl_registry_bind(registry, name, &wl_compositor_interface,
_glfw.wl.wl_compositor_version);
_glfw.wl.compositorVersion);
}
else if (strcmp(interface, "wl_shm") == 0)
{
@ -643,16 +699,38 @@ void _glfwPlatformTerminate(void)
_glfwTerminateJoysticksLinux();
_glfwTerminateThreadLocalStoragePOSIX();
xkb_compose_state_unref(_glfw.wl.xkb.composeState);
xkb_keymap_unref(_glfw.wl.xkb.keymap);
xkb_state_unref(_glfw.wl.xkb.state);
xkb_context_unref(_glfw.wl.xkb.context);
if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursorSurface)
wl_surface_destroy(_glfw.wl.cursorSurface);
if (_glfw.wl.compositor)
wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm);
if (_glfw.wl.shell)
wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.pointer)
wl_pointer_destroy(_glfw.wl.pointer);
if (_glfw.wl.keyboard)
wl_keyboard_destroy(_glfw.wl.keyboard);
if (_glfw.wl.seat)
wl_seat_destroy(_glfw.wl.seat);
if (_glfw.wl.relativePointerManager)
zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
if (_glfw.wl.pointerConstraints)
zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
if (_glfw.wl.registry)
wl_registry_destroy(_glfw.wl.registry);
if (_glfw.wl.display)
{
wl_display_flush(_glfw.wl.display);
if (_glfw.wl.display)
wl_display_disconnect(_glfw.wl.display);
}
}
const char* _glfwPlatformGetVersionString(void)

View File

@ -50,11 +50,21 @@ static void geometry(void* data,
int32_t transform)
{
struct _GLFWmonitor *monitor = data;
char* name;
size_t nameLength;
monitor->wl.x = x;
monitor->wl.y = y;
monitor->widthMM = physicalWidth;
monitor->heightMM = physicalHeight;
nameLength = strlen(make) + 1 + strlen(model) + 1;
name = realloc(monitor->name, nameLength);
if (name)
{
sprintf(name, "%s %s", make, model);
monitor->name = name;
}
}
static void mode(void* data,
@ -102,7 +112,7 @@ static void scale(void* data,
monitor->wl.scale = factor;
}
static const struct wl_output_listener output_listener = {
static const struct wl_output_listener outputListener = {
geometry,
mode,
done,
@ -118,10 +128,6 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
{
_GLFWmonitor *monitor;
struct wl_output *output;
char name_str[80];
memset(name_str, 0, sizeof(name_str));
snprintf(name_str, 79, "wl_output@%u", name);
if (version < 2)
{
@ -130,7 +136,8 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
return;
}
monitor = _glfwAllocMonitor(name_str, 0, 0);
// The actual name of this output will be set in the geometry handler.
monitor = _glfwAllocMonitor(NULL, 0, 0);
output = wl_registry_bind(_glfw.wl.registry,
name,
@ -148,7 +155,7 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
monitor->wl.scale = 1;
monitor->wl.output = output;
wl_output_add_listener(output, &output_listener, monitor);
wl_output_add_listener(output, &outputListener, monitor);
if (_glfw.wl.monitorsCount + 1 >= _glfw.wl.monitorsSize)
{

View File

@ -29,6 +29,7 @@
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <dlfcn.h>
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
@ -83,7 +84,7 @@ typedef struct _GLFWwindowWayland
GLFWbool maximized;
struct wl_surface* surface;
struct wl_egl_window* native;
struct wl_shell_surface* shell_surface;
struct wl_shell_surface* shellSurface;
struct wl_callback* callback;
_GLFWcursor* currentCursor;
@ -119,7 +120,7 @@ typedef struct _GLFWlibraryWayland
struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints;
int wl_compositor_version;
int compositorVersion;
struct wl_cursor_theme* cursorTheme;
struct wl_surface* cursorSurface;
@ -136,10 +137,11 @@ typedef struct _GLFWlibraryWayland
struct xkb_context* context;
struct xkb_keymap* keymap;
struct xkb_state* state;
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
xkb_mod_mask_t shift_mask;
xkb_mod_mask_t super_mask;
struct xkb_compose_state* composeState;
xkb_mod_mask_t controlMask;
xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask;
xkb_mod_mask_t superMask;
unsigned int modifiers;
} xkb;

View File

@ -105,7 +105,7 @@ static void checkScaleChange(_GLFWwindow* window)
int monitorScale;
// Check if we will be able to set the buffer scale or not.
if (_glfw.wl.wl_compositor_version < 3)
if (_glfw.wl.compositorVersion < 3)
return;
// Get the scale factor from the highest scale monitor.
@ -220,33 +220,33 @@ static GLFWbool createSurface(_GLFWwindow* window,
static GLFWbool createShellSurface(_GLFWwindow* window)
{
window->wl.shell_surface = wl_shell_get_shell_surface(_glfw.wl.shell,
window->wl.surface);
if (!window->wl.shell_surface)
window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,
window->wl.surface);
if (!window->wl.shellSurface)
return GLFW_FALSE;
wl_shell_surface_add_listener(window->wl.shell_surface,
wl_shell_surface_add_listener(window->wl.shellSurface,
&shellSurfaceListener,
window);
if (window->wl.title)
wl_shell_surface_set_title(window->wl.shell_surface, window->wl.title);
wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title);
if (window->monitor)
{
wl_shell_surface_set_fullscreen(
window->wl.shell_surface,
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0,
window->monitor->wl.output);
}
else if (window->wl.maximized)
{
wl_shell_surface_set_maximized(window->wl.shell_surface, NULL);
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
}
else
{
wl_shell_surface_set_toplevel(window->wl.shell_surface);
wl_shell_surface_set_toplevel(window->wl.shellSurface);
}
return GLFW_TRUE;
@ -411,7 +411,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
}
else
{
window->wl.shell_surface = NULL;
window->wl.shellSurface = NULL;
window->wl.visible = GLFW_FALSE;
}
@ -443,8 +443,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->wl.native)
wl_egl_window_destroy(window->wl.native);
if (window->wl.shell_surface)
wl_shell_surface_destroy(window->wl.shell_surface);
if (window->wl.shellSurface)
wl_shell_surface_destroy(window->wl.shellSurface);
if (window->wl.surface)
wl_surface_destroy(window->wl.surface);
@ -458,8 +458,8 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
if (window->wl.title)
free(window->wl.title);
window->wl.title = strdup(title);
if (window->wl.shell_surface)
wl_shell_surface_set_title(window->wl.shell_surface, title);
if (window->wl.shellSurface)
wl_shell_surface_set_title(window->wl.shellSurface, title);
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
@ -546,8 +546,8 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
// TODO: also do the same for iconified.
if (window->monitor || window->wl.maximized)
{
if (window->wl.shell_surface)
wl_shell_surface_set_toplevel(window->wl.shell_surface);
if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
window->wl.maximized = GLFW_FALSE;
}
@ -557,10 +557,10 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
if (!window->monitor && !window->wl.maximized)
{
if (window->wl.shell_surface)
if (window->wl.shellSurface)
{
// Let the compositor select the best output.
wl_shell_surface_set_maximized(window->wl.shell_surface, NULL);
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
}
window->wl.maximized = GLFW_TRUE;
}
@ -570,7 +570,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
{
if (!window->monitor)
{
if (!window->wl.shell_surface)
if (!window->wl.shellSurface)
createShellSurface(window);
window->wl.visible = GLFW_TRUE;
}
@ -580,8 +580,8 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
{
if (!window->monitor)
{
if (window->wl.shell_surface)
wl_shell_surface_destroy(window->wl.shell_surface);
if (window->wl.shellSurface)
wl_shell_surface_destroy(window->wl.shellSurface);
window->wl.visible = GLFW_FALSE;
}
}
@ -601,14 +601,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
if (monitor)
{
wl_shell_surface_set_fullscreen(
window->wl.shell_surface,
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
refreshRate * 1000, // Convert Hz to mHz.
monitor->wl.output);
}
else
{
wl_shell_surface_set_toplevel(window->wl.shell_surface);
wl_shell_surface_set_toplevel(window->wl.shellSurface);
}
_glfwInputWindowMonitorChange(window, monitor);
}

View File

@ -50,7 +50,7 @@ if (VULKAN_FOUND)
add_executable(vulkan WIN32 vulkan.c ${ICON})
target_include_directories(vulkan PRIVATE "${VULKAN_INCLUDE_DIR}")
if (NOT GLFW_VULKAN_STATIC)
target_link_libraries(vulkan "${VULKAN_LIBRARY}")
target_link_libraries(vulkan "${VULKAN_LIBRARY}" ${GLFW_VULKAN_DEPS})
endif()
list(APPEND WINDOWS_BINARIES vulkan)
endif()

View File

@ -459,26 +459,26 @@ static void monitor_callback(GLFWmonitor* monitor, int event)
}
}
static void joystick_callback(int joy, int event)
static void joystick_callback(int jid, int event)
{
if (event == GLFW_CONNECTED)
{
int axisCount, buttonCount;
glfwGetJoystickAxes(joy, &axisCount);
glfwGetJoystickButtons(joy, &buttonCount);
glfwGetJoystickAxes(jid, &axisCount);
glfwGetJoystickButtons(jid, &buttonCount);
printf("%08x at %0.3f: Joystick %i (%s) was connected with %i axes and %i buttons\n",
counter++, glfwGetTime(),
joy,
glfwGetJoystickName(joy),
jid,
glfwGetJoystickName(jid),
axisCount,
buttonCount);
}
else
{
printf("%08x at %0.3f: Joystick %i was disconnected\n",
counter++, glfwGetTime(), joy);
counter++, glfwGetTime(), jid);
}
}

View File

@ -46,8 +46,6 @@
#include <stdio.h>
#include <stdlib.h>
static int windowed_xpos, windowed_ypos, windowed_width, windowed_height;
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);

View File

@ -820,9 +820,14 @@ int main(int argc, char** argv)
re = glfwGetRequiredInstanceExtensions(&re_count);
printf("Vulkan required instance extensions:");
for (i = 0; i < re_count; i++)
printf(" %s", re[i]);
putchar('\n');
if (re)
{
for (i = 0; i < re_count; i++)
printf(" %s", re[i]);
putchar('\n');
}
else
printf(" missing\n");
if (list_extensions)
list_vulkan_instance_extensions();

View File

@ -60,17 +60,17 @@ static void error_callback(int error, const char* description)
fprintf(stderr, "Error: %s\n", description);
}
static void joystick_callback(int joy, int event)
static void joystick_callback(int jid, int event)
{
if (event == GLFW_CONNECTED)
joysticks[joystick_count++] = joy;
joysticks[joystick_count++] = jid;
else if (event == GLFW_DISCONNECTED)
{
int i;
for (i = 0; i < joystick_count; i++)
{
if (joysticks[i] == joy)
if (joysticks[i] == jid)
break;
}
@ -90,7 +90,7 @@ static const char* joystick_label(int jid)
int main(void)
{
int joy;
int jid;
GLFWwindow* window;
struct nk_context* nk;
struct nk_font_atlas* atlas;
@ -102,10 +102,10 @@ int main(void)
if (!glfwInit())
exit(EXIT_FAILURE);
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (glfwJoystickPresent(joy))
joystick_callback(joy, GLFW_CONNECTED);
if (glfwJoystickPresent(jid))
joystick_callback(jid, GLFW_CONNECTED);
}
glfwSetJoystickCallback(joystick_callback);

View File

@ -52,6 +52,12 @@ static void error_callback(int error, const char* description)
fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
static int thread_main(void* data)
{
const Thread* thread = data;
@ -101,6 +107,8 @@ int main(void)
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(threads[i].window, key_callback);
glfwSetWindowPos(threads[i].window, 200 + 250 * i, 200);
glfwShowWindow(threads[i].window);
}

View File

@ -3,24 +3,17 @@
* Copyright (c) 2015-2016 Valve Corporation
* Copyright (c) 2015-2016 LunarG, 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:
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* The above copyright notice(s) and this permission notice shall be included in
* all copies or substantial portions of the Materials.
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Chia-I Wu <olvaffe@gmail.com>
* Author: Cody Northrop <cody@lunarg.com>
@ -28,6 +21,8 @@
* Author: Ian Elliott <ian@LunarG.com>
* Author: Jon Ashburn <jon@lunarg.com>
* Author: Piers Daniell <pdaniell@nvidia.com>
* Author: Gwan-gyeong Mun <elongbug@gmail.com>
* Porter: Camilla Berglund <elmindreda@glfw.org>
*/
/*
* Draw a textured triangle with depth testing. This is written against Intel
@ -35,22 +30,24 @@
* should. It also does no error checking.
*/
#ifndef _MSC_VER
#define _ISOC11_SOURCE /* for aligned_alloc() */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <signal.h>
#include <vulkan/vulkan.h>
#ifdef _WIN32
#include <windows.h>
#endif
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#define DEMO_TEXTURE_COUNT 1
#define VERTEX_BUFFER_BIND_ID 0
#define APP_SHORT_NAME "vulkan"
#define APP_SHORT_NAME "tri"
#define APP_LONG_NAME "The Vulkan Triangle Demo Program"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@ -245,39 +242,23 @@ struct texture_object {
int32_t tex_width, tex_height;
};
static int validation_error = 0;
VKAPI_ATTR VkBool32 VKAPI_CALL
dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
uint64_t srcObject, size_t location, int32_t msgCode,
const char *pLayerPrefix, const char *pMsg, void *pUserData) {
char *message = (char *)malloc(strlen(pMsg) + 100);
BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
uint64_t srcObject, size_t location, int32_t msgCode,
const char *pLayerPrefix, const char *pMsg,
void *pUserData) {
#ifdef _WIN32
DebugBreak();
#else
raise(SIGTRAP);
#endif
assert(message);
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode,
pMsg);
} else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode,
pMsg);
} else {
return false;
}
printf("%s\n", message);
fflush(stdout);
free(message);
/*
* false indicates that layer should not bail-out of an
* API call that had validation failures. This may mean that the
* app dies inside the driver due to invalid parameter(s).
* That's what would happen without validation layers, so we'll
* keep that behavior here.
*/
return false;
}
typedef struct _SwapchainBuffers {
typedef struct {
VkImage image;
VkCommandBuffer cmd;
VkImageView view;
@ -288,20 +269,19 @@ struct demo {
VkSurfaceKHR surface;
bool use_staging_buffer;
VkAllocationCallbacks allocator;
VkInstance inst;
VkPhysicalDevice gpu;
VkDevice device;
VkQueue queue;
VkPhysicalDeviceProperties gpu_props;
VkPhysicalDeviceFeatures gpu_features;
VkQueueFamilyProperties *queue_props;
uint32_t graphics_queue_node_index;
uint32_t enabled_extension_count;
uint32_t enabled_layer_count;
const char *extension_names[64];
char *device_validation_layers[64];
const char *enabled_layers[64];
int width, height;
VkFormat format;
@ -363,10 +343,14 @@ struct demo {
VkPhysicalDeviceMemoryProperties memory_properties;
int32_t curFrame;
int32_t frameCount;
bool validate;
bool use_break;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
VkDebugReportCallbackEXT msg_callback;
PFN_vkDebugReportMessageEXT DebugReportMessage;
float depthStencil;
float depthIncrement;
@ -375,6 +359,40 @@ struct demo {
uint32_t queue_count;
};
VKAPI_ATTR VkBool32 VKAPI_CALL
dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
uint64_t srcObject, size_t location, int32_t msgCode,
const char *pLayerPrefix, const char *pMsg, void *pUserData) {
char *message = (char *)malloc(strlen(pMsg) + 100);
assert(message);
validation_error = 1;
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode,
pMsg);
} else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode,
pMsg);
} else {
return false;
}
printf("%s\n", message);
fflush(stdout);
free(message);
/*
* false indicates that layer should not bail-out of an
* API call that had validation failures. This may mean that the
* app dies inside the driver due to invalid parameter(s).
* That's what would happen without validation layers, so we'll
* keep that behavior here.
*/
return false;
}
// Forward declaration:
static void demo_resize(struct demo *demo);
@ -382,9 +400,8 @@ static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
VkFlags requirements_mask,
uint32_t *typeIndex) {
uint32_t i;
// Search memtypes to find first index with those properties
for (i = 0; i < 32; i++) {
for (i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
if ((typeBits & 1) == 1) {
// Type is available, does it match user properties?
if ((demo->memory_properties.memoryTypes[i].propertyFlags &
@ -433,7 +450,9 @@ static void demo_flush_init_cmd(struct demo *demo) {
static void demo_set_image_layout(struct demo *demo, VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout old_image_layout,
VkImageLayout new_image_layout) {
VkImageLayout new_image_layout,
VkAccessFlagBits srcAccessMask) {
VkResult U_ASSERT_ONLY err;
if (demo->setup_cmd == VK_NULL_HANDLE) {
@ -448,21 +467,11 @@ static void demo_set_image_layout(struct demo *demo, VkImage image,
err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->setup_cmd);
assert(!err);
VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
.pNext = NULL,
.renderPass = VK_NULL_HANDLE,
.subpass = 0,
.framebuffer = VK_NULL_HANDLE,
.occlusionQueryEnable = VK_FALSE,
.queryFlags = 0,
.pipelineStatistics = 0,
};
VkCommandBufferBeginInfo cmd_buf_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = 0,
.pInheritanceInfo = &cmd_buf_hinfo,
.pInheritanceInfo = NULL,
};
err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info);
assert(!err);
@ -471,7 +480,7 @@ static void demo_set_image_layout(struct demo *demo, VkImage image,
VkImageMemoryBarrier image_memory_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = NULL,
.srcAccessMask = 0,
.srcAccessMask = srcAccessMask,
.dstAccessMask = 0,
.oldLayout = old_image_layout,
.newLayout = new_image_layout,
@ -509,21 +518,11 @@ static void demo_set_image_layout(struct demo *demo, VkImage image,
}
static void demo_draw_build_cmd(struct demo *demo) {
const VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
.pNext = NULL,
.renderPass = VK_NULL_HANDLE,
.subpass = 0,
.framebuffer = VK_NULL_HANDLE,
.occlusionQueryEnable = VK_FALSE,
.queryFlags = 0,
.pipelineStatistics = 0,
};
const VkCommandBufferBeginInfo cmd_buf_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = 0,
.pInheritanceInfo = &cmd_buf_hinfo,
.pInheritanceInfo = NULL,
};
const VkClearValue clear_values[2] = {
[0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
@ -546,6 +545,23 @@ static void demo_draw_build_cmd(struct demo *demo) {
err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info);
assert(!err);
// We can use LAYOUT_UNDEFINED as a wildcard here because we don't care what
// happens to the previous contents of the image
VkImageMemoryBarrier image_memory_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = NULL,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = demo->buffers[demo->current_buffer].image,
.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0,
NULL, 1, &image_memory_barrier);
vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
demo->pipeline);
@ -599,20 +615,24 @@ static void demo_draw_build_cmd(struct demo *demo) {
static void demo_draw(struct demo *demo) {
VkResult U_ASSERT_ONLY err;
VkSemaphore presentCompleteSemaphore;
VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
VkSemaphore imageAcquiredSemaphore, drawCompleteSemaphore;
VkSemaphoreCreateInfo semaphoreCreateInfo = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = NULL,
.flags = 0,
};
err = vkCreateSemaphore(demo->device, &presentCompleteSemaphoreCreateInfo,
NULL, &presentCompleteSemaphore);
err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo,
NULL, &imageAcquiredSemaphore);
assert(!err);
err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo,
NULL, &drawCompleteSemaphore);
assert(!err);
// Get the index of the next available swapchain image:
err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
presentCompleteSemaphore,
imageAcquiredSemaphore,
(VkFence)0, // TODO: Show use of fence
&demo->current_buffer);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
@ -620,7 +640,8 @@ static void demo_draw(struct demo *demo) {
// must be recreated:
demo_resize(demo);
demo_draw(demo);
vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
vkDestroySemaphore(demo->device, imageAcquiredSemaphore, NULL);
vkDestroySemaphore(demo->device, drawCompleteSemaphore, NULL);
return;
} else if (err == VK_SUBOPTIMAL_KHR) {
// demo->swapchain is not as optimal as it could be, but the platform's
@ -629,12 +650,6 @@ static void demo_draw(struct demo *demo) {
assert(!err);
}
// Assume the command buffer has been run on current_buffer before so
// we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL
demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
demo_flush_init_cmd(demo);
// Wait for the present complete semaphore to be signaled to ensure
@ -642,7 +657,6 @@ static void demo_draw(struct demo *demo) {
// engine has fully released ownership to the application, and it is
// okay to render to the image.
// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
demo_draw_build_cmd(demo);
VkFence nullFence = VK_NULL_HANDLE;
VkPipelineStageFlags pipe_stage_flags =
@ -650,12 +664,12 @@ static void demo_draw(struct demo *demo) {
VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = NULL,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &presentCompleteSemaphore,
.pWaitSemaphores = &imageAcquiredSemaphore,
.pWaitDstStageMask = &pipe_stage_flags,
.commandBufferCount = 1,
.pCommandBuffers = &demo->draw_cmd,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL};
.signalSemaphoreCount = 1,
.pSignalSemaphores = &drawCompleteSemaphore};
err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
assert(!err);
@ -663,12 +677,13 @@ static void demo_draw(struct demo *demo) {
VkPresentInfoKHR present = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = NULL,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &drawCompleteSemaphore,
.swapchainCount = 1,
.pSwapchains = &demo->swapchain,
.pImageIndices = &demo->current_buffer,
};
// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
err = demo->fpQueuePresentKHR(demo->queue, &present);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// demo->swapchain is out of date (e.g. the window was resized) and
@ -684,7 +699,8 @@ static void demo_draw(struct demo *demo) {
err = vkQueueWaitIdle(demo->queue);
assert(err == VK_SUCCESS);
vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
vkDestroySemaphore(demo->device, imageAcquiredSemaphore, NULL);
vkDestroySemaphore(demo->device, drawCompleteSemaphore, NULL);
}
static void demo_prepare_buffers(struct demo *demo) {
@ -709,12 +725,25 @@ static void demo_prepare_buffers(struct demo *demo) {
assert(!err);
VkExtent2D swapchainExtent;
// width and height are either both -1, or both not -1.
if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
// If the surface size is undefined, the size is set to
// the size of the images requested.
// width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
// If the surface size is undefined, the size is set to the size
// of the images requested, which must fit within the minimum and
// maximum values.
swapchainExtent.width = demo->width;
swapchainExtent.height = demo->height;
if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
swapchainExtent.width = surfCapabilities.minImageExtent.width;
} else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) {
swapchainExtent.width = surfCapabilities.maxImageExtent.width;
}
if (swapchainExtent.height < surfCapabilities.minImageExtent.height) {
swapchainExtent.height = surfCapabilities.minImageExtent.height;
} else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {
swapchainExtent.height = surfCapabilities.maxImageExtent.height;
}
} else {
// If the surface size is defined, the swap chain size must match
swapchainExtent = surfCapabilities.currentExtent;
@ -724,15 +753,16 @@ static void demo_prepare_buffers(struct demo *demo) {
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
// Determine the number of VkImage's to use in the swap chain (we desire to
// own only 1 image at a time, besides the images being displayed and
// queued for display):
uint32_t desiredNumberOfSwapchainImages =
surfCapabilities.minImageCount + 1;
// Determine the number of VkImage's to use in the swap chain.
// Application desires to only acquire 1 image at a time (which is
// "surfCapabilities.minImageCount").
uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
// If maxImageCount is 0, we can ask for as many images as we want;
// otherwise we're limited to maxImageCount
if ((surfCapabilities.maxImageCount > 0) &&
(desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
(desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
// Application must settle for fewer images than desired:
desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
}
VkSurfaceTransformFlagsKHR preTransform;
@ -747,7 +777,7 @@ static void demo_prepare_buffers(struct demo *demo) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = NULL,
.surface = demo->surface,
.minImageCount = desiredNumberOfSwapchainImages,
.minImageCount = desiredNumOfSwapchainImages,
.imageFormat = demo->format,
.imageColorSpace = demo->color_space,
.imageExtent =
@ -818,14 +848,6 @@ static void demo_prepare_buffers(struct demo *demo) {
demo->buffers[i].image = swapchainImages[i];
// Render loop will expect image to have been used before and in
// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
// layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image
// to that state
demo_set_image_layout(
demo, demo->buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
color_attachment_view.image = demo->buffers[i].image;
err = vkCreateImageView(demo->device, &color_attachment_view, NULL,
@ -906,7 +928,8 @@ static void demo_prepare_depth(struct demo *demo) {
demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
0);
/* create image view */
view.image = demo->depth.image;
@ -939,6 +962,7 @@ demo_prepare_texture_image(struct demo *demo, const uint32_t *tex_colors,
.tiling = tiling,
.usage = usage,
.flags = 0,
.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
};
VkMemoryAllocateInfo mem_alloc = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
@ -997,7 +1021,8 @@ demo_prepare_texture_image(struct demo *demo, const uint32_t *tex_colors,
tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, tex_obj->imageLayout);
VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout,
VK_ACCESS_HOST_WRITE_BIT);
/* setting the image layout does not reference the actual memory so no need
* to add a mem ref */
}
@ -1025,20 +1050,22 @@ static void demo_prepare_textures(struct demo *demo) {
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
!demo->use_staging_buffer) {
/* Device can texture using linear textures */
demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
demo_prepare_texture_image(
demo, tex_colors[i], &demo->textures[i], VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
} else if (props.optimalTilingFeatures &
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
/* Must use staging buffer to copy linear texture to optimized */
struct texture_object staging_texture;
memset(&staging_texture, 0, sizeof(staging_texture));
demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
demo_prepare_texture_image(
demo, tex_colors[i], &staging_texture, VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
demo_prepare_texture_image(
demo, tex_colors[i], &demo->textures[i],
@ -1049,12 +1076,14 @@ static void demo_prepare_textures(struct demo *demo) {
demo_set_image_layout(demo, staging_texture.image,
VK_IMAGE_ASPECT_COLOR_BIT,
staging_texture.imageLayout,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
0);
demo_set_image_layout(demo, demo->textures[i].image,
VK_IMAGE_ASPECT_COLOR_BIT,
demo->textures[i].imageLayout,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
0);
VkImageCopy copy_region = {
.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
@ -1072,7 +1101,8 @@ static void demo_prepare_textures(struct demo *demo) {
demo_set_image_layout(demo, demo->textures[i].image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
demo->textures[i].imageLayout);
demo->textures[i].imageLayout,
0);
demo_flush_init_cmd(demo);
@ -1165,7 +1195,8 @@ static void demo_prepare_vertices(struct demo *demo) {
mem_alloc.allocationSize = mem_reqs.size;
pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&mem_alloc.memoryTypeIndex);
assert(pass);
@ -1376,6 +1407,7 @@ static void demo_prepare_pipeline(struct demo *demo) {
rs.depthClampEnable = VK_FALSE;
rs.rasterizerDiscardEnable = VK_FALSE;
rs.depthBiasEnable = VK_FALSE;
rs.lineWidth = 1.0f;
memset(&cb, 0, sizeof(cb));
cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
@ -1608,6 +1640,9 @@ static void demo_run(struct demo *demo) {
// Wait for work to finish before updating MVP.
vkDeviceWaitIdle(demo->device);
demo->curFrame++;
if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
glfwSetWindowShouldClose(demo->window, GLFW_TRUE);
}
}
@ -1636,7 +1671,7 @@ static void demo_create_window(struct demo *demo) {
* Return 1 (true) if all layer names specified in check_names
* can be found in given layer properties.
*/
static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
static VkBool32 demo_check_layers(uint32_t check_count, const char **check_names,
uint32_t layer_count,
VkLayerProperties *layers) {
uint32_t i, j;
@ -1656,79 +1691,77 @@ static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
return 1;
}
VKAPI_ATTR void *VKAPI_CALL myrealloc(void *pUserData, void *pOriginal,
size_t size, size_t alignment,
VkSystemAllocationScope allocationScope) {
return realloc(pOriginal, size);
}
VKAPI_ATTR void *VKAPI_CALL myalloc(void *pUserData, size_t size,
size_t alignment,
VkSystemAllocationScope allocationScope) {
#ifdef _MSC_VER
return _aligned_malloc(size, alignment);
#else
return aligned_alloc(alignment, size);
#endif
}
VKAPI_ATTR void VKAPI_CALL myfree(void *pUserData, void *pMemory) {
#ifdef _MSC_VER
_aligned_free(pMemory);
#else
free(pMemory);
#endif
}
static void demo_init_vk(struct demo *demo) {
VkResult err;
uint32_t required_extension_count;
const char** required_extensions;
uint32_t i;
uint32_t i = 0;
uint32_t required_extension_count = 0;
uint32_t instance_extension_count = 0;
uint32_t instance_layer_count = 0;
uint32_t device_validation_layer_count = 0;
uint32_t validation_layer_count = 0;
const char **required_extensions = NULL;
const char **instance_validation_layers = NULL;
demo->enabled_extension_count = 0;
demo->enabled_layer_count = 0;
char *instance_validation_layers[] = {
"VK_LAYER_LUNARG_mem_tracker",
"VK_LAYER_GOOGLE_unique_objects",
char *instance_validation_layers_alt1[] = {
"VK_LAYER_LUNARG_standard_validation"
};
demo->device_validation_layers[0] = "VK_LAYER_LUNARG_mem_tracker";
demo->device_validation_layers[1] = "VK_LAYER_GOOGLE_unique_objects";
device_validation_layer_count = 2;
char *instance_validation_layers_alt2[] = {
"VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
"VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image",
"VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain",
"VK_LAYER_GOOGLE_unique_objects"
};
/* Look for validation layers */
VkBool32 validation_found = 0;
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
assert(!err);
if (demo->validate) {
if (instance_layer_count > 0) {
VkLayerProperties *instance_layers =
malloc(sizeof(VkLayerProperties) * instance_layer_count);
err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
instance_layers);
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
assert(!err);
if (demo->validate) {
instance_validation_layers = instance_validation_layers_alt1;
if (instance_layer_count > 0) {
VkLayerProperties *instance_layers =
malloc(sizeof (VkLayerProperties) * instance_layer_count);
err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
instance_layers);
assert(!err);
validation_found = demo_check_layers(
ARRAY_SIZE(instance_validation_layers),
instance_validation_layers, instance_layer_count,
instance_layers);
demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers);
ARRAY_SIZE(instance_validation_layers_alt1),
instance_validation_layers, instance_layer_count,
instance_layers);
if (validation_found) {
demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
demo->enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation";
validation_layer_count = 1;
} else {
// use alternative set of validation layers
instance_validation_layers = instance_validation_layers_alt2;
demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
validation_found = demo_check_layers(
ARRAY_SIZE(instance_validation_layers_alt2),
instance_validation_layers, instance_layer_count,
instance_layers);
validation_layer_count =
ARRAY_SIZE(instance_validation_layers_alt2);
for (i = 0; i < validation_layer_count; i++) {
demo->enabled_layers[i] = instance_validation_layers[i];
}
}
free(instance_layers);
}
free(instance_layers);
}
if (demo->validate && !validation_found) {
ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
"required validation layer.\n\n"
"Please look at the Getting Started guide for additional "
"information.\n",
"vkCreateInstance Failure");
if (!validation_found) {
ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
"required validation layer.\n\n"
"Please look at the Getting Started guide for additional "
"information.\n",
"vkCreateInstance Failure");
}
}
/* Look for instance extensions */
@ -1792,11 +1825,7 @@ static void demo_init_vk(struct demo *demo) {
uint32_t gpu_count;
demo->allocator.pfnAllocation = myalloc;
demo->allocator.pfnFree = myfree;
demo->allocator.pfnReallocation = myrealloc;
err = vkCreateInstance(&inst_info, &demo->allocator, &demo->inst);
err = vkCreateInstance(&inst_info, NULL, &demo->inst);
if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
"(ICD).\n\nPlease look at the Getting Started guide for "
@ -1834,40 +1863,6 @@ static void demo_init_vk(struct demo *demo) {
"vkEnumeratePhysicalDevices Failure");
}
/* Look for validation layers */
validation_found = 0;
demo->enabled_layer_count = 0;
uint32_t device_layer_count = 0;
err =
vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
assert(!err);
if (device_layer_count > 0) {
VkLayerProperties *device_layers =
malloc(sizeof(VkLayerProperties) * device_layer_count);
err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
device_layers);
assert(!err);
if (demo->validate) {
validation_found = demo_check_layers(device_validation_layer_count,
demo->device_validation_layers,
device_layer_count,
device_layers);
demo->enabled_layer_count = device_validation_layer_count;
}
free(device_layers);
}
if (demo->validate && !validation_found) {
ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
"a required validation layer.\n\n"
"Please look at the Getting Started guide for additional "
"information.\n",
"vkCreateDevice Failure");
}
/* Look for device extensions */
uint32_t device_extension_count = 0;
VkBool32 swapchainExtFound = 0;
@ -1911,17 +1906,33 @@ static void demo_init_vk(struct demo *demo) {
demo->CreateDebugReportCallback =
(PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
demo->inst, "vkCreateDebugReportCallbackEXT");
demo->DestroyDebugReportCallback =
(PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
demo->inst, "vkDestroyDebugReportCallbackEXT");
if (!demo->CreateDebugReportCallback) {
ERR_EXIT(
"GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
"vkGetProcAddr Failure");
}
if (!demo->DestroyDebugReportCallback) {
ERR_EXIT(
"GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
"vkGetProcAddr Failure");
}
demo->DebugReportMessage =
(PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
demo->inst, "vkDebugReportMessageEXT");
if (!demo->DebugReportMessage) {
ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
"vkGetProcAddr Failure");
}
VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
dbgCreateInfo.flags =
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
dbgCreateInfo.pfnCallback = dbgFunc;
dbgCreateInfo.pUserData = NULL;
dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
dbgCreateInfo.pUserData = demo;
dbgCreateInfo.pNext = NULL;
err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
&demo->msg_callback);
@ -1945,11 +1956,6 @@ static void demo_init_vk(struct demo *demo) {
GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
@ -1963,6 +1969,8 @@ static void demo_init_vk(struct demo *demo) {
demo->queue_props);
assert(demo->queue_count >= 1);
vkGetPhysicalDeviceFeatures(demo->gpu, &demo->gpu_features);
// Graphics queue and MemMgr queue can be separate.
// TODO: Add support for separate queues, including synchronization,
// and appropriate tracking for QueueSubmit
@ -1979,18 +1987,23 @@ static void demo_init_device(struct demo *demo) {
.queueCount = 1,
.pQueuePriorities = queue_priorities};
VkPhysicalDeviceFeatures features;
memset(&features, 0, sizeof(features));
if (demo->gpu_features.shaderClipDistance) {
features.shaderClipDistance = VK_TRUE;
}
VkDeviceCreateInfo device = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = NULL,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queue,
.enabledLayerCount = demo->enabled_layer_count,
.ppEnabledLayerNames =
(const char *const *)((demo->validate)
? demo->device_validation_layers
: NULL),
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = demo->enabled_extension_count,
.ppEnabledExtensionNames = (const char *const *)demo->extension_names,
.pEnabledFeatures = &features,
};
err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
@ -2092,6 +2105,8 @@ static void demo_init_vk_swapchain(struct demo *demo) {
}
demo->color_space = surfFormats[0].colorSpace;
demo->curFrame = 0;
// Get Memory information and properties
vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
}
@ -2115,12 +2130,34 @@ static void demo_init_connection(struct demo *demo) {
static void demo_init(struct demo *demo, const int argc, const char *argv[])
{
int i;
memset(demo, 0, sizeof(*demo));
demo->frameCount = INT32_MAX;
for (i = 0; i < argc; i++) {
if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0)
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--use_staging") == 0) {
demo->use_staging_buffer = true;
continue;
}
if (strcmp(argv[i], "--break") == 0) {
demo->use_break = true;
continue;
}
if (strcmp(argv[i], "--validate") == 0) {
demo->validate = true;
continue;
}
if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
demo->frameCount >= 0) {
i++;
continue;
}
fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] "
"[--c <framecount>]\n",
APP_SHORT_NAME);
fflush(stderr);
exit(1);
}
demo_init_connection(demo);
@ -2174,8 +2211,11 @@ static void demo_cleanup(struct demo *demo) {
free(demo->buffers);
vkDestroyDevice(demo->device, NULL);
if (demo->validate) {
demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
}
vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
vkDestroyInstance(demo->inst, &demo->allocator);
vkDestroyInstance(demo->inst, NULL);
free(demo->queue_props);
@ -2186,6 +2226,11 @@ static void demo_cleanup(struct demo *demo) {
static void demo_resize(struct demo *demo) {
uint32_t i;
// In order to properly resize the window, we must re-create the swapchain
// AND redo the command buffers, etc.
//
// First, perform part of the demo_cleanup() function:
for (i = 0; i < demo->swapchainImageCount; i++) {
vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
}
@ -2240,6 +2285,6 @@ int main(const int argc, const char *argv[]) {
demo_cleanup(&demo);
return 0;
return validation_error;
}