mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2024-11-14 05:17:40 -07:00
No more context mess (#1531)
* WIP: use Duckstation's context code to directly render into QT Widget from separate thread without two OpenGL contexts currently only works on Windows * reenable gay OSD * add back vsync * make it atleast a little more thread safe * linux support * don't segfault on closing * reorganise and cleanup build system it's still not good, but better than before * macos? * try to get it working on Ubuntu CI also update instructions * let's try this * ok how about this * try creating an OGL 4.3 context first (https://i.kym-cdn.com/photos/images/original/001/264/842/220.png) * fix Ubuntu * hm * try again for Windows * let's try this * make the OpenGL renderer work again that was stupid * do OGL surface resizing from the mainthread * Fix small mistake in GL context creation on macOS causing version 3.2 to be considered invalid * C stupidness * cleanup * don't let the emuthread deinit OGL if there's no OGL * reset lastScreenWidth/Height when deiniting OpenGL * disable stencil test while drawing framebuffers * macOS: Link Cocoa framework explicitly when not building with Qt6 Seems to be needed for the classes used by DuckStation's GL context code. * Set ScreenPanelGL's minimum size immediately Fixes GL context creation for OpenGL display on macOS using the wrong size as the underlying window was not resized to the correct size by Qt yet. * don't emit window updates when OGL display is used * stuff Arisotura said Co-authored-by: Nadia Holmquist Pedersen <nadia@nhp.sh>
This commit is contained in:
parent
31ba585d39
commit
ac3118cbc5
2
.github/workflows/build-ubuntu-aarch64.yml
vendored
2
.github/workflows/build-ubuntu-aarch64.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
||||
rm /etc/apt/sources.list
|
||||
mv /etc/apt/sources.list{.new,}
|
||||
apt update
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y {gcc-10,g++-10,pkg-config}-aarch64-linux-gnu {libsdl2,qtbase5,qtmultimedia5,libslirp,libarchive,libepoxy}-dev:arm64 cmake dpkg-dev
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y {gcc-10,g++-10,pkg-config}-aarch64-linux-gnu {libsdl2,qtbase5,qtbase5-private,qtmultimedia5,libslirp,libarchive}-dev:arm64 cmake extra-cmake-modules dpkg-dev
|
||||
- name: Configure
|
||||
shell: bash
|
||||
run: |
|
||||
|
2
.github/workflows/build-ubuntu.yml
vendored
2
.github/workflows/build-ubuntu.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
run: |
|
||||
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list
|
||||
sudo apt update
|
||||
sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtmultimedia5-dev libslirp0 libslirp-dev libarchive-dev libepoxy-dev --allow-downgrades
|
||||
sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp0 libslirp-dev libarchive-dev --allow-downgrades
|
||||
- name: Create build environment
|
||||
run: mkdir ${{runner.workspace}}/build
|
||||
- name: Configure
|
||||
|
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
update: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: pacman -Sq --noconfirm git make mingw-w64-x86_64-{cmake,mesa,SDL2,qt5-static,libslirp,libarchive,libepoxy,toolchain}
|
||||
run: pacman -Sq --noconfirm git make pkgconf mingw-w64-x86_64-{cmake,mesa,SDL2,qt5-static,libslirp,libarchive,libepoxy,toolchain}
|
||||
|
||||
- name: Create build environment
|
||||
working-directory: ${{runner.workspace}}
|
||||
|
12
README.md
12
README.md
@ -36,9 +36,9 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||
|
||||
### Linux
|
||||
1. Install dependencies:
|
||||
* Ubuntu 22.04: `sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtmultimedia5-dev libslirp-dev libarchive-dev libepoxy-dev`
|
||||
* Older Ubuntu: `sudo apt install cmake libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtmultimedia5-dev libslirp-dev libarchive-dev libepoxy-dev`
|
||||
* Arch Linux: `sudo pacman -S base-devel cmake git libpcap sdl2 qt5-base qt5-multimedia libslirp libarchive libepoxy`
|
||||
* Ubuntu 22.04: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qtbase5-dev qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev`
|
||||
* Older Ubuntu: `sudo apt install cmake extra-cmake-modules libcurl4-gnutls-dev libpcap0.8-dev libsdl2-dev qt5-default qtbase5-private-dev qtmultimedia5-dev libslirp-dev libarchive-dev`
|
||||
* Arch Linux: `sudo pacman -S base-devel cmake extra-cmake-modules git libpcap sdl2 qt5-base qt5-multimedia libslirp libarchive`
|
||||
3. Download the melonDS repository and prepare:
|
||||
```bash
|
||||
git clone https://github.com/melonDS-emu/melonDS
|
||||
@ -65,7 +65,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||
cd melonDS
|
||||
```
|
||||
#### Dynamic builds (with DLLs)
|
||||
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,libslirp,libarchive,libepoxy}`
|
||||
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-base,qt5-svg,qt5-multimedia,libslirp,libarchive}`
|
||||
6. Compile:
|
||||
```bash
|
||||
cmake -B build -G "MSYS Makefiles"
|
||||
@ -76,7 +76,7 @@ As for the rest, the interface should be pretty straightforward. If you have a q
|
||||
If everything went well, melonDS and the libraries it needs should now be in the `dist` folder.
|
||||
|
||||
#### Static builds (without DLLs, standalone executable)
|
||||
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-static,libslirp,libarchive,libepoxy}`
|
||||
5. Install dependencies: `pacman -S make mingw-w64-x86_64-{cmake,mesa,SDL2,toolchain,qt5-static,libslirp,libarchive}`
|
||||
6. Compile:
|
||||
```bash
|
||||
cmake -B build -G 'MSYS Makefiles' -DBUILD_STATIC=ON -DCMAKE_PREFIX_PATH=/mingw64/qt5-static
|
||||
@ -86,7 +86,7 @@ If everything went well, melonDS should now be in the `build` folder.
|
||||
|
||||
### macOS
|
||||
1. Install the [Homebrew Package Manager](https://brew.sh)
|
||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive libepoxy`
|
||||
2. Install dependencies: `brew install git pkg-config cmake sdl2 qt@6 libslirp libarchive`
|
||||
3. Download the melonDS repository and prepare:
|
||||
```zsh
|
||||
git clone https://github.com/melonDS-emu/melonDS
|
||||
|
297
cmake/ECMFindModuleHelpers.cmake
Normal file
297
cmake/ECMFindModuleHelpers.cmake
Normal file
@ -0,0 +1,297 @@
|
||||
#.rst:
|
||||
# ECMFindModuleHelpers
|
||||
# --------------------
|
||||
#
|
||||
# Helper macros for find modules: ecm_find_package_version_check(),
|
||||
# ecm_find_package_parse_components() and
|
||||
# ecm_find_package_handle_library_components().
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_version_check(<name>)
|
||||
#
|
||||
# Prints warnings if the CMake version or the project's required CMake version
|
||||
# is older than that required by extra-cmake-modules.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_parse_components(<name>
|
||||
# RESULT_VAR <variable>
|
||||
# KNOWN_COMPONENTS <component1> [<component2> [...]]
|
||||
# [SKIP_DEPENDENCY_HANDLING])
|
||||
#
|
||||
# This macro will populate <variable> with a list of components found in
|
||||
# <name>_FIND_COMPONENTS, after checking that all those components are in the
|
||||
# list of KNOWN_COMPONENTS; if there are any unknown components, it will print
|
||||
# an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
|
||||
# return().
|
||||
#
|
||||
# The order of components in <variable> is guaranteed to match the order they
|
||||
# are listed in the KNOWN_COMPONENTS argument.
|
||||
#
|
||||
# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable
|
||||
# <name>_<component>_component_deps will be checked for dependent components.
|
||||
# If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
|
||||
# dependencies will also be added to <variable>.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_find_package_handle_library_components(<name>
|
||||
# COMPONENTS <component> [<component> [...]]
|
||||
# [SKIP_DEPENDENCY_HANDLING])
|
||||
# [SKIP_PKG_CONFIG])
|
||||
#
|
||||
# Creates an imported library target for each component. The operation of this
|
||||
# macro depends on the presence of a number of CMake variables.
|
||||
#
|
||||
# The <name>_<component>_lib variable should contain the name of this library,
|
||||
# and <name>_<component>_header variable should contain the name of a header
|
||||
# file associated with it (whatever relative path is normally passed to
|
||||
# '#include'). <name>_<component>_header_subdir variable can be used to specify
|
||||
# which subdirectory of the include path the headers will be found in.
|
||||
# ecm_find_package_components() will then search for the library
|
||||
# and include directory (creating appropriate cache variables) and create an
|
||||
# imported library target named <name>::<component>.
|
||||
#
|
||||
# Additional variables can be used to provide additional information:
|
||||
#
|
||||
# If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and
|
||||
# pkg-config is found, the pkg-config module given by
|
||||
# <name>_<component>_pkg_config will be searched for and used to help locate the
|
||||
# library and header file. It will also be used to set
|
||||
# <name>_<component>_VERSION.
|
||||
#
|
||||
# Note that if version information is found via pkg-config,
|
||||
# <name>_<component>_FIND_VERSION can be set to require a particular version
|
||||
# for each component.
|
||||
#
|
||||
# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
|
||||
# of the imported target for <component> will be set to contain the imported
|
||||
# targets for the components listed in <name>_<component>_component_deps.
|
||||
# <component>_FOUND will also be set to false if any of the compoments in
|
||||
# <name>_<component>_component_deps are not found. This requires the components
|
||||
# in <name>_<component>_component_deps to be listed before <component> in the
|
||||
# COMPONENTS argument.
|
||||
#
|
||||
# The following variables will be set:
|
||||
#
|
||||
# ``<name>_TARGETS``
|
||||
# the imported targets
|
||||
# ``<name>_LIBRARIES``
|
||||
# the found libraries
|
||||
# ``<name>_INCLUDE_DIRS``
|
||||
# the combined required include directories for the components
|
||||
# ``<name>_DEFINITIONS``
|
||||
# the "other" CFLAGS provided by pkg-config, if any
|
||||
# ``<name>_VERSION``
|
||||
# the value of ``<name>_<component>_VERSION`` for the first component that
|
||||
# has this variable set (note that components are searched for in the order
|
||||
# they are passed to the macro), although if it is already set, it will not
|
||||
# be altered
|
||||
#
|
||||
# Note that these variables are never cleared, so if
|
||||
# ecm_find_package_handle_library_components() is called multiple times with
|
||||
# different components (typically because of multiple find_package() calls) then
|
||||
# ``<name>_TARGETS``, for example, will contain all the targets found in any
|
||||
# call (although no duplicates).
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
macro(ecm_find_package_version_check module_name)
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
|
||||
endif()
|
||||
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
|
||||
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ecm_find_package_parse_components module_name)
|
||||
set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
|
||||
set(ecm_fppc_oneValueArgs RESULT_VAR)
|
||||
set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
|
||||
cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})
|
||||
|
||||
if(ECM_FPPC_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_RESULT_VAR)
|
||||
message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_KNOWN_COMPONENTS)
|
||||
message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
|
||||
endif()
|
||||
if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
|
||||
set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
|
||||
endif()
|
||||
|
||||
if(${module_name}_FIND_COMPONENTS)
|
||||
set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})
|
||||
|
||||
if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
|
||||
# Make sure deps are included
|
||||
foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
|
||||
foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
|
||||
list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
|
||||
if("${ecm_fppc_index}" STREQUAL "-1")
|
||||
if(NOT ${module_name}_FIND_QUIETLY)
|
||||
message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
|
||||
endif()
|
||||
list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
else()
|
||||
message(STATUS "Skipping dependency handling for ${module_name}")
|
||||
endif()
|
||||
list(REMOVE_DUPLICATES ecm_fppc_requestedComps)
|
||||
|
||||
# This makes sure components are listed in the same order as
|
||||
# KNOWN_COMPONENTS (potentially important for inter-dependencies)
|
||||
set(${ECM_FPPC_RESULT_VAR})
|
||||
foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
|
||||
list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
|
||||
if(NOT "${ecm_fppc_index}" STREQUAL "-1")
|
||||
list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
|
||||
list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
|
||||
endif()
|
||||
endforeach()
|
||||
# if there are any left, they are unknown components
|
||||
if(ecm_fppc_requestedComps)
|
||||
set(ecm_fppc_msgType STATUS)
|
||||
if(${module_name}_FIND_REQUIRED)
|
||||
set(ecm_fppc_msgType FATAL_ERROR)
|
||||
endif()
|
||||
if(NOT ${module_name}_FIND_QUIETLY)
|
||||
message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
else()
|
||||
set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(ecm_find_package_handle_library_components module_name)
|
||||
set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
|
||||
set(ecm_fpwc_oneValueArgs)
|
||||
set(ecm_fpwc_multiValueArgs COMPONENTS)
|
||||
cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})
|
||||
|
||||
if(ECM_FPWC_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
if(NOT ECM_FPWC_COMPONENTS)
|
||||
message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package(PkgConfig)
|
||||
foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
|
||||
set(ecm_fpwc_dep_vars)
|
||||
set(ecm_fpwc_dep_targets)
|
||||
if(NOT SKIP_DEPENDENCY_HANDLING)
|
||||
foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
|
||||
list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
|
||||
list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
|
||||
pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
|
||||
${${module_name}_${ecm_fpwc_comp}_pkg_config})
|
||||
endif()
|
||||
|
||||
find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
NAMES ${${module_name}_${ecm_fpwc_comp}_header}
|
||||
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
|
||||
)
|
||||
find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
|
||||
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
|
||||
if(NOT ${module_name}_VERSION)
|
||||
set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
|
||||
FOUND_VAR
|
||||
${module_name}_${ecm_fpwc_comp}_FOUND
|
||||
REQUIRED_VARS
|
||||
${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
${ecm_fpwc_dep_vars}
|
||||
VERSION_VAR
|
||||
${module_name}_${ecm_fpwc_comp}_VERSION
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
${module_name}_${ecm_fpwc_comp}_LIBRARY
|
||||
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(${module_name}_${ecm_fpwc_comp}_FOUND)
|
||||
list(APPEND ${module_name}_LIBRARIES
|
||||
"${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
|
||||
list(APPEND ${module_name}_INCLUDE_DIRS
|
||||
"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
|
||||
set(${module_name}_DEFINITIONS
|
||||
${${module_name}_DEFINITIONS}
|
||||
${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
|
||||
if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
|
||||
add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
|
||||
set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
|
||||
IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
|
||||
)
|
||||
endif()
|
||||
list(APPEND ${module_name}_TARGETS
|
||||
"${module_name}::${ecm_fpwc_comp}")
|
||||
endif()
|
||||
endforeach()
|
||||
if(${module_name}_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
|
||||
endif()
|
||||
if(${module_name}_INCLUDE_DIRS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
|
||||
endif()
|
||||
if(${module_name}_DEFINITIONS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
|
||||
endif()
|
||||
if(${module_name}_TARGETS)
|
||||
list(REMOVE_DUPLICATES ${module_name}_TARGETS)
|
||||
endif()
|
||||
endmacro()
|
1
cmake/ECMFindModuleHelpersStub.cmake
Normal file
1
cmake/ECMFindModuleHelpersStub.cmake
Normal file
@ -0,0 +1 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake)
|
172
cmake/FindEGL.cmake
Normal file
172
cmake/FindEGL.cmake
Normal file
@ -0,0 +1,172 @@
|
||||
#.rst:
|
||||
# FindEGL
|
||||
# -------
|
||||
#
|
||||
# Try to find EGL.
|
||||
#
|
||||
# This will define the following variables:
|
||||
#
|
||||
# ``EGL_FOUND``
|
||||
# True if (the requested version of) EGL is available
|
||||
# ``EGL_VERSION``
|
||||
# The version of EGL; note that this is the API version defined in the
|
||||
# headers, rather than the version of the implementation (eg: Mesa)
|
||||
# ``EGL_LIBRARIES``
|
||||
# This can be passed to target_link_libraries() instead of the ``EGL::EGL``
|
||||
# target
|
||||
# ``EGL_INCLUDE_DIRS``
|
||||
# This should be passed to target_include_directories() if the target is not
|
||||
# used for linking
|
||||
# ``EGL_DEFINITIONS``
|
||||
# This should be passed to target_compile_options() if the target is not
|
||||
# used for linking
|
||||
#
|
||||
# If ``EGL_FOUND`` is TRUE, it will also define the following imported target:
|
||||
#
|
||||
# ``EGL::EGL``
|
||||
# The EGL library
|
||||
#
|
||||
# In general we recommend using the imported target, as it is easier to use.
|
||||
# Bear in mind, however, that if the target is in the link interface of an
|
||||
# exported library, it must be made available by the package config file.
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#=============================================================================
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
ecm_find_package_version_check(EGL)
|
||||
|
||||
# Use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PKG_EGL QUIET egl)
|
||||
|
||||
set(EGL_DEFINITIONS ${PKG_EGL_CFLAGS_OTHER})
|
||||
|
||||
find_path(EGL_INCLUDE_DIR
|
||||
NAMES
|
||||
EGL/egl.h
|
||||
HINTS
|
||||
${PKG_EGL_INCLUDE_DIRS}
|
||||
)
|
||||
find_library(EGL_LIBRARY
|
||||
NAMES
|
||||
EGL
|
||||
HINTS
|
||||
${PKG_EGL_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# NB: We do *not* use the version information from pkg-config, as that
|
||||
# is the implementation version (eg: the Mesa version)
|
||||
if(EGL_INCLUDE_DIR)
|
||||
# egl.h has defines of the form EGL_VERSION_x_y for each supported
|
||||
# version; so the header for EGL 1.1 will define EGL_VERSION_1_0 and
|
||||
# EGL_VERSION_1_1. Finding the highest supported version involves
|
||||
# finding all these defines and selecting the highest numbered.
|
||||
file(READ "${EGL_INCLUDE_DIR}/EGL/egl.h" _EGL_header_contents)
|
||||
string(REGEX MATCHALL
|
||||
"[ \t]EGL_VERSION_[0-9_]+"
|
||||
_EGL_version_lines
|
||||
"${_EGL_header_contents}"
|
||||
)
|
||||
unset(_EGL_header_contents)
|
||||
foreach(_EGL_version_line ${_EGL_version_lines})
|
||||
string(REGEX REPLACE
|
||||
"[ \t]EGL_VERSION_([0-9_]+)"
|
||||
"\\1"
|
||||
_version_candidate
|
||||
"${_EGL_version_line}"
|
||||
)
|
||||
string(REPLACE "_" "." _version_candidate "${_version_candidate}")
|
||||
if(NOT DEFINED EGL_VERSION OR EGL_VERSION VERSION_LESS _version_candidate)
|
||||
set(EGL_VERSION "${_version_candidate}")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_EGL_version_lines)
|
||||
endif()
|
||||
|
||||
cmake_push_check_state(RESET)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}")
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <EGL/egl.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0;
|
||||
eglDestroyContext(dpy, ctx);
|
||||
}" HAVE_EGL)
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(required_vars EGL_INCLUDE_DIR HAVE_EGL)
|
||||
if(NOT EMSCRIPTEN)
|
||||
list(APPEND required_vars EGL_LIBRARY)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(EGL
|
||||
FOUND_VAR
|
||||
EGL_FOUND
|
||||
REQUIRED_VARS
|
||||
${required_vars}
|
||||
VERSION_VAR
|
||||
EGL_VERSION
|
||||
)
|
||||
|
||||
if(EGL_FOUND AND NOT TARGET EGL::EGL)
|
||||
if (EMSCRIPTEN)
|
||||
add_library(EGL::EGL INTERFACE IMPORTED)
|
||||
# Nothing further to be done, system include paths have headers and linkage is implicit.
|
||||
else()
|
||||
add_library(EGL::EGL UNKNOWN IMPORTED)
|
||||
set_target_properties(EGL::EGL PROPERTIES
|
||||
IMPORTED_LOCATION "${EGL_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${EGL_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${EGL_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
mark_as_advanced(EGL_LIBRARY EGL_INCLUDE_DIR HAVE_EGL)
|
||||
|
||||
# compatibility variables
|
||||
set(EGL_LIBRARIES ${EGL_LIBRARY})
|
||||
set(EGL_INCLUDE_DIRS ${EGL_INCLUDE_DIR})
|
||||
set(EGL_VERSION_STRING ${EGL_VERSION})
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(EGL PROPERTIES
|
||||
URL "https://www.khronos.org/egl/"
|
||||
DESCRIPTION "A platform-agnostic mechanism for creating rendering surfaces for use with other graphics libraries, such as OpenGL|ES and OpenVG."
|
||||
)
|
@ -65,6 +65,8 @@ if (ENABLE_OGLRENDERER)
|
||||
GPU3D_OpenGL.cpp
|
||||
GPU3D_OpenGL_shaders.h
|
||||
OpenGLSupport.cpp)
|
||||
|
||||
target_compile_definitions(core PUBLIC OGLRENDERER_ENABLED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_JIT)
|
||||
@ -116,20 +118,9 @@ if (MATH_LIBRARY)
|
||||
target_link_libraries(core PRIVATE ${MATH_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (ENABLE_OGLRENDERER)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(Epoxy REQUIRED IMPORTED_TARGET epoxy)
|
||||
fix_interface_includes(PkgConfig::Epoxy)
|
||||
|
||||
target_link_libraries(core PUBLIC PkgConfig::Epoxy)
|
||||
|
||||
target_compile_definitions(core PUBLIC OGLRENDERER_ENABLED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_JIT)
|
||||
target_compile_definitions(core PUBLIC JIT_ENABLED)
|
||||
|
||||
|
||||
if (ENABLE_JIT_PROFILING)
|
||||
include(cmake/FindVTune.cmake)
|
||||
add_definitions(-DJIT_PROFILING_ENABLED)
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "NDS.h"
|
||||
#include "GPU.h"
|
||||
#include "GPU3D_OpenGL.h"
|
||||
#include "OpenGLSupport.h"
|
||||
#include "GPU_OpenGL_shaders.h"
|
||||
|
||||
|
@ -22,10 +22,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
|
||||
#include "Platform.h"
|
||||
#include "PlatformOGL.h"
|
||||
|
||||
|
||||
namespace OpenGL
|
||||
|
9
src/PlatformOGL.h
Normal file
9
src/PlatformOGL.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef PLATFORMOGL_H
|
||||
#define PLATFORMOGL_H
|
||||
|
||||
// if you don't wanna use glad for your platform
|
||||
// add your header here!
|
||||
|
||||
#include "frontend/glad/glad.h"
|
||||
|
||||
#endif
|
17
src/frontend/duckstation/duckstation_compat.h
Normal file
17
src/frontend/duckstation/duckstation_compat.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef DUCKSTATION_COMPAT_H
|
||||
#define DUCKSTATION_COMPAT_H
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
|
||||
#define AssertMsg(cond, msg) assert(cond && msg)
|
||||
#define Assert(cond) assert(cond)
|
||||
|
||||
#define Panic(msg) assert(false && msg)
|
||||
|
||||
#define UnreachableCode() __builtin_unreachable
|
||||
|
||||
#endif
|
175
src/frontend/duckstation/gl/context.cpp
Normal file
175
src/frontend/duckstation/gl/context.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
#include "context.h"
|
||||
#include "../log.h"
|
||||
#include "loader.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#ifdef __APPLE__
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
Log_SetChannel(GL::Context);
|
||||
|
||||
#if defined(_WIN32) && !defined(_M_ARM64)
|
||||
#include "context_wgl.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include "context_agl.h"
|
||||
#else
|
||||
#include "context_egl_wayland.h"
|
||||
#include "context_egl_x11.h"
|
||||
#include "context_glx.h"
|
||||
#endif
|
||||
|
||||
namespace GL {
|
||||
|
||||
static bool ShouldPreferESContext()
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
const char* value = std::getenv("PREFER_GLES_CONTEXT");
|
||||
return (value && strcmp(value, "1") == 0);
|
||||
#else
|
||||
char buffer[2] = {};
|
||||
size_t buffer_size = sizeof(buffer);
|
||||
getenv_s(&buffer_size, buffer, "PREFER_GLES_CONTEXT");
|
||||
return (std::strcmp(buffer, "1") == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Context::Context(const WindowInfo& wi) : m_wi(wi) {}
|
||||
|
||||
Context::~Context() = default;
|
||||
|
||||
std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
if (ShouldPreferESContext())
|
||||
{
|
||||
// move ES versions to the front
|
||||
Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * num_versions_to_try));
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
if (versions_to_try[i].profile == Profile::ES)
|
||||
new_versions_to_try[count++] = versions_to_try[i];
|
||||
}
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
if (versions_to_try[i].profile != Profile::ES)
|
||||
new_versions_to_try[count++] = versions_to_try[i];
|
||||
}
|
||||
versions_to_try = new_versions_to_try;
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> context;
|
||||
#if defined(_WIN32) && !defined(_M_ARM64)
|
||||
context = ContextWGL::Create(wi, versions_to_try, num_versions_to_try);
|
||||
#elif defined(__APPLE__)
|
||||
context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try);
|
||||
#else
|
||||
if (wi.type == WindowInfo::Type::X11)
|
||||
{
|
||||
const char* use_egl_x11 = std::getenv("USE_EGL_X11");
|
||||
if (use_egl_x11 && std::strcmp(use_egl_x11, "1") == 0)
|
||||
context = ContextEGLX11::Create(wi, versions_to_try, num_versions_to_try);
|
||||
else
|
||||
context = ContextGLX::Create(wi, versions_to_try, num_versions_to_try);
|
||||
}
|
||||
|
||||
if (wi.type == WindowInfo::Type::Wayland)
|
||||
context = ContextEGLWayland::Create(wi, versions_to_try, num_versions_to_try);
|
||||
#endif
|
||||
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
Log_InfoPrintf("Created a %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL");
|
||||
|
||||
// TODO: Not thread-safe.
|
||||
static Context* context_being_created;
|
||||
context_being_created = context.get();
|
||||
|
||||
if (!gladLoadGLLoader([](const char* name) { return context_being_created->GetProcAddress(name); }))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load GL functions for GLAD");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
const char* gl_shading_language_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
Log_InfoPrintf("GL_VENDOR: %s", gl_vendor);
|
||||
Log_InfoPrintf("GL_RENDERER: %s", gl_renderer);
|
||||
Log_InfoPrintf("GL_VERSION: %s", gl_version);
|
||||
Log_InfoPrintf("GL_SHADING_LANGUAGE_VERSION: %s", gl_shading_language_version);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
const std::array<Context::Version, 11>& Context::GetAllDesktopVersionsList()
|
||||
{
|
||||
static constexpr std::array<Version, 11> vlist = {{{Profile::Core, 4, 6},
|
||||
{Profile::Core, 4, 5},
|
||||
{Profile::Core, 4, 4},
|
||||
{Profile::Core, 4, 3},
|
||||
{Profile::Core, 4, 2},
|
||||
{Profile::Core, 4, 1},
|
||||
{Profile::Core, 4, 0},
|
||||
{Profile::Core, 3, 3},
|
||||
{Profile::Core, 3, 2},
|
||||
{Profile::Core, 3, 1},
|
||||
{Profile::Core, 3, 0}}};
|
||||
return vlist;
|
||||
}
|
||||
|
||||
const std::array<Context::Version, 12>& Context::GetAllDesktopVersionsListWithFallback()
|
||||
{
|
||||
static constexpr std::array<Version, 12> vlist = {{{Profile::Core, 4, 6},
|
||||
{Profile::Core, 4, 5},
|
||||
{Profile::Core, 4, 4},
|
||||
{Profile::Core, 4, 3},
|
||||
{Profile::Core, 4, 2},
|
||||
{Profile::Core, 4, 1},
|
||||
{Profile::Core, 4, 0},
|
||||
{Profile::Core, 3, 3},
|
||||
{Profile::Core, 3, 2},
|
||||
{Profile::Core, 3, 1},
|
||||
{Profile::Core, 3, 0},
|
||||
{Profile::NoProfile, 0, 0}}};
|
||||
return vlist;
|
||||
}
|
||||
|
||||
const std::array<Context::Version, 4>& Context::GetAllESVersionsList()
|
||||
{
|
||||
static constexpr std::array<Version, 4> vlist = {
|
||||
{{Profile::ES, 3, 2}, {Profile::ES, 3, 1}, {Profile::ES, 3, 0}, {Profile::ES, 2, 0}}};
|
||||
return vlist;
|
||||
}
|
||||
|
||||
const std::array<Context::Version, 16>& Context::GetAllVersionsList()
|
||||
{
|
||||
static constexpr std::array<Version, 16> vlist = {{{Profile::Core, 4, 6},
|
||||
{Profile::Core, 4, 5},
|
||||
{Profile::Core, 4, 4},
|
||||
{Profile::Core, 4, 3},
|
||||
{Profile::Core, 4, 2},
|
||||
{Profile::Core, 4, 1},
|
||||
{Profile::Core, 4, 0},
|
||||
{Profile::Core, 3, 3},
|
||||
{Profile::Core, 3, 2},
|
||||
{Profile::Core, 3, 1},
|
||||
{Profile::Core, 3, 0},
|
||||
{Profile::ES, 3, 2},
|
||||
{Profile::ES, 3, 1},
|
||||
{Profile::ES, 3, 0},
|
||||
{Profile::ES, 2, 0},
|
||||
{Profile::NoProfile, 0, 0}}};
|
||||
return vlist;
|
||||
}
|
||||
|
||||
} // namespace GL
|
76
src/frontend/duckstation/gl/context.h
Normal file
76
src/frontend/duckstation/gl/context.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include "../duckstation_compat.h"
|
||||
#include "../window_info.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace GL {
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(const WindowInfo& wi);
|
||||
virtual ~Context();
|
||||
|
||||
enum class Profile
|
||||
{
|
||||
NoProfile,
|
||||
Core,
|
||||
ES
|
||||
};
|
||||
|
||||
struct Version
|
||||
{
|
||||
Profile profile;
|
||||
int major_version;
|
||||
int minor_version;
|
||||
};
|
||||
|
||||
struct FullscreenModeInfo
|
||||
{
|
||||
u32 width;
|
||||
u32 height;
|
||||
float refresh_rate;
|
||||
};
|
||||
|
||||
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_wi; }
|
||||
ALWAYS_INLINE bool IsGLES() const { return (m_version.profile == Profile::ES); }
|
||||
ALWAYS_INLINE u32 GetSurfaceWidth() const { return m_wi.surface_width; }
|
||||
ALWAYS_INLINE u32 GetSurfaceHeight() const { return m_wi.surface_height; }
|
||||
ALWAYS_INLINE WindowInfo::SurfaceFormat GetSurfaceFormat() const { return m_wi.surface_format; }
|
||||
|
||||
virtual void* GetProcAddress(const char* name) = 0;
|
||||
virtual bool ChangeSurface(const WindowInfo& new_wi) = 0;
|
||||
virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) = 0;
|
||||
virtual bool SwapBuffers() = 0;
|
||||
virtual bool MakeCurrent() = 0;
|
||||
virtual bool DoneCurrent() = 0;
|
||||
virtual bool SetSwapInterval(s32 interval) = 0;
|
||||
virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) = 0;
|
||||
|
||||
virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes();
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
template<size_t N>
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const std::array<Version, N>& versions_to_try)
|
||||
{
|
||||
return Create(wi, versions_to_try.data(), versions_to_try.size());
|
||||
}
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi) { return Create(wi, GetAllVersionsList()); }
|
||||
|
||||
static const std::array<Version, 11>& GetAllDesktopVersionsList();
|
||||
static const std::array<Version, 12>& GetAllDesktopVersionsListWithFallback();
|
||||
static const std::array<Version, 4>& GetAllESVersionsList();
|
||||
static const std::array<Version, 16>& GetAllVersionsList();
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
#endif
|
||||
|
||||
WindowInfo m_wi;
|
||||
Version m_version = {};
|
||||
};
|
||||
} // namespace GL
|
49
src/frontend/duckstation/gl/context_agl.h
Normal file
49
src/frontend/duckstation/gl/context_agl.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "context.h"
|
||||
#include "loader.h"
|
||||
|
||||
#if defined(__APPLE__) && defined(__OBJC__)
|
||||
#import <AppKit/AppKit.h>
|
||||
#else
|
||||
struct NSOpenGLContext;
|
||||
struct NSOpenGLPixelFormat;
|
||||
struct NSView;
|
||||
#define __bridge
|
||||
#endif
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextAGL final : public Context
|
||||
{
|
||||
public:
|
||||
ContextAGL(const WindowInfo& wi);
|
||||
~ContextAGL() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
bool ChangeSurface(const WindowInfo& new_wi) override;
|
||||
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
bool SwapBuffers() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SetSwapInterval(s32 interval) override;
|
||||
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE NSView* GetView() const { return static_cast<NSView*>((__bridge NSView*)m_wi.window_handle); }
|
||||
|
||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||
bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current);
|
||||
void BindContextToView();
|
||||
|
||||
// returns true if dimensions have changed
|
||||
bool UpdateDimensions();
|
||||
|
||||
NSOpenGLContext* m_context = nullptr;
|
||||
NSOpenGLPixelFormat* m_pixel_format = nullptr;
|
||||
void* m_opengl_module_handle = nullptr;
|
||||
};
|
||||
|
||||
} // namespace GL
|
214
src/frontend/duckstation/gl/context_agl.mm
Normal file
214
src/frontend/duckstation/gl/context_agl.mm
Normal file
@ -0,0 +1,214 @@
|
||||
#include "context_agl.h"
|
||||
#include "../duckstation_compat.h"
|
||||
#include "../log.h"
|
||||
#include "loader.h"
|
||||
#include <dlfcn.h>
|
||||
Log_SetChannel(GL::ContextAGL);
|
||||
|
||||
namespace GL {
|
||||
ContextAGL::ContextAGL(const WindowInfo& wi) : Context(wi)
|
||||
{
|
||||
m_opengl_module_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_NOW);
|
||||
if (!m_opengl_module_handle)
|
||||
Log_ErrorPrint("Could not open OpenGL.framework, function lookups will probably fail");
|
||||
}
|
||||
|
||||
ContextAGL::~ContextAGL()
|
||||
{
|
||||
if ([NSOpenGLContext currentContext] == m_context)
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
if (m_context)
|
||||
[m_context release];
|
||||
|
||||
if (m_pixel_format)
|
||||
[m_pixel_format release];
|
||||
|
||||
if (m_opengl_module_handle)
|
||||
dlclose(m_opengl_module_handle);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextAGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
{
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
const Version& cv = versions_to_try[i];
|
||||
if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true))
|
||||
{
|
||||
// we already have the dummy context, so just use that
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
else if (cv.profile == Profile::Core)
|
||||
{
|
||||
if (cv.major_version > 4 && cv.minor_version > 1)
|
||||
continue;
|
||||
|
||||
const NSOpenGLPixelFormatAttribute profile = (cv.major_version > 3 || cv.minor_version > 2) ? NSOpenGLProfileVersion4_1Core : NSOpenGLProfileVersion3_2Core;
|
||||
if (CreateContext(nullptr, static_cast<int>(profile), true))
|
||||
{
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* ContextAGL::GetProcAddress(const char* name)
|
||||
{
|
||||
void* addr = m_opengl_module_handle ? dlsym(m_opengl_module_handle, name) : nullptr;
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
return dlsym(RTLD_NEXT, name);
|
||||
}
|
||||
|
||||
bool ContextAGL::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
m_wi = new_wi;
|
||||
BindContextToView();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextAGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
|
||||
{
|
||||
UpdateDimensions();
|
||||
}
|
||||
|
||||
bool ContextAGL::UpdateDimensions()
|
||||
{
|
||||
const NSSize window_size = [GetView() frame].size;
|
||||
const CGFloat window_scale = [[GetView() window] backingScaleFactor];
|
||||
const u32 new_width = static_cast<u32>(static_cast<CGFloat>(window_size.width) * window_scale);
|
||||
const u32 new_height = static_cast<u32>(static_cast<CGFloat>(window_size.height) * window_scale);
|
||||
|
||||
if (m_wi.surface_width == new_width && m_wi.surface_height == new_height)
|
||||
return false;
|
||||
|
||||
m_wi.surface_width = new_width;
|
||||
m_wi.surface_height = new_height;
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
[m_context update];
|
||||
};
|
||||
|
||||
if ([NSThread isMainThread])
|
||||
block();
|
||||
else
|
||||
dispatch_sync(dispatch_get_main_queue(), block);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::SwapBuffers()
|
||||
{
|
||||
[m_context flushBuffer];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::MakeCurrent()
|
||||
{
|
||||
[m_context makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::DoneCurrent()
|
||||
{
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextAGL::SetSwapInterval(s32 interval)
|
||||
{
|
||||
GLint gl_interval = static_cast<GLint>(interval);
|
||||
[m_context setValues:&gl_interval forParameter:NSOpenGLCPSwapInterval];
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextAGL::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
|
||||
|
||||
context->m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:m_context];
|
||||
if (context->m_context == nil)
|
||||
return nullptr;
|
||||
|
||||
context->m_version = m_version;
|
||||
context->m_pixel_format = m_pixel_format;
|
||||
[context->m_pixel_format retain];
|
||||
|
||||
if (wi.type == WindowInfo::Type::MacOS)
|
||||
context->BindContextToView();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextAGL::CreateContext(NSOpenGLContext* share_context, int profile, bool make_current)
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
[m_context release];
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
if (m_pixel_format)
|
||||
[m_pixel_format release];
|
||||
|
||||
const std::array<NSOpenGLPixelFormatAttribute, 5> attribs = {{
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFAOpenGLProfile,
|
||||
static_cast<NSOpenGLPixelFormatAttribute>(profile),
|
||||
NSOpenGLPFAAccelerated,
|
||||
0}};
|
||||
m_pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs.data()];
|
||||
if (m_pixel_format == nil)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to initialize pixel format");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:nil];
|
||||
if (m_context == nil)
|
||||
return false;
|
||||
|
||||
if (m_wi.type == WindowInfo::Type::MacOS)
|
||||
BindContextToView();
|
||||
|
||||
if (make_current)
|
||||
[m_context makeCurrentContext];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextAGL::BindContextToView()
|
||||
{
|
||||
NSView* const view = GetView();
|
||||
NSWindow* const window = [view window];
|
||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
|
||||
UpdateDimensions();
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
[window makeFirstResponder:view];
|
||||
[m_context setView:view];
|
||||
[window makeKeyAndOrderFront:nil];
|
||||
};
|
||||
|
||||
if ([NSThread isMainThread])
|
||||
block();
|
||||
else
|
||||
dispatch_sync(dispatch_get_main_queue(), block);
|
||||
}
|
||||
} // namespace GL
|
432
src/frontend/duckstation/gl/context_egl.cpp
Normal file
432
src/frontend/duckstation/gl/context_egl.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
#include "context_egl.h"
|
||||
#include "../log.h"
|
||||
#include "../duckstation_compat.h"
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
Log_SetChannel(GL::ContextEGL);
|
||||
|
||||
namespace GL {
|
||||
ContextEGL::ContextEGL(const WindowInfo& wi) : Context(wi) {}
|
||||
|
||||
ContextEGL::~ContextEGL()
|
||||
{
|
||||
DestroySurface();
|
||||
DestroyContext();
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
{
|
||||
if (!gladLoadEGL())
|
||||
{
|
||||
Log_ErrorPrintf("Loading GLAD EGL functions failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetDisplay())
|
||||
return false;
|
||||
|
||||
int egl_major, egl_minor;
|
||||
if (!eglInitialize(m_display, &egl_major, &egl_minor))
|
||||
{
|
||||
Log_ErrorPrintf("eglInitialize() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor);
|
||||
|
||||
const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS);
|
||||
if (extensions)
|
||||
{
|
||||
Log_InfoPrintf("EGL Extensions: %s", extensions);
|
||||
m_supports_surfaceless = std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr;
|
||||
}
|
||||
if (!m_supports_surfaceless)
|
||||
Log_WarningPrint("EGL implementation does not support surfaceless contexts, emulating with pbuffers");
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
if (CreateContextAndSurface(versions_to_try[i], nullptr, true))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ContextEGL::SetDisplay()
|
||||
{
|
||||
m_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wi.display_connection));
|
||||
if (!m_display)
|
||||
{
|
||||
Log_ErrorPrintf("eglGetDisplay() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* ContextEGL::GetProcAddress(const char* name)
|
||||
{
|
||||
return reinterpret_cast<void*>(eglGetProcAddress(name));
|
||||
}
|
||||
|
||||
bool ContextEGL::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
const bool was_current = (eglGetCurrentContext() == m_context);
|
||||
if (was_current)
|
||||
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (m_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface(m_display, m_surface);
|
||||
m_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
m_wi = new_wi;
|
||||
if (!CreateSurface())
|
||||
return false;
|
||||
|
||||
if (was_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make context current again after surface change");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextEGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
|
||||
{
|
||||
if (new_surface_width == 0 && new_surface_height == 0)
|
||||
{
|
||||
EGLint surface_width, surface_height;
|
||||
if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) &&
|
||||
eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height))
|
||||
{
|
||||
m_wi.surface_width = static_cast<u32>(surface_width);
|
||||
m_wi.surface_height = static_cast<u32>(surface_height);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError());
|
||||
}
|
||||
}
|
||||
|
||||
m_wi.surface_width = new_surface_width;
|
||||
m_wi.surface_height = new_surface_height;
|
||||
}
|
||||
|
||||
bool ContextEGL::SwapBuffers()
|
||||
{
|
||||
return eglSwapBuffers(m_display, m_surface);
|
||||
}
|
||||
|
||||
bool ContextEGL::MakeCurrent()
|
||||
{
|
||||
if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context))
|
||||
{
|
||||
Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextEGL::DoneCurrent()
|
||||
{
|
||||
return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
bool ContextEGL::SetSwapInterval(s32 interval)
|
||||
{
|
||||
return eglSwapInterval(m_display, interval);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextEGL::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi);
|
||||
context->m_display = m_display;
|
||||
context->m_supports_surfaceless = m_supports_surfaceless;
|
||||
|
||||
if (!context->CreateContextAndSurface(m_version, m_context, false))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
EGLNativeWindowType ContextEGL::GetNativeWindow(EGLConfig config)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ContextEGL::CreateSurface()
|
||||
{
|
||||
if (m_wi.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
if (m_supports_surfaceless)
|
||||
return true;
|
||||
else
|
||||
return CreatePBufferSurface();
|
||||
}
|
||||
|
||||
EGLNativeWindowType native_window = GetNativeWindow(m_config);
|
||||
m_surface = eglCreateWindowSurface(m_display, m_config, native_window, nullptr);
|
||||
if (!m_surface)
|
||||
{
|
||||
Log_ErrorPrintf("eglCreateWindowSurface() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some implementations may require the size to be queried at runtime.
|
||||
EGLint surface_width, surface_height;
|
||||
if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) &&
|
||||
eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height))
|
||||
{
|
||||
m_wi.surface_width = static_cast<u32>(surface_width);
|
||||
m_wi.surface_height = static_cast<u32>(surface_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("eglQuerySurface() failed: %d", eglGetError());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextEGL::CreatePBufferSurface()
|
||||
{
|
||||
const u32 width = std::max<u32>(m_wi.surface_width, 1);
|
||||
const u32 height = std::max<u32>(m_wi.surface_height, 1);
|
||||
|
||||
// TODO: Format
|
||||
EGLint attrib_list[] = {
|
||||
EGL_WIDTH, static_cast<EGLint>(width), EGL_HEIGHT, static_cast<EGLint>(height), EGL_NONE,
|
||||
};
|
||||
|
||||
m_surface = eglCreatePbufferSurface(m_display, m_config, attrib_list);
|
||||
if (!m_surface)
|
||||
{
|
||||
Log_ErrorPrintf("eglCreatePbufferSurface() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_DevPrintf("Created %ux%u pbuffer surface", width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextEGL::CheckConfigSurfaceFormat(EGLConfig config, WindowInfo::SurfaceFormat format) const
|
||||
{
|
||||
int red_size, green_size, blue_size, alpha_size;
|
||||
if (!eglGetConfigAttrib(m_display, config, EGL_RED_SIZE, &red_size) ||
|
||||
!eglGetConfigAttrib(m_display, config, EGL_GREEN_SIZE, &green_size) ||
|
||||
!eglGetConfigAttrib(m_display, config, EGL_BLUE_SIZE, &blue_size) ||
|
||||
!eglGetConfigAttrib(m_display, config, EGL_ALPHA_SIZE, &alpha_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case WindowInfo::SurfaceFormat::Auto:
|
||||
return true;
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGB8:
|
||||
return (red_size == 8 && green_size == 8 && blue_size == 8);
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGBA8:
|
||||
return (red_size == 8 && green_size == 8 && blue_size == 8 && alpha_size == 8);
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGB565:
|
||||
return (red_size == 5 && green_size == 6 && blue_size == 5);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextEGL::DestroyContext()
|
||||
{
|
||||
if (eglGetCurrentContext() == m_context)
|
||||
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (m_context != EGL_NO_CONTEXT)
|
||||
{
|
||||
eglDestroyContext(m_display, m_context);
|
||||
m_context = EGL_NO_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextEGL::DestroySurface()
|
||||
{
|
||||
if (eglGetCurrentSurface(EGL_DRAW) == m_surface)
|
||||
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (m_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface(m_display, m_surface);
|
||||
m_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextEGL::CreateContext(const Version& version, EGLContext share_context)
|
||||
{
|
||||
Log_DevPrintf(
|
||||
"Trying version %u.%u (%s)", version.major_version, version.minor_version,
|
||||
version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None"));
|
||||
int surface_attribs[16] = {
|
||||
EGL_RENDERABLE_TYPE,
|
||||
(version.profile == Profile::ES) ?
|
||||
((version.major_version >= 3) ? EGL_OPENGL_ES3_BIT :
|
||||
((version.major_version == 2) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT)) :
|
||||
EGL_OPENGL_BIT,
|
||||
EGL_SURFACE_TYPE,
|
||||
(m_wi.type != WindowInfo::Type::Surfaceless) ? EGL_WINDOW_BIT : 0,
|
||||
};
|
||||
int nsurface_attribs = 4;
|
||||
|
||||
switch (m_wi.surface_format)
|
||||
{
|
||||
case WindowInfo::SurfaceFormat::RGB8:
|
||||
surface_attribs[nsurface_attribs++] = EGL_RED_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGBA8:
|
||||
surface_attribs[nsurface_attribs++] = EGL_RED_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
surface_attribs[nsurface_attribs++] = EGL_ALPHA_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 8;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGB565:
|
||||
surface_attribs[nsurface_attribs++] = EGL_RED_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 5;
|
||||
surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 6;
|
||||
surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE;
|
||||
surface_attribs[nsurface_attribs++] = 5;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::Auto:
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
surface_attribs[nsurface_attribs++] = EGL_NONE;
|
||||
surface_attribs[nsurface_attribs++] = 0;
|
||||
|
||||
EGLint num_configs;
|
||||
if (!eglChooseConfig(m_display, surface_attribs, nullptr, 0, &num_configs) || num_configs == 0)
|
||||
{
|
||||
Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<EGLConfig> configs(static_cast<u32>(num_configs));
|
||||
if (!eglChooseConfig(m_display, surface_attribs, configs.data(), num_configs, &num_configs))
|
||||
{
|
||||
Log_ErrorPrintf("eglChooseConfig() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
configs.resize(static_cast<u32>(num_configs));
|
||||
|
||||
std::optional<EGLConfig> config;
|
||||
for (EGLConfig check_config : configs)
|
||||
{
|
||||
if (CheckConfigSurfaceFormat(check_config, m_wi.surface_format))
|
||||
{
|
||||
config = check_config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.has_value())
|
||||
{
|
||||
Log_WarningPrintf("No EGL configs matched exactly, using first.");
|
||||
config = configs.front();
|
||||
}
|
||||
|
||||
int attribs[8];
|
||||
int nattribs = 0;
|
||||
if (version.profile != Profile::NoProfile)
|
||||
{
|
||||
attribs[nattribs++] = EGL_CONTEXT_MAJOR_VERSION;
|
||||
attribs[nattribs++] = version.major_version;
|
||||
attribs[nattribs++] = EGL_CONTEXT_MINOR_VERSION;
|
||||
attribs[nattribs++] = version.minor_version;
|
||||
}
|
||||
attribs[nattribs++] = EGL_NONE;
|
||||
attribs[nattribs++] = 0;
|
||||
|
||||
if (!eglBindAPI((version.profile == Profile::ES) ? EGL_OPENGL_ES_API : EGL_OPENGL_API))
|
||||
{
|
||||
Log_ErrorPrintf("eglBindAPI(%s) failed", (version.profile == Profile::ES) ? "EGL_OPENGL_ES_API" : "EGL_OPENGL_API");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_context = eglCreateContext(m_display, config.value(), share_context, attribs);
|
||||
if (!m_context)
|
||||
{
|
||||
Log_ErrorPrintf("eglCreateContext() failed: %d", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_InfoPrintf(
|
||||
"Got version %u.%u (%s)", version.major_version, version.minor_version,
|
||||
version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None"));
|
||||
|
||||
m_config = config.value();
|
||||
m_version = version;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextEGL::CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current)
|
||||
{
|
||||
if (!CreateContext(version, share_context))
|
||||
return false;
|
||||
|
||||
if (!CreateSurface())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create surface for context");
|
||||
eglDestroyContext(m_display, m_context);
|
||||
m_context = EGL_NO_CONTEXT;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (make_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context))
|
||||
{
|
||||
Log_ErrorPrintf("eglMakeCurrent() failed: %d", eglGetError());
|
||||
if (m_surface != EGL_NO_SURFACE)
|
||||
{
|
||||
eglDestroySurface(m_display, m_surface);
|
||||
m_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
eglDestroyContext(m_display, m_context);
|
||||
m_context = EGL_NO_CONTEXT;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace GL
|
48
src/frontend/duckstation/gl/context_egl.h
Normal file
48
src/frontend/duckstation/gl/context_egl.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "context.h"
|
||||
#include "../../glad/glad_egl.h"
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextEGL : public Context
|
||||
{
|
||||
public:
|
||||
ContextEGL(const WindowInfo& wi);
|
||||
~ContextEGL() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
virtual bool ChangeSurface(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
bool SwapBuffers() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SetSwapInterval(s32 interval) override;
|
||||
virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
|
||||
protected:
|
||||
virtual bool SetDisplay();
|
||||
virtual EGLNativeWindowType GetNativeWindow(EGLConfig config);
|
||||
|
||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||
bool CreateDisplay();
|
||||
bool CreateContext(const Version& version, EGLContext share_context);
|
||||
bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current);
|
||||
bool CreateSurface();
|
||||
bool CreatePBufferSurface();
|
||||
bool CheckConfigSurfaceFormat(EGLConfig config, WindowInfo::SurfaceFormat format) const;
|
||||
void DestroyContext();
|
||||
void DestroySurface();
|
||||
|
||||
EGLDisplay m_display = EGL_NO_DISPLAY;
|
||||
EGLSurface m_surface = EGL_NO_SURFACE;
|
||||
EGLContext m_context = EGL_NO_CONTEXT;
|
||||
|
||||
EGLConfig m_config = {};
|
||||
|
||||
bool m_supports_surfaceless = false;
|
||||
};
|
||||
|
||||
} // namespace GL
|
86
src/frontend/duckstation/gl/context_egl_wayland.cpp
Normal file
86
src/frontend/duckstation/gl/context_egl_wayland.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "context_egl_wayland.h"
|
||||
#include "../log.h"
|
||||
#include <dlfcn.h>
|
||||
Log_SetChannel(ContextEGLWayland);
|
||||
|
||||
namespace GL {
|
||||
static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1";
|
||||
|
||||
ContextEGLWayland::ContextEGLWayland(const WindowInfo& wi) : ContextEGL(wi) {}
|
||||
ContextEGLWayland::~ContextEGLWayland()
|
||||
{
|
||||
if (m_wl_window)
|
||||
m_wl_egl_window_destroy(m_wl_window);
|
||||
if (m_wl_module)
|
||||
dlclose(m_wl_module);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
|
||||
if (!context->LoadModule() || !context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextEGLWayland::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
|
||||
context->m_display = m_display;
|
||||
|
||||
if (!context->LoadModule() || !context->CreateContextAndSurface(m_version, m_context, false))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void ContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height)
|
||||
{
|
||||
if (m_wl_window)
|
||||
m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0);
|
||||
|
||||
ContextEGL::ResizeSurface(new_surface_width, new_surface_height);
|
||||
}
|
||||
|
||||
EGLNativeWindowType ContextEGLWayland::GetNativeWindow(EGLConfig config)
|
||||
{
|
||||
if (m_wl_window)
|
||||
{
|
||||
m_wl_egl_window_destroy(m_wl_window);
|
||||
m_wl_window = nullptr;
|
||||
}
|
||||
|
||||
m_wl_window =
|
||||
m_wl_egl_window_create(static_cast<wl_surface*>(m_wi.window_handle), m_wi.surface_width, m_wi.surface_height);
|
||||
if (!m_wl_window)
|
||||
return {};
|
||||
|
||||
return reinterpret_cast<EGLNativeWindowType>(m_wl_window);
|
||||
}
|
||||
|
||||
bool ContextEGLWayland::LoadModule()
|
||||
{
|
||||
m_wl_module = dlopen(WAYLAND_EGL_MODNAME, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!m_wl_module)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load %s.", WAYLAND_EGL_MODNAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_wl_egl_window_create =
|
||||
reinterpret_cast<decltype(m_wl_egl_window_create)>(dlsym(m_wl_module, "wl_egl_window_create"));
|
||||
m_wl_egl_window_destroy =
|
||||
reinterpret_cast<decltype(m_wl_egl_window_destroy)>(dlsym(m_wl_module, "wl_egl_window_destroy"));
|
||||
m_wl_egl_window_resize =
|
||||
reinterpret_cast<decltype(m_wl_egl_window_resize)>(dlsym(m_wl_module, "wl_egl_window_resize"));
|
||||
if (!m_wl_egl_window_create || !m_wl_egl_window_destroy || !m_wl_egl_window_resize)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load one or more functions from %s.", WAYLAND_EGL_MODNAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace GL
|
33
src/frontend/duckstation/gl/context_egl_wayland.h
Normal file
33
src/frontend/duckstation/gl/context_egl_wayland.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "context_egl.h"
|
||||
#include <wayland-egl.h>
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextEGLWayland final : public ContextEGL
|
||||
{
|
||||
public:
|
||||
ContextEGLWayland(const WindowInfo& wi);
|
||||
~ContextEGLWayland() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
|
||||
protected:
|
||||
EGLNativeWindowType GetNativeWindow(EGLConfig config) override;
|
||||
|
||||
private:
|
||||
bool LoadModule();
|
||||
|
||||
wl_egl_window* m_wl_window = nullptr;
|
||||
|
||||
void* m_wl_module = nullptr;
|
||||
wl_egl_window* (*m_wl_egl_window_create)(struct wl_surface* surface, int width, int height);
|
||||
void (*m_wl_egl_window_destroy)(struct wl_egl_window* egl_window);
|
||||
void (*m_wl_egl_window_resize)(struct wl_egl_window* egl_window, int width, int height, int dx, int dy);
|
||||
};
|
||||
|
||||
} // namespace GL
|
69
src/frontend/duckstation/gl/context_egl_x11.cpp
Normal file
69
src/frontend/duckstation/gl/context_egl_x11.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "context_egl_x11.h"
|
||||
#include "../log.h"
|
||||
Log_SetChannel(GL::ContextEGLX11);
|
||||
|
||||
namespace GL {
|
||||
ContextEGLX11::ContextEGLX11(const WindowInfo& wi) : ContextEGL(wi) {}
|
||||
ContextEGLX11::~ContextEGLX11() = default;
|
||||
|
||||
std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextEGLX11::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi);
|
||||
context->m_display = m_display;
|
||||
|
||||
if (!context->CreateContextAndSurface(m_version, m_context, false))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void ContextEGLX11::ResizeSurface(u32 new_surface_width, u32 new_surface_height)
|
||||
{
|
||||
m_window.Resize();
|
||||
ContextEGL::ResizeSurface(new_surface_width, new_surface_height);
|
||||
}
|
||||
|
||||
EGLNativeWindowType ContextEGLX11::GetNativeWindow(EGLConfig config)
|
||||
{
|
||||
X11InhibitErrors ei;
|
||||
|
||||
EGLint native_visual_id = 0;
|
||||
if (!eglGetConfigAttrib(m_display, m_config, EGL_NATIVE_VISUAL_ID, &native_visual_id))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to get X11 visual ID");
|
||||
return false;
|
||||
}
|
||||
|
||||
XVisualInfo vi_query = {};
|
||||
vi_query.visualid = native_visual_id;
|
||||
|
||||
int num_vis;
|
||||
XVisualInfo* vi = XGetVisualInfo(static_cast<Display*>(m_wi.display_connection), VisualIDMask, &vi_query, &num_vis);
|
||||
if (num_vis <= 0 || !vi)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to query visual from X11");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window.Destroy();
|
||||
if (!m_window.Create(GetDisplay(), static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), vi))
|
||||
{
|
||||
Log_ErrorPrintf("Faild to create X11 child window");
|
||||
XFree(vi);
|
||||
return false;
|
||||
}
|
||||
|
||||
XFree(vi);
|
||||
return static_cast<EGLNativeWindowType>(m_window.GetWindow());
|
||||
}
|
||||
} // namespace GL
|
28
src/frontend/duckstation/gl/context_egl_x11.h
Normal file
28
src/frontend/duckstation/gl/context_egl_x11.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "context_egl.h"
|
||||
#include "x11_window.h"
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextEGLX11 final : public ContextEGL
|
||||
{
|
||||
public:
|
||||
ContextEGLX11(const WindowInfo& wi);
|
||||
~ContextEGLX11() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
|
||||
protected:
|
||||
EGLNativeWindowType GetNativeWindow(EGLConfig config) override;
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE Display* GetDisplay() const { return static_cast<Display*>(m_wi.display_connection); }
|
||||
|
||||
X11Window m_window;
|
||||
};
|
||||
|
||||
} // namespace GL
|
328
src/frontend/duckstation/gl/context_glx.cpp
Normal file
328
src/frontend/duckstation/gl/context_glx.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
#include "context_glx.h"
|
||||
#include "../duckstation_compat.h"
|
||||
#include "../log.h"
|
||||
#include <dlfcn.h>
|
||||
Log_SetChannel(GL::ContextGLX);
|
||||
|
||||
namespace GL {
|
||||
ContextGLX::ContextGLX(const WindowInfo& wi) : Context(wi) {}
|
||||
|
||||
ContextGLX::~ContextGLX()
|
||||
{
|
||||
if (glXGetCurrentContext() == m_context)
|
||||
glXMakeCurrent(GetDisplay(), None, nullptr);
|
||||
|
||||
if (m_context)
|
||||
glXDestroyContext(GetDisplay(), m_context);
|
||||
|
||||
if (m_vi)
|
||||
XFree(m_vi);
|
||||
|
||||
if (m_libGL_handle)
|
||||
dlclose(m_libGL_handle);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextGLX::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextGLX::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
{
|
||||
// We need libGL loaded, because GLAD loads its own, then releases it.
|
||||
m_libGL_handle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!m_libGL_handle)
|
||||
{
|
||||
m_libGL_handle = dlopen("libGL.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!m_libGL_handle)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load libGL.so: %s", dlerror());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const int screen = DefaultScreen(GetDisplay());
|
||||
if (!gladLoadGLX(GetDisplay(), screen))
|
||||
{
|
||||
Log_ErrorPrintf("Loading GLAD GLX functions failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_wi.type == WindowInfo::Type::X11)
|
||||
{
|
||||
if (!CreateWindow(screen))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Panic("Create pbuffer");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
const Version& cv = versions_to_try[i];
|
||||
if (cv.profile == Profile::NoProfile && CreateAnyContext(nullptr, true))
|
||||
{
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
else if (cv.profile != Profile::NoProfile && CreateVersionContext(cv, nullptr, true))
|
||||
{
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* ContextGLX::GetProcAddress(const char* name)
|
||||
{
|
||||
return reinterpret_cast<void*>(glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)));
|
||||
}
|
||||
|
||||
bool ContextGLX::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
const bool was_current = (glXGetCurrentContext() == m_context);
|
||||
if (was_current)
|
||||
glXMakeCurrent(GetDisplay(), None, nullptr);
|
||||
|
||||
m_window.Destroy();
|
||||
m_wi = new_wi;
|
||||
|
||||
if (new_wi.type == WindowInfo::Type::X11)
|
||||
{
|
||||
const int screen = DefaultScreen(GetDisplay());
|
||||
if (!CreateWindow(screen))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (was_current && !glXMakeCurrent(GetDisplay(), GetDrawable(), m_context))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make context current again after surface change");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextGLX::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
|
||||
{
|
||||
m_window.Resize(new_surface_width, new_surface_height);
|
||||
m_wi.surface_width = m_window.GetWidth();
|
||||
m_wi.surface_height = m_window.GetHeight();
|
||||
}
|
||||
|
||||
bool ContextGLX::SwapBuffers()
|
||||
{
|
||||
glXSwapBuffers(GetDisplay(), GetDrawable());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextGLX::MakeCurrent()
|
||||
{
|
||||
return (glXMakeCurrent(GetDisplay(), GetDrawable(), m_context) == True);
|
||||
}
|
||||
|
||||
bool ContextGLX::DoneCurrent()
|
||||
{
|
||||
return (glXMakeCurrent(GetDisplay(), None, nullptr) == True);
|
||||
}
|
||||
|
||||
bool ContextGLX::SetSwapInterval(s32 interval)
|
||||
{
|
||||
if (GLAD_GLX_EXT_swap_control)
|
||||
{
|
||||
glXSwapIntervalEXT(GetDisplay(), GetDrawable(), interval);
|
||||
return true;
|
||||
}
|
||||
else if (GLAD_GLX_MESA_swap_control)
|
||||
{
|
||||
return (glXSwapIntervalMESA(static_cast<u32>(std::max(interval, 0))) != 0);
|
||||
}
|
||||
else if (GLAD_GLX_SGI_swap_control)
|
||||
{
|
||||
return (glXSwapIntervalSGI(interval) != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextGLX::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextGLX> context = std::make_unique<ContextGLX>(wi);
|
||||
if (wi.type == WindowInfo::Type::X11)
|
||||
{
|
||||
const int screen = DefaultScreen(context->GetDisplay());
|
||||
if (!context->CreateWindow(screen))
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Panic("Create pbuffer");
|
||||
}
|
||||
|
||||
if (m_version.profile == Profile::NoProfile)
|
||||
{
|
||||
if (!context->CreateAnyContext(m_context, false))
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!context->CreateVersionContext(m_version, m_context, false))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
context->m_version = m_version;
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextGLX::CreateWindow(int screen)
|
||||
{
|
||||
int attribs[32] = {GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_DOUBLEBUFFER, True};
|
||||
int nattribs = 8;
|
||||
|
||||
switch (m_wi.surface_format)
|
||||
{
|
||||
case WindowInfo::SurfaceFormat::RGB8:
|
||||
attribs[nattribs++] = GLX_RED_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
attribs[nattribs++] = GLX_GREEN_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
attribs[nattribs++] = GLX_BLUE_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGBA8:
|
||||
attribs[nattribs++] = GLX_RED_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
attribs[nattribs++] = GLX_GREEN_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
attribs[nattribs++] = GLX_BLUE_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
attribs[nattribs++] = GLX_ALPHA_SIZE;
|
||||
attribs[nattribs++] = 8;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::RGB565:
|
||||
attribs[nattribs++] = GLX_RED_SIZE;
|
||||
attribs[nattribs++] = 5;
|
||||
attribs[nattribs++] = GLX_GREEN_SIZE;
|
||||
attribs[nattribs++] = 6;
|
||||
attribs[nattribs++] = GLX_BLUE_SIZE;
|
||||
attribs[nattribs++] = 5;
|
||||
break;
|
||||
|
||||
case WindowInfo::SurfaceFormat::Auto:
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
attribs[nattribs++] = None;
|
||||
attribs[nattribs++] = 0;
|
||||
|
||||
int fbcount = 0;
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(GetDisplay(), screen, attribs, &fbcount);
|
||||
if (!fbc || !fbcount)
|
||||
{
|
||||
Log_ErrorPrintf("glXChooseFBConfig() failed");
|
||||
return false;
|
||||
}
|
||||
m_fb_config = *fbc;
|
||||
XFree(fbc);
|
||||
|
||||
if (!GLAD_GLX_VERSION_1_3)
|
||||
{
|
||||
Log_ErrorPrintf("GLX Version 1.3 is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vi = glXGetVisualFromFBConfig(GetDisplay(), m_fb_config);
|
||||
if (!m_vi)
|
||||
{
|
||||
Log_ErrorPrintf("glXGetVisualFromFBConfig() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_window.Create(GetDisplay(), static_cast<Window>(reinterpret_cast<uintptr_t>(m_wi.window_handle)), m_vi);
|
||||
}
|
||||
|
||||
bool ContextGLX::CreateAnyContext(GLXContext share_context, bool make_current)
|
||||
{
|
||||
X11InhibitErrors ie;
|
||||
|
||||
m_context = glXCreateContext(GetDisplay(), m_vi, share_context, True);
|
||||
if (!m_context || ie.HadError())
|
||||
{
|
||||
Log_ErrorPrintf("glxCreateContext() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (make_current)
|
||||
{
|
||||
if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context))
|
||||
{
|
||||
Log_ErrorPrintf("glXMakeCurrent() failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextGLX::CreateVersionContext(const Version& version, GLXContext share_context, bool make_current)
|
||||
{
|
||||
// we need create context attribs
|
||||
if (!GLAD_GLX_VERSION_1_3)
|
||||
{
|
||||
Log_ErrorPrint("Missing GLX version 1.3.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int attribs[32];
|
||||
int nattribs = 0;
|
||||
attribs[nattribs++] = GLX_CONTEXT_PROFILE_MASK_ARB;
|
||||
attribs[nattribs++] =
|
||||
((version.profile == Profile::ES) ?
|
||||
((version.major_version >= 2) ? GLX_CONTEXT_ES2_PROFILE_BIT_EXT : GLX_CONTEXT_ES_PROFILE_BIT_EXT) :
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
|
||||
attribs[nattribs++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
|
||||
attribs[nattribs++] = version.major_version;
|
||||
attribs[nattribs++] = GLX_CONTEXT_MINOR_VERSION_ARB;
|
||||
attribs[nattribs++] = version.minor_version;
|
||||
attribs[nattribs++] = None;
|
||||
attribs[nattribs++] = 0;
|
||||
|
||||
X11InhibitErrors ie;
|
||||
m_context = glXCreateContextAttribsARB(GetDisplay(), m_fb_config, share_context, True, attribs);
|
||||
XSync(GetDisplay(), False);
|
||||
if (ie.HadError())
|
||||
m_context = nullptr;
|
||||
if (!m_context)
|
||||
return false;
|
||||
|
||||
if (make_current)
|
||||
{
|
||||
if (!glXMakeCurrent(GetDisplay(), GetDrawable(), m_context))
|
||||
{
|
||||
Log_ErrorPrint("glXMakeCurrent() failed");
|
||||
glXDestroyContext(GetDisplay(), m_context);
|
||||
m_context = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace GL
|
44
src/frontend/duckstation/gl/context_glx.h
Normal file
44
src/frontend/duckstation/gl/context_glx.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "context.h"
|
||||
#include "../../glad/glad_glx.h"
|
||||
#include "x11_window.h"
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextGLX final : public Context
|
||||
{
|
||||
public:
|
||||
ContextGLX(const WindowInfo& wi);
|
||||
~ContextGLX() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
bool ChangeSurface(const WindowInfo& new_wi) override;
|
||||
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
bool SwapBuffers() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SetSwapInterval(s32 interval) override;
|
||||
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE Display* GetDisplay() const { return static_cast<Display*>(m_wi.display_connection); }
|
||||
ALWAYS_INLINE GLXDrawable GetDrawable() const { return static_cast<GLXDrawable>(m_window.GetWindow()); }
|
||||
|
||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||
bool CreateWindow(int screen);
|
||||
bool CreateAnyContext(GLXContext share_context, bool make_current);
|
||||
bool CreateVersionContext(const Version& version, GLXContext share_context, bool make_current);
|
||||
|
||||
GLXContext m_context = nullptr;
|
||||
GLXFBConfig m_fb_config = {};
|
||||
XVisualInfo* m_vi = nullptr;
|
||||
X11Window m_window;
|
||||
|
||||
// GLAD releases its reference to libGL.so, so we need to maintain our own.
|
||||
void* m_libGL_handle = nullptr;
|
||||
};
|
||||
|
||||
} // namespace GL
|
452
src/frontend/duckstation/gl/context_wgl.cpp
Normal file
452
src/frontend/duckstation/gl/context_wgl.cpp
Normal file
@ -0,0 +1,452 @@
|
||||
#include "context_wgl.h"
|
||||
#include "../duckstation_compat.h"
|
||||
#include "../log.h"
|
||||
#include "../scoped_guard.h"
|
||||
#include "loader.h"
|
||||
Log_SetChannel(GL::ContextWGL);
|
||||
|
||||
// TODO: get rid of this
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
|
||||
static void* GetProcAddressCallback(const char* name)
|
||||
{
|
||||
void* addr = reinterpret_cast<void*>(wglGetProcAddress(name));
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
// try opengl32.dll
|
||||
return reinterpret_cast<void*>(::GetProcAddress(GetModuleHandleA("opengl32.dll"), name));
|
||||
}
|
||||
|
||||
namespace GL {
|
||||
ContextWGL::ContextWGL(const WindowInfo& wi) : Context(wi) {}
|
||||
|
||||
ContextWGL::~ContextWGL()
|
||||
{
|
||||
if (wglGetCurrentContext() == m_rc)
|
||||
wglMakeCurrent(m_dc, nullptr);
|
||||
|
||||
if (m_rc)
|
||||
wglDeleteContext(m_rc);
|
||||
|
||||
ReleaseDC();
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try)
|
||||
{
|
||||
std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi);
|
||||
if (!context->Initialize(versions_to_try, num_versions_to_try))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextWGL::Initialize(const Version* versions_to_try, size_t num_versions_to_try)
|
||||
{
|
||||
if (m_wi.type == WindowInfo::Type::Win32)
|
||||
{
|
||||
if (!InitializeDC())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrint("ContextWGL must always start with a valid surface.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything including core/ES requires a dummy profile to load the WGL extensions.
|
||||
if (!CreateAnyContext(nullptr, true))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < num_versions_to_try; i++)
|
||||
{
|
||||
const Version& cv = versions_to_try[i];
|
||||
if (cv.profile == Profile::NoProfile)
|
||||
{
|
||||
// we already have the dummy context, so just use that
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
else if (CreateVersionContext(cv, nullptr, true))
|
||||
{
|
||||
m_version = cv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* ContextWGL::GetProcAddress(const char* name)
|
||||
{
|
||||
return GetProcAddressCallback(name);
|
||||
}
|
||||
|
||||
bool ContextWGL::ChangeSurface(const WindowInfo& new_wi)
|
||||
{
|
||||
const bool was_current = (wglGetCurrentContext() == m_rc);
|
||||
|
||||
ReleaseDC();
|
||||
|
||||
m_wi = new_wi;
|
||||
if (!InitializeDC())
|
||||
return false;
|
||||
|
||||
if (was_current && !wglMakeCurrent(m_dc, m_rc))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make context current again after surface change: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ContextWGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
|
||||
{
|
||||
RECT client_rc = {};
|
||||
GetClientRect(GetHWND(), &client_rc);
|
||||
m_wi.surface_width = static_cast<u32>(client_rc.right - client_rc.left);
|
||||
m_wi.surface_height = static_cast<u32>(client_rc.bottom - client_rc.top);
|
||||
}
|
||||
|
||||
bool ContextWGL::SwapBuffers()
|
||||
{
|
||||
return ::SwapBuffers(m_dc);
|
||||
}
|
||||
|
||||
bool ContextWGL::MakeCurrent()
|
||||
{
|
||||
if (!wglMakeCurrent(m_dc, m_rc))
|
||||
{
|
||||
Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextWGL::DoneCurrent()
|
||||
{
|
||||
return wglMakeCurrent(m_dc, nullptr);
|
||||
}
|
||||
|
||||
bool ContextWGL::SetSwapInterval(s32 interval)
|
||||
{
|
||||
if (!GLAD_WGL_EXT_swap_control)
|
||||
return false;
|
||||
|
||||
return wglSwapIntervalEXT(interval);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextWGL::CreateSharedContext(const WindowInfo& wi)
|
||||
{
|
||||
std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi);
|
||||
if (wi.type == WindowInfo::Type::Win32)
|
||||
{
|
||||
if (!context->InitializeDC())
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrint("PBuffer not implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_version.profile == Profile::NoProfile)
|
||||
{
|
||||
if (!context->CreateAnyContext(m_rc, false))
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!context->CreateVersionContext(m_version, m_rc, false))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
context->m_version = m_version;
|
||||
return context;
|
||||
}
|
||||
|
||||
HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd = {};
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.dwLayerMask = PFD_MAIN_PLANE;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cColorBits = 24;
|
||||
|
||||
HDC hDC = ::GetDC(hwnd);
|
||||
if (!hDC)
|
||||
{
|
||||
Log_ErrorPrintf("GetDC() failed: 0x%08X", GetLastError());
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_pixel_format.has_value())
|
||||
{
|
||||
const int pf = ChoosePixelFormat(hDC, &pfd);
|
||||
if (pf == 0)
|
||||
{
|
||||
Log_ErrorPrintf("ChoosePixelFormat() failed: 0x%08X", GetLastError());
|
||||
::ReleaseDC(hwnd, hDC);
|
||||
return {};
|
||||
}
|
||||
|
||||
m_pixel_format = pf;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd))
|
||||
{
|
||||
Log_ErrorPrintf("SetPixelFormat() failed: 0x%08X", GetLastError());
|
||||
::ReleaseDC(hwnd, hDC);
|
||||
return {};
|
||||
}
|
||||
|
||||
return hDC;
|
||||
}
|
||||
|
||||
bool ContextWGL::InitializeDC()
|
||||
{
|
||||
if (m_wi.type == WindowInfo::Type::Win32)
|
||||
{
|
||||
m_dc = GetDCAndSetPixelFormat(GetHWND());
|
||||
if (!m_dc)
|
||||
{
|
||||
Log_ErrorPrint("Failed to get DC for window");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_wi.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
return CreatePBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("Unknown window info type %u", static_cast<unsigned>(m_wi.type));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextWGL::ReleaseDC()
|
||||
{
|
||||
if (m_pbuffer)
|
||||
{
|
||||
wglReleasePbufferDCARB(m_pbuffer, m_dc);
|
||||
m_dc = {};
|
||||
|
||||
wglDestroyPbufferARB(m_pbuffer);
|
||||
m_pbuffer = {};
|
||||
|
||||
::ReleaseDC(m_dummy_window, m_dummy_dc);
|
||||
m_dummy_dc = {};
|
||||
|
||||
DestroyWindow(m_dummy_window);
|
||||
m_dummy_window = {};
|
||||
}
|
||||
else if (m_dc)
|
||||
{
|
||||
::ReleaseDC(GetHWND(), m_dc);
|
||||
m_dc = {};
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextWGL::CreatePBuffer()
|
||||
{
|
||||
static bool window_class_registered = false;
|
||||
static const wchar_t* window_class_name = L"ContextWGLPBuffer";
|
||||
|
||||
if (!window_class_registered)
|
||||
{
|
||||
WNDCLASSEXW wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = DefWindowProcW;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.hIcon = NULL;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = window_class_name;
|
||||
wc.hIconSm = NULL;
|
||||
|
||||
if (!RegisterClassExW(&wc))
|
||||
{
|
||||
Log_ErrorPrint("(ContextWGL::CreatePBuffer) RegisterClassExW() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
window_class_registered = true;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
||||
if (!hwnd)
|
||||
{
|
||||
Log_ErrorPrint("(ContextWGL::CreatePBuffer) CreateWindowEx() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); });
|
||||
|
||||
HDC hdc = GetDCAndSetPixelFormat(hwnd);
|
||||
if (!hdc)
|
||||
return false;
|
||||
|
||||
ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); });
|
||||
|
||||
static constexpr const int pb_attribs[] = {0, 0};
|
||||
|
||||
AssertMsg(m_pixel_format.has_value(), "Has pixel format for pbuffer");
|
||||
HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs);
|
||||
if (!pbuffer)
|
||||
{
|
||||
Log_ErrorPrint("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); });
|
||||
|
||||
m_dc = wglGetPbufferDCARB(pbuffer);
|
||||
if (!m_dc)
|
||||
{
|
||||
Log_ErrorPrint("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dummy_window = hwnd;
|
||||
m_dummy_dc = hdc;
|
||||
m_pbuffer = pbuffer;
|
||||
|
||||
pbuffer_guard.Cancel();
|
||||
hdc_guard.Cancel();
|
||||
hwnd_guard.Cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextWGL::CreateAnyContext(HGLRC share_context, bool make_current)
|
||||
{
|
||||
m_rc = wglCreateContext(m_dc);
|
||||
if (!m_rc)
|
||||
{
|
||||
Log_ErrorPrintf("wglCreateContext() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (make_current)
|
||||
{
|
||||
if (!wglMakeCurrent(m_dc, m_rc))
|
||||
{
|
||||
Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// re-init glad-wgl
|
||||
if (!gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, m_dc))
|
||||
{
|
||||
Log_ErrorPrint("Loading GLAD WGL functions failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (share_context && !wglShareLists(share_context, m_rc))
|
||||
{
|
||||
Log_ErrorPrintf("wglShareLists() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextWGL::CreateVersionContext(const Version& version, HGLRC share_context, bool make_current)
|
||||
{
|
||||
// we need create context attribs
|
||||
if (!GLAD_WGL_ARB_create_context)
|
||||
{
|
||||
Log_ErrorPrint("Missing GLAD_WGL_ARB_create_context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
HGLRC new_rc;
|
||||
if (version.profile == Profile::Core)
|
||||
{
|
||||
const int attribs[] = {WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||
version.major_version,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||
version.minor_version,
|
||||
#ifdef _DEBUG
|
||||
WGL_CONTEXT_FLAGS_ARB,
|
||||
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
#else
|
||||
WGL_CONTEXT_FLAGS_ARB,
|
||||
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
||||
#endif
|
||||
0,
|
||||
0};
|
||||
|
||||
new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs);
|
||||
}
|
||||
else if (version.profile == Profile::ES)
|
||||
{
|
||||
if ((version.major_version >= 2 && !GLAD_WGL_EXT_create_context_es2_profile) ||
|
||||
(version.major_version < 2 && !GLAD_WGL_EXT_create_context_es_profile))
|
||||
{
|
||||
Log_ErrorPrint("WGL_EXT_create_context_es_profile not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int attribs[] = {
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
((version.major_version >= 2) ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT : WGL_CONTEXT_ES_PROFILE_BIT_EXT),
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||
version.major_version,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||
version.minor_version,
|
||||
0,
|
||||
0};
|
||||
|
||||
new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrint("Unknown profile");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!new_rc)
|
||||
return false;
|
||||
|
||||
// destroy and swap contexts
|
||||
if (m_rc)
|
||||
{
|
||||
if (!wglMakeCurrent(m_dc, make_current ? new_rc : nullptr))
|
||||
{
|
||||
Log_ErrorPrintf("wglMakeCurrent() failed: 0x%08X", GetLastError());
|
||||
wglDeleteContext(new_rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// re-init glad-wgl
|
||||
if (make_current && !gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, m_dc))
|
||||
{
|
||||
Log_ErrorPrint("Loading GLAD WGL functions failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
wglDeleteContext(m_rc);
|
||||
}
|
||||
|
||||
m_rc = new_rc;
|
||||
return true;
|
||||
}
|
||||
} // namespace GL
|
53
src/frontend/duckstation/gl/context_wgl.h
Normal file
53
src/frontend/duckstation/gl/context_wgl.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "../windows_headers.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "../../glad/glad_wgl.h"
|
||||
#include "loader.h"
|
||||
#include <optional>
|
||||
|
||||
namespace GL {
|
||||
|
||||
class ContextWGL final : public Context
|
||||
{
|
||||
public:
|
||||
ContextWGL(const WindowInfo& wi);
|
||||
~ContextWGL() override;
|
||||
|
||||
static std::unique_ptr<Context> Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
size_t num_versions_to_try);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
bool ChangeSurface(const WindowInfo& new_wi) override;
|
||||
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
|
||||
bool SwapBuffers() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SetSwapInterval(s32 interval) override;
|
||||
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); }
|
||||
|
||||
HDC GetDCAndSetPixelFormat(HWND hwnd);
|
||||
|
||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||
bool InitializeDC();
|
||||
void ReleaseDC();
|
||||
bool CreatePBuffer();
|
||||
bool CreateAnyContext(HGLRC share_context, bool make_current);
|
||||
bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current);
|
||||
|
||||
HDC m_dc = {};
|
||||
HGLRC m_rc = {};
|
||||
|
||||
// Can't change pixel format once it's set for a RC.
|
||||
std::optional<int> m_pixel_format;
|
||||
|
||||
// Dummy window for creating a PBuffer off when we're surfaceless.
|
||||
HWND m_dummy_window = {};
|
||||
HDC m_dummy_dc = {};
|
||||
HPBUFFERARB m_pbuffer = {};
|
||||
};
|
||||
|
||||
} // namespace GL
|
8
src/frontend/duckstation/gl/loader.h
Normal file
8
src/frontend/duckstation/gl/loader.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Fix glad.h including windows.h
|
||||
#ifdef _WIN32
|
||||
#include "../windows_headers.h"
|
||||
#endif
|
||||
|
||||
#include "../../glad/glad.h"
|
101
src/frontend/duckstation/gl/x11_window.cpp
Normal file
101
src/frontend/duckstation/gl/x11_window.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include "x11_window.h"
|
||||
#include "../log.h"
|
||||
#include "../duckstation_compat.h"
|
||||
#include <cstdio>
|
||||
Log_SetChannel(X11Window);
|
||||
|
||||
namespace GL {
|
||||
X11Window::X11Window() = default;
|
||||
|
||||
X11Window::~X11Window()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool X11Window::Create(Display* display, Window parent_window, const XVisualInfo* vi)
|
||||
{
|
||||
m_display = display;
|
||||
m_parent_window = parent_window;
|
||||
XSync(m_display, True);
|
||||
|
||||
XWindowAttributes parent_wa = {};
|
||||
XGetWindowAttributes(m_display, m_parent_window, &parent_wa);
|
||||
m_width = static_cast<u32>(parent_wa.width);
|
||||
m_height = static_cast<u32>(parent_wa.height);
|
||||
|
||||
// Failed X calls terminate the process so no need to check for errors.
|
||||
// We could swap the error handler out here as well.
|
||||
m_colormap = XCreateColormap(m_display, m_parent_window, vi->visual, AllocNone);
|
||||
|
||||
XSetWindowAttributes wa = {};
|
||||
wa.colormap = m_colormap;
|
||||
|
||||
m_window = XCreateWindow(m_display, m_parent_window, 0, 0, m_width, m_height, 0, vi->depth, InputOutput, vi->visual,
|
||||
CWColormap, &wa);
|
||||
XMapWindow(m_display, m_window);
|
||||
XSync(m_display, True);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11Window::Destroy()
|
||||
{
|
||||
if (m_window)
|
||||
{
|
||||
XUnmapWindow(m_display, m_window);
|
||||
XDestroyWindow(m_display, m_window);
|
||||
m_window = {};
|
||||
}
|
||||
|
||||
if (m_colormap)
|
||||
{
|
||||
XFreeColormap(m_display, m_colormap);
|
||||
m_colormap = {};
|
||||
}
|
||||
}
|
||||
|
||||
void X11Window::Resize(u32 width, u32 height)
|
||||
{
|
||||
if (width != 0 && height != 0)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
XWindowAttributes parent_wa = {};
|
||||
XGetWindowAttributes(m_display, m_parent_window, &parent_wa);
|
||||
m_width = static_cast<u32>(parent_wa.width);
|
||||
m_height = static_cast<u32>(parent_wa.height);
|
||||
}
|
||||
|
||||
XResizeWindow(m_display, m_window, m_width, m_height);
|
||||
}
|
||||
|
||||
static X11InhibitErrors* s_current_error_inhibiter;
|
||||
|
||||
X11InhibitErrors::X11InhibitErrors()
|
||||
{
|
||||
Assert(!s_current_error_inhibiter);
|
||||
m_old_handler = XSetErrorHandler(ErrorHandler);
|
||||
s_current_error_inhibiter = this;
|
||||
}
|
||||
|
||||
X11InhibitErrors::~X11InhibitErrors()
|
||||
{
|
||||
Assert(s_current_error_inhibiter == this);
|
||||
s_current_error_inhibiter = nullptr;
|
||||
XSetErrorHandler(m_old_handler);
|
||||
}
|
||||
|
||||
int X11InhibitErrors::ErrorHandler(Display* display, XErrorEvent* ee)
|
||||
{
|
||||
char error_string[256] = {};
|
||||
XGetErrorText(display, ee->error_code, error_string, sizeof(error_string));
|
||||
Log_WarningPrintf("X11 Error: %s (Error %u Minor %u Request %u)", error_string, ee->error_code, ee->minor_code,
|
||||
ee->request_code);
|
||||
|
||||
s_current_error_inhibiter->m_had_error = true;
|
||||
return 0;
|
||||
}
|
||||
} // namespace GL
|
48
src/frontend/duckstation/gl/x11_window.h
Normal file
48
src/frontend/duckstation/gl/x11_window.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "../duckstation_compat.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
namespace GL {
|
||||
class X11Window
|
||||
{
|
||||
public:
|
||||
X11Window();
|
||||
~X11Window();
|
||||
|
||||
ALWAYS_INLINE Window GetWindow() const { return m_window; }
|
||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
||||
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
||||
|
||||
bool Create(Display* display, Window parent_window, const XVisualInfo* vi);
|
||||
void Destroy();
|
||||
|
||||
// Setting a width/height of 0 will use parent dimensions.
|
||||
void Resize(u32 width = 0, u32 height = 0);
|
||||
|
||||
private:
|
||||
Display* m_display = nullptr;
|
||||
Window m_parent_window = {};
|
||||
Window m_window = {};
|
||||
Colormap m_colormap = {};
|
||||
u32 m_width = 0;
|
||||
u32 m_height = 0;
|
||||
};
|
||||
|
||||
// Helper class for managing X errors
|
||||
class X11InhibitErrors
|
||||
{
|
||||
public:
|
||||
X11InhibitErrors();
|
||||
~X11InhibitErrors();
|
||||
|
||||
ALWAYS_INLINE bool HadError() const { return m_had_error; }
|
||||
|
||||
private:
|
||||
static int ErrorHandler(Display* display, XErrorEvent* ee);
|
||||
|
||||
XErrorHandler m_old_handler = {};
|
||||
bool m_had_error = false;
|
||||
};
|
||||
|
||||
} // namespace GL
|
46
src/frontend/duckstation/log.h
Normal file
46
src/frontend/duckstation/log.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define Log_SetChannel(ChannelName)
|
||||
#define Log_ErrorPrint(msg) puts(msg "\n");
|
||||
#define Log_ErrorPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_WarningPrint(msg) puts(msg)
|
||||
#define Log_WarningPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_PerfPrint(msg) puts(msg)
|
||||
#define Log_PerfPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_InfoPrint(msg) puts(msg)
|
||||
#define Log_InfoPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_VerbosePrint(msg) puts(msg)
|
||||
#define Log_VerbosePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_DevPrint(msg) puts(msg)
|
||||
#define Log_DevPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_ProfilePrint(msg) puts(msg)
|
||||
#define Log_ProfilePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define Log_DebugPrint(msg) puts(msg)
|
||||
#define Log_DebugPrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#define Log_TracePrint(msg) puts(msg)
|
||||
#define Log_TracePrintf(...) do { printf(__VA_ARGS__); putchar('\n'); } while (0)
|
||||
#else
|
||||
#define Log_DebugPrint(msg) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define Log_DebugPrintf(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define Log_TracePrint(msg) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define Log_TracePrintf(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
34
src/frontend/duckstation/scoped_guard.h
Normal file
34
src/frontend/duckstation/scoped_guard.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
/// ScopedGuard provides an object which runs a function (usually a lambda) when
|
||||
/// it goes out of scope. This can be useful for releasing resources or handles
|
||||
/// which do not normally have C++ types to automatically release.
|
||||
template<typename T>
|
||||
class ScopedGuard final
|
||||
{
|
||||
public:
|
||||
ALWAYS_INLINE ScopedGuard(T&& func) : m_func(std::forward<T>(func)) {}
|
||||
ALWAYS_INLINE ScopedGuard(ScopedGuard&& other) : m_func(std::move(other.m_func)) { other.m_func = nullptr; }
|
||||
ALWAYS_INLINE ~ScopedGuard() { Invoke(); }
|
||||
|
||||
ScopedGuard(const ScopedGuard&) = delete;
|
||||
void operator=(const ScopedGuard&) = delete;
|
||||
|
||||
/// Prevents the function from being invoked when we go out of scope.
|
||||
ALWAYS_INLINE void Cancel() { m_func.reset(); }
|
||||
|
||||
/// Explicitly fires the function.
|
||||
ALWAYS_INLINE void Invoke()
|
||||
{
|
||||
if (!m_func.has_value())
|
||||
return;
|
||||
|
||||
m_func.value()();
|
||||
m_func.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<T> m_func;
|
||||
};
|
191
src/frontend/duckstation/window_info.cpp
Normal file
191
src/frontend/duckstation/window_info.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
#include "window_info.h"
|
||||
#include "common/log.h"
|
||||
Log_SetChannel(WindowInfo);
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "common/windows_headers.h"
|
||||
#include <dwmapi.h>
|
||||
|
||||
static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate)
|
||||
{
|
||||
static HMODULE dwm_module = nullptr;
|
||||
static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = nullptr;
|
||||
static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr;
|
||||
static bool load_tried = false;
|
||||
if (!load_tried)
|
||||
{
|
||||
load_tried = true;
|
||||
dwm_module = LoadLibrary("dwmapi.dll");
|
||||
if (dwm_module)
|
||||
{
|
||||
std::atexit([]() {
|
||||
FreeLibrary(dwm_module);
|
||||
dwm_module = nullptr;
|
||||
});
|
||||
is_composition_enabled =
|
||||
reinterpret_cast<decltype(is_composition_enabled)>(GetProcAddress(dwm_module, "DwmIsCompositionEnabled"));
|
||||
get_timing_info =
|
||||
reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo"));
|
||||
}
|
||||
}
|
||||
|
||||
BOOL composition_enabled;
|
||||
if (!is_composition_enabled || FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info))
|
||||
return false;
|
||||
|
||||
DWM_TIMING_INFO ti = {};
|
||||
ti.cbSize = sizeof(ti);
|
||||
HRESULT hr = get_timing_info(nullptr, &ti);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0)
|
||||
return false;
|
||||
|
||||
*refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate)
|
||||
{
|
||||
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!mon)
|
||||
return false;
|
||||
|
||||
MONITORINFOEXW mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfoW(mon, &mi))
|
||||
{
|
||||
DEVMODEW dm = {};
|
||||
dm.dmSize = sizeof(dm);
|
||||
|
||||
// 0/1 are reserved for "defaults".
|
||||
if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1)
|
||||
{
|
||||
*refresh_rate = static_cast<float>(dm.dmDisplayFrequency);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||
{
|
||||
if (wi.type != Type::Win32 || !wi.window_handle)
|
||||
return false;
|
||||
|
||||
// Try DWM first, then fall back to integer values.
|
||||
const HWND hwnd = static_cast<HWND>(wi.window_handle);
|
||||
return GetRefreshRateFromDWM(hwnd, refresh_rate) || GetRefreshRateFromMonitor(hwnd, refresh_rate);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef USE_X11
|
||||
|
||||
#include "common/scoped_guard.h"
|
||||
#include "gl/x11_window.h"
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
|
||||
static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate)
|
||||
{
|
||||
Display* display = static_cast<Display*>(wi.display_connection);
|
||||
Window window = static_cast<Window>(reinterpret_cast<uintptr_t>(wi.window_handle));
|
||||
if (!display || !window)
|
||||
return false;
|
||||
|
||||
GL::X11InhibitErrors inhibiter;
|
||||
|
||||
XRRScreenResources* res = XRRGetScreenResources(display, window);
|
||||
if (!res)
|
||||
{
|
||||
Log_ErrorPrint("XRRGetScreenResources() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard res_guard([res]() { XRRFreeScreenResources(res); });
|
||||
|
||||
int num_monitors;
|
||||
XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors);
|
||||
if (num_monitors < 0)
|
||||
{
|
||||
Log_ErrorPrint("XRRGetMonitors() failed");
|
||||
return false;
|
||||
}
|
||||
else if (num_monitors > 1)
|
||||
{
|
||||
Log_WarningPrintf("XRRGetMonitors() returned %d monitors, using first", num_monitors);
|
||||
}
|
||||
|
||||
ScopedGuard mi_guard([mi]() { XRRFreeMonitors(mi); });
|
||||
if (mi->noutput <= 0)
|
||||
{
|
||||
Log_ErrorPrint("Monitor has no outputs");
|
||||
return false;
|
||||
}
|
||||
else if (mi->noutput > 1)
|
||||
{
|
||||
Log_WarningPrintf("Monitor has %d outputs, using first", mi->noutput);
|
||||
}
|
||||
|
||||
XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]);
|
||||
if (!oi)
|
||||
{
|
||||
Log_ErrorPrint("XRRGetOutputInfo() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); });
|
||||
|
||||
XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc);
|
||||
if (!ci)
|
||||
{
|
||||
Log_ErrorPrint("XRRGetCrtcInfo() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); });
|
||||
|
||||
XRRModeInfo* mode = nullptr;
|
||||
for (int i = 0; i < res->nmode; i++)
|
||||
{
|
||||
if (res->modes[i].id == ci->mode)
|
||||
{
|
||||
mode = &res->modes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mode)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to look up mode %d (of %d)", static_cast<int>(ci->mode), res->nmode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0)
|
||||
{
|
||||
Log_ErrorPrintf("Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, mode->vTotal);
|
||||
return false;
|
||||
}
|
||||
|
||||
*refresh_rate =
|
||||
static_cast<double>(mode->dotClock) / (static_cast<double>(mode->hTotal) * static_cast<double>(mode->vTotal));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // USE_X11
|
||||
|
||||
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||
{
|
||||
#if defined(USE_X11)
|
||||
if (wi.type == WindowInfo::Type::X11)
|
||||
return GetRefreshRateFromXRandR(wi, refresh_rate);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
43
src/frontend/duckstation/window_info.h
Normal file
43
src/frontend/duckstation/window_info.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
|
||||
// Contains the information required to create a graphics context in a window.
|
||||
struct WindowInfo
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
Surfaceless,
|
||||
Win32,
|
||||
X11,
|
||||
Wayland,
|
||||
MacOS,
|
||||
Android,
|
||||
Display,
|
||||
};
|
||||
|
||||
enum class SurfaceFormat
|
||||
{
|
||||
None,
|
||||
Auto,
|
||||
RGB8,
|
||||
RGBA8,
|
||||
RGB565,
|
||||
Count
|
||||
};
|
||||
|
||||
Type type = Type::Surfaceless;
|
||||
void* display_connection = nullptr;
|
||||
void* window_handle = nullptr;
|
||||
u32 surface_width = 0;
|
||||
u32 surface_height = 0;
|
||||
float surface_refresh_rate = 0.0f;
|
||||
float surface_scale = 1.0f;
|
||||
SurfaceFormat surface_format = SurfaceFormat::RGB8;
|
||||
|
||||
// Needed for macOS.
|
||||
#ifdef __APPLE__
|
||||
void* surface_handle = nullptr;
|
||||
#endif
|
||||
|
||||
static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate);
|
||||
};
|
26
src/frontend/duckstation/windows_headers.h
Normal file
26
src/frontend/duckstation/windows_headers.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX 1
|
||||
#endif
|
||||
|
||||
// require vista+
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(CreateDirectory)
|
||||
#undef CreateDirectory
|
||||
#endif
|
||||
#if defined(CopyFile)
|
||||
#undef CopyFile
|
||||
#endif
|
||||
#if defined(DeleteFile)
|
||||
#undef DeleteFile
|
||||
#endif
|
169
src/frontend/glad/eglplatform.h
Normal file
169
src/frontend/glad/eglplatform.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef __eglplatform_h_
|
||||
#define __eglplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright 2007-2020 The Khronos Group Inc.
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Platform-specific types and definitions for egl.h
|
||||
*
|
||||
* Adopters may modify khrplatform.h and this file to suit their platform.
|
||||
* You are encouraged to submit all modifications to the Khronos group so that
|
||||
* they can be included in future versions of this file. Please submit changes
|
||||
* by filing an issue or pull request on the public Khronos EGL Registry, at
|
||||
* https://www.github.com/KhronosGroup/EGL-Registry/
|
||||
*/
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
/* Macros used in EGL function prototype declarations.
|
||||
*
|
||||
* EGL functions should be prototyped as:
|
||||
*
|
||||
* EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
|
||||
* typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
|
||||
*
|
||||
* KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
|
||||
*/
|
||||
|
||||
#ifndef EGLAPI
|
||||
#define EGLAPI KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
#ifndef EGLAPIENTRY
|
||||
#define EGLAPIENTRY KHRONOS_APIENTRY
|
||||
#endif
|
||||
#define EGLAPIENTRYP EGLAPIENTRY*
|
||||
|
||||
/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
|
||||
* are aliases of window-system-dependent types, such as X Display * or
|
||||
* Windows Device Context. They must be defined in platform-specific
|
||||
* code below. The EGL-prefixed versions of Native*Type are the same
|
||||
* types, renamed in EGL 1.3 so all types in the API start with "EGL".
|
||||
*
|
||||
* Khronos STRONGLY RECOMMENDS that you use the default definitions
|
||||
* provided below, since these changes affect both binary and source
|
||||
* portability of applications using EGL running on different EGL
|
||||
* implementations.
|
||||
*/
|
||||
|
||||
#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
typedef HDC EGLNativeDisplayType;
|
||||
typedef HBITMAP EGLNativePixmapType;
|
||||
typedef HWND EGLNativeWindowType;
|
||||
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef int EGLNativePixmapType;
|
||||
typedef int EGLNativeWindowType;
|
||||
|
||||
#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(WL_EGL_PLATFORM)
|
||||
|
||||
typedef struct wl_display *EGLNativeDisplayType;
|
||||
typedef struct wl_egl_pixmap *EGLNativePixmapType;
|
||||
typedef struct wl_egl_window *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__GBM__)
|
||||
|
||||
typedef struct gbm_device *EGLNativeDisplayType;
|
||||
typedef struct gbm_bo *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
|
||||
struct ANativeWindow;
|
||||
struct egl_native_pixmap_t;
|
||||
|
||||
typedef void* EGLNativeDisplayType;
|
||||
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
|
||||
typedef struct ANativeWindow* EGLNativeWindowType;
|
||||
|
||||
#elif defined(USE_OZONE)
|
||||
|
||||
typedef intptr_t EGLNativeDisplayType;
|
||||
typedef intptr_t EGLNativePixmapType;
|
||||
typedef intptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(USE_X11)
|
||||
|
||||
/* X11 (tentative) */
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
typedef Display *EGLNativeDisplayType;
|
||||
typedef Pixmap EGLNativePixmapType;
|
||||
typedef Window EGLNativeWindowType;
|
||||
|
||||
#elif defined(__unix__)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
typedef int EGLNativeDisplayType;
|
||||
typedef void *EGLNativePixmapType;
|
||||
typedef void *EGLNativeWindowType;
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
#include <kernel/image.h>
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#elif defined(__Fuchsia__)
|
||||
|
||||
typedef void *EGLNativeDisplayType;
|
||||
typedef khronos_uintptr_t EGLNativePixmapType;
|
||||
typedef khronos_uintptr_t EGLNativeWindowType;
|
||||
|
||||
#else
|
||||
#error "Platform not recognized"
|
||||
#endif
|
||||
|
||||
/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
|
||||
typedef EGLNativeDisplayType NativeDisplayType;
|
||||
typedef EGLNativePixmapType NativePixmapType;
|
||||
typedef EGLNativeWindowType NativeWindowType;
|
||||
|
||||
|
||||
/* Define EGLint. This must be a signed integral type large enough to contain
|
||||
* all legal attribute names and values passed into and out of EGL, whether
|
||||
* their type is boolean, bitmask, enumerant (symbolic constant), integer,
|
||||
* handle, or other. While in general a 32-bit integer will suffice, if
|
||||
* handles are 64 bit types, then EGLint should be defined as a signed 64-bit
|
||||
* integer type.
|
||||
*/
|
||||
typedef khronos_int32_t EGLint;
|
||||
|
||||
|
||||
/* C++ / C typecast macros for special EGL handle values */
|
||||
#if defined(__cplusplus)
|
||||
#define EGL_CAST(type, value) (static_cast<type>(value))
|
||||
#else
|
||||
#define EGL_CAST(type, value) ((type) (value))
|
||||
#endif
|
||||
|
||||
#endif /* __eglplatform_h */
|
1545
src/frontend/glad/glad.c
Normal file
1545
src/frontend/glad/glad.c
Normal file
File diff suppressed because it is too large
Load Diff
3202
src/frontend/glad/glad.h
Normal file
3202
src/frontend/glad/glad.h
Normal file
File diff suppressed because it is too large
Load Diff
45
src/frontend/glad/glad_egl.c
Normal file
45
src/frontend/glad/glad_egl.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
EGL loader generated by glad 0.1.36 on Thu Sep 15 11:06:51 2022.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: egl
|
||||
APIs: egl=1.5
|
||||
Profile: -
|
||||
Extensions:
|
||||
|
||||
Loader: True
|
||||
Local files: True
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--api="egl=1.5" --generator="c" --spec="egl" --local-files --extensions=""
|
||||
Online:
|
||||
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glad_egl.h"
|
||||
|
||||
int gladLoadEGL(void) {
|
||||
return gladLoadEGLLoader((GLADloadproc)eglGetProcAddress);
|
||||
}
|
||||
|
||||
static int find_extensionsEGL(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void find_coreEGL(void) {
|
||||
}
|
||||
|
||||
int gladLoadEGLLoader(GLADloadproc load) {
|
||||
(void) load;
|
||||
find_coreEGL();
|
||||
|
||||
if (!find_extensionsEGL()) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
317
src/frontend/glad/glad_egl.h
Normal file
317
src/frontend/glad/glad_egl.h
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
|
||||
EGL loader generated by glad 0.1.36 on Thu Sep 15 11:06:51 2022.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: egl
|
||||
APIs: egl=1.5
|
||||
Profile: -
|
||||
Extensions:
|
||||
|
||||
Loader: True
|
||||
Local files: True
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--api="egl=1.5" --generator="c" --spec="egl" --local-files --extensions=""
|
||||
Online:
|
||||
https://glad.dav1d.de/#language=c&specification=egl&loader=on&api=egl%3D1.5
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __glad_egl_h_
|
||||
|
||||
#ifdef __egl_h_
|
||||
#error EGL header already included, remove this include, glad already provides it
|
||||
#endif
|
||||
|
||||
#define __glad_egl_h_
|
||||
#define __egl_h_
|
||||
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
#define APIENTRY __stdcall
|
||||
#endif
|
||||
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* (* GLADloadproc)(const char *name);
|
||||
|
||||
GLAPI int gladLoadEGL(void);
|
||||
GLAPI int gladLoadEGLLoader(GLADloadproc);
|
||||
|
||||
#include "khrplatform.h"
|
||||
#include <EGL/eglplatform.h>
|
||||
struct AHardwareBuffer;
|
||||
struct wl_buffer;
|
||||
struct wl_display;
|
||||
struct wl_resource;
|
||||
typedef unsigned int EGLBoolean;
|
||||
typedef unsigned int EGLenum;
|
||||
typedef intptr_t EGLAttribKHR;
|
||||
typedef intptr_t EGLAttrib;
|
||||
typedef void *EGLClientBuffer;
|
||||
typedef void *EGLConfig;
|
||||
typedef void *EGLContext;
|
||||
typedef void *EGLDeviceEXT;
|
||||
typedef void *EGLDisplay;
|
||||
typedef void *EGLImage;
|
||||
typedef void *EGLImageKHR;
|
||||
typedef void *EGLLabelKHR;
|
||||
typedef void *EGLObjectKHR;
|
||||
typedef void *EGLOutputLayerEXT;
|
||||
typedef void *EGLOutputPortEXT;
|
||||
typedef void *EGLStreamKHR;
|
||||
typedef void *EGLSurface;
|
||||
typedef void *EGLSync;
|
||||
typedef void *EGLSyncKHR;
|
||||
typedef void *EGLSyncNV;
|
||||
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
|
||||
typedef khronos_utime_nanoseconds_t EGLTimeKHR;
|
||||
typedef khronos_utime_nanoseconds_t EGLTime;
|
||||
typedef khronos_utime_nanoseconds_t EGLTimeNV;
|
||||
typedef khronos_utime_nanoseconds_t EGLuint64NV;
|
||||
typedef khronos_uint64_t EGLuint64KHR;
|
||||
typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
|
||||
typedef int EGLNativeFileDescriptorKHR;
|
||||
typedef khronos_ssize_t EGLsizeiANDROID;
|
||||
typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
|
||||
typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
|
||||
struct EGLClientPixmapHI {
|
||||
void *pData;
|
||||
EGLint iWidth;
|
||||
EGLint iHeight;
|
||||
EGLint iStride;
|
||||
};
|
||||
typedef void (APIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
|
||||
#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
|
||||
#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
|
||||
#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
|
||||
#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
|
||||
#define EGL_ALPHA_SIZE 0x3021
|
||||
#define EGL_BAD_ACCESS 0x3002
|
||||
#define EGL_BAD_ALLOC 0x3003
|
||||
#define EGL_BAD_ATTRIBUTE 0x3004
|
||||
#define EGL_BAD_CONFIG 0x3005
|
||||
#define EGL_BAD_CONTEXT 0x3006
|
||||
#define EGL_BAD_CURRENT_SURFACE 0x3007
|
||||
#define EGL_BAD_DISPLAY 0x3008
|
||||
#define EGL_BAD_MATCH 0x3009
|
||||
#define EGL_BAD_NATIVE_PIXMAP 0x300A
|
||||
#define EGL_BAD_NATIVE_WINDOW 0x300B
|
||||
#define EGL_BAD_PARAMETER 0x300C
|
||||
#define EGL_BAD_SURFACE 0x300D
|
||||
#define EGL_BLUE_SIZE 0x3022
|
||||
#define EGL_BUFFER_SIZE 0x3020
|
||||
#define EGL_CONFIG_CAVEAT 0x3027
|
||||
#define EGL_CONFIG_ID 0x3028
|
||||
#define EGL_CORE_NATIVE_ENGINE 0x305B
|
||||
#define EGL_DEPTH_SIZE 0x3025
|
||||
#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
|
||||
#define EGL_DRAW 0x3059
|
||||
#define EGL_EXTENSIONS 0x3055
|
||||
#define EGL_FALSE 0
|
||||
#define EGL_GREEN_SIZE 0x3023
|
||||
#define EGL_HEIGHT 0x3056
|
||||
#define EGL_LARGEST_PBUFFER 0x3058
|
||||
#define EGL_LEVEL 0x3029
|
||||
#define EGL_MAX_PBUFFER_HEIGHT 0x302A
|
||||
#define EGL_MAX_PBUFFER_PIXELS 0x302B
|
||||
#define EGL_MAX_PBUFFER_WIDTH 0x302C
|
||||
#define EGL_NATIVE_RENDERABLE 0x302D
|
||||
#define EGL_NATIVE_VISUAL_ID 0x302E
|
||||
#define EGL_NATIVE_VISUAL_TYPE 0x302F
|
||||
#define EGL_NONE 0x3038
|
||||
#define EGL_NON_CONFORMANT_CONFIG 0x3051
|
||||
#define EGL_NOT_INITIALIZED 0x3001
|
||||
#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
|
||||
#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
|
||||
#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
|
||||
#define EGL_PBUFFER_BIT 0x0001
|
||||
#define EGL_PIXMAP_BIT 0x0002
|
||||
#define EGL_READ 0x305A
|
||||
#define EGL_RED_SIZE 0x3024
|
||||
#define EGL_SAMPLES 0x3031
|
||||
#define EGL_SAMPLE_BUFFERS 0x3032
|
||||
#define EGL_SLOW_CONFIG 0x3050
|
||||
#define EGL_STENCIL_SIZE 0x3026
|
||||
#define EGL_SUCCESS 0x3000
|
||||
#define EGL_SURFACE_TYPE 0x3033
|
||||
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
|
||||
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
|
||||
#define EGL_TRANSPARENT_RED_VALUE 0x3037
|
||||
#define EGL_TRANSPARENT_RGB 0x3052
|
||||
#define EGL_TRANSPARENT_TYPE 0x3034
|
||||
#define EGL_TRUE 1
|
||||
#define EGL_VENDOR 0x3053
|
||||
#define EGL_VERSION 0x3054
|
||||
#define EGL_WIDTH 0x3057
|
||||
#define EGL_WINDOW_BIT 0x0004
|
||||
#define EGL_BACK_BUFFER 0x3084
|
||||
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
|
||||
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
|
||||
#define EGL_CONTEXT_LOST 0x300E
|
||||
#define EGL_MIN_SWAP_INTERVAL 0x303B
|
||||
#define EGL_MAX_SWAP_INTERVAL 0x303C
|
||||
#define EGL_MIPMAP_TEXTURE 0x3082
|
||||
#define EGL_MIPMAP_LEVEL 0x3083
|
||||
#define EGL_NO_TEXTURE 0x305C
|
||||
#define EGL_TEXTURE_2D 0x305F
|
||||
#define EGL_TEXTURE_FORMAT 0x3080
|
||||
#define EGL_TEXTURE_RGB 0x305D
|
||||
#define EGL_TEXTURE_RGBA 0x305E
|
||||
#define EGL_TEXTURE_TARGET 0x3081
|
||||
#define EGL_ALPHA_FORMAT 0x3088
|
||||
#define EGL_ALPHA_FORMAT_NONPRE 0x308B
|
||||
#define EGL_ALPHA_FORMAT_PRE 0x308C
|
||||
#define EGL_ALPHA_MASK_SIZE 0x303E
|
||||
#define EGL_BUFFER_PRESERVED 0x3094
|
||||
#define EGL_BUFFER_DESTROYED 0x3095
|
||||
#define EGL_CLIENT_APIS 0x308D
|
||||
#define EGL_COLORSPACE 0x3087
|
||||
#define EGL_COLORSPACE_sRGB 0x3089
|
||||
#define EGL_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_COLOR_BUFFER_TYPE 0x303F
|
||||
#define EGL_CONTEXT_CLIENT_TYPE 0x3097
|
||||
#define EGL_DISPLAY_SCALING 10000
|
||||
#define EGL_HORIZONTAL_RESOLUTION 0x3090
|
||||
#define EGL_LUMINANCE_BUFFER 0x308F
|
||||
#define EGL_LUMINANCE_SIZE 0x303D
|
||||
#define EGL_OPENGL_ES_BIT 0x0001
|
||||
#define EGL_OPENVG_BIT 0x0002
|
||||
#define EGL_OPENGL_ES_API 0x30A0
|
||||
#define EGL_OPENVG_API 0x30A1
|
||||
#define EGL_OPENVG_IMAGE 0x3096
|
||||
#define EGL_PIXEL_ASPECT_RATIO 0x3092
|
||||
#define EGL_RENDERABLE_TYPE 0x3040
|
||||
#define EGL_RENDER_BUFFER 0x3086
|
||||
#define EGL_RGB_BUFFER 0x308E
|
||||
#define EGL_SINGLE_BUFFER 0x3085
|
||||
#define EGL_SWAP_BEHAVIOR 0x3093
|
||||
#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
|
||||
#define EGL_VERTICAL_RESOLUTION 0x3091
|
||||
#define EGL_CONFORMANT 0x3042
|
||||
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
|
||||
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||
#define EGL_VG_ALPHA_FORMAT 0x3088
|
||||
#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
|
||||
#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
|
||||
#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
|
||||
#define EGL_VG_COLORSPACE 0x3087
|
||||
#define EGL_VG_COLORSPACE_sRGB 0x3089
|
||||
#define EGL_VG_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
|
||||
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
|
||||
#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
|
||||
#define EGL_MULTISAMPLE_RESOLVE 0x3099
|
||||
#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
|
||||
#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
|
||||
#define EGL_OPENGL_API 0x30A2
|
||||
#define EGL_OPENGL_BIT 0x0008
|
||||
#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
|
||||
#define EGL_CONTEXT_MAJOR_VERSION 0x3098
|
||||
#define EGL_CONTEXT_MINOR_VERSION 0x30FB
|
||||
#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
|
||||
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
|
||||
#define EGL_NO_RESET_NOTIFICATION 0x31BE
|
||||
#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
|
||||
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
|
||||
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
|
||||
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
|
||||
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
|
||||
#define EGL_OPENGL_ES3_BIT 0x00000040
|
||||
#define EGL_CL_EVENT_HANDLE 0x309C
|
||||
#define EGL_SYNC_CL_EVENT 0x30FE
|
||||
#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
|
||||
#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
|
||||
#define EGL_SYNC_TYPE 0x30F7
|
||||
#define EGL_SYNC_STATUS 0x30F1
|
||||
#define EGL_SYNC_CONDITION 0x30F8
|
||||
#define EGL_SIGNALED 0x30F2
|
||||
#define EGL_UNSIGNALED 0x30F3
|
||||
#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
|
||||
#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF
|
||||
#define EGL_TIMEOUT_EXPIRED 0x30F5
|
||||
#define EGL_CONDITION_SATISFIED 0x30F6
|
||||
#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
|
||||
#define EGL_SYNC_FENCE 0x30F9
|
||||
#define EGL_GL_COLORSPACE 0x309D
|
||||
#define EGL_GL_COLORSPACE_SRGB 0x3089
|
||||
#define EGL_GL_COLORSPACE_LINEAR 0x308A
|
||||
#define EGL_GL_RENDERBUFFER 0x30B9
|
||||
#define EGL_GL_TEXTURE_2D 0x30B1
|
||||
#define EGL_GL_TEXTURE_LEVEL 0x30BC
|
||||
#define EGL_GL_TEXTURE_3D 0x30B2
|
||||
#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
|
||||
#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
|
||||
#define EGL_IMAGE_PRESERVED 0x30D2
|
||||
#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
|
||||
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
|
||||
EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
|
||||
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
|
||||
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
|
||||
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
|
||||
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
|
||||
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
|
||||
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
|
||||
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
|
||||
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
|
||||
EGLDisplay eglGetCurrentDisplay(void);
|
||||
EGLSurface eglGetCurrentSurface(EGLint readdraw);
|
||||
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);
|
||||
EGLint eglGetError(void);
|
||||
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname);
|
||||
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
|
||||
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
|
||||
EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
|
||||
const char *eglQueryString(EGLDisplay dpy, EGLint name);
|
||||
EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
|
||||
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
|
||||
EGLBoolean eglTerminate(EGLDisplay dpy);
|
||||
EGLBoolean eglWaitGL(void);
|
||||
EGLBoolean eglWaitNative(EGLint engine);
|
||||
EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
||||
EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
|
||||
EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
|
||||
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
|
||||
EGLBoolean eglBindAPI(EGLenum api);
|
||||
EGLenum eglQueryAPI(void);
|
||||
EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
|
||||
EGLBoolean eglReleaseThread(void);
|
||||
EGLBoolean eglWaitClient(void);
|
||||
EGLContext eglGetCurrentContext(void);
|
||||
EGLSync eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
|
||||
EGLBoolean eglDestroySync(EGLDisplay dpy, EGLSync sync);
|
||||
EGLint eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
|
||||
EGLBoolean eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
|
||||
EGLImage eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
|
||||
EGLBoolean eglDestroyImage(EGLDisplay dpy, EGLImage image);
|
||||
EGLDisplay eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
|
||||
EGLSurface eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
|
||||
EGLSurface eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
|
||||
EGLBoolean eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
880
src/frontend/glad/glad_glx.c
Normal file
880
src/frontend/glad/glad_glx.c
Normal file
@ -0,0 +1,880 @@
|
||||
/*
|
||||
|
||||
GLX loader generated by glad 0.1.36 on Sat Oct 8 13:52:35 2022.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: glx
|
||||
APIs: glx=1.4
|
||||
Profile: -
|
||||
Extensions:
|
||||
GLX_3DFX_multisample,
|
||||
GLX_AMD_gpu_association,
|
||||
GLX_ARB_context_flush_control,
|
||||
GLX_ARB_create_context,
|
||||
GLX_ARB_create_context_no_error,
|
||||
GLX_ARB_create_context_profile,
|
||||
GLX_ARB_create_context_robustness,
|
||||
GLX_ARB_fbconfig_float,
|
||||
GLX_ARB_framebuffer_sRGB,
|
||||
GLX_ARB_get_proc_address,
|
||||
GLX_ARB_multisample,
|
||||
GLX_ARB_robustness_application_isolation,
|
||||
GLX_ARB_robustness_share_group_isolation,
|
||||
GLX_ARB_vertex_buffer_object,
|
||||
GLX_EXT_buffer_age,
|
||||
GLX_EXT_context_priority,
|
||||
GLX_EXT_create_context_es2_profile,
|
||||
GLX_EXT_create_context_es_profile,
|
||||
GLX_EXT_fbconfig_packed_float,
|
||||
GLX_EXT_framebuffer_sRGB,
|
||||
GLX_EXT_get_drawable_type,
|
||||
GLX_EXT_import_context,
|
||||
GLX_EXT_libglvnd,
|
||||
GLX_EXT_no_config_context,
|
||||
GLX_EXT_stereo_tree,
|
||||
GLX_EXT_swap_control,
|
||||
GLX_EXT_swap_control_tear,
|
||||
GLX_EXT_texture_from_pixmap,
|
||||
GLX_EXT_visual_info,
|
||||
GLX_EXT_visual_rating,
|
||||
GLX_INTEL_swap_event,
|
||||
GLX_MESA_agp_offset,
|
||||
GLX_MESA_copy_sub_buffer,
|
||||
GLX_MESA_pixmap_colormap,
|
||||
GLX_MESA_query_renderer,
|
||||
GLX_MESA_release_buffers,
|
||||
GLX_MESA_set_3dfx_mode,
|
||||
GLX_MESA_swap_control,
|
||||
GLX_NV_copy_buffer,
|
||||
GLX_NV_copy_image,
|
||||
GLX_NV_delay_before_swap,
|
||||
GLX_NV_float_buffer,
|
||||
GLX_NV_multigpu_context,
|
||||
GLX_NV_multisample_coverage,
|
||||
GLX_NV_present_video,
|
||||
GLX_NV_robustness_video_memory_purge,
|
||||
GLX_NV_swap_group,
|
||||
GLX_NV_video_capture,
|
||||
GLX_NV_video_out,
|
||||
GLX_OML_swap_method,
|
||||
GLX_OML_sync_control,
|
||||
GLX_SGIS_blended_overlay,
|
||||
GLX_SGIS_multisample,
|
||||
GLX_SGIS_shared_multisample,
|
||||
GLX_SGIX_dmbuffer,
|
||||
GLX_SGIX_fbconfig,
|
||||
GLX_SGIX_hyperpipe,
|
||||
GLX_SGIX_pbuffer,
|
||||
GLX_SGIX_swap_barrier,
|
||||
GLX_SGIX_swap_group,
|
||||
GLX_SGIX_video_resize,
|
||||
GLX_SGIX_video_source,
|
||||
GLX_SGIX_visual_select_group,
|
||||
GLX_SGI_cushion,
|
||||
GLX_SGI_make_current_read,
|
||||
GLX_SGI_swap_control,
|
||||
GLX_SGI_video_sync,
|
||||
GLX_SUN_get_transparent_index
|
||||
Loader: True
|
||||
Local files: True
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--api="glx=1.4" --generator="c" --spec="glx" --local-files --extensions="GLX_3DFX_multisample,GLX_AMD_gpu_association,GLX_ARB_context_flush_control,GLX_ARB_create_context,GLX_ARB_create_context_no_error,GLX_ARB_create_context_profile,GLX_ARB_create_context_robustness,GLX_ARB_fbconfig_float,GLX_ARB_framebuffer_sRGB,GLX_ARB_get_proc_address,GLX_ARB_multisample,GLX_ARB_robustness_application_isolation,GLX_ARB_robustness_share_group_isolation,GLX_ARB_vertex_buffer_object,GLX_EXT_buffer_age,GLX_EXT_context_priority,GLX_EXT_create_context_es2_profile,GLX_EXT_create_context_es_profile,GLX_EXT_fbconfig_packed_float,GLX_EXT_framebuffer_sRGB,GLX_EXT_get_drawable_type,GLX_EXT_import_context,GLX_EXT_libglvnd,GLX_EXT_no_config_context,GLX_EXT_stereo_tree,GLX_EXT_swap_control,GLX_EXT_swap_control_tear,GLX_EXT_texture_from_pixmap,GLX_EXT_visual_info,GLX_EXT_visual_rating,GLX_INTEL_swap_event,GLX_MESA_agp_offset,GLX_MESA_copy_sub_buffer,GLX_MESA_pixmap_colormap,GLX_MESA_query_renderer,GLX_MESA_release_buffers,GLX_MESA_set_3dfx_mode,GLX_MESA_swap_control,GLX_NV_copy_buffer,GLX_NV_copy_image,GLX_NV_delay_before_swap,GLX_NV_float_buffer,GLX_NV_multigpu_context,GLX_NV_multisample_coverage,GLX_NV_present_video,GLX_NV_robustness_video_memory_purge,GLX_NV_swap_group,GLX_NV_video_capture,GLX_NV_video_out,GLX_OML_swap_method,GLX_OML_sync_control,GLX_SGIS_blended_overlay,GLX_SGIS_multisample,GLX_SGIS_shared_multisample,GLX_SGIX_dmbuffer,GLX_SGIX_fbconfig,GLX_SGIX_hyperpipe,GLX_SGIX_pbuffer,GLX_SGIX_swap_barrier,GLX_SGIX_swap_group,GLX_SGIX_video_resize,GLX_SGIX_video_source,GLX_SGIX_visual_select_group,GLX_SGI_cushion,GLX_SGI_make_current_read,GLX_SGI_swap_control,GLX_SGI_video_sync,GLX_SUN_get_transparent_index"
|
||||
Online:
|
||||
Too many extensions
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glad_glx.h"
|
||||
|
||||
static void* get_proc(const char *namez);
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifndef _WINDOWS_
|
||||
#undef APIENTRY
|
||||
#endif
|
||||
#include <windows.h>
|
||||
static HMODULE libGL;
|
||||
|
||||
typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);
|
||||
static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef __has_include
|
||||
#if __has_include(<winapifamily.h>)
|
||||
#define HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
|
||||
#define HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINAPIFAMILY
|
||||
#include <winapifamily.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#define IS_UWP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static
|
||||
int open_glx(void) {
|
||||
#ifndef IS_UWP
|
||||
libGL = LoadLibraryW(L"opengl32.dll");
|
||||
if(libGL != NULL) {
|
||||
void (* tmp)(void);
|
||||
tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress");
|
||||
gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;
|
||||
return gladGetProcAddressPtr != NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void close_glx(void) {
|
||||
if(libGL != NULL) {
|
||||
FreeLibrary((HMODULE) libGL);
|
||||
libGL = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
static void* libGL;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__HAIKU__)
|
||||
typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
|
||||
static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
|
||||
#endif
|
||||
|
||||
static
|
||||
int open_glx(void) {
|
||||
#ifdef __APPLE__
|
||||
static const char *NAMES[] = {
|
||||
"../Frameworks/OpenGL.framework/OpenGL",
|
||||
"/Library/Frameworks/OpenGL.framework/OpenGL",
|
||||
"/System/Library/Frameworks/OpenGL.framework/OpenGL",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
|
||||
};
|
||||
#else
|
||||
static const char *NAMES[] = {"libGL.so.1", "libGL.so"};
|
||||
#endif
|
||||
|
||||
unsigned int index = 0;
|
||||
for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {
|
||||
libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
|
||||
|
||||
if(libGL != NULL) {
|
||||
#if defined(__APPLE__) || defined(__HAIKU__)
|
||||
return 1;
|
||||
#else
|
||||
gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
|
||||
"glXGetProcAddressARB");
|
||||
return gladGetProcAddressPtr != NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void close_glx(void) {
|
||||
if(libGL != NULL) {
|
||||
dlclose(libGL);
|
||||
libGL = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
void* get_proc(const char *namez) {
|
||||
void* result = NULL;
|
||||
if(libGL == NULL) return NULL;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__HAIKU__)
|
||||
if(gladGetProcAddressPtr != NULL) {
|
||||
result = gladGetProcAddressPtr(namez);
|
||||
}
|
||||
#endif
|
||||
if(result == NULL) {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
result = (void*)GetProcAddress((HMODULE) libGL, namez);
|
||||
#else
|
||||
result = dlsym(libGL, namez);
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int gladLoadGLX(Display *dpy, int screen) {
|
||||
int status = 0;
|
||||
|
||||
if(open_glx()) {
|
||||
status = gladLoadGLXLoader((GLADloadproc)get_proc, dpy, screen);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void gladUnloadGLX(void) {
|
||||
close_glx();
|
||||
}
|
||||
|
||||
static Display *GLADGLXDisplay = 0;
|
||||
static int GLADGLXscreen = 0;
|
||||
|
||||
static int get_exts(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void free_exts(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int has_ext(const char *ext) {
|
||||
const char *terminator;
|
||||
const char *loc;
|
||||
const char *extensions;
|
||||
|
||||
if(!GLAD_GLX_VERSION_1_1)
|
||||
return 0;
|
||||
|
||||
extensions = glXQueryExtensionsString(GLADGLXDisplay, GLADGLXscreen);
|
||||
|
||||
if(extensions == NULL || ext == NULL)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
loc = strstr(extensions, ext);
|
||||
if(loc == NULL)
|
||||
break;
|
||||
|
||||
terminator = loc + strlen(ext);
|
||||
if((loc == extensions || *(loc - 1) == ' ') &&
|
||||
(*terminator == ' ' || *terminator == '\0'))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
extensions = terminator;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GLAD_GLX_VERSION_1_0 = 0;
|
||||
int GLAD_GLX_VERSION_1_1 = 0;
|
||||
int GLAD_GLX_VERSION_1_2 = 0;
|
||||
int GLAD_GLX_VERSION_1_3 = 0;
|
||||
int GLAD_GLX_VERSION_1_4 = 0;
|
||||
PFNGLXCHOOSEFBCONFIGPROC glad_glXChooseFBConfig = NULL;
|
||||
PFNGLXCHOOSEVISUALPROC glad_glXChooseVisual = NULL;
|
||||
PFNGLXCOPYCONTEXTPROC glad_glXCopyContext = NULL;
|
||||
PFNGLXCREATECONTEXTPROC glad_glXCreateContext = NULL;
|
||||
PFNGLXCREATEGLXPIXMAPPROC glad_glXCreateGLXPixmap = NULL;
|
||||
PFNGLXCREATENEWCONTEXTPROC glad_glXCreateNewContext = NULL;
|
||||
PFNGLXCREATEPBUFFERPROC glad_glXCreatePbuffer = NULL;
|
||||
PFNGLXCREATEPIXMAPPROC glad_glXCreatePixmap = NULL;
|
||||
PFNGLXCREATEWINDOWPROC glad_glXCreateWindow = NULL;
|
||||
PFNGLXDESTROYCONTEXTPROC glad_glXDestroyContext = NULL;
|
||||
PFNGLXDESTROYGLXPIXMAPPROC glad_glXDestroyGLXPixmap = NULL;
|
||||
PFNGLXDESTROYPBUFFERPROC glad_glXDestroyPbuffer = NULL;
|
||||
PFNGLXDESTROYPIXMAPPROC glad_glXDestroyPixmap = NULL;
|
||||
PFNGLXDESTROYWINDOWPROC glad_glXDestroyWindow = NULL;
|
||||
PFNGLXGETCLIENTSTRINGPROC glad_glXGetClientString = NULL;
|
||||
PFNGLXGETCONFIGPROC glad_glXGetConfig = NULL;
|
||||
PFNGLXGETCURRENTCONTEXTPROC glad_glXGetCurrentContext = NULL;
|
||||
PFNGLXGETCURRENTDISPLAYPROC glad_glXGetCurrentDisplay = NULL;
|
||||
PFNGLXGETCURRENTDRAWABLEPROC glad_glXGetCurrentDrawable = NULL;
|
||||
PFNGLXGETCURRENTREADDRAWABLEPROC glad_glXGetCurrentReadDrawable = NULL;
|
||||
PFNGLXGETFBCONFIGATTRIBPROC glad_glXGetFBConfigAttrib = NULL;
|
||||
PFNGLXGETFBCONFIGSPROC glad_glXGetFBConfigs = NULL;
|
||||
PFNGLXGETPROCADDRESSPROC glad_glXGetProcAddress = NULL;
|
||||
PFNGLXGETSELECTEDEVENTPROC glad_glXGetSelectedEvent = NULL;
|
||||
PFNGLXGETVISUALFROMFBCONFIGPROC glad_glXGetVisualFromFBConfig = NULL;
|
||||
PFNGLXISDIRECTPROC glad_glXIsDirect = NULL;
|
||||
PFNGLXMAKECONTEXTCURRENTPROC glad_glXMakeContextCurrent = NULL;
|
||||
PFNGLXMAKECURRENTPROC glad_glXMakeCurrent = NULL;
|
||||
PFNGLXQUERYCONTEXTPROC glad_glXQueryContext = NULL;
|
||||
PFNGLXQUERYDRAWABLEPROC glad_glXQueryDrawable = NULL;
|
||||
PFNGLXQUERYEXTENSIONPROC glad_glXQueryExtension = NULL;
|
||||
PFNGLXQUERYEXTENSIONSSTRINGPROC glad_glXQueryExtensionsString = NULL;
|
||||
PFNGLXQUERYSERVERSTRINGPROC glad_glXQueryServerString = NULL;
|
||||
PFNGLXQUERYVERSIONPROC glad_glXQueryVersion = NULL;
|
||||
PFNGLXSELECTEVENTPROC glad_glXSelectEvent = NULL;
|
||||
PFNGLXSWAPBUFFERSPROC glad_glXSwapBuffers = NULL;
|
||||
PFNGLXUSEXFONTPROC glad_glXUseXFont = NULL;
|
||||
PFNGLXWAITGLPROC glad_glXWaitGL = NULL;
|
||||
PFNGLXWAITXPROC glad_glXWaitX = NULL;
|
||||
int GLAD_GLX_3DFX_multisample = 0;
|
||||
int GLAD_GLX_AMD_gpu_association = 0;
|
||||
int GLAD_GLX_ARB_context_flush_control = 0;
|
||||
int GLAD_GLX_ARB_create_context = 0;
|
||||
int GLAD_GLX_ARB_create_context_no_error = 0;
|
||||
int GLAD_GLX_ARB_create_context_profile = 0;
|
||||
int GLAD_GLX_ARB_create_context_robustness = 0;
|
||||
int GLAD_GLX_ARB_fbconfig_float = 0;
|
||||
int GLAD_GLX_ARB_framebuffer_sRGB = 0;
|
||||
int GLAD_GLX_ARB_get_proc_address = 0;
|
||||
int GLAD_GLX_ARB_multisample = 0;
|
||||
int GLAD_GLX_ARB_robustness_application_isolation = 0;
|
||||
int GLAD_GLX_ARB_robustness_share_group_isolation = 0;
|
||||
int GLAD_GLX_ARB_vertex_buffer_object = 0;
|
||||
int GLAD_GLX_EXT_buffer_age = 0;
|
||||
int GLAD_GLX_EXT_context_priority = 0;
|
||||
int GLAD_GLX_EXT_create_context_es2_profile = 0;
|
||||
int GLAD_GLX_EXT_create_context_es_profile = 0;
|
||||
int GLAD_GLX_EXT_fbconfig_packed_float = 0;
|
||||
int GLAD_GLX_EXT_framebuffer_sRGB = 0;
|
||||
int GLAD_GLX_EXT_get_drawable_type = 0;
|
||||
int GLAD_GLX_EXT_import_context = 0;
|
||||
int GLAD_GLX_EXT_libglvnd = 0;
|
||||
int GLAD_GLX_EXT_no_config_context = 0;
|
||||
int GLAD_GLX_EXT_stereo_tree = 0;
|
||||
int GLAD_GLX_EXT_swap_control = 0;
|
||||
int GLAD_GLX_EXT_swap_control_tear = 0;
|
||||
int GLAD_GLX_EXT_texture_from_pixmap = 0;
|
||||
int GLAD_GLX_EXT_visual_info = 0;
|
||||
int GLAD_GLX_EXT_visual_rating = 0;
|
||||
int GLAD_GLX_INTEL_swap_event = 0;
|
||||
int GLAD_GLX_MESA_agp_offset = 0;
|
||||
int GLAD_GLX_MESA_copy_sub_buffer = 0;
|
||||
int GLAD_GLX_MESA_pixmap_colormap = 0;
|
||||
int GLAD_GLX_MESA_query_renderer = 0;
|
||||
int GLAD_GLX_MESA_release_buffers = 0;
|
||||
int GLAD_GLX_MESA_set_3dfx_mode = 0;
|
||||
int GLAD_GLX_MESA_swap_control = 0;
|
||||
int GLAD_GLX_NV_copy_buffer = 0;
|
||||
int GLAD_GLX_NV_copy_image = 0;
|
||||
int GLAD_GLX_NV_delay_before_swap = 0;
|
||||
int GLAD_GLX_NV_float_buffer = 0;
|
||||
int GLAD_GLX_NV_multigpu_context = 0;
|
||||
int GLAD_GLX_NV_multisample_coverage = 0;
|
||||
int GLAD_GLX_NV_present_video = 0;
|
||||
int GLAD_GLX_NV_robustness_video_memory_purge = 0;
|
||||
int GLAD_GLX_NV_swap_group = 0;
|
||||
int GLAD_GLX_NV_video_capture = 0;
|
||||
int GLAD_GLX_NV_video_out = 0;
|
||||
int GLAD_GLX_OML_swap_method = 0;
|
||||
int GLAD_GLX_OML_sync_control = 0;
|
||||
int GLAD_GLX_SGIS_blended_overlay = 0;
|
||||
int GLAD_GLX_SGIS_multisample = 0;
|
||||
int GLAD_GLX_SGIS_shared_multisample = 0;
|
||||
int GLAD_GLX_SGIX_dmbuffer = 0;
|
||||
int GLAD_GLX_SGIX_fbconfig = 0;
|
||||
int GLAD_GLX_SGIX_hyperpipe = 0;
|
||||
int GLAD_GLX_SGIX_pbuffer = 0;
|
||||
int GLAD_GLX_SGIX_swap_barrier = 0;
|
||||
int GLAD_GLX_SGIX_swap_group = 0;
|
||||
int GLAD_GLX_SGIX_video_resize = 0;
|
||||
int GLAD_GLX_SGIX_video_source = 0;
|
||||
int GLAD_GLX_SGIX_visual_select_group = 0;
|
||||
int GLAD_GLX_SGI_cushion = 0;
|
||||
int GLAD_GLX_SGI_make_current_read = 0;
|
||||
int GLAD_GLX_SGI_swap_control = 0;
|
||||
int GLAD_GLX_SGI_video_sync = 0;
|
||||
int GLAD_GLX_SUN_get_transparent_index = 0;
|
||||
PFNGLXGETGPUIDSAMDPROC glad_glXGetGPUIDsAMD = NULL;
|
||||
PFNGLXGETGPUINFOAMDPROC glad_glXGetGPUInfoAMD = NULL;
|
||||
PFNGLXGETCONTEXTGPUIDAMDPROC glad_glXGetContextGPUIDAMD = NULL;
|
||||
PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC glad_glXCreateAssociatedContextAMD = NULL;
|
||||
PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC glad_glXCreateAssociatedContextAttribsAMD = NULL;
|
||||
PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC glad_glXDeleteAssociatedContextAMD = NULL;
|
||||
PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC glad_glXMakeAssociatedContextCurrentAMD = NULL;
|
||||
PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC glad_glXGetCurrentAssociatedContextAMD = NULL;
|
||||
PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC glad_glXBlitContextFramebufferAMD = NULL;
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC glad_glXCreateContextAttribsARB = NULL;
|
||||
PFNGLXGETPROCADDRESSARBPROC glad_glXGetProcAddressARB = NULL;
|
||||
PFNGLXGETCURRENTDISPLAYEXTPROC glad_glXGetCurrentDisplayEXT = NULL;
|
||||
PFNGLXQUERYCONTEXTINFOEXTPROC glad_glXQueryContextInfoEXT = NULL;
|
||||
PFNGLXGETCONTEXTIDEXTPROC glad_glXGetContextIDEXT = NULL;
|
||||
PFNGLXIMPORTCONTEXTEXTPROC glad_glXImportContextEXT = NULL;
|
||||
PFNGLXFREECONTEXTEXTPROC glad_glXFreeContextEXT = NULL;
|
||||
PFNGLXSWAPINTERVALEXTPROC glad_glXSwapIntervalEXT = NULL;
|
||||
PFNGLXBINDTEXIMAGEEXTPROC glad_glXBindTexImageEXT = NULL;
|
||||
PFNGLXRELEASETEXIMAGEEXTPROC glad_glXReleaseTexImageEXT = NULL;
|
||||
PFNGLXGETAGPOFFSETMESAPROC glad_glXGetAGPOffsetMESA = NULL;
|
||||
PFNGLXCOPYSUBBUFFERMESAPROC glad_glXCopySubBufferMESA = NULL;
|
||||
PFNGLXCREATEGLXPIXMAPMESAPROC glad_glXCreateGLXPixmapMESA = NULL;
|
||||
PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC glad_glXQueryCurrentRendererIntegerMESA = NULL;
|
||||
PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC glad_glXQueryCurrentRendererStringMESA = NULL;
|
||||
PFNGLXQUERYRENDERERINTEGERMESAPROC glad_glXQueryRendererIntegerMESA = NULL;
|
||||
PFNGLXQUERYRENDERERSTRINGMESAPROC glad_glXQueryRendererStringMESA = NULL;
|
||||
PFNGLXRELEASEBUFFERSMESAPROC glad_glXReleaseBuffersMESA = NULL;
|
||||
PFNGLXSET3DFXMODEMESAPROC glad_glXSet3DfxModeMESA = NULL;
|
||||
PFNGLXGETSWAPINTERVALMESAPROC glad_glXGetSwapIntervalMESA = NULL;
|
||||
PFNGLXSWAPINTERVALMESAPROC glad_glXSwapIntervalMESA = NULL;
|
||||
PFNGLXCOPYBUFFERSUBDATANVPROC glad_glXCopyBufferSubDataNV = NULL;
|
||||
PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC glad_glXNamedCopyBufferSubDataNV = NULL;
|
||||
PFNGLXCOPYIMAGESUBDATANVPROC glad_glXCopyImageSubDataNV = NULL;
|
||||
PFNGLXDELAYBEFORESWAPNVPROC glad_glXDelayBeforeSwapNV = NULL;
|
||||
PFNGLXENUMERATEVIDEODEVICESNVPROC glad_glXEnumerateVideoDevicesNV = NULL;
|
||||
PFNGLXBINDVIDEODEVICENVPROC glad_glXBindVideoDeviceNV = NULL;
|
||||
PFNGLXJOINSWAPGROUPNVPROC glad_glXJoinSwapGroupNV = NULL;
|
||||
PFNGLXBINDSWAPBARRIERNVPROC glad_glXBindSwapBarrierNV = NULL;
|
||||
PFNGLXQUERYSWAPGROUPNVPROC glad_glXQuerySwapGroupNV = NULL;
|
||||
PFNGLXQUERYMAXSWAPGROUPSNVPROC glad_glXQueryMaxSwapGroupsNV = NULL;
|
||||
PFNGLXQUERYFRAMECOUNTNVPROC glad_glXQueryFrameCountNV = NULL;
|
||||
PFNGLXRESETFRAMECOUNTNVPROC glad_glXResetFrameCountNV = NULL;
|
||||
PFNGLXBINDVIDEOCAPTUREDEVICENVPROC glad_glXBindVideoCaptureDeviceNV = NULL;
|
||||
PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC glad_glXEnumerateVideoCaptureDevicesNV = NULL;
|
||||
PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC glad_glXLockVideoCaptureDeviceNV = NULL;
|
||||
PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC glad_glXQueryVideoCaptureDeviceNV = NULL;
|
||||
PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC glad_glXReleaseVideoCaptureDeviceNV = NULL;
|
||||
PFNGLXGETVIDEODEVICENVPROC glad_glXGetVideoDeviceNV = NULL;
|
||||
PFNGLXRELEASEVIDEODEVICENVPROC glad_glXReleaseVideoDeviceNV = NULL;
|
||||
PFNGLXBINDVIDEOIMAGENVPROC glad_glXBindVideoImageNV = NULL;
|
||||
PFNGLXRELEASEVIDEOIMAGENVPROC glad_glXReleaseVideoImageNV = NULL;
|
||||
PFNGLXSENDPBUFFERTOVIDEONVPROC glad_glXSendPbufferToVideoNV = NULL;
|
||||
PFNGLXGETVIDEOINFONVPROC glad_glXGetVideoInfoNV = NULL;
|
||||
PFNGLXGETSYNCVALUESOMLPROC glad_glXGetSyncValuesOML = NULL;
|
||||
PFNGLXGETMSCRATEOMLPROC glad_glXGetMscRateOML = NULL;
|
||||
PFNGLXSWAPBUFFERSMSCOMLPROC glad_glXSwapBuffersMscOML = NULL;
|
||||
PFNGLXWAITFORMSCOMLPROC glad_glXWaitForMscOML = NULL;
|
||||
PFNGLXWAITFORSBCOMLPROC glad_glXWaitForSbcOML = NULL;
|
||||
#ifdef _DM_BUFFER_H_
|
||||
PFNGLXASSOCIATEDMPBUFFERSGIXPROC glad_glXAssociateDMPbufferSGIX = NULL;
|
||||
#endif
|
||||
PFNGLXGETFBCONFIGATTRIBSGIXPROC glad_glXGetFBConfigAttribSGIX = NULL;
|
||||
PFNGLXCHOOSEFBCONFIGSGIXPROC glad_glXChooseFBConfigSGIX = NULL;
|
||||
PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC glad_glXCreateGLXPixmapWithConfigSGIX = NULL;
|
||||
PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC glad_glXCreateContextWithConfigSGIX = NULL;
|
||||
PFNGLXGETVISUALFROMFBCONFIGSGIXPROC glad_glXGetVisualFromFBConfigSGIX = NULL;
|
||||
PFNGLXGETFBCONFIGFROMVISUALSGIXPROC glad_glXGetFBConfigFromVisualSGIX = NULL;
|
||||
PFNGLXQUERYHYPERPIPENETWORKSGIXPROC glad_glXQueryHyperpipeNetworkSGIX = NULL;
|
||||
PFNGLXHYPERPIPECONFIGSGIXPROC glad_glXHyperpipeConfigSGIX = NULL;
|
||||
PFNGLXQUERYHYPERPIPECONFIGSGIXPROC glad_glXQueryHyperpipeConfigSGIX = NULL;
|
||||
PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC glad_glXDestroyHyperpipeConfigSGIX = NULL;
|
||||
PFNGLXBINDHYPERPIPESGIXPROC glad_glXBindHyperpipeSGIX = NULL;
|
||||
PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC glad_glXQueryHyperpipeBestAttribSGIX = NULL;
|
||||
PFNGLXHYPERPIPEATTRIBSGIXPROC glad_glXHyperpipeAttribSGIX = NULL;
|
||||
PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC glad_glXQueryHyperpipeAttribSGIX = NULL;
|
||||
PFNGLXCREATEGLXPBUFFERSGIXPROC glad_glXCreateGLXPbufferSGIX = NULL;
|
||||
PFNGLXDESTROYGLXPBUFFERSGIXPROC glad_glXDestroyGLXPbufferSGIX = NULL;
|
||||
PFNGLXQUERYGLXPBUFFERSGIXPROC glad_glXQueryGLXPbufferSGIX = NULL;
|
||||
PFNGLXSELECTEVENTSGIXPROC glad_glXSelectEventSGIX = NULL;
|
||||
PFNGLXGETSELECTEDEVENTSGIXPROC glad_glXGetSelectedEventSGIX = NULL;
|
||||
PFNGLXBINDSWAPBARRIERSGIXPROC glad_glXBindSwapBarrierSGIX = NULL;
|
||||
PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC glad_glXQueryMaxSwapBarriersSGIX = NULL;
|
||||
PFNGLXJOINSWAPGROUPSGIXPROC glad_glXJoinSwapGroupSGIX = NULL;
|
||||
PFNGLXBINDCHANNELTOWINDOWSGIXPROC glad_glXBindChannelToWindowSGIX = NULL;
|
||||
PFNGLXCHANNELRECTSGIXPROC glad_glXChannelRectSGIX = NULL;
|
||||
PFNGLXQUERYCHANNELRECTSGIXPROC glad_glXQueryChannelRectSGIX = NULL;
|
||||
PFNGLXQUERYCHANNELDELTASSGIXPROC glad_glXQueryChannelDeltasSGIX = NULL;
|
||||
PFNGLXCHANNELRECTSYNCSGIXPROC glad_glXChannelRectSyncSGIX = NULL;
|
||||
#ifdef _VL_H_
|
||||
PFNGLXCREATEGLXVIDEOSOURCESGIXPROC glad_glXCreateGLXVideoSourceSGIX = NULL;
|
||||
PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC glad_glXDestroyGLXVideoSourceSGIX = NULL;
|
||||
#endif
|
||||
PFNGLXCUSHIONSGIPROC glad_glXCushionSGI = NULL;
|
||||
PFNGLXMAKECURRENTREADSGIPROC glad_glXMakeCurrentReadSGI = NULL;
|
||||
PFNGLXGETCURRENTREADDRAWABLESGIPROC glad_glXGetCurrentReadDrawableSGI = NULL;
|
||||
PFNGLXSWAPINTERVALSGIPROC glad_glXSwapIntervalSGI = NULL;
|
||||
PFNGLXGETVIDEOSYNCSGIPROC glad_glXGetVideoSyncSGI = NULL;
|
||||
PFNGLXWAITVIDEOSYNCSGIPROC glad_glXWaitVideoSyncSGI = NULL;
|
||||
PFNGLXGETTRANSPARENTINDEXSUNPROC glad_glXGetTransparentIndexSUN = NULL;
|
||||
static void load_GLX_VERSION_1_0(GLADloadproc load) {
|
||||
if(!GLAD_GLX_VERSION_1_0) return;
|
||||
glad_glXChooseVisual = (PFNGLXCHOOSEVISUALPROC)load("glXChooseVisual");
|
||||
glad_glXCreateContext = (PFNGLXCREATECONTEXTPROC)load("glXCreateContext");
|
||||
glad_glXDestroyContext = (PFNGLXDESTROYCONTEXTPROC)load("glXDestroyContext");
|
||||
glad_glXMakeCurrent = (PFNGLXMAKECURRENTPROC)load("glXMakeCurrent");
|
||||
glad_glXCopyContext = (PFNGLXCOPYCONTEXTPROC)load("glXCopyContext");
|
||||
glad_glXSwapBuffers = (PFNGLXSWAPBUFFERSPROC)load("glXSwapBuffers");
|
||||
glad_glXCreateGLXPixmap = (PFNGLXCREATEGLXPIXMAPPROC)load("glXCreateGLXPixmap");
|
||||
glad_glXDestroyGLXPixmap = (PFNGLXDESTROYGLXPIXMAPPROC)load("glXDestroyGLXPixmap");
|
||||
glad_glXQueryExtension = (PFNGLXQUERYEXTENSIONPROC)load("glXQueryExtension");
|
||||
glad_glXQueryVersion = (PFNGLXQUERYVERSIONPROC)load("glXQueryVersion");
|
||||
glad_glXIsDirect = (PFNGLXISDIRECTPROC)load("glXIsDirect");
|
||||
glad_glXGetConfig = (PFNGLXGETCONFIGPROC)load("glXGetConfig");
|
||||
glad_glXGetCurrentContext = (PFNGLXGETCURRENTCONTEXTPROC)load("glXGetCurrentContext");
|
||||
glad_glXGetCurrentDrawable = (PFNGLXGETCURRENTDRAWABLEPROC)load("glXGetCurrentDrawable");
|
||||
glad_glXWaitGL = (PFNGLXWAITGLPROC)load("glXWaitGL");
|
||||
glad_glXWaitX = (PFNGLXWAITXPROC)load("glXWaitX");
|
||||
glad_glXUseXFont = (PFNGLXUSEXFONTPROC)load("glXUseXFont");
|
||||
}
|
||||
static void load_GLX_VERSION_1_1(GLADloadproc load) {
|
||||
if(!GLAD_GLX_VERSION_1_1) return;
|
||||
glad_glXQueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC)load("glXQueryExtensionsString");
|
||||
glad_glXQueryServerString = (PFNGLXQUERYSERVERSTRINGPROC)load("glXQueryServerString");
|
||||
glad_glXGetClientString = (PFNGLXGETCLIENTSTRINGPROC)load("glXGetClientString");
|
||||
}
|
||||
static void load_GLX_VERSION_1_2(GLADloadproc load) {
|
||||
if(!GLAD_GLX_VERSION_1_2) return;
|
||||
glad_glXGetCurrentDisplay = (PFNGLXGETCURRENTDISPLAYPROC)load("glXGetCurrentDisplay");
|
||||
}
|
||||
static void load_GLX_VERSION_1_3(GLADloadproc load) {
|
||||
if(!GLAD_GLX_VERSION_1_3) return;
|
||||
glad_glXGetFBConfigs = (PFNGLXGETFBCONFIGSPROC)load("glXGetFBConfigs");
|
||||
glad_glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)load("glXChooseFBConfig");
|
||||
glad_glXGetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC)load("glXGetFBConfigAttrib");
|
||||
glad_glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)load("glXGetVisualFromFBConfig");
|
||||
glad_glXCreateWindow = (PFNGLXCREATEWINDOWPROC)load("glXCreateWindow");
|
||||
glad_glXDestroyWindow = (PFNGLXDESTROYWINDOWPROC)load("glXDestroyWindow");
|
||||
glad_glXCreatePixmap = (PFNGLXCREATEPIXMAPPROC)load("glXCreatePixmap");
|
||||
glad_glXDestroyPixmap = (PFNGLXDESTROYPIXMAPPROC)load("glXDestroyPixmap");
|
||||
glad_glXCreatePbuffer = (PFNGLXCREATEPBUFFERPROC)load("glXCreatePbuffer");
|
||||
glad_glXDestroyPbuffer = (PFNGLXDESTROYPBUFFERPROC)load("glXDestroyPbuffer");
|
||||
glad_glXQueryDrawable = (PFNGLXQUERYDRAWABLEPROC)load("glXQueryDrawable");
|
||||
glad_glXCreateNewContext = (PFNGLXCREATENEWCONTEXTPROC)load("glXCreateNewContext");
|
||||
glad_glXMakeContextCurrent = (PFNGLXMAKECONTEXTCURRENTPROC)load("glXMakeContextCurrent");
|
||||
glad_glXGetCurrentReadDrawable = (PFNGLXGETCURRENTREADDRAWABLEPROC)load("glXGetCurrentReadDrawable");
|
||||
glad_glXQueryContext = (PFNGLXQUERYCONTEXTPROC)load("glXQueryContext");
|
||||
glad_glXSelectEvent = (PFNGLXSELECTEVENTPROC)load("glXSelectEvent");
|
||||
glad_glXGetSelectedEvent = (PFNGLXGETSELECTEDEVENTPROC)load("glXGetSelectedEvent");
|
||||
}
|
||||
static void load_GLX_VERSION_1_4(GLADloadproc load) {
|
||||
if(!GLAD_GLX_VERSION_1_4) return;
|
||||
glad_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)load("glXGetProcAddress");
|
||||
}
|
||||
static void load_GLX_AMD_gpu_association(GLADloadproc load) {
|
||||
if(!GLAD_GLX_AMD_gpu_association) return;
|
||||
glad_glXGetGPUIDsAMD = (PFNGLXGETGPUIDSAMDPROC)load("glXGetGPUIDsAMD");
|
||||
glad_glXGetGPUInfoAMD = (PFNGLXGETGPUINFOAMDPROC)load("glXGetGPUInfoAMD");
|
||||
glad_glXGetContextGPUIDAMD = (PFNGLXGETCONTEXTGPUIDAMDPROC)load("glXGetContextGPUIDAMD");
|
||||
glad_glXCreateAssociatedContextAMD = (PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC)load("glXCreateAssociatedContextAMD");
|
||||
glad_glXCreateAssociatedContextAttribsAMD = (PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC)load("glXCreateAssociatedContextAttribsAMD");
|
||||
glad_glXDeleteAssociatedContextAMD = (PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC)load("glXDeleteAssociatedContextAMD");
|
||||
glad_glXMakeAssociatedContextCurrentAMD = (PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC)load("glXMakeAssociatedContextCurrentAMD");
|
||||
glad_glXGetCurrentAssociatedContextAMD = (PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC)load("glXGetCurrentAssociatedContextAMD");
|
||||
glad_glXBlitContextFramebufferAMD = (PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC)load("glXBlitContextFramebufferAMD");
|
||||
}
|
||||
static void load_GLX_ARB_create_context(GLADloadproc load) {
|
||||
if(!GLAD_GLX_ARB_create_context) return;
|
||||
glad_glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)load("glXCreateContextAttribsARB");
|
||||
}
|
||||
static void load_GLX_ARB_get_proc_address(GLADloadproc load) {
|
||||
if(!GLAD_GLX_ARB_get_proc_address) return;
|
||||
glad_glXGetProcAddressARB = (PFNGLXGETPROCADDRESSARBPROC)load("glXGetProcAddressARB");
|
||||
}
|
||||
static void load_GLX_EXT_import_context(GLADloadproc load) {
|
||||
if(!GLAD_GLX_EXT_import_context) return;
|
||||
glad_glXGetCurrentDisplayEXT = (PFNGLXGETCURRENTDISPLAYEXTPROC)load("glXGetCurrentDisplayEXT");
|
||||
glad_glXQueryContextInfoEXT = (PFNGLXQUERYCONTEXTINFOEXTPROC)load("glXQueryContextInfoEXT");
|
||||
glad_glXGetContextIDEXT = (PFNGLXGETCONTEXTIDEXTPROC)load("glXGetContextIDEXT");
|
||||
glad_glXImportContextEXT = (PFNGLXIMPORTCONTEXTEXTPROC)load("glXImportContextEXT");
|
||||
glad_glXFreeContextEXT = (PFNGLXFREECONTEXTEXTPROC)load("glXFreeContextEXT");
|
||||
}
|
||||
static void load_GLX_EXT_swap_control(GLADloadproc load) {
|
||||
if(!GLAD_GLX_EXT_swap_control) return;
|
||||
glad_glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)load("glXSwapIntervalEXT");
|
||||
}
|
||||
static void load_GLX_EXT_texture_from_pixmap(GLADloadproc load) {
|
||||
if(!GLAD_GLX_EXT_texture_from_pixmap) return;
|
||||
glad_glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)load("glXBindTexImageEXT");
|
||||
glad_glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)load("glXReleaseTexImageEXT");
|
||||
}
|
||||
static void load_GLX_MESA_agp_offset(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_agp_offset) return;
|
||||
glad_glXGetAGPOffsetMESA = (PFNGLXGETAGPOFFSETMESAPROC)load("glXGetAGPOffsetMESA");
|
||||
}
|
||||
static void load_GLX_MESA_copy_sub_buffer(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_copy_sub_buffer) return;
|
||||
glad_glXCopySubBufferMESA = (PFNGLXCOPYSUBBUFFERMESAPROC)load("glXCopySubBufferMESA");
|
||||
}
|
||||
static void load_GLX_MESA_pixmap_colormap(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_pixmap_colormap) return;
|
||||
glad_glXCreateGLXPixmapMESA = (PFNGLXCREATEGLXPIXMAPMESAPROC)load("glXCreateGLXPixmapMESA");
|
||||
}
|
||||
static void load_GLX_MESA_query_renderer(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_query_renderer) return;
|
||||
glad_glXQueryCurrentRendererIntegerMESA = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)load("glXQueryCurrentRendererIntegerMESA");
|
||||
glad_glXQueryCurrentRendererStringMESA = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC)load("glXQueryCurrentRendererStringMESA");
|
||||
glad_glXQueryRendererIntegerMESA = (PFNGLXQUERYRENDERERINTEGERMESAPROC)load("glXQueryRendererIntegerMESA");
|
||||
glad_glXQueryRendererStringMESA = (PFNGLXQUERYRENDERERSTRINGMESAPROC)load("glXQueryRendererStringMESA");
|
||||
}
|
||||
static void load_GLX_MESA_release_buffers(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_release_buffers) return;
|
||||
glad_glXReleaseBuffersMESA = (PFNGLXRELEASEBUFFERSMESAPROC)load("glXReleaseBuffersMESA");
|
||||
}
|
||||
static void load_GLX_MESA_set_3dfx_mode(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_set_3dfx_mode) return;
|
||||
glad_glXSet3DfxModeMESA = (PFNGLXSET3DFXMODEMESAPROC)load("glXSet3DfxModeMESA");
|
||||
}
|
||||
static void load_GLX_MESA_swap_control(GLADloadproc load) {
|
||||
if(!GLAD_GLX_MESA_swap_control) return;
|
||||
glad_glXGetSwapIntervalMESA = (PFNGLXGETSWAPINTERVALMESAPROC)load("glXGetSwapIntervalMESA");
|
||||
glad_glXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)load("glXSwapIntervalMESA");
|
||||
}
|
||||
static void load_GLX_NV_copy_buffer(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_copy_buffer) return;
|
||||
glad_glXCopyBufferSubDataNV = (PFNGLXCOPYBUFFERSUBDATANVPROC)load("glXCopyBufferSubDataNV");
|
||||
glad_glXNamedCopyBufferSubDataNV = (PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC)load("glXNamedCopyBufferSubDataNV");
|
||||
}
|
||||
static void load_GLX_NV_copy_image(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_copy_image) return;
|
||||
glad_glXCopyImageSubDataNV = (PFNGLXCOPYIMAGESUBDATANVPROC)load("glXCopyImageSubDataNV");
|
||||
}
|
||||
static void load_GLX_NV_delay_before_swap(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_delay_before_swap) return;
|
||||
glad_glXDelayBeforeSwapNV = (PFNGLXDELAYBEFORESWAPNVPROC)load("glXDelayBeforeSwapNV");
|
||||
}
|
||||
static void load_GLX_NV_present_video(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_present_video) return;
|
||||
glad_glXEnumerateVideoDevicesNV = (PFNGLXENUMERATEVIDEODEVICESNVPROC)load("glXEnumerateVideoDevicesNV");
|
||||
glad_glXBindVideoDeviceNV = (PFNGLXBINDVIDEODEVICENVPROC)load("glXBindVideoDeviceNV");
|
||||
}
|
||||
static void load_GLX_NV_swap_group(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_swap_group) return;
|
||||
glad_glXJoinSwapGroupNV = (PFNGLXJOINSWAPGROUPNVPROC)load("glXJoinSwapGroupNV");
|
||||
glad_glXBindSwapBarrierNV = (PFNGLXBINDSWAPBARRIERNVPROC)load("glXBindSwapBarrierNV");
|
||||
glad_glXQuerySwapGroupNV = (PFNGLXQUERYSWAPGROUPNVPROC)load("glXQuerySwapGroupNV");
|
||||
glad_glXQueryMaxSwapGroupsNV = (PFNGLXQUERYMAXSWAPGROUPSNVPROC)load("glXQueryMaxSwapGroupsNV");
|
||||
glad_glXQueryFrameCountNV = (PFNGLXQUERYFRAMECOUNTNVPROC)load("glXQueryFrameCountNV");
|
||||
glad_glXResetFrameCountNV = (PFNGLXRESETFRAMECOUNTNVPROC)load("glXResetFrameCountNV");
|
||||
}
|
||||
static void load_GLX_NV_video_capture(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_video_capture) return;
|
||||
glad_glXBindVideoCaptureDeviceNV = (PFNGLXBINDVIDEOCAPTUREDEVICENVPROC)load("glXBindVideoCaptureDeviceNV");
|
||||
glad_glXEnumerateVideoCaptureDevicesNV = (PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC)load("glXEnumerateVideoCaptureDevicesNV");
|
||||
glad_glXLockVideoCaptureDeviceNV = (PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC)load("glXLockVideoCaptureDeviceNV");
|
||||
glad_glXQueryVideoCaptureDeviceNV = (PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC)load("glXQueryVideoCaptureDeviceNV");
|
||||
glad_glXReleaseVideoCaptureDeviceNV = (PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC)load("glXReleaseVideoCaptureDeviceNV");
|
||||
}
|
||||
static void load_GLX_NV_video_out(GLADloadproc load) {
|
||||
if(!GLAD_GLX_NV_video_out) return;
|
||||
glad_glXGetVideoDeviceNV = (PFNGLXGETVIDEODEVICENVPROC)load("glXGetVideoDeviceNV");
|
||||
glad_glXReleaseVideoDeviceNV = (PFNGLXRELEASEVIDEODEVICENVPROC)load("glXReleaseVideoDeviceNV");
|
||||
glad_glXBindVideoImageNV = (PFNGLXBINDVIDEOIMAGENVPROC)load("glXBindVideoImageNV");
|
||||
glad_glXReleaseVideoImageNV = (PFNGLXRELEASEVIDEOIMAGENVPROC)load("glXReleaseVideoImageNV");
|
||||
glad_glXSendPbufferToVideoNV = (PFNGLXSENDPBUFFERTOVIDEONVPROC)load("glXSendPbufferToVideoNV");
|
||||
glad_glXGetVideoInfoNV = (PFNGLXGETVIDEOINFONVPROC)load("glXGetVideoInfoNV");
|
||||
}
|
||||
static void load_GLX_OML_sync_control(GLADloadproc load) {
|
||||
if(!GLAD_GLX_OML_sync_control) return;
|
||||
glad_glXGetSyncValuesOML = (PFNGLXGETSYNCVALUESOMLPROC)load("glXGetSyncValuesOML");
|
||||
glad_glXGetMscRateOML = (PFNGLXGETMSCRATEOMLPROC)load("glXGetMscRateOML");
|
||||
glad_glXSwapBuffersMscOML = (PFNGLXSWAPBUFFERSMSCOMLPROC)load("glXSwapBuffersMscOML");
|
||||
glad_glXWaitForMscOML = (PFNGLXWAITFORMSCOMLPROC)load("glXWaitForMscOML");
|
||||
glad_glXWaitForSbcOML = (PFNGLXWAITFORSBCOMLPROC)load("glXWaitForSbcOML");
|
||||
}
|
||||
static void load_GLX_SGIX_dmbuffer(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_dmbuffer) return;
|
||||
#ifdef _DM_BUFFER_H_
|
||||
glad_glXAssociateDMPbufferSGIX = (PFNGLXASSOCIATEDMPBUFFERSGIXPROC)load("glXAssociateDMPbufferSGIX");
|
||||
#else
|
||||
(void)load;
|
||||
#endif
|
||||
}
|
||||
static void load_GLX_SGIX_fbconfig(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_fbconfig) return;
|
||||
glad_glXGetFBConfigAttribSGIX = (PFNGLXGETFBCONFIGATTRIBSGIXPROC)load("glXGetFBConfigAttribSGIX");
|
||||
glad_glXChooseFBConfigSGIX = (PFNGLXCHOOSEFBCONFIGSGIXPROC)load("glXChooseFBConfigSGIX");
|
||||
glad_glXCreateGLXPixmapWithConfigSGIX = (PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC)load("glXCreateGLXPixmapWithConfigSGIX");
|
||||
glad_glXCreateContextWithConfigSGIX = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC)load("glXCreateContextWithConfigSGIX");
|
||||
glad_glXGetVisualFromFBConfigSGIX = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC)load("glXGetVisualFromFBConfigSGIX");
|
||||
glad_glXGetFBConfigFromVisualSGIX = (PFNGLXGETFBCONFIGFROMVISUALSGIXPROC)load("glXGetFBConfigFromVisualSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_hyperpipe(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_hyperpipe) return;
|
||||
glad_glXQueryHyperpipeNetworkSGIX = (PFNGLXQUERYHYPERPIPENETWORKSGIXPROC)load("glXQueryHyperpipeNetworkSGIX");
|
||||
glad_glXHyperpipeConfigSGIX = (PFNGLXHYPERPIPECONFIGSGIXPROC)load("glXHyperpipeConfigSGIX");
|
||||
glad_glXQueryHyperpipeConfigSGIX = (PFNGLXQUERYHYPERPIPECONFIGSGIXPROC)load("glXQueryHyperpipeConfigSGIX");
|
||||
glad_glXDestroyHyperpipeConfigSGIX = (PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC)load("glXDestroyHyperpipeConfigSGIX");
|
||||
glad_glXBindHyperpipeSGIX = (PFNGLXBINDHYPERPIPESGIXPROC)load("glXBindHyperpipeSGIX");
|
||||
glad_glXQueryHyperpipeBestAttribSGIX = (PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC)load("glXQueryHyperpipeBestAttribSGIX");
|
||||
glad_glXHyperpipeAttribSGIX = (PFNGLXHYPERPIPEATTRIBSGIXPROC)load("glXHyperpipeAttribSGIX");
|
||||
glad_glXQueryHyperpipeAttribSGIX = (PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC)load("glXQueryHyperpipeAttribSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_pbuffer(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_pbuffer) return;
|
||||
glad_glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC)load("glXCreateGLXPbufferSGIX");
|
||||
glad_glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC)load("glXDestroyGLXPbufferSGIX");
|
||||
glad_glXQueryGLXPbufferSGIX = (PFNGLXQUERYGLXPBUFFERSGIXPROC)load("glXQueryGLXPbufferSGIX");
|
||||
glad_glXSelectEventSGIX = (PFNGLXSELECTEVENTSGIXPROC)load("glXSelectEventSGIX");
|
||||
glad_glXGetSelectedEventSGIX = (PFNGLXGETSELECTEDEVENTSGIXPROC)load("glXGetSelectedEventSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_swap_barrier(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_swap_barrier) return;
|
||||
glad_glXBindSwapBarrierSGIX = (PFNGLXBINDSWAPBARRIERSGIXPROC)load("glXBindSwapBarrierSGIX");
|
||||
glad_glXQueryMaxSwapBarriersSGIX = (PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC)load("glXQueryMaxSwapBarriersSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_swap_group(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_swap_group) return;
|
||||
glad_glXJoinSwapGroupSGIX = (PFNGLXJOINSWAPGROUPSGIXPROC)load("glXJoinSwapGroupSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_video_resize(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_video_resize) return;
|
||||
glad_glXBindChannelToWindowSGIX = (PFNGLXBINDCHANNELTOWINDOWSGIXPROC)load("glXBindChannelToWindowSGIX");
|
||||
glad_glXChannelRectSGIX = (PFNGLXCHANNELRECTSGIXPROC)load("glXChannelRectSGIX");
|
||||
glad_glXQueryChannelRectSGIX = (PFNGLXQUERYCHANNELRECTSGIXPROC)load("glXQueryChannelRectSGIX");
|
||||
glad_glXQueryChannelDeltasSGIX = (PFNGLXQUERYCHANNELDELTASSGIXPROC)load("glXQueryChannelDeltasSGIX");
|
||||
glad_glXChannelRectSyncSGIX = (PFNGLXCHANNELRECTSYNCSGIXPROC)load("glXChannelRectSyncSGIX");
|
||||
}
|
||||
static void load_GLX_SGIX_video_source(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGIX_video_source) return;
|
||||
#ifdef _VL_H_
|
||||
glad_glXCreateGLXVideoSourceSGIX = (PFNGLXCREATEGLXVIDEOSOURCESGIXPROC)load("glXCreateGLXVideoSourceSGIX");
|
||||
glad_glXDestroyGLXVideoSourceSGIX = (PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC)load("glXDestroyGLXVideoSourceSGIX");
|
||||
#else
|
||||
(void)load;
|
||||
#endif
|
||||
}
|
||||
static void load_GLX_SGI_cushion(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGI_cushion) return;
|
||||
glad_glXCushionSGI = (PFNGLXCUSHIONSGIPROC)load("glXCushionSGI");
|
||||
}
|
||||
static void load_GLX_SGI_make_current_read(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGI_make_current_read) return;
|
||||
glad_glXMakeCurrentReadSGI = (PFNGLXMAKECURRENTREADSGIPROC)load("glXMakeCurrentReadSGI");
|
||||
glad_glXGetCurrentReadDrawableSGI = (PFNGLXGETCURRENTREADDRAWABLESGIPROC)load("glXGetCurrentReadDrawableSGI");
|
||||
}
|
||||
static void load_GLX_SGI_swap_control(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGI_swap_control) return;
|
||||
glad_glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)load("glXSwapIntervalSGI");
|
||||
}
|
||||
static void load_GLX_SGI_video_sync(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SGI_video_sync) return;
|
||||
glad_glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC)load("glXGetVideoSyncSGI");
|
||||
glad_glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)load("glXWaitVideoSyncSGI");
|
||||
}
|
||||
static void load_GLX_SUN_get_transparent_index(GLADloadproc load) {
|
||||
if(!GLAD_GLX_SUN_get_transparent_index) return;
|
||||
glad_glXGetTransparentIndexSUN = (PFNGLXGETTRANSPARENTINDEXSUNPROC)load("glXGetTransparentIndexSUN");
|
||||
}
|
||||
static int find_extensionsGLX(void) {
|
||||
if (!get_exts()) return 0;
|
||||
GLAD_GLX_3DFX_multisample = has_ext("GLX_3DFX_multisample");
|
||||
GLAD_GLX_AMD_gpu_association = has_ext("GLX_AMD_gpu_association");
|
||||
GLAD_GLX_ARB_context_flush_control = has_ext("GLX_ARB_context_flush_control");
|
||||
GLAD_GLX_ARB_create_context = has_ext("GLX_ARB_create_context");
|
||||
GLAD_GLX_ARB_create_context_no_error = has_ext("GLX_ARB_create_context_no_error");
|
||||
GLAD_GLX_ARB_create_context_profile = has_ext("GLX_ARB_create_context_profile");
|
||||
GLAD_GLX_ARB_create_context_robustness = has_ext("GLX_ARB_create_context_robustness");
|
||||
GLAD_GLX_ARB_fbconfig_float = has_ext("GLX_ARB_fbconfig_float");
|
||||
GLAD_GLX_ARB_framebuffer_sRGB = has_ext("GLX_ARB_framebuffer_sRGB");
|
||||
GLAD_GLX_ARB_get_proc_address = has_ext("GLX_ARB_get_proc_address");
|
||||
GLAD_GLX_ARB_multisample = has_ext("GLX_ARB_multisample");
|
||||
GLAD_GLX_ARB_robustness_application_isolation = has_ext("GLX_ARB_robustness_application_isolation");
|
||||
GLAD_GLX_ARB_robustness_share_group_isolation = has_ext("GLX_ARB_robustness_share_group_isolation");
|
||||
GLAD_GLX_ARB_vertex_buffer_object = has_ext("GLX_ARB_vertex_buffer_object");
|
||||
GLAD_GLX_EXT_buffer_age = has_ext("GLX_EXT_buffer_age");
|
||||
GLAD_GLX_EXT_context_priority = has_ext("GLX_EXT_context_priority");
|
||||
GLAD_GLX_EXT_create_context_es2_profile = has_ext("GLX_EXT_create_context_es2_profile");
|
||||
GLAD_GLX_EXT_create_context_es_profile = has_ext("GLX_EXT_create_context_es_profile");
|
||||
GLAD_GLX_EXT_fbconfig_packed_float = has_ext("GLX_EXT_fbconfig_packed_float");
|
||||
GLAD_GLX_EXT_framebuffer_sRGB = has_ext("GLX_EXT_framebuffer_sRGB");
|
||||
GLAD_GLX_EXT_get_drawable_type = has_ext("GLX_EXT_get_drawable_type");
|
||||
GLAD_GLX_EXT_import_context = has_ext("GLX_EXT_import_context");
|
||||
GLAD_GLX_EXT_libglvnd = has_ext("GLX_EXT_libglvnd");
|
||||
GLAD_GLX_EXT_no_config_context = has_ext("GLX_EXT_no_config_context");
|
||||
GLAD_GLX_EXT_stereo_tree = has_ext("GLX_EXT_stereo_tree");
|
||||
GLAD_GLX_EXT_swap_control = has_ext("GLX_EXT_swap_control");
|
||||
GLAD_GLX_EXT_swap_control_tear = has_ext("GLX_EXT_swap_control_tear");
|
||||
GLAD_GLX_EXT_texture_from_pixmap = has_ext("GLX_EXT_texture_from_pixmap");
|
||||
GLAD_GLX_EXT_visual_info = has_ext("GLX_EXT_visual_info");
|
||||
GLAD_GLX_EXT_visual_rating = has_ext("GLX_EXT_visual_rating");
|
||||
GLAD_GLX_INTEL_swap_event = has_ext("GLX_INTEL_swap_event");
|
||||
GLAD_GLX_MESA_agp_offset = has_ext("GLX_MESA_agp_offset");
|
||||
GLAD_GLX_MESA_copy_sub_buffer = has_ext("GLX_MESA_copy_sub_buffer");
|
||||
GLAD_GLX_MESA_pixmap_colormap = has_ext("GLX_MESA_pixmap_colormap");
|
||||
GLAD_GLX_MESA_query_renderer = has_ext("GLX_MESA_query_renderer");
|
||||
GLAD_GLX_MESA_release_buffers = has_ext("GLX_MESA_release_buffers");
|
||||
GLAD_GLX_MESA_set_3dfx_mode = has_ext("GLX_MESA_set_3dfx_mode");
|
||||
GLAD_GLX_MESA_swap_control = has_ext("GLX_MESA_swap_control");
|
||||
GLAD_GLX_NV_copy_buffer = has_ext("GLX_NV_copy_buffer");
|
||||
GLAD_GLX_NV_copy_image = has_ext("GLX_NV_copy_image");
|
||||
GLAD_GLX_NV_delay_before_swap = has_ext("GLX_NV_delay_before_swap");
|
||||
GLAD_GLX_NV_float_buffer = has_ext("GLX_NV_float_buffer");
|
||||
GLAD_GLX_NV_multigpu_context = has_ext("GLX_NV_multigpu_context");
|
||||
GLAD_GLX_NV_multisample_coverage = has_ext("GLX_NV_multisample_coverage");
|
||||
GLAD_GLX_NV_present_video = has_ext("GLX_NV_present_video");
|
||||
GLAD_GLX_NV_robustness_video_memory_purge = has_ext("GLX_NV_robustness_video_memory_purge");
|
||||
GLAD_GLX_NV_swap_group = has_ext("GLX_NV_swap_group");
|
||||
GLAD_GLX_NV_video_capture = has_ext("GLX_NV_video_capture");
|
||||
GLAD_GLX_NV_video_out = has_ext("GLX_NV_video_out");
|
||||
GLAD_GLX_OML_swap_method = has_ext("GLX_OML_swap_method");
|
||||
GLAD_GLX_OML_sync_control = has_ext("GLX_OML_sync_control");
|
||||
GLAD_GLX_SGIS_blended_overlay = has_ext("GLX_SGIS_blended_overlay");
|
||||
GLAD_GLX_SGIS_multisample = has_ext("GLX_SGIS_multisample");
|
||||
GLAD_GLX_SGIS_shared_multisample = has_ext("GLX_SGIS_shared_multisample");
|
||||
GLAD_GLX_SGIX_dmbuffer = has_ext("GLX_SGIX_dmbuffer");
|
||||
GLAD_GLX_SGIX_fbconfig = has_ext("GLX_SGIX_fbconfig");
|
||||
GLAD_GLX_SGIX_hyperpipe = has_ext("GLX_SGIX_hyperpipe");
|
||||
GLAD_GLX_SGIX_pbuffer = has_ext("GLX_SGIX_pbuffer");
|
||||
GLAD_GLX_SGIX_swap_barrier = has_ext("GLX_SGIX_swap_barrier");
|
||||
GLAD_GLX_SGIX_swap_group = has_ext("GLX_SGIX_swap_group");
|
||||
GLAD_GLX_SGIX_video_resize = has_ext("GLX_SGIX_video_resize");
|
||||
GLAD_GLX_SGIX_video_source = has_ext("GLX_SGIX_video_source");
|
||||
GLAD_GLX_SGIX_visual_select_group = has_ext("GLX_SGIX_visual_select_group");
|
||||
GLAD_GLX_SGI_cushion = has_ext("GLX_SGI_cushion");
|
||||
GLAD_GLX_SGI_make_current_read = has_ext("GLX_SGI_make_current_read");
|
||||
GLAD_GLX_SGI_swap_control = has_ext("GLX_SGI_swap_control");
|
||||
GLAD_GLX_SGI_video_sync = has_ext("GLX_SGI_video_sync");
|
||||
GLAD_GLX_SUN_get_transparent_index = has_ext("GLX_SUN_get_transparent_index");
|
||||
free_exts();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void find_coreGLX(Display *dpy, int screen) {
|
||||
int major = 0, minor = 0;
|
||||
if(dpy == 0 && GLADGLXDisplay == 0) {
|
||||
dpy = XOpenDisplay(0);
|
||||
screen = XScreenNumberOfScreen(XDefaultScreenOfDisplay(dpy));
|
||||
} else if(dpy == 0) {
|
||||
dpy = GLADGLXDisplay;
|
||||
screen = GLADGLXscreen;
|
||||
}
|
||||
glXQueryVersion(dpy, &major, &minor);
|
||||
GLADGLXDisplay = dpy;
|
||||
GLADGLXscreen = screen;
|
||||
GLAD_GLX_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
|
||||
GLAD_GLX_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
|
||||
GLAD_GLX_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
|
||||
GLAD_GLX_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
|
||||
GLAD_GLX_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
|
||||
}
|
||||
|
||||
int gladLoadGLXLoader(GLADloadproc load, Display *dpy, int screen) {
|
||||
glXQueryVersion = (PFNGLXQUERYVERSIONPROC)load("glXQueryVersion");
|
||||
if(glXQueryVersion == NULL) return 0;
|
||||
find_coreGLX(dpy, screen);
|
||||
load_GLX_VERSION_1_0(load);
|
||||
load_GLX_VERSION_1_1(load);
|
||||
load_GLX_VERSION_1_2(load);
|
||||
load_GLX_VERSION_1_3(load);
|
||||
load_GLX_VERSION_1_4(load);
|
||||
|
||||
if (!find_extensionsGLX()) return 0;
|
||||
load_GLX_AMD_gpu_association(load);
|
||||
load_GLX_ARB_create_context(load);
|
||||
load_GLX_ARB_get_proc_address(load);
|
||||
load_GLX_EXT_import_context(load);
|
||||
load_GLX_EXT_swap_control(load);
|
||||
load_GLX_EXT_texture_from_pixmap(load);
|
||||
load_GLX_MESA_agp_offset(load);
|
||||
load_GLX_MESA_copy_sub_buffer(load);
|
||||
load_GLX_MESA_pixmap_colormap(load);
|
||||
load_GLX_MESA_query_renderer(load);
|
||||
load_GLX_MESA_release_buffers(load);
|
||||
load_GLX_MESA_set_3dfx_mode(load);
|
||||
load_GLX_MESA_swap_control(load);
|
||||
load_GLX_NV_copy_buffer(load);
|
||||
load_GLX_NV_copy_image(load);
|
||||
load_GLX_NV_delay_before_swap(load);
|
||||
load_GLX_NV_present_video(load);
|
||||
load_GLX_NV_swap_group(load);
|
||||
load_GLX_NV_video_capture(load);
|
||||
load_GLX_NV_video_out(load);
|
||||
load_GLX_OML_sync_control(load);
|
||||
load_GLX_SGIX_dmbuffer(load);
|
||||
load_GLX_SGIX_fbconfig(load);
|
||||
load_GLX_SGIX_hyperpipe(load);
|
||||
load_GLX_SGIX_pbuffer(load);
|
||||
load_GLX_SGIX_swap_barrier(load);
|
||||
load_GLX_SGIX_swap_group(load);
|
||||
load_GLX_SGIX_video_resize(load);
|
||||
load_GLX_SGIX_video_source(load);
|
||||
load_GLX_SGI_cushion(load);
|
||||
load_GLX_SGI_make_current_read(load);
|
||||
load_GLX_SGI_swap_control(load);
|
||||
load_GLX_SGI_video_sync(load);
|
||||
load_GLX_SUN_get_transparent_index(load);
|
||||
return 1;
|
||||
}
|
||||
|
1268
src/frontend/glad/glad_glx.h
Normal file
1268
src/frontend/glad/glad_glx.h
Normal file
File diff suppressed because it is too large
Load Diff
756
src/frontend/glad/glad_wgl.c
Normal file
756
src/frontend/glad/glad_wgl.c
Normal file
@ -0,0 +1,756 @@
|
||||
/*
|
||||
|
||||
WGL loader generated by glad 0.1.36 on Thu Sep 15 11:18:46 2022.
|
||||
|
||||
Language/Generator: C/C++
|
||||
Specification: wgl
|
||||
APIs: wgl=1.0
|
||||
Profile: -
|
||||
Extensions:
|
||||
WGL_3DFX_multisample,
|
||||
WGL_3DL_stereo_control,
|
||||
WGL_AMD_gpu_association,
|
||||
WGL_ARB_buffer_region,
|
||||
WGL_ARB_context_flush_control,
|
||||
WGL_ARB_create_context,
|
||||
WGL_ARB_create_context_no_error,
|
||||
WGL_ARB_create_context_profile,
|
||||
WGL_ARB_create_context_robustness,
|
||||
WGL_ARB_extensions_string,
|
||||
WGL_ARB_framebuffer_sRGB,
|
||||
WGL_ARB_make_current_read,
|
||||
WGL_ARB_multisample,
|
||||
WGL_ARB_pbuffer,
|
||||
WGL_ARB_pixel_format,
|
||||
WGL_ARB_pixel_format_float,
|
||||
WGL_ARB_render_texture,
|
||||
WGL_ARB_robustness_application_isolation,
|
||||
WGL_ARB_robustness_share_group_isolation,
|
||||
WGL_ATI_pixel_format_float,
|
||||
WGL_ATI_render_texture_rectangle,
|
||||
WGL_EXT_colorspace,
|
||||
WGL_EXT_create_context_es2_profile,
|
||||
WGL_EXT_create_context_es_profile,
|
||||
WGL_EXT_depth_float,
|
||||
WGL_EXT_display_color_table,
|
||||
WGL_EXT_extensions_string,
|
||||
WGL_EXT_framebuffer_sRGB,
|
||||
WGL_EXT_make_current_read,
|
||||
WGL_EXT_multisample,
|
||||
WGL_EXT_pbuffer,
|
||||
WGL_EXT_pixel_format,
|
||||
WGL_EXT_pixel_format_packed_float,
|
||||
WGL_EXT_swap_control,
|
||||
WGL_EXT_swap_control_tear,
|
||||
WGL_I3D_digital_video_control,
|
||||
WGL_I3D_gamma,
|
||||
WGL_I3D_genlock,
|
||||
WGL_I3D_image_buffer,
|
||||
WGL_I3D_swap_frame_lock,
|
||||
WGL_I3D_swap_frame_usage,
|
||||
WGL_NV_DX_interop,
|
||||
WGL_NV_DX_interop2,
|
||||
WGL_NV_copy_image,
|
||||
WGL_NV_delay_before_swap,
|
||||
WGL_NV_float_buffer,
|
||||
WGL_NV_gpu_affinity,
|
||||
WGL_NV_multigpu_context,
|
||||
WGL_NV_multisample_coverage,
|
||||
WGL_NV_present_video,
|
||||
WGL_NV_render_depth_texture,
|
||||
WGL_NV_render_texture_rectangle,
|
||||
WGL_NV_swap_group,
|
||||
WGL_NV_vertex_array_range,
|
||||
WGL_NV_video_capture,
|
||||
WGL_NV_video_output,
|
||||
WGL_OML_sync_control
|
||||
Loader: True
|
||||
Local files: True
|
||||
Omit khrplatform: False
|
||||
Reproducible: False
|
||||
|
||||
Commandline:
|
||||
--api="wgl=1.0" --generator="c" --spec="wgl" --local-files --extensions="WGL_3DFX_multisample,WGL_3DL_stereo_control,WGL_AMD_gpu_association,WGL_ARB_buffer_region,WGL_ARB_context_flush_control,WGL_ARB_create_context,WGL_ARB_create_context_no_error,WGL_ARB_create_context_profile,WGL_ARB_create_context_robustness,WGL_ARB_extensions_string,WGL_ARB_framebuffer_sRGB,WGL_ARB_make_current_read,WGL_ARB_multisample,WGL_ARB_pbuffer,WGL_ARB_pixel_format,WGL_ARB_pixel_format_float,WGL_ARB_render_texture,WGL_ARB_robustness_application_isolation,WGL_ARB_robustness_share_group_isolation,WGL_ATI_pixel_format_float,WGL_ATI_render_texture_rectangle,WGL_EXT_colorspace,WGL_EXT_create_context_es2_profile,WGL_EXT_create_context_es_profile,WGL_EXT_depth_float,WGL_EXT_display_color_table,WGL_EXT_extensions_string,WGL_EXT_framebuffer_sRGB,WGL_EXT_make_current_read,WGL_EXT_multisample,WGL_EXT_pbuffer,WGL_EXT_pixel_format,WGL_EXT_pixel_format_packed_float,WGL_EXT_swap_control,WGL_EXT_swap_control_tear,WGL_I3D_digital_video_control,WGL_I3D_gamma,WGL_I3D_genlock,WGL_I3D_image_buffer,WGL_I3D_swap_frame_lock,WGL_I3D_swap_frame_usage,WGL_NV_DX_interop,WGL_NV_DX_interop2,WGL_NV_copy_image,WGL_NV_delay_before_swap,WGL_NV_float_buffer,WGL_NV_gpu_affinity,WGL_NV_multigpu_context,WGL_NV_multisample_coverage,WGL_NV_present_video,WGL_NV_render_depth_texture,WGL_NV_render_texture_rectangle,WGL_NV_swap_group,WGL_NV_vertex_array_range,WGL_NV_video_capture,WGL_NV_video_output,WGL_OML_sync_control"
|
||||
Online:
|
||||
Too many extensions
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glad_wgl.h"
|
||||
|
||||
static void* get_proc(const char *namez);
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifndef _WINDOWS_
|
||||
#undef APIENTRY
|
||||
#endif
|
||||
#include <windows.h>
|
||||
static HMODULE libGL;
|
||||
|
||||
typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*);
|
||||
static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef __has_include
|
||||
#if __has_include(<winapifamily.h>)
|
||||
#define HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
|
||||
#define HAVE_WINAPIFAMILY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINAPIFAMILY
|
||||
#include <winapifamily.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#define IS_UWP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static
|
||||
int open_wgl(void) {
|
||||
#ifndef IS_UWP
|
||||
libGL = LoadLibraryW(L"opengl32.dll");
|
||||
if(libGL != NULL) {
|
||||
void (* tmp)(void);
|
||||
tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress");
|
||||
gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp;
|
||||
return gladGetProcAddressPtr != NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void close_wgl(void) {
|
||||
if(libGL != NULL) {
|
||||
FreeLibrary((HMODULE) libGL);
|
||||
libGL = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
static void* libGL;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__HAIKU__)
|
||||
typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*);
|
||||
static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr;
|
||||
#endif
|
||||
|
||||
static
|
||||
int open_wgl(void) {
|
||||
#ifdef __APPLE__
|
||||
static const char *NAMES[] = {
|
||||
"../Frameworks/OpenGL.framework/OpenGL",
|
||||
"/Library/Frameworks/OpenGL.framework/OpenGL",
|
||||
"/System/Library/Frameworks/OpenGL.framework/OpenGL",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
|
||||
};
|
||||
#else
|
||||
static const char *NAMES[] = {"libGL.so.1", "libGL.so"};
|
||||
#endif
|
||||
|
||||
unsigned int index = 0;
|
||||
for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) {
|
||||
libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL);
|
||||
|
||||
if(libGL != NULL) {
|
||||
#if defined(__APPLE__) || defined(__HAIKU__)
|
||||
return 1;
|
||||
#else
|
||||
gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL,
|
||||
"glXGetProcAddressARB");
|
||||
return gladGetProcAddressPtr != NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void close_wgl(void) {
|
||||
if(libGL != NULL) {
|
||||
dlclose(libGL);
|
||||
libGL = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
void* get_proc(const char *namez) {
|
||||
void* result = NULL;
|
||||
if(libGL == NULL) return NULL;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__HAIKU__)
|
||||
if(gladGetProcAddressPtr != NULL) {
|
||||
result = gladGetProcAddressPtr(namez);
|
||||
}
|
||||
#endif
|
||||
if(result == NULL) {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
result = (void*)GetProcAddress((HMODULE) libGL, namez);
|
||||
#else
|
||||
result = dlsym(libGL, namez);
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int gladLoadWGL(HDC hdc) {
|
||||
int status = 0;
|
||||
|
||||
if(open_wgl()) {
|
||||
status = gladLoadWGLLoader((GLADloadproc)get_proc, hdc);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void gladUnloadGLX(void) {
|
||||
close_wgl();
|
||||
}
|
||||
|
||||
static HDC GLADWGLhdc = (HDC)INVALID_HANDLE_VALUE;
|
||||
|
||||
static int get_exts(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void free_exts(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int has_ext(const char *ext) {
|
||||
const char *terminator;
|
||||
const char *loc;
|
||||
const char *extensions;
|
||||
|
||||
if(wglGetExtensionsStringEXT == NULL && wglGetExtensionsStringARB == NULL)
|
||||
return 0;
|
||||
|
||||
if(wglGetExtensionsStringARB == NULL || GLADWGLhdc == INVALID_HANDLE_VALUE)
|
||||
extensions = wglGetExtensionsStringEXT();
|
||||
else
|
||||
extensions = wglGetExtensionsStringARB(GLADWGLhdc);
|
||||
|
||||
if(extensions == NULL || ext == NULL)
|
||||
return 0;
|
||||
|
||||
while(1) {
|
||||
loc = strstr(extensions, ext);
|
||||
if(loc == NULL)
|
||||
break;
|
||||
|
||||
terminator = loc + strlen(ext);
|
||||
if((loc == extensions || *(loc - 1) == ' ') &&
|
||||
(*terminator == ' ' || *terminator == '\0'))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
extensions = terminator;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int GLAD_WGL_VERSION_1_0 = 0;
|
||||
int GLAD_WGL_3DFX_multisample = 0;
|
||||
int GLAD_WGL_3DL_stereo_control = 0;
|
||||
int GLAD_WGL_AMD_gpu_association = 0;
|
||||
int GLAD_WGL_ARB_buffer_region = 0;
|
||||
int GLAD_WGL_ARB_context_flush_control = 0;
|
||||
int GLAD_WGL_ARB_create_context = 0;
|
||||
int GLAD_WGL_ARB_create_context_no_error = 0;
|
||||
int GLAD_WGL_ARB_create_context_profile = 0;
|
||||
int GLAD_WGL_ARB_create_context_robustness = 0;
|
||||
int GLAD_WGL_ARB_extensions_string = 0;
|
||||
int GLAD_WGL_ARB_framebuffer_sRGB = 0;
|
||||
int GLAD_WGL_ARB_make_current_read = 0;
|
||||
int GLAD_WGL_ARB_multisample = 0;
|
||||
int GLAD_WGL_ARB_pbuffer = 0;
|
||||
int GLAD_WGL_ARB_pixel_format = 0;
|
||||
int GLAD_WGL_ARB_pixel_format_float = 0;
|
||||
int GLAD_WGL_ARB_render_texture = 0;
|
||||
int GLAD_WGL_ARB_robustness_application_isolation = 0;
|
||||
int GLAD_WGL_ARB_robustness_share_group_isolation = 0;
|
||||
int GLAD_WGL_ATI_pixel_format_float = 0;
|
||||
int GLAD_WGL_ATI_render_texture_rectangle = 0;
|
||||
int GLAD_WGL_EXT_colorspace = 0;
|
||||
int GLAD_WGL_EXT_create_context_es2_profile = 0;
|
||||
int GLAD_WGL_EXT_create_context_es_profile = 0;
|
||||
int GLAD_WGL_EXT_depth_float = 0;
|
||||
int GLAD_WGL_EXT_display_color_table = 0;
|
||||
int GLAD_WGL_EXT_extensions_string = 0;
|
||||
int GLAD_WGL_EXT_framebuffer_sRGB = 0;
|
||||
int GLAD_WGL_EXT_make_current_read = 0;
|
||||
int GLAD_WGL_EXT_multisample = 0;
|
||||
int GLAD_WGL_EXT_pbuffer = 0;
|
||||
int GLAD_WGL_EXT_pixel_format = 0;
|
||||
int GLAD_WGL_EXT_pixel_format_packed_float = 0;
|
||||
int GLAD_WGL_EXT_swap_control = 0;
|
||||
int GLAD_WGL_EXT_swap_control_tear = 0;
|
||||
int GLAD_WGL_I3D_digital_video_control = 0;
|
||||
int GLAD_WGL_I3D_gamma = 0;
|
||||
int GLAD_WGL_I3D_genlock = 0;
|
||||
int GLAD_WGL_I3D_image_buffer = 0;
|
||||
int GLAD_WGL_I3D_swap_frame_lock = 0;
|
||||
int GLAD_WGL_I3D_swap_frame_usage = 0;
|
||||
int GLAD_WGL_NV_DX_interop = 0;
|
||||
int GLAD_WGL_NV_DX_interop2 = 0;
|
||||
int GLAD_WGL_NV_copy_image = 0;
|
||||
int GLAD_WGL_NV_delay_before_swap = 0;
|
||||
int GLAD_WGL_NV_float_buffer = 0;
|
||||
int GLAD_WGL_NV_gpu_affinity = 0;
|
||||
int GLAD_WGL_NV_multigpu_context = 0;
|
||||
int GLAD_WGL_NV_multisample_coverage = 0;
|
||||
int GLAD_WGL_NV_present_video = 0;
|
||||
int GLAD_WGL_NV_render_depth_texture = 0;
|
||||
int GLAD_WGL_NV_render_texture_rectangle = 0;
|
||||
int GLAD_WGL_NV_swap_group = 0;
|
||||
int GLAD_WGL_NV_vertex_array_range = 0;
|
||||
int GLAD_WGL_NV_video_capture = 0;
|
||||
int GLAD_WGL_NV_video_output = 0;
|
||||
int GLAD_WGL_OML_sync_control = 0;
|
||||
PFNWGLSETSTEREOEMITTERSTATE3DLPROC glad_wglSetStereoEmitterState3DL = NULL;
|
||||
PFNWGLGETGPUIDSAMDPROC glad_wglGetGPUIDsAMD = NULL;
|
||||
PFNWGLGETGPUINFOAMDPROC glad_wglGetGPUInfoAMD = NULL;
|
||||
PFNWGLGETCONTEXTGPUIDAMDPROC glad_wglGetContextGPUIDAMD = NULL;
|
||||
PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC glad_wglCreateAssociatedContextAMD = NULL;
|
||||
PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC glad_wglCreateAssociatedContextAttribsAMD = NULL;
|
||||
PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC glad_wglDeleteAssociatedContextAMD = NULL;
|
||||
PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC glad_wglMakeAssociatedContextCurrentAMD = NULL;
|
||||
PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC glad_wglGetCurrentAssociatedContextAMD = NULL;
|
||||
PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC glad_wglBlitContextFramebufferAMD = NULL;
|
||||
PFNWGLCREATEBUFFERREGIONARBPROC glad_wglCreateBufferRegionARB = NULL;
|
||||
PFNWGLDELETEBUFFERREGIONARBPROC glad_wglDeleteBufferRegionARB = NULL;
|
||||
PFNWGLSAVEBUFFERREGIONARBPROC glad_wglSaveBufferRegionARB = NULL;
|
||||
PFNWGLRESTOREBUFFERREGIONARBPROC glad_wglRestoreBufferRegionARB = NULL;
|
||||
PFNWGLCREATECONTEXTATTRIBSARBPROC glad_wglCreateContextAttribsARB = NULL;
|
||||
PFNWGLGETEXTENSIONSSTRINGARBPROC glad_wglGetExtensionsStringARB = NULL;
|
||||
PFNWGLMAKECONTEXTCURRENTARBPROC glad_wglMakeContextCurrentARB = NULL;
|
||||
PFNWGLGETCURRENTREADDCARBPROC glad_wglGetCurrentReadDCARB = NULL;
|
||||
PFNWGLCREATEPBUFFERARBPROC glad_wglCreatePbufferARB = NULL;
|
||||
PFNWGLGETPBUFFERDCARBPROC glad_wglGetPbufferDCARB = NULL;
|
||||
PFNWGLRELEASEPBUFFERDCARBPROC glad_wglReleasePbufferDCARB = NULL;
|
||||
PFNWGLDESTROYPBUFFERARBPROC glad_wglDestroyPbufferARB = NULL;
|
||||
PFNWGLQUERYPBUFFERARBPROC glad_wglQueryPbufferARB = NULL;
|
||||
PFNWGLGETPIXELFORMATATTRIBIVARBPROC glad_wglGetPixelFormatAttribivARB = NULL;
|
||||
PFNWGLGETPIXELFORMATATTRIBFVARBPROC glad_wglGetPixelFormatAttribfvARB = NULL;
|
||||
PFNWGLCHOOSEPIXELFORMATARBPROC glad_wglChoosePixelFormatARB = NULL;
|
||||
PFNWGLBINDTEXIMAGEARBPROC glad_wglBindTexImageARB = NULL;
|
||||
PFNWGLRELEASETEXIMAGEARBPROC glad_wglReleaseTexImageARB = NULL;
|
||||
PFNWGLSETPBUFFERATTRIBARBPROC glad_wglSetPbufferAttribARB = NULL;
|
||||
PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC glad_wglCreateDisplayColorTableEXT = NULL;
|
||||
PFNWGLLOADDISPLAYCOLORTABLEEXTPROC glad_wglLoadDisplayColorTableEXT = NULL;
|
||||
PFNWGLBINDDISPLAYCOLORTABLEEXTPROC glad_wglBindDisplayColorTableEXT = NULL;
|
||||
PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC glad_wglDestroyDisplayColorTableEXT = NULL;
|
||||
PFNWGLGETEXTENSIONSSTRINGEXTPROC glad_wglGetExtensionsStringEXT = NULL;
|
||||
PFNWGLMAKECONTEXTCURRENTEXTPROC glad_wglMakeContextCurrentEXT = NULL;
|
||||
PFNWGLGETCURRENTREADDCEXTPROC glad_wglGetCurrentReadDCEXT = NULL;
|
||||
PFNWGLCREATEPBUFFEREXTPROC glad_wglCreatePbufferEXT = NULL;
|
||||
PFNWGLGETPBUFFERDCEXTPROC glad_wglGetPbufferDCEXT = NULL;
|
||||
PFNWGLRELEASEPBUFFERDCEXTPROC glad_wglReleasePbufferDCEXT = NULL;
|
||||
PFNWGLDESTROYPBUFFEREXTPROC glad_wglDestroyPbufferEXT = NULL;
|
||||
PFNWGLQUERYPBUFFEREXTPROC glad_wglQueryPbufferEXT = NULL;
|
||||
PFNWGLGETPIXELFORMATATTRIBIVEXTPROC glad_wglGetPixelFormatAttribivEXT = NULL;
|
||||
PFNWGLGETPIXELFORMATATTRIBFVEXTPROC glad_wglGetPixelFormatAttribfvEXT = NULL;
|
||||
PFNWGLCHOOSEPIXELFORMATEXTPROC glad_wglChoosePixelFormatEXT = NULL;
|
||||
PFNWGLSWAPINTERVALEXTPROC glad_wglSwapIntervalEXT = NULL;
|
||||
PFNWGLGETSWAPINTERVALEXTPROC glad_wglGetSwapIntervalEXT = NULL;
|
||||
PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC glad_wglGetDigitalVideoParametersI3D = NULL;
|
||||
PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC glad_wglSetDigitalVideoParametersI3D = NULL;
|
||||
PFNWGLGETGAMMATABLEPARAMETERSI3DPROC glad_wglGetGammaTableParametersI3D = NULL;
|
||||
PFNWGLSETGAMMATABLEPARAMETERSI3DPROC glad_wglSetGammaTableParametersI3D = NULL;
|
||||
PFNWGLGETGAMMATABLEI3DPROC glad_wglGetGammaTableI3D = NULL;
|
||||
PFNWGLSETGAMMATABLEI3DPROC glad_wglSetGammaTableI3D = NULL;
|
||||
PFNWGLENABLEGENLOCKI3DPROC glad_wglEnableGenlockI3D = NULL;
|
||||
PFNWGLDISABLEGENLOCKI3DPROC glad_wglDisableGenlockI3D = NULL;
|
||||
PFNWGLISENABLEDGENLOCKI3DPROC glad_wglIsEnabledGenlockI3D = NULL;
|
||||
PFNWGLGENLOCKSOURCEI3DPROC glad_wglGenlockSourceI3D = NULL;
|
||||
PFNWGLGETGENLOCKSOURCEI3DPROC glad_wglGetGenlockSourceI3D = NULL;
|
||||
PFNWGLGENLOCKSOURCEEDGEI3DPROC glad_wglGenlockSourceEdgeI3D = NULL;
|
||||
PFNWGLGETGENLOCKSOURCEEDGEI3DPROC glad_wglGetGenlockSourceEdgeI3D = NULL;
|
||||
PFNWGLGENLOCKSAMPLERATEI3DPROC glad_wglGenlockSampleRateI3D = NULL;
|
||||
PFNWGLGETGENLOCKSAMPLERATEI3DPROC glad_wglGetGenlockSampleRateI3D = NULL;
|
||||
PFNWGLGENLOCKSOURCEDELAYI3DPROC glad_wglGenlockSourceDelayI3D = NULL;
|
||||
PFNWGLGETGENLOCKSOURCEDELAYI3DPROC glad_wglGetGenlockSourceDelayI3D = NULL;
|
||||
PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC glad_wglQueryGenlockMaxSourceDelayI3D = NULL;
|
||||
PFNWGLCREATEIMAGEBUFFERI3DPROC glad_wglCreateImageBufferI3D = NULL;
|
||||
PFNWGLDESTROYIMAGEBUFFERI3DPROC glad_wglDestroyImageBufferI3D = NULL;
|
||||
PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC glad_wglAssociateImageBufferEventsI3D = NULL;
|
||||
PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC glad_wglReleaseImageBufferEventsI3D = NULL;
|
||||
PFNWGLENABLEFRAMELOCKI3DPROC glad_wglEnableFrameLockI3D = NULL;
|
||||
PFNWGLDISABLEFRAMELOCKI3DPROC glad_wglDisableFrameLockI3D = NULL;
|
||||
PFNWGLISENABLEDFRAMELOCKI3DPROC glad_wglIsEnabledFrameLockI3D = NULL;
|
||||
PFNWGLQUERYFRAMELOCKMASTERI3DPROC glad_wglQueryFrameLockMasterI3D = NULL;
|
||||
PFNWGLGETFRAMEUSAGEI3DPROC glad_wglGetFrameUsageI3D = NULL;
|
||||
PFNWGLBEGINFRAMETRACKINGI3DPROC glad_wglBeginFrameTrackingI3D = NULL;
|
||||
PFNWGLENDFRAMETRACKINGI3DPROC glad_wglEndFrameTrackingI3D = NULL;
|
||||
PFNWGLQUERYFRAMETRACKINGI3DPROC glad_wglQueryFrameTrackingI3D = NULL;
|
||||
PFNWGLDXSETRESOURCESHAREHANDLENVPROC glad_wglDXSetResourceShareHandleNV = NULL;
|
||||
PFNWGLDXOPENDEVICENVPROC glad_wglDXOpenDeviceNV = NULL;
|
||||
PFNWGLDXCLOSEDEVICENVPROC glad_wglDXCloseDeviceNV = NULL;
|
||||
PFNWGLDXREGISTEROBJECTNVPROC glad_wglDXRegisterObjectNV = NULL;
|
||||
PFNWGLDXUNREGISTEROBJECTNVPROC glad_wglDXUnregisterObjectNV = NULL;
|
||||
PFNWGLDXOBJECTACCESSNVPROC glad_wglDXObjectAccessNV = NULL;
|
||||
PFNWGLDXLOCKOBJECTSNVPROC glad_wglDXLockObjectsNV = NULL;
|
||||
PFNWGLDXUNLOCKOBJECTSNVPROC glad_wglDXUnlockObjectsNV = NULL;
|
||||
PFNWGLCOPYIMAGESUBDATANVPROC glad_wglCopyImageSubDataNV = NULL;
|
||||
PFNWGLDELAYBEFORESWAPNVPROC glad_wglDelayBeforeSwapNV = NULL;
|
||||
PFNWGLENUMGPUSNVPROC glad_wglEnumGpusNV = NULL;
|
||||
PFNWGLENUMGPUDEVICESNVPROC glad_wglEnumGpuDevicesNV = NULL;
|
||||
PFNWGLCREATEAFFINITYDCNVPROC glad_wglCreateAffinityDCNV = NULL;
|
||||
PFNWGLENUMGPUSFROMAFFINITYDCNVPROC glad_wglEnumGpusFromAffinityDCNV = NULL;
|
||||
PFNWGLDELETEDCNVPROC glad_wglDeleteDCNV = NULL;
|
||||
PFNWGLENUMERATEVIDEODEVICESNVPROC glad_wglEnumerateVideoDevicesNV = NULL;
|
||||
PFNWGLBINDVIDEODEVICENVPROC glad_wglBindVideoDeviceNV = NULL;
|
||||
PFNWGLQUERYCURRENTCONTEXTNVPROC glad_wglQueryCurrentContextNV = NULL;
|
||||
PFNWGLJOINSWAPGROUPNVPROC glad_wglJoinSwapGroupNV = NULL;
|
||||
PFNWGLBINDSWAPBARRIERNVPROC glad_wglBindSwapBarrierNV = NULL;
|
||||
PFNWGLQUERYSWAPGROUPNVPROC glad_wglQuerySwapGroupNV = NULL;
|
||||
PFNWGLQUERYMAXSWAPGROUPSNVPROC glad_wglQueryMaxSwapGroupsNV = NULL;
|
||||
PFNWGLQUERYFRAMECOUNTNVPROC glad_wglQueryFrameCountNV = NULL;
|
||||
PFNWGLRESETFRAMECOUNTNVPROC glad_wglResetFrameCountNV = NULL;
|
||||
PFNWGLALLOCATEMEMORYNVPROC glad_wglAllocateMemoryNV = NULL;
|
||||
PFNWGLFREEMEMORYNVPROC glad_wglFreeMemoryNV = NULL;
|
||||
PFNWGLBINDVIDEOCAPTUREDEVICENVPROC glad_wglBindVideoCaptureDeviceNV = NULL;
|
||||
PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC glad_wglEnumerateVideoCaptureDevicesNV = NULL;
|
||||
PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC glad_wglLockVideoCaptureDeviceNV = NULL;
|
||||
PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC glad_wglQueryVideoCaptureDeviceNV = NULL;
|
||||
PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC glad_wglReleaseVideoCaptureDeviceNV = NULL;
|
||||
PFNWGLGETVIDEODEVICENVPROC glad_wglGetVideoDeviceNV = NULL;
|
||||
PFNWGLRELEASEVIDEODEVICENVPROC glad_wglReleaseVideoDeviceNV = NULL;
|
||||
PFNWGLBINDVIDEOIMAGENVPROC glad_wglBindVideoImageNV = NULL;
|
||||
PFNWGLRELEASEVIDEOIMAGENVPROC glad_wglReleaseVideoImageNV = NULL;
|
||||
PFNWGLSENDPBUFFERTOVIDEONVPROC glad_wglSendPbufferToVideoNV = NULL;
|
||||
PFNWGLGETVIDEOINFONVPROC glad_wglGetVideoInfoNV = NULL;
|
||||
PFNWGLGETSYNCVALUESOMLPROC glad_wglGetSyncValuesOML = NULL;
|
||||
PFNWGLGETMSCRATEOMLPROC glad_wglGetMscRateOML = NULL;
|
||||
PFNWGLSWAPBUFFERSMSCOMLPROC glad_wglSwapBuffersMscOML = NULL;
|
||||
PFNWGLSWAPLAYERBUFFERSMSCOMLPROC glad_wglSwapLayerBuffersMscOML = NULL;
|
||||
PFNWGLWAITFORMSCOMLPROC glad_wglWaitForMscOML = NULL;
|
||||
PFNWGLWAITFORSBCOMLPROC glad_wglWaitForSbcOML = NULL;
|
||||
static void load_WGL_3DL_stereo_control(GLADloadproc load) {
|
||||
if(!GLAD_WGL_3DL_stereo_control) return;
|
||||
glad_wglSetStereoEmitterState3DL = (PFNWGLSETSTEREOEMITTERSTATE3DLPROC)load("wglSetStereoEmitterState3DL");
|
||||
}
|
||||
static void load_WGL_AMD_gpu_association(GLADloadproc load) {
|
||||
if(!GLAD_WGL_AMD_gpu_association) return;
|
||||
glad_wglGetGPUIDsAMD = (PFNWGLGETGPUIDSAMDPROC)load("wglGetGPUIDsAMD");
|
||||
glad_wglGetGPUInfoAMD = (PFNWGLGETGPUINFOAMDPROC)load("wglGetGPUInfoAMD");
|
||||
glad_wglGetContextGPUIDAMD = (PFNWGLGETCONTEXTGPUIDAMDPROC)load("wglGetContextGPUIDAMD");
|
||||
glad_wglCreateAssociatedContextAMD = (PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC)load("wglCreateAssociatedContextAMD");
|
||||
glad_wglCreateAssociatedContextAttribsAMD = (PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC)load("wglCreateAssociatedContextAttribsAMD");
|
||||
glad_wglDeleteAssociatedContextAMD = (PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC)load("wglDeleteAssociatedContextAMD");
|
||||
glad_wglMakeAssociatedContextCurrentAMD = (PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC)load("wglMakeAssociatedContextCurrentAMD");
|
||||
glad_wglGetCurrentAssociatedContextAMD = (PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC)load("wglGetCurrentAssociatedContextAMD");
|
||||
glad_wglBlitContextFramebufferAMD = (PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC)load("wglBlitContextFramebufferAMD");
|
||||
}
|
||||
static void load_WGL_ARB_buffer_region(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_buffer_region) return;
|
||||
glad_wglCreateBufferRegionARB = (PFNWGLCREATEBUFFERREGIONARBPROC)load("wglCreateBufferRegionARB");
|
||||
glad_wglDeleteBufferRegionARB = (PFNWGLDELETEBUFFERREGIONARBPROC)load("wglDeleteBufferRegionARB");
|
||||
glad_wglSaveBufferRegionARB = (PFNWGLSAVEBUFFERREGIONARBPROC)load("wglSaveBufferRegionARB");
|
||||
glad_wglRestoreBufferRegionARB = (PFNWGLRESTOREBUFFERREGIONARBPROC)load("wglRestoreBufferRegionARB");
|
||||
}
|
||||
static void load_WGL_ARB_create_context(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_create_context) return;
|
||||
glad_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)load("wglCreateContextAttribsARB");
|
||||
}
|
||||
static void load_WGL_ARB_extensions_string(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_extensions_string) return;
|
||||
glad_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)load("wglGetExtensionsStringARB");
|
||||
}
|
||||
static void load_WGL_ARB_make_current_read(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_make_current_read) return;
|
||||
glad_wglMakeContextCurrentARB = (PFNWGLMAKECONTEXTCURRENTARBPROC)load("wglMakeContextCurrentARB");
|
||||
glad_wglGetCurrentReadDCARB = (PFNWGLGETCURRENTREADDCARBPROC)load("wglGetCurrentReadDCARB");
|
||||
}
|
||||
static void load_WGL_ARB_pbuffer(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_pbuffer) return;
|
||||
glad_wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)load("wglCreatePbufferARB");
|
||||
glad_wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)load("wglGetPbufferDCARB");
|
||||
glad_wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)load("wglReleasePbufferDCARB");
|
||||
glad_wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)load("wglDestroyPbufferARB");
|
||||
glad_wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)load("wglQueryPbufferARB");
|
||||
}
|
||||
static void load_WGL_ARB_pixel_format(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_pixel_format) return;
|
||||
glad_wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)load("wglGetPixelFormatAttribivARB");
|
||||
glad_wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)load("wglGetPixelFormatAttribfvARB");
|
||||
glad_wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)load("wglChoosePixelFormatARB");
|
||||
}
|
||||
static void load_WGL_ARB_render_texture(GLADloadproc load) {
|
||||
if(!GLAD_WGL_ARB_render_texture) return;
|
||||
glad_wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)load("wglBindTexImageARB");
|
||||
glad_wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)load("wglReleaseTexImageARB");
|
||||
glad_wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)load("wglSetPbufferAttribARB");
|
||||
}
|
||||
static void load_WGL_EXT_display_color_table(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_display_color_table) return;
|
||||
glad_wglCreateDisplayColorTableEXT = (PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC)load("wglCreateDisplayColorTableEXT");
|
||||
glad_wglLoadDisplayColorTableEXT = (PFNWGLLOADDISPLAYCOLORTABLEEXTPROC)load("wglLoadDisplayColorTableEXT");
|
||||
glad_wglBindDisplayColorTableEXT = (PFNWGLBINDDISPLAYCOLORTABLEEXTPROC)load("wglBindDisplayColorTableEXT");
|
||||
glad_wglDestroyDisplayColorTableEXT = (PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC)load("wglDestroyDisplayColorTableEXT");
|
||||
}
|
||||
static void load_WGL_EXT_extensions_string(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_extensions_string) return;
|
||||
glad_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)load("wglGetExtensionsStringEXT");
|
||||
}
|
||||
static void load_WGL_EXT_make_current_read(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_make_current_read) return;
|
||||
glad_wglMakeContextCurrentEXT = (PFNWGLMAKECONTEXTCURRENTEXTPROC)load("wglMakeContextCurrentEXT");
|
||||
glad_wglGetCurrentReadDCEXT = (PFNWGLGETCURRENTREADDCEXTPROC)load("wglGetCurrentReadDCEXT");
|
||||
}
|
||||
static void load_WGL_EXT_pbuffer(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_pbuffer) return;
|
||||
glad_wglCreatePbufferEXT = (PFNWGLCREATEPBUFFEREXTPROC)load("wglCreatePbufferEXT");
|
||||
glad_wglGetPbufferDCEXT = (PFNWGLGETPBUFFERDCEXTPROC)load("wglGetPbufferDCEXT");
|
||||
glad_wglReleasePbufferDCEXT = (PFNWGLRELEASEPBUFFERDCEXTPROC)load("wglReleasePbufferDCEXT");
|
||||
glad_wglDestroyPbufferEXT = (PFNWGLDESTROYPBUFFEREXTPROC)load("wglDestroyPbufferEXT");
|
||||
glad_wglQueryPbufferEXT = (PFNWGLQUERYPBUFFEREXTPROC)load("wglQueryPbufferEXT");
|
||||
}
|
||||
static void load_WGL_EXT_pixel_format(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_pixel_format) return;
|
||||
glad_wglGetPixelFormatAttribivEXT = (PFNWGLGETPIXELFORMATATTRIBIVEXTPROC)load("wglGetPixelFormatAttribivEXT");
|
||||
glad_wglGetPixelFormatAttribfvEXT = (PFNWGLGETPIXELFORMATATTRIBFVEXTPROC)load("wglGetPixelFormatAttribfvEXT");
|
||||
glad_wglChoosePixelFormatEXT = (PFNWGLCHOOSEPIXELFORMATEXTPROC)load("wglChoosePixelFormatEXT");
|
||||
}
|
||||
static void load_WGL_EXT_swap_control(GLADloadproc load) {
|
||||
if(!GLAD_WGL_EXT_swap_control) return;
|
||||
glad_wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)load("wglSwapIntervalEXT");
|
||||
glad_wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)load("wglGetSwapIntervalEXT");
|
||||
}
|
||||
static void load_WGL_I3D_digital_video_control(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_digital_video_control) return;
|
||||
glad_wglGetDigitalVideoParametersI3D = (PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC)load("wglGetDigitalVideoParametersI3D");
|
||||
glad_wglSetDigitalVideoParametersI3D = (PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC)load("wglSetDigitalVideoParametersI3D");
|
||||
}
|
||||
static void load_WGL_I3D_gamma(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_gamma) return;
|
||||
glad_wglGetGammaTableParametersI3D = (PFNWGLGETGAMMATABLEPARAMETERSI3DPROC)load("wglGetGammaTableParametersI3D");
|
||||
glad_wglSetGammaTableParametersI3D = (PFNWGLSETGAMMATABLEPARAMETERSI3DPROC)load("wglSetGammaTableParametersI3D");
|
||||
glad_wglGetGammaTableI3D = (PFNWGLGETGAMMATABLEI3DPROC)load("wglGetGammaTableI3D");
|
||||
glad_wglSetGammaTableI3D = (PFNWGLSETGAMMATABLEI3DPROC)load("wglSetGammaTableI3D");
|
||||
}
|
||||
static void load_WGL_I3D_genlock(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_genlock) return;
|
||||
glad_wglEnableGenlockI3D = (PFNWGLENABLEGENLOCKI3DPROC)load("wglEnableGenlockI3D");
|
||||
glad_wglDisableGenlockI3D = (PFNWGLDISABLEGENLOCKI3DPROC)load("wglDisableGenlockI3D");
|
||||
glad_wglIsEnabledGenlockI3D = (PFNWGLISENABLEDGENLOCKI3DPROC)load("wglIsEnabledGenlockI3D");
|
||||
glad_wglGenlockSourceI3D = (PFNWGLGENLOCKSOURCEI3DPROC)load("wglGenlockSourceI3D");
|
||||
glad_wglGetGenlockSourceI3D = (PFNWGLGETGENLOCKSOURCEI3DPROC)load("wglGetGenlockSourceI3D");
|
||||
glad_wglGenlockSourceEdgeI3D = (PFNWGLGENLOCKSOURCEEDGEI3DPROC)load("wglGenlockSourceEdgeI3D");
|
||||
glad_wglGetGenlockSourceEdgeI3D = (PFNWGLGETGENLOCKSOURCEEDGEI3DPROC)load("wglGetGenlockSourceEdgeI3D");
|
||||
glad_wglGenlockSampleRateI3D = (PFNWGLGENLOCKSAMPLERATEI3DPROC)load("wglGenlockSampleRateI3D");
|
||||
glad_wglGetGenlockSampleRateI3D = (PFNWGLGETGENLOCKSAMPLERATEI3DPROC)load("wglGetGenlockSampleRateI3D");
|
||||
glad_wglGenlockSourceDelayI3D = (PFNWGLGENLOCKSOURCEDELAYI3DPROC)load("wglGenlockSourceDelayI3D");
|
||||
glad_wglGetGenlockSourceDelayI3D = (PFNWGLGETGENLOCKSOURCEDELAYI3DPROC)load("wglGetGenlockSourceDelayI3D");
|
||||
glad_wglQueryGenlockMaxSourceDelayI3D = (PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC)load("wglQueryGenlockMaxSourceDelayI3D");
|
||||
}
|
||||
static void load_WGL_I3D_image_buffer(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_image_buffer) return;
|
||||
glad_wglCreateImageBufferI3D = (PFNWGLCREATEIMAGEBUFFERI3DPROC)load("wglCreateImageBufferI3D");
|
||||
glad_wglDestroyImageBufferI3D = (PFNWGLDESTROYIMAGEBUFFERI3DPROC)load("wglDestroyImageBufferI3D");
|
||||
glad_wglAssociateImageBufferEventsI3D = (PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC)load("wglAssociateImageBufferEventsI3D");
|
||||
glad_wglReleaseImageBufferEventsI3D = (PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC)load("wglReleaseImageBufferEventsI3D");
|
||||
}
|
||||
static void load_WGL_I3D_swap_frame_lock(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_swap_frame_lock) return;
|
||||
glad_wglEnableFrameLockI3D = (PFNWGLENABLEFRAMELOCKI3DPROC)load("wglEnableFrameLockI3D");
|
||||
glad_wglDisableFrameLockI3D = (PFNWGLDISABLEFRAMELOCKI3DPROC)load("wglDisableFrameLockI3D");
|
||||
glad_wglIsEnabledFrameLockI3D = (PFNWGLISENABLEDFRAMELOCKI3DPROC)load("wglIsEnabledFrameLockI3D");
|
||||
glad_wglQueryFrameLockMasterI3D = (PFNWGLQUERYFRAMELOCKMASTERI3DPROC)load("wglQueryFrameLockMasterI3D");
|
||||
}
|
||||
static void load_WGL_I3D_swap_frame_usage(GLADloadproc load) {
|
||||
if(!GLAD_WGL_I3D_swap_frame_usage) return;
|
||||
glad_wglGetFrameUsageI3D = (PFNWGLGETFRAMEUSAGEI3DPROC)load("wglGetFrameUsageI3D");
|
||||
glad_wglBeginFrameTrackingI3D = (PFNWGLBEGINFRAMETRACKINGI3DPROC)load("wglBeginFrameTrackingI3D");
|
||||
glad_wglEndFrameTrackingI3D = (PFNWGLENDFRAMETRACKINGI3DPROC)load("wglEndFrameTrackingI3D");
|
||||
glad_wglQueryFrameTrackingI3D = (PFNWGLQUERYFRAMETRACKINGI3DPROC)load("wglQueryFrameTrackingI3D");
|
||||
}
|
||||
static void load_WGL_NV_DX_interop(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_DX_interop) return;
|
||||
glad_wglDXSetResourceShareHandleNV = (PFNWGLDXSETRESOURCESHAREHANDLENVPROC)load("wglDXSetResourceShareHandleNV");
|
||||
glad_wglDXOpenDeviceNV = (PFNWGLDXOPENDEVICENVPROC)load("wglDXOpenDeviceNV");
|
||||
glad_wglDXCloseDeviceNV = (PFNWGLDXCLOSEDEVICENVPROC)load("wglDXCloseDeviceNV");
|
||||
glad_wglDXRegisterObjectNV = (PFNWGLDXREGISTEROBJECTNVPROC)load("wglDXRegisterObjectNV");
|
||||
glad_wglDXUnregisterObjectNV = (PFNWGLDXUNREGISTEROBJECTNVPROC)load("wglDXUnregisterObjectNV");
|
||||
glad_wglDXObjectAccessNV = (PFNWGLDXOBJECTACCESSNVPROC)load("wglDXObjectAccessNV");
|
||||
glad_wglDXLockObjectsNV = (PFNWGLDXLOCKOBJECTSNVPROC)load("wglDXLockObjectsNV");
|
||||
glad_wglDXUnlockObjectsNV = (PFNWGLDXUNLOCKOBJECTSNVPROC)load("wglDXUnlockObjectsNV");
|
||||
}
|
||||
static void load_WGL_NV_copy_image(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_copy_image) return;
|
||||
glad_wglCopyImageSubDataNV = (PFNWGLCOPYIMAGESUBDATANVPROC)load("wglCopyImageSubDataNV");
|
||||
}
|
||||
static void load_WGL_NV_delay_before_swap(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_delay_before_swap) return;
|
||||
glad_wglDelayBeforeSwapNV = (PFNWGLDELAYBEFORESWAPNVPROC)load("wglDelayBeforeSwapNV");
|
||||
}
|
||||
static void load_WGL_NV_gpu_affinity(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_gpu_affinity) return;
|
||||
glad_wglEnumGpusNV = (PFNWGLENUMGPUSNVPROC)load("wglEnumGpusNV");
|
||||
glad_wglEnumGpuDevicesNV = (PFNWGLENUMGPUDEVICESNVPROC)load("wglEnumGpuDevicesNV");
|
||||
glad_wglCreateAffinityDCNV = (PFNWGLCREATEAFFINITYDCNVPROC)load("wglCreateAffinityDCNV");
|
||||
glad_wglEnumGpusFromAffinityDCNV = (PFNWGLENUMGPUSFROMAFFINITYDCNVPROC)load("wglEnumGpusFromAffinityDCNV");
|
||||
glad_wglDeleteDCNV = (PFNWGLDELETEDCNVPROC)load("wglDeleteDCNV");
|
||||
}
|
||||
static void load_WGL_NV_present_video(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_present_video) return;
|
||||
glad_wglEnumerateVideoDevicesNV = (PFNWGLENUMERATEVIDEODEVICESNVPROC)load("wglEnumerateVideoDevicesNV");
|
||||
glad_wglBindVideoDeviceNV = (PFNWGLBINDVIDEODEVICENVPROC)load("wglBindVideoDeviceNV");
|
||||
glad_wglQueryCurrentContextNV = (PFNWGLQUERYCURRENTCONTEXTNVPROC)load("wglQueryCurrentContextNV");
|
||||
}
|
||||
static void load_WGL_NV_swap_group(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_swap_group) return;
|
||||
glad_wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)load("wglJoinSwapGroupNV");
|
||||
glad_wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)load("wglBindSwapBarrierNV");
|
||||
glad_wglQuerySwapGroupNV = (PFNWGLQUERYSWAPGROUPNVPROC)load("wglQuerySwapGroupNV");
|
||||
glad_wglQueryMaxSwapGroupsNV = (PFNWGLQUERYMAXSWAPGROUPSNVPROC)load("wglQueryMaxSwapGroupsNV");
|
||||
glad_wglQueryFrameCountNV = (PFNWGLQUERYFRAMECOUNTNVPROC)load("wglQueryFrameCountNV");
|
||||
glad_wglResetFrameCountNV = (PFNWGLRESETFRAMECOUNTNVPROC)load("wglResetFrameCountNV");
|
||||
}
|
||||
static void load_WGL_NV_vertex_array_range(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_vertex_array_range) return;
|
||||
glad_wglAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC)load("wglAllocateMemoryNV");
|
||||
glad_wglFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC)load("wglFreeMemoryNV");
|
||||
}
|
||||
static void load_WGL_NV_video_capture(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_video_capture) return;
|
||||
glad_wglBindVideoCaptureDeviceNV = (PFNWGLBINDVIDEOCAPTUREDEVICENVPROC)load("wglBindVideoCaptureDeviceNV");
|
||||
glad_wglEnumerateVideoCaptureDevicesNV = (PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC)load("wglEnumerateVideoCaptureDevicesNV");
|
||||
glad_wglLockVideoCaptureDeviceNV = (PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC)load("wglLockVideoCaptureDeviceNV");
|
||||
glad_wglQueryVideoCaptureDeviceNV = (PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC)load("wglQueryVideoCaptureDeviceNV");
|
||||
glad_wglReleaseVideoCaptureDeviceNV = (PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC)load("wglReleaseVideoCaptureDeviceNV");
|
||||
}
|
||||
static void load_WGL_NV_video_output(GLADloadproc load) {
|
||||
if(!GLAD_WGL_NV_video_output) return;
|
||||
glad_wglGetVideoDeviceNV = (PFNWGLGETVIDEODEVICENVPROC)load("wglGetVideoDeviceNV");
|
||||
glad_wglReleaseVideoDeviceNV = (PFNWGLRELEASEVIDEODEVICENVPROC)load("wglReleaseVideoDeviceNV");
|
||||
glad_wglBindVideoImageNV = (PFNWGLBINDVIDEOIMAGENVPROC)load("wglBindVideoImageNV");
|
||||
glad_wglReleaseVideoImageNV = (PFNWGLRELEASEVIDEOIMAGENVPROC)load("wglReleaseVideoImageNV");
|
||||
glad_wglSendPbufferToVideoNV = (PFNWGLSENDPBUFFERTOVIDEONVPROC)load("wglSendPbufferToVideoNV");
|
||||
glad_wglGetVideoInfoNV = (PFNWGLGETVIDEOINFONVPROC)load("wglGetVideoInfoNV");
|
||||
}
|
||||
static void load_WGL_OML_sync_control(GLADloadproc load) {
|
||||
if(!GLAD_WGL_OML_sync_control) return;
|
||||
glad_wglGetSyncValuesOML = (PFNWGLGETSYNCVALUESOMLPROC)load("wglGetSyncValuesOML");
|
||||
glad_wglGetMscRateOML = (PFNWGLGETMSCRATEOMLPROC)load("wglGetMscRateOML");
|
||||
glad_wglSwapBuffersMscOML = (PFNWGLSWAPBUFFERSMSCOMLPROC)load("wglSwapBuffersMscOML");
|
||||
glad_wglSwapLayerBuffersMscOML = (PFNWGLSWAPLAYERBUFFERSMSCOMLPROC)load("wglSwapLayerBuffersMscOML");
|
||||
glad_wglWaitForMscOML = (PFNWGLWAITFORMSCOMLPROC)load("wglWaitForMscOML");
|
||||
glad_wglWaitForSbcOML = (PFNWGLWAITFORSBCOMLPROC)load("wglWaitForSbcOML");
|
||||
}
|
||||
static int find_extensionsWGL(void) {
|
||||
if (!get_exts()) return 0;
|
||||
GLAD_WGL_3DFX_multisample = has_ext("WGL_3DFX_multisample");
|
||||
GLAD_WGL_3DL_stereo_control = has_ext("WGL_3DL_stereo_control");
|
||||
GLAD_WGL_AMD_gpu_association = has_ext("WGL_AMD_gpu_association");
|
||||
GLAD_WGL_ARB_buffer_region = has_ext("WGL_ARB_buffer_region");
|
||||
GLAD_WGL_ARB_context_flush_control = has_ext("WGL_ARB_context_flush_control");
|
||||
GLAD_WGL_ARB_create_context = has_ext("WGL_ARB_create_context");
|
||||
GLAD_WGL_ARB_create_context_no_error = has_ext("WGL_ARB_create_context_no_error");
|
||||
GLAD_WGL_ARB_create_context_profile = has_ext("WGL_ARB_create_context_profile");
|
||||
GLAD_WGL_ARB_create_context_robustness = has_ext("WGL_ARB_create_context_robustness");
|
||||
GLAD_WGL_ARB_extensions_string = has_ext("WGL_ARB_extensions_string");
|
||||
GLAD_WGL_ARB_framebuffer_sRGB = has_ext("WGL_ARB_framebuffer_sRGB");
|
||||
GLAD_WGL_ARB_make_current_read = has_ext("WGL_ARB_make_current_read");
|
||||
GLAD_WGL_ARB_multisample = has_ext("WGL_ARB_multisample");
|
||||
GLAD_WGL_ARB_pbuffer = has_ext("WGL_ARB_pbuffer");
|
||||
GLAD_WGL_ARB_pixel_format = has_ext("WGL_ARB_pixel_format");
|
||||
GLAD_WGL_ARB_pixel_format_float = has_ext("WGL_ARB_pixel_format_float");
|
||||
GLAD_WGL_ARB_render_texture = has_ext("WGL_ARB_render_texture");
|
||||
GLAD_WGL_ARB_robustness_application_isolation = has_ext("WGL_ARB_robustness_application_isolation");
|
||||
GLAD_WGL_ARB_robustness_share_group_isolation = has_ext("WGL_ARB_robustness_share_group_isolation");
|
||||
GLAD_WGL_ATI_pixel_format_float = has_ext("WGL_ATI_pixel_format_float");
|
||||
GLAD_WGL_ATI_render_texture_rectangle = has_ext("WGL_ATI_render_texture_rectangle");
|
||||
GLAD_WGL_EXT_colorspace = has_ext("WGL_EXT_colorspace");
|
||||
GLAD_WGL_EXT_create_context_es2_profile = has_ext("WGL_EXT_create_context_es2_profile");
|
||||
GLAD_WGL_EXT_create_context_es_profile = has_ext("WGL_EXT_create_context_es_profile");
|
||||
GLAD_WGL_EXT_depth_float = has_ext("WGL_EXT_depth_float");
|
||||
GLAD_WGL_EXT_display_color_table = has_ext("WGL_EXT_display_color_table");
|
||||
GLAD_WGL_EXT_extensions_string = has_ext("WGL_EXT_extensions_string");
|
||||
GLAD_WGL_EXT_framebuffer_sRGB = has_ext("WGL_EXT_framebuffer_sRGB");
|
||||
GLAD_WGL_EXT_make_current_read = has_ext("WGL_EXT_make_current_read");
|
||||
GLAD_WGL_EXT_multisample = has_ext("WGL_EXT_multisample");
|
||||
GLAD_WGL_EXT_pbuffer = has_ext("WGL_EXT_pbuffer");
|
||||
GLAD_WGL_EXT_pixel_format = has_ext("WGL_EXT_pixel_format");
|
||||
GLAD_WGL_EXT_pixel_format_packed_float = has_ext("WGL_EXT_pixel_format_packed_float");
|
||||
GLAD_WGL_EXT_swap_control = has_ext("WGL_EXT_swap_control");
|
||||
GLAD_WGL_EXT_swap_control_tear = has_ext("WGL_EXT_swap_control_tear");
|
||||
GLAD_WGL_I3D_digital_video_control = has_ext("WGL_I3D_digital_video_control");
|
||||
GLAD_WGL_I3D_gamma = has_ext("WGL_I3D_gamma");
|
||||
GLAD_WGL_I3D_genlock = has_ext("WGL_I3D_genlock");
|
||||
GLAD_WGL_I3D_image_buffer = has_ext("WGL_I3D_image_buffer");
|
||||
GLAD_WGL_I3D_swap_frame_lock = has_ext("WGL_I3D_swap_frame_lock");
|
||||
GLAD_WGL_I3D_swap_frame_usage = has_ext("WGL_I3D_swap_frame_usage");
|
||||
GLAD_WGL_NV_DX_interop = has_ext("WGL_NV_DX_interop");
|
||||
GLAD_WGL_NV_DX_interop2 = has_ext("WGL_NV_DX_interop2");
|
||||
GLAD_WGL_NV_copy_image = has_ext("WGL_NV_copy_image");
|
||||
GLAD_WGL_NV_delay_before_swap = has_ext("WGL_NV_delay_before_swap");
|
||||
GLAD_WGL_NV_float_buffer = has_ext("WGL_NV_float_buffer");
|
||||
GLAD_WGL_NV_gpu_affinity = has_ext("WGL_NV_gpu_affinity");
|
||||
GLAD_WGL_NV_multigpu_context = has_ext("WGL_NV_multigpu_context");
|
||||
GLAD_WGL_NV_multisample_coverage = has_ext("WGL_NV_multisample_coverage");
|
||||
GLAD_WGL_NV_present_video = has_ext("WGL_NV_present_video");
|
||||
GLAD_WGL_NV_render_depth_texture = has_ext("WGL_NV_render_depth_texture");
|
||||
GLAD_WGL_NV_render_texture_rectangle = has_ext("WGL_NV_render_texture_rectangle");
|
||||
GLAD_WGL_NV_swap_group = has_ext("WGL_NV_swap_group");
|
||||
GLAD_WGL_NV_vertex_array_range = has_ext("WGL_NV_vertex_array_range");
|
||||
GLAD_WGL_NV_video_capture = has_ext("WGL_NV_video_capture");
|
||||
GLAD_WGL_NV_video_output = has_ext("WGL_NV_video_output");
|
||||
GLAD_WGL_OML_sync_control = has_ext("WGL_OML_sync_control");
|
||||
free_exts();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void find_coreWGL(HDC hdc) {
|
||||
GLADWGLhdc = hdc;
|
||||
}
|
||||
|
||||
int gladLoadWGLLoader(GLADloadproc load, HDC hdc) {
|
||||
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)load("wglGetExtensionsStringARB");
|
||||
wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)load("wglGetExtensionsStringEXT");
|
||||
if(wglGetExtensionsStringARB == NULL && wglGetExtensionsStringEXT == NULL) return 0;
|
||||
find_coreWGL(hdc);
|
||||
|
||||
if (!find_extensionsWGL()) return 0;
|
||||
load_WGL_3DL_stereo_control(load);
|
||||
load_WGL_AMD_gpu_association(load);
|
||||
load_WGL_ARB_buffer_region(load);
|
||||
load_WGL_ARB_create_context(load);
|
||||
load_WGL_ARB_extensions_string(load);
|
||||
load_WGL_ARB_make_current_read(load);
|
||||
load_WGL_ARB_pbuffer(load);
|
||||
load_WGL_ARB_pixel_format(load);
|
||||
load_WGL_ARB_render_texture(load);
|
||||
load_WGL_EXT_display_color_table(load);
|
||||
load_WGL_EXT_extensions_string(load);
|
||||
load_WGL_EXT_make_current_read(load);
|
||||
load_WGL_EXT_pbuffer(load);
|
||||
load_WGL_EXT_pixel_format(load);
|
||||
load_WGL_EXT_swap_control(load);
|
||||
load_WGL_I3D_digital_video_control(load);
|
||||
load_WGL_I3D_gamma(load);
|
||||
load_WGL_I3D_genlock(load);
|
||||
load_WGL_I3D_image_buffer(load);
|
||||
load_WGL_I3D_swap_frame_lock(load);
|
||||
load_WGL_I3D_swap_frame_usage(load);
|
||||
load_WGL_NV_DX_interop(load);
|
||||
load_WGL_NV_copy_image(load);
|
||||
load_WGL_NV_delay_before_swap(load);
|
||||
load_WGL_NV_gpu_affinity(load);
|
||||
load_WGL_NV_present_video(load);
|
||||
load_WGL_NV_swap_group(load);
|
||||
load_WGL_NV_vertex_array_range(load);
|
||||
load_WGL_NV_video_capture(load);
|
||||
load_WGL_NV_video_output(load);
|
||||
load_WGL_OML_sync_control(load);
|
||||
return 1;
|
||||
}
|
||||
|
1015
src/frontend/glad/glad_wgl.h
Normal file
1015
src/frontend/glad/glad_wgl.h
Normal file
File diff suppressed because it is too large
Load Diff
311
src/frontend/glad/khrplatform.h
Normal file
311
src/frontend/glad/khrplatform.h
Normal file
@ -0,0 +1,311 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
@ -45,8 +45,11 @@ set(SOURCES_QT_SDL
|
||||
../FrontendUtil.h
|
||||
../mic_blow.h
|
||||
|
||||
../glad/glad.c
|
||||
../duckstation/gl/context.cpp
|
||||
|
||||
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
||||
)
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
option(USE_QT6 "Build using Qt 6 instead of 5" ON)
|
||||
@ -71,12 +74,13 @@ set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (BUILD_STATIC)
|
||||
list(APPEND PKG_CONFIG_EXECUTABLE "--static")
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
||||
pkg_check_modules(Slirp REQUIRED IMPORTED_TARGET slirp)
|
||||
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
|
||||
@ -87,6 +91,47 @@ add_compile_definitions(ARCHIVE_SUPPORT_ENABLED)
|
||||
|
||||
add_executable(melonDS ${SOURCES_QT_SDL})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(melonDS PUBLIC opengl32)
|
||||
|
||||
target_sources(melonDS PRIVATE
|
||||
../duckstation/gl/context_wgl.cpp
|
||||
|
||||
../glad/glad_wgl.c
|
||||
)
|
||||
elseif (APPLE)
|
||||
if (NOT USE_QT6)
|
||||
find_library(COCOA_LIB Cocoa)
|
||||
target_link_libraries(melonDS PRIVATE ${COCOA_LIB})
|
||||
endif()
|
||||
target_sources(melonDS PRIVATE
|
||||
../duckstation/gl/context_agl.mm
|
||||
)
|
||||
else()
|
||||
# we only need ECM for Wayland
|
||||
# so we only require it from here
|
||||
find_package(ECM REQUIRED NO_MODULE)
|
||||
list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}")
|
||||
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(EGL REQUIRED)
|
||||
find_package(Wayland REQUIRED Client)
|
||||
|
||||
target_sources(melonDS PRIVATE
|
||||
../duckstation/gl/context_egl.cpp
|
||||
../duckstation/gl/context_egl_x11.cpp
|
||||
../duckstation/gl/context_glx.cpp
|
||||
../duckstation/gl/context_egl_wayland.cpp
|
||||
../duckstation/gl/x11_window.cpp
|
||||
|
||||
../glad/glad_egl.c
|
||||
../glad/glad_glx.c
|
||||
)
|
||||
target_link_libraries(melonDS PRIVATE "${X11_LIBRARIES}" "${EGL_LIBRARIES}")
|
||||
target_include_directories(melonDS PRIVATE "${X11_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
|
||||
if (BUILD_STATIC)
|
||||
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
|
||||
target_link_options(melonDS PRIVATE -static)
|
||||
@ -95,6 +140,11 @@ endif()
|
||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||
if (USE_QT6)
|
||||
target_include_directories(melonDS PUBLIC ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
else()
|
||||
target_include_directories(melonDS PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
target_link_libraries(melonDS PRIVATE core)
|
||||
target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::Slirp PkgConfig::LibArchive)
|
||||
target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS})
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../types.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "OpenGLSupport.h"
|
||||
#include <QPainter>
|
||||
|
||||
#include "OSD.h"
|
||||
@ -52,42 +53,37 @@ struct Item
|
||||
|
||||
bool GLTextureLoaded;
|
||||
GLuint GLTexture;
|
||||
|
||||
};
|
||||
|
||||
std::deque<Item> ItemQueue;
|
||||
|
||||
QOpenGLShaderProgram* Shader;
|
||||
GLuint Shader[3];
|
||||
GLint uScreenSize, uOSDPos, uOSDSize;
|
||||
GLfloat uScaleFactor;
|
||||
GLuint OSDVertexArray;
|
||||
GLuint OSDVertexBuffer;
|
||||
|
||||
volatile bool Rendering;
|
||||
QMutex Rendering;
|
||||
|
||||
|
||||
bool Init(QOpenGLFunctions_3_2_Core* f)
|
||||
bool Init(bool openGL)
|
||||
{
|
||||
if (f)
|
||||
if (openGL)
|
||||
{
|
||||
Shader = new QOpenGLShaderProgram();
|
||||
Shader->addShaderFromSourceCode(QOpenGLShader::Vertex, kScreenVS_OSD);
|
||||
Shader->addShaderFromSourceCode(QOpenGLShader::Fragment, kScreenFS_OSD);
|
||||
OpenGL::BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, Shader, "OSDShader");
|
||||
|
||||
GLuint pid = Shader->programId();
|
||||
f->glBindAttribLocation(pid, 0, "vPosition");
|
||||
f->glBindFragDataLocation(pid, 0, "oColor");
|
||||
GLuint pid = Shader[2];
|
||||
glBindAttribLocation(pid, 0, "vPosition");
|
||||
glBindFragDataLocation(pid, 0, "oColor");
|
||||
|
||||
Shader->link();
|
||||
OpenGL::LinkShaderProgram(Shader);
|
||||
glUseProgram(pid);
|
||||
glUniform1i(glGetUniformLocation(pid, "OSDTex"), 0);
|
||||
|
||||
Shader->bind();
|
||||
Shader->setUniformValue("OSDTex", (GLint)0);
|
||||
Shader->release();
|
||||
|
||||
uScreenSize = Shader->uniformLocation("uScreenSize");
|
||||
uOSDPos = Shader->uniformLocation("uOSDPos");
|
||||
uOSDSize = Shader->uniformLocation("uOSDSize");
|
||||
uScaleFactor = Shader->uniformLocation("uScaleFactor");
|
||||
uScreenSize = glGetUniformLocation(pid, "uScreenSize");
|
||||
uOSDPos = glGetUniformLocation(pid, "uOSDPos");
|
||||
uOSDSize = glGetUniformLocation(pid, "uOSDSize");
|
||||
uScaleFactor = glGetUniformLocation(pid, "uScaleFactor");
|
||||
|
||||
float vertices[6*2] =
|
||||
{
|
||||
@ -99,32 +95,30 @@ bool Init(QOpenGLFunctions_3_2_Core* f)
|
||||
1, 1
|
||||
};
|
||||
|
||||
f->glGenBuffers(1, &OSDVertexBuffer);
|
||||
f->glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
||||
f->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glGenBuffers(1, &OSDVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
f->glGenVertexArrays(1, &OSDVertexArray);
|
||||
f->glBindVertexArray(OSDVertexArray);
|
||||
f->glEnableVertexAttribArray(0); // position
|
||||
f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
||||
glGenVertexArrays(1, &OSDVertexArray);
|
||||
glBindVertexArray(OSDVertexArray);
|
||||
glEnableVertexAttribArray(0); // position
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeInit(QOpenGLFunctions_3_2_Core* f)
|
||||
void DeInit()
|
||||
{
|
||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
||||
{
|
||||
Item& item = *it;
|
||||
|
||||
if (item.GLTextureLoaded && f) f->glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.Bitmap) delete[] item.Bitmap;
|
||||
|
||||
it = ItemQueue.erase(it);
|
||||
}
|
||||
|
||||
if (f) delete Shader;
|
||||
}
|
||||
|
||||
|
||||
@ -329,7 +323,7 @@ void AddMessage(u32 color, const char* text)
|
||||
{
|
||||
if (!Config::ShowOSD) return;
|
||||
|
||||
while (Rendering);
|
||||
Rendering.lock();
|
||||
|
||||
Item item;
|
||||
|
||||
@ -342,27 +336,29 @@ void AddMessage(u32 color, const char* text)
|
||||
item.GLTextureLoaded = false;
|
||||
|
||||
ItemQueue.push_back(item);
|
||||
|
||||
Rendering.unlock();
|
||||
}
|
||||
|
||||
void Update(QOpenGLFunctions_3_2_Core* f)
|
||||
void Update()
|
||||
{
|
||||
if (!Config::ShowOSD)
|
||||
{
|
||||
Rendering = true;
|
||||
Rendering.lock();
|
||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
||||
{
|
||||
Item& item = *it;
|
||||
|
||||
if (item.GLTextureLoaded && f) f->glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.Bitmap) delete[] item.Bitmap;
|
||||
|
||||
it = ItemQueue.erase(it);
|
||||
}
|
||||
Rendering = false;
|
||||
Rendering.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
Rendering = true;
|
||||
Rendering.lock();
|
||||
|
||||
Uint32 tick_now = SDL_GetTicks();
|
||||
Uint32 tick_min = tick_now - 2500;
|
||||
@ -373,7 +369,7 @@ void Update(QOpenGLFunctions_3_2_Core* f)
|
||||
|
||||
if (item.Timestamp < tick_min)
|
||||
{
|
||||
if (item.GLTextureLoaded) f->glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
|
||||
if (item.Bitmap) delete[] item.Bitmap;
|
||||
|
||||
it = ItemQueue.erase(it);
|
||||
@ -388,14 +384,14 @@ void Update(QOpenGLFunctions_3_2_Core* f)
|
||||
it++;
|
||||
}
|
||||
|
||||
Rendering = false;
|
||||
Rendering.unlock();
|
||||
}
|
||||
|
||||
void DrawNative(QPainter& painter)
|
||||
{
|
||||
if (!Config::ShowOSD) return;
|
||||
|
||||
Rendering = true;
|
||||
Rendering.lock();
|
||||
|
||||
u32 y = kOSDMargin;
|
||||
|
||||
@ -417,30 +413,30 @@ void DrawNative(QPainter& painter)
|
||||
it++;
|
||||
}
|
||||
|
||||
Rendering = false;
|
||||
Rendering.unlock();
|
||||
}
|
||||
|
||||
void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h)
|
||||
void DrawGL(float w, float h)
|
||||
{
|
||||
if (!Config::ShowOSD) return;
|
||||
if (!mainWindow || !mainWindow->panel) return;
|
||||
|
||||
Rendering = true;
|
||||
Rendering.lock();
|
||||
|
||||
u32 y = kOSDMargin;
|
||||
|
||||
Shader->bind();
|
||||
glUseProgram(Shader[2]);
|
||||
|
||||
f->glUniform2f(uScreenSize, w, h);
|
||||
f->glUniform1f(uScaleFactor, mainWindow->devicePixelRatioF());
|
||||
glUniform2f(uScreenSize, w, h);
|
||||
glUniform1f(uScaleFactor, mainWindow->devicePixelRatioF());
|
||||
|
||||
f->glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
||||
f->glBindVertexArray(OSDVertexArray);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
|
||||
glBindVertexArray(OSDVertexArray);
|
||||
|
||||
f->glActiveTexture(GL_TEXTURE0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
f->glEnable(GL_BLEND);
|
||||
f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
|
||||
{
|
||||
@ -448,30 +444,30 @@ void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h)
|
||||
|
||||
if (!item.GLTextureLoaded)
|
||||
{
|
||||
f->glGenTextures(1, &item.GLTexture);
|
||||
f->glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
|
||||
glGenTextures(1, &item.GLTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
|
||||
|
||||
item.GLTextureLoaded = true;
|
||||
}
|
||||
|
||||
f->glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
||||
f->glUniform2i(uOSDPos, kOSDMargin, y);
|
||||
f->glUniform2i(uOSDSize, item.Width, item.Height);
|
||||
f->glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
||||
glBindTexture(GL_TEXTURE_2D, item.GLTexture);
|
||||
glUniform2i(uOSDPos, kOSDMargin, y);
|
||||
glUniform2i(uOSDSize, item.Width, item.Height);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
||||
|
||||
y += item.Height;
|
||||
it++;
|
||||
}
|
||||
|
||||
f->glDisable(GL_BLEND);
|
||||
Shader->release();
|
||||
glDisable(GL_BLEND);
|
||||
glUseProgram(0);
|
||||
|
||||
Rendering = false;
|
||||
Rendering.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,14 +22,14 @@
|
||||
namespace OSD
|
||||
{
|
||||
|
||||
bool Init(QOpenGLFunctions_3_2_Core* f);
|
||||
void DeInit(QOpenGLFunctions_3_2_Core* f);
|
||||
bool Init(bool openGL);
|
||||
void DeInit();
|
||||
|
||||
void AddMessage(u32 color, const char* text);
|
||||
|
||||
void Update(QOpenGLFunctions_3_2_Core* f);
|
||||
void Update();
|
||||
void DrawNative(QPainter& painter);
|
||||
void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h);
|
||||
void DrawGL(float w, float h);
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,11 @@
|
||||
#include "ui_VideoSettingsDialog.h"
|
||||
|
||||
|
||||
inline bool UsesGL()
|
||||
{
|
||||
return (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
}
|
||||
|
||||
VideoSettingsDialog* VideoSettingsDialog::currentDlg = nullptr;
|
||||
|
||||
|
||||
@ -73,6 +78,7 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
|
||||
|
||||
if (!Config::ScreenVSync)
|
||||
ui->sbVSyncInterval->setEnabled(false);
|
||||
setVsyncControlEnable(UsesGL());
|
||||
|
||||
if (Config::_3DRenderer == 0)
|
||||
{
|
||||
@ -88,14 +94,6 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
|
||||
ui->cbxGLResolution->setEnabled(true);
|
||||
ui->cbBetterPolygons->setEnabled(true);
|
||||
}
|
||||
|
||||
// sorry
|
||||
ui->cbVSync->hide();
|
||||
ui->cbVSync->setEnabled(false);
|
||||
ui->sbVSyncInterval->hide();
|
||||
ui->sbVSyncInterval->setEnabled(false);
|
||||
ui->label_2->hide();
|
||||
ui->groupBox->layout()->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
}
|
||||
|
||||
VideoSettingsDialog::~VideoSettingsDialog()
|
||||
@ -112,7 +110,7 @@ void VideoSettingsDialog::on_VideoSettingsDialog_accepted()
|
||||
|
||||
void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
|
||||
{
|
||||
bool old_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
bool old_gl = UsesGL();
|
||||
|
||||
Config::_3DRenderer = oldRenderer;
|
||||
Config::ScreenUseGL = oldGLDisplay;
|
||||
@ -122,12 +120,17 @@ void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
|
||||
Config::GL_ScaleFactor = oldGLScale;
|
||||
Config::GL_BetterPolygons = oldGLBetterPolygons;
|
||||
|
||||
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
emit updateVideoSettings(old_gl != new_gl);
|
||||
emit updateVideoSettings(old_gl != UsesGL());
|
||||
|
||||
closeDlg();
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::setVsyncControlEnable(bool hasOGL)
|
||||
{
|
||||
ui->cbVSync->setEnabled(hasOGL);
|
||||
ui->sbVSyncInterval->setEnabled(hasOGL);
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::onChange3DRenderer(int renderer)
|
||||
{
|
||||
bool old_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
@ -149,8 +152,7 @@ void VideoSettingsDialog::onChange3DRenderer(int renderer)
|
||||
ui->cbBetterPolygons->setEnabled(true);
|
||||
}
|
||||
|
||||
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
emit updateVideoSettings(old_gl != new_gl);
|
||||
emit updateVideoSettings(old_gl != UsesGL());
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::on_cbGLDisplay_stateChanged(int state)
|
||||
@ -159,8 +161,9 @@ void VideoSettingsDialog::on_cbGLDisplay_stateChanged(int state)
|
||||
|
||||
Config::ScreenUseGL = (state != 0);
|
||||
|
||||
bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
emit updateVideoSettings(old_gl != new_gl);
|
||||
setVsyncControlEnable(UsesGL());
|
||||
|
||||
emit updateVideoSettings(old_gl != UsesGL());
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::on_cbVSync_stateChanged(int state)
|
||||
@ -168,11 +171,13 @@ void VideoSettingsDialog::on_cbVSync_stateChanged(int state)
|
||||
bool vsync = (state != 0);
|
||||
ui->sbVSyncInterval->setEnabled(vsync);
|
||||
Config::ScreenVSync = vsync;
|
||||
emit updateVideoSettings(false);
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::on_sbVSyncInterval_valueChanged(int val)
|
||||
{
|
||||
Config::ScreenVSyncInterval = val;
|
||||
emit updateVideoSettings(false);
|
||||
}
|
||||
|
||||
void VideoSettingsDialog::on_cbSoftwareThreaded_stateChanged(int state)
|
||||
@ -189,6 +194,8 @@ void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx)
|
||||
|
||||
Config::GL_ScaleFactor = idx+1;
|
||||
|
||||
setVsyncControlEnable(UsesGL());
|
||||
|
||||
emit updateVideoSettings(false);
|
||||
}
|
||||
|
||||
|
@ -67,8 +67,9 @@ private slots:
|
||||
void on_cbBetterPolygons_stateChanged(int state);
|
||||
|
||||
void on_cbSoftwareThreaded_stateChanged(int state);
|
||||
|
||||
private:
|
||||
void setVsyncControlEnable(bool hasOGL);
|
||||
|
||||
Ui::VideoSettingsDialog* ui;
|
||||
|
||||
QButtonGroup* grp3DRenderer;
|
||||
|
@ -37,17 +37,20 @@
|
||||
#include <QMimeData>
|
||||
#include <QVector>
|
||||
#ifndef _WIN32
|
||||
#include <QGuiApplication>
|
||||
#include <QSocketNotifier>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
#ifndef APPLE
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
#include "OpenGLSupport.h"
|
||||
#endif
|
||||
#include "duckstation/gl/context.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "Input.h"
|
||||
@ -369,51 +372,121 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
|
||||
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
|
||||
|
||||
if (mainWindow->hasOGL) initOpenGL();
|
||||
static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this);
|
||||
}
|
||||
|
||||
void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix)
|
||||
{
|
||||
screenSettingsLock.lock();
|
||||
|
||||
if (lastScreenWidth != windowInfo.surface_width || lastScreenHeight != windowInfo.surface_height)
|
||||
{
|
||||
if (oglContext)
|
||||
oglContext->ResizeSurface(windowInfo.surface_width, windowInfo.surface_height);
|
||||
lastScreenWidth = windowInfo.surface_width;
|
||||
lastScreenHeight = windowInfo.surface_height;
|
||||
}
|
||||
|
||||
this->filter = filter;
|
||||
this->windowInfo = windowInfo;
|
||||
this->numScreens = numScreens;
|
||||
memcpy(this->screenKind, screenKind, sizeof(int)*numScreens);
|
||||
memcpy(this->screenMatrix, screenMatrix, sizeof(float)*numScreens*6);
|
||||
|
||||
screenSettingsLock.unlock();
|
||||
}
|
||||
|
||||
void EmuThread::initOpenGL()
|
||||
{
|
||||
QOpenGLContext* windowctx = mainWindow->getOGLContext();
|
||||
QSurfaceFormat format = windowctx->format();
|
||||
GL::Context* windowctx = mainWindow->getOGLContext();
|
||||
|
||||
format.setSwapInterval(0);
|
||||
oglContext = windowctx;
|
||||
oglContext->MakeCurrent();
|
||||
|
||||
oglSurface = new QOffscreenSurface();
|
||||
oglSurface->setFormat(format);
|
||||
oglSurface->create();
|
||||
if (!oglSurface->isValid())
|
||||
OpenGL::BuildShaderProgram(kScreenVS, kScreenFS, screenShaderProgram, "ScreenShader");
|
||||
GLuint pid = screenShaderProgram[2];
|
||||
glBindAttribLocation(pid, 0, "vPosition");
|
||||
glBindAttribLocation(pid, 1, "vTexcoord");
|
||||
glBindFragDataLocation(pid, 0, "oColor");
|
||||
|
||||
OpenGL::LinkShaderProgram(screenShaderProgram);
|
||||
|
||||
glUseProgram(pid);
|
||||
glUniform1i(glGetUniformLocation(pid, "ScreenTex"), 0);
|
||||
|
||||
screenShaderScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize");
|
||||
screenShaderTransformULoc = glGetUniformLocation(pid, "uTransform");
|
||||
|
||||
// to prevent bleeding between both parts of the screen
|
||||
// with bilinear filtering enabled
|
||||
const int paddedHeight = 192*2+2;
|
||||
const float padPixels = 1.f / paddedHeight;
|
||||
|
||||
const float vertices[] =
|
||||
{
|
||||
// TODO handle this!
|
||||
printf("oglSurface shat itself :(\n");
|
||||
delete oglSurface;
|
||||
return;
|
||||
}
|
||||
0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 192.f, 0.f, 0.5f - padPixels,
|
||||
256.f, 192.f, 1.f, 0.5f - padPixels,
|
||||
0.f, 0.f, 0.f, 0.f,
|
||||
256.f, 192.f, 1.f, 0.5f - padPixels,
|
||||
256.f, 0.f, 1.f, 0.f,
|
||||
|
||||
oglContext = new QOpenGLContext();
|
||||
oglContext->setFormat(oglSurface->format());
|
||||
oglContext->setShareContext(windowctx);
|
||||
if (!oglContext->create())
|
||||
{
|
||||
// TODO handle this!
|
||||
printf("oglContext shat itself :(\n");
|
||||
delete oglContext;
|
||||
delete oglSurface;
|
||||
return;
|
||||
}
|
||||
0.f, 0.f, 0.f, 0.5f + padPixels,
|
||||
0.f, 192.f, 0.f, 1.f,
|
||||
256.f, 192.f, 1.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.5f + padPixels,
|
||||
256.f, 192.f, 1.f, 1.f,
|
||||
256.f, 0.f, 1.f, 0.5f + padPixels
|
||||
};
|
||||
|
||||
oglContext->moveToThread(this);
|
||||
glGenBuffers(1, &screenVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glGenVertexArrays(1, &screenVertexArray);
|
||||
glBindVertexArray(screenVertexArray);
|
||||
glEnableVertexAttribArray(0); // position
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
|
||||
glEnableVertexAttribArray(1); // texcoord
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
|
||||
|
||||
glGenTextures(1, &screenTexture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
// fill the padding
|
||||
u8 zeroData[256*4*4];
|
||||
memset(zeroData, 0, sizeof(zeroData));
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
|
||||
|
||||
OSD::Init(true);
|
||||
|
||||
oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
|
||||
}
|
||||
|
||||
void EmuThread::deinitOpenGL()
|
||||
{
|
||||
delete oglContext;
|
||||
delete oglSurface;
|
||||
glDeleteTextures(1, &screenTexture);
|
||||
|
||||
glDeleteVertexArrays(1, &screenVertexArray);
|
||||
glDeleteBuffers(1, &screenVertexBuffer);
|
||||
|
||||
OpenGL::DeleteShaderProgram(screenShaderProgram);
|
||||
|
||||
OSD::DeInit();
|
||||
|
||||
oglContext->DoneCurrent();
|
||||
oglContext = nullptr;
|
||||
|
||||
lastScreenWidth = lastScreenHeight = -1;
|
||||
}
|
||||
|
||||
void EmuThread::run()
|
||||
{
|
||||
bool hasOGL = mainWindow->hasOGL;
|
||||
u32 mainScreenPos[3];
|
||||
|
||||
NDS::Init();
|
||||
@ -428,14 +501,12 @@ void EmuThread::run()
|
||||
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
|
||||
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (hasOGL)
|
||||
if (mainWindow->hasOGL)
|
||||
{
|
||||
oglContext->makeCurrent(oglSurface);
|
||||
initOpenGL();
|
||||
videoRenderer = Config::_3DRenderer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
videoRenderer = 0;
|
||||
}
|
||||
@ -498,25 +569,24 @@ void EmuThread::run()
|
||||
if (EmuRunning == 3) EmuRunning = 2;
|
||||
|
||||
// update render settings if needed
|
||||
if (videoSettingsDirty)
|
||||
// HACK:
|
||||
// once the fast forward hotkey is released, we need to update vsync
|
||||
// to the old setting again
|
||||
if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward))
|
||||
{
|
||||
if (hasOGL != mainWindow->hasOGL)
|
||||
if (oglContext)
|
||||
{
|
||||
hasOGL = mainWindow->hasOGL;
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (hasOGL)
|
||||
{
|
||||
oglContext->makeCurrent(oglSurface);
|
||||
videoRenderer = Config::_3DRenderer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
videoRenderer = 0;
|
||||
}
|
||||
oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
|
||||
videoRenderer = Config::_3DRenderer;
|
||||
}
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
else
|
||||
videoRenderer = hasOGL ? Config::_3DRenderer : 0;
|
||||
#endif
|
||||
{
|
||||
videoRenderer = 0;
|
||||
}
|
||||
|
||||
videoRenderer = oglContext ? Config::_3DRenderer : 0;
|
||||
|
||||
videoSettingsDirty = false;
|
||||
|
||||
@ -570,15 +640,6 @@ void EmuThread::run()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (videoRenderer == 1)
|
||||
{
|
||||
FrontBufferLock.lock();
|
||||
if (FrontBufferReverseSyncs[FrontBuffer ^ 1])
|
||||
glWaitSync(FrontBufferReverseSyncs[FrontBuffer ^ 1], 0, GL_TIMEOUT_IGNORED);
|
||||
FrontBufferLock.unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
// emulate
|
||||
u32 nlines = NDS::RunFrame();
|
||||
@ -589,21 +650,17 @@ void EmuThread::run()
|
||||
if (ROMManager::GBASave)
|
||||
ROMManager::GBASave->CheckFlush();
|
||||
|
||||
FrontBufferLock.lock();
|
||||
FrontBuffer = GPU::FrontBuffer;
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (videoRenderer == 1)
|
||||
if (!oglContext)
|
||||
{
|
||||
if (FrontBufferSyncs[FrontBuffer])
|
||||
glDeleteSync(FrontBufferSyncs[FrontBuffer]);
|
||||
FrontBufferSyncs[FrontBuffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
// this is hacky but this is the easiest way to call
|
||||
// this function without dealling with a ton of
|
||||
// macro mess
|
||||
epoxy_glFlush();
|
||||
FrontBufferLock.lock();
|
||||
FrontBuffer = GPU::FrontBuffer;
|
||||
FrontBufferLock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
FrontBuffer = GPU::FrontBuffer;
|
||||
drawScreenGL();
|
||||
}
|
||||
#endif
|
||||
FrontBufferLock.unlock();
|
||||
|
||||
#ifdef MELONCAP
|
||||
MelonCap::Update();
|
||||
@ -612,7 +669,7 @@ void EmuThread::run()
|
||||
if (EmuRunning == 0) break;
|
||||
|
||||
winUpdateCount++;
|
||||
if (winUpdateCount >= winUpdateFreq)
|
||||
if (winUpdateCount >= winUpdateFreq && !oglContext)
|
||||
{
|
||||
emit windowUpdate();
|
||||
winUpdateCount = 0;
|
||||
@ -620,6 +677,11 @@ void EmuThread::run()
|
||||
|
||||
bool fastforward = Input::HotkeyDown(HK_FastForward);
|
||||
|
||||
if (fastforward && oglContext && Config::ScreenVSync)
|
||||
{
|
||||
oglContext->SetSwapInterval(0);
|
||||
}
|
||||
|
||||
if (Config::AudioSync && !fastforward && audioDevice)
|
||||
{
|
||||
SDL_LockMutex(audioSyncLock);
|
||||
@ -700,6 +762,21 @@ void EmuThread::run()
|
||||
changeWindowTitle(melontitle);
|
||||
|
||||
SDL_Delay(75);
|
||||
|
||||
if (oglContext)
|
||||
drawScreenGL();
|
||||
|
||||
int contextRequest = ContextRequest;
|
||||
if (contextRequest == 1)
|
||||
{
|
||||
initOpenGL();
|
||||
ContextRequest = 0;
|
||||
}
|
||||
else if (contextRequest == 2)
|
||||
{
|
||||
deinitOpenGL();
|
||||
ContextRequest = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,12 +785,6 @@ void EmuThread::run()
|
||||
GPU::DeInitRenderer();
|
||||
NDS::DeInit();
|
||||
//Platform::LAN_DeInit();
|
||||
|
||||
if (hasOGL)
|
||||
{
|
||||
oglContext->doneCurrent();
|
||||
deinitOpenGL();
|
||||
}
|
||||
}
|
||||
|
||||
void EmuThread::changeWindowTitle(char* title)
|
||||
@ -733,6 +804,18 @@ void EmuThread::emuRun()
|
||||
micOpen();
|
||||
}
|
||||
|
||||
void EmuThread::initContext()
|
||||
{
|
||||
ContextRequest = 1;
|
||||
while (ContextRequest != 0);
|
||||
}
|
||||
|
||||
void EmuThread::deinitContext()
|
||||
{
|
||||
ContextRequest = 2;
|
||||
while (ContextRequest != 0);
|
||||
}
|
||||
|
||||
void EmuThread::emuPause()
|
||||
{
|
||||
EmuPause++;
|
||||
@ -784,6 +867,72 @@ bool EmuThread::emuIsActive()
|
||||
return (RunningSomething == 1);
|
||||
}
|
||||
|
||||
void EmuThread::drawScreenGL()
|
||||
{
|
||||
int w = windowInfo.surface_width;
|
||||
int h = windowInfo.surface_height;
|
||||
float factor = windowInfo.surface_scale;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(false);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, w, h);
|
||||
|
||||
glUseProgram(screenShaderProgram[2]);
|
||||
glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor);
|
||||
|
||||
int frontbuf = FrontBuffer;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (GPU::Renderer != 0)
|
||||
{
|
||||
// hardware-accelerated render
|
||||
GPU::CurGLCompositor->BindOutputTexture(frontbuf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// regular render
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
|
||||
if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
|
||||
}
|
||||
}
|
||||
|
||||
screenSettingsLock.lock();
|
||||
|
||||
GLint filter = this->filter ? GL_LINEAR : GL_NEAREST;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||
glBindVertexArray(screenVertexArray);
|
||||
|
||||
for (int i = 0; i < numScreens; i++)
|
||||
{
|
||||
glUniformMatrix2x3fv(screenShaderTransformULoc, 1, GL_TRUE, screenMatrix[i]);
|
||||
glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3);
|
||||
}
|
||||
|
||||
screenSettingsLock.unlock();
|
||||
|
||||
OSD::Update();
|
||||
OSD::DrawGL(w, h);
|
||||
|
||||
oglContext->SwapBuffers();
|
||||
}
|
||||
|
||||
ScreenHandler::ScreenHandler(QWidget* widget)
|
||||
{
|
||||
widget->setMouseTracking(true);
|
||||
@ -1001,12 +1150,12 @@ ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent), ScreenH
|
||||
screenTrans[0].reset();
|
||||
screenTrans[1].reset();
|
||||
|
||||
OSD::Init(nullptr);
|
||||
OSD::Init(false);
|
||||
}
|
||||
|
||||
ScreenPanelNative::~ScreenPanelNative()
|
||||
{
|
||||
OSD::DeInit(nullptr);
|
||||
OSD::DeInit();
|
||||
}
|
||||
|
||||
void ScreenPanelNative::setupScreenLayout()
|
||||
@ -1057,7 +1206,7 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
OSD::Update(nullptr);
|
||||
OSD::Update();
|
||||
OSD::DrawNative(painter);
|
||||
}
|
||||
|
||||
@ -1105,23 +1254,98 @@ void ScreenPanelNative::onScreenLayoutChanged()
|
||||
}
|
||||
|
||||
|
||||
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QOpenGLWidget(parent), ScreenHandler(this)
|
||||
{}
|
||||
ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QWidget(parent), ScreenHandler(this)
|
||||
{
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_NativeWindow, true);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
setAttribute(Qt::WA_KeyCompression, false);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMinimumSize(screenGetMinSize());
|
||||
}
|
||||
|
||||
ScreenPanelGL::~ScreenPanelGL()
|
||||
{}
|
||||
|
||||
bool ScreenPanelGL::createContext()
|
||||
{
|
||||
makeCurrent();
|
||||
std::optional<WindowInfo> windowInfo = getWindowInfo();
|
||||
std::array<GL::Context::Version, 2> versionsToTry = {
|
||||
GL::Context::Version{GL::Context::Profile::Core, 4, 3},
|
||||
GL::Context::Version{GL::Context::Profile::Core, 3, 2}};
|
||||
if (windowInfo.has_value())
|
||||
{
|
||||
glContext = GL::Context::Create(*getWindowInfo(), versionsToTry);
|
||||
glContext->DoneCurrent();
|
||||
}
|
||||
|
||||
OSD::DeInit(this);
|
||||
return glContext != nullptr;
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &screenTexture);
|
||||
qreal ScreenPanelGL::devicePixelRatioFromScreen() const
|
||||
{
|
||||
const QScreen* screen_for_ratio = window()->windowHandle()->screen();
|
||||
if (!screen_for_ratio)
|
||||
screen_for_ratio = QGuiApplication::primaryScreen();
|
||||
|
||||
glDeleteVertexArrays(1, &screenVertexArray);
|
||||
glDeleteBuffers(1, &screenVertexBuffer);
|
||||
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
|
||||
}
|
||||
|
||||
delete screenShader;
|
||||
int ScreenPanelGL::scaledWindowWidth() const
|
||||
{
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioFromScreen())), 1);
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
int ScreenPanelGL::scaledWindowHeight() const
|
||||
{
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen())), 1);
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> ScreenPanelGL::getWindowInfo()
|
||||
{
|
||||
WindowInfo wi;
|
||||
|
||||
// Windows and Apple are easy here since there's no display connection.
|
||||
#if defined(_WIN32)
|
||||
wi.type = WindowInfo::Type::Win32;
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
#elif defined(__APPLE__)
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
const QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("xcb"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::X11;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
|
||||
wi.window_handle = reinterpret_cast<void*>(winId());
|
||||
}
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::Wayland;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
|
||||
wi.window_handle = pni->nativeResourceForWindow("surface", windowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Unknown PNI platform " << platform_name;
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
wi.surface_width = static_cast<u32>(scaledWindowWidth());
|
||||
wi.surface_height = static_cast<u32>(scaledWindowHeight());
|
||||
wi.surface_scale = static_cast<float>(devicePixelRatioFromScreen());
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
|
||||
QPaintEngine* ScreenPanelGL::paintEngine() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ScreenPanelGL::setupScreenLayout()
|
||||
@ -1130,163 +1354,15 @@ void ScreenPanelGL::setupScreenLayout()
|
||||
int h = height();
|
||||
|
||||
screenSetupLayout(w, h);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::initializeGL()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
|
||||
const GLubyte* version = glGetString(GL_VERSION); // version as a string
|
||||
printf("OpenGL: renderer: %s\n", renderer);
|
||||
printf("OpenGL: version: %s\n", version);
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
||||
screenShader = new QOpenGLShaderProgram(this);
|
||||
screenShader->addShaderFromSourceCode(QOpenGLShader::Vertex, kScreenVS);
|
||||
screenShader->addShaderFromSourceCode(QOpenGLShader::Fragment, kScreenFS);
|
||||
|
||||
GLuint pid = screenShader->programId();
|
||||
glBindAttribLocation(pid, 0, "vPosition");
|
||||
glBindAttribLocation(pid, 1, "vTexcoord");
|
||||
glBindFragDataLocation(pid, 0, "oColor");
|
||||
|
||||
screenShader->link();
|
||||
|
||||
screenShader->bind();
|
||||
screenShader->setUniformValue("ScreenTex", (GLint)0);
|
||||
screenShader->release();
|
||||
|
||||
// to prevent bleeding between both parts of the screen
|
||||
// with bilinear filtering enabled
|
||||
const int paddedHeight = 192*2+2;
|
||||
const float padPixels = 1.f / paddedHeight;
|
||||
|
||||
const float vertices[] =
|
||||
{
|
||||
0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 192.f, 0.f, 0.5f - padPixels,
|
||||
256.f, 192.f, 1.f, 0.5f - padPixels,
|
||||
0.f, 0.f, 0.f, 0.f,
|
||||
256.f, 192.f, 1.f, 0.5f - padPixels,
|
||||
256.f, 0.f, 1.f, 0.f,
|
||||
|
||||
0.f, 0.f, 0.f, 0.5f + padPixels,
|
||||
0.f, 192.f, 0.f, 1.f,
|
||||
256.f, 192.f, 1.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.5f + padPixels,
|
||||
256.f, 192.f, 1.f, 1.f,
|
||||
256.f, 0.f, 1.f, 0.5f + padPixels
|
||||
};
|
||||
|
||||
glGenBuffers(1, &screenVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glGenVertexArrays(1, &screenVertexArray);
|
||||
glBindVertexArray(screenVertexArray);
|
||||
glEnableVertexAttribArray(0); // position
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
|
||||
glEnableVertexAttribArray(1); // texcoord
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
|
||||
|
||||
glGenTextures(1, &screenTexture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
// fill the padding
|
||||
u8 zeroData[256*4*4];
|
||||
memset(zeroData, 0, sizeof(zeroData));
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
|
||||
|
||||
OSD::Init(this);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::paintGL()
|
||||
{
|
||||
int w = width();
|
||||
int h = height();
|
||||
float factor = devicePixelRatioF();
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, w*factor, h*factor);
|
||||
|
||||
if (emuThread)
|
||||
{
|
||||
screenShader->bind();
|
||||
|
||||
screenShader->setUniformValue("uScreenSize", (float)w, (float)h);
|
||||
screenShader->setUniformValue("uScaleFactor", factor);
|
||||
|
||||
emuThread->FrontBufferLock.lock();
|
||||
int frontbuf = emuThread->FrontBuffer;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
#ifdef OGLRENDERER_ENABLED
|
||||
if (GPU::Renderer != 0)
|
||||
{
|
||||
if (emuThread->FrontBufferSyncs[emuThread->FrontBuffer])
|
||||
glWaitSync(emuThread->FrontBufferSyncs[emuThread->FrontBuffer], 0, GL_TIMEOUT_IGNORED);
|
||||
// hardware-accelerated render
|
||||
GPU::CurGLCompositor->BindOutputTexture(frontbuf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// regular render
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
|
||||
if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
|
||||
}
|
||||
}
|
||||
|
||||
GLint filter = Config::ScreenFilter ? GL_LINEAR : GL_NEAREST;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||
glBindVertexArray(screenVertexArray);
|
||||
|
||||
GLint transloc = screenShader->uniformLocation("uTransform");
|
||||
|
||||
for (int i = 0; i < numScreens; i++)
|
||||
{
|
||||
glUniformMatrix2x3fv(transloc, 1, GL_TRUE, screenMatrix[i]);
|
||||
glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3);
|
||||
}
|
||||
|
||||
screenShader->release();
|
||||
|
||||
if (emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer])
|
||||
glDeleteSync(emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer]);
|
||||
emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
emuThread->FrontBufferLock.unlock();
|
||||
}
|
||||
|
||||
OSD::Update(this);
|
||||
OSD::DrawGL(this, w*factor, h*factor);
|
||||
transferLayout(emuThread);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
setupScreenLayout();
|
||||
|
||||
QOpenGLWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::resizeGL(int w, int h)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::mousePressEvent(QMouseEvent* event)
|
||||
@ -1321,6 +1397,13 @@ bool ScreenPanelGL::event(QEvent* event)
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::transferLayout(EmuThread* thread)
|
||||
{
|
||||
std::optional<WindowInfo> windowInfo = getWindowInfo();
|
||||
if (windowInfo.has_value())
|
||||
thread->updateScreenSettings(Config::ScreenFilter, *windowInfo, numScreens, screenKind, &screenMatrix[0][0]);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::onScreenLayoutChanged()
|
||||
{
|
||||
setMinimumSize(screenGetMinSize());
|
||||
@ -1817,6 +1900,18 @@ MainWindow::~MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (hasOGL)
|
||||
{
|
||||
// we intentionally don't unpause here
|
||||
emuThread->emuPause();
|
||||
emuThread->deinitContext();
|
||||
}
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::createScreenPanel()
|
||||
{
|
||||
hasOGL = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
|
||||
@ -1829,17 +1924,7 @@ void MainWindow::createScreenPanel()
|
||||
panel = panelGL;
|
||||
panelWidget = panelGL;
|
||||
|
||||
if (!panelGL->isValid())
|
||||
hasOGL = false;
|
||||
else
|
||||
{
|
||||
QSurfaceFormat fmt = panelGL->format();
|
||||
if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 2))
|
||||
hasOGL = false;
|
||||
}
|
||||
|
||||
if (!hasOGL)
|
||||
delete panelGL;
|
||||
panelGL->createContext();
|
||||
}
|
||||
|
||||
if (!hasOGL)
|
||||
@ -1855,12 +1940,12 @@ void MainWindow::createScreenPanel()
|
||||
emit screenLayoutChange();
|
||||
}
|
||||
|
||||
QOpenGLContext* MainWindow::getOGLContext()
|
||||
GL::Context* MainWindow::getOGLContext()
|
||||
{
|
||||
if (!hasOGL) return nullptr;
|
||||
|
||||
QOpenGLWidget* glpanel = dynamic_cast<QOpenGLWidget*>(panel);
|
||||
return glpanel->context();
|
||||
ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
|
||||
return glpanel->getContext();
|
||||
}
|
||||
|
||||
void MainWindow::resizeEvent(QResizeEvent* event)
|
||||
@ -3002,13 +3087,14 @@ void MainWindow::onChangeIntegerScaling(bool checked)
|
||||
void MainWindow::onChangeScreenFiltering(bool checked)
|
||||
{
|
||||
Config::ScreenFilter = checked?1:0;
|
||||
|
||||
emit screenLayoutChange();
|
||||
}
|
||||
|
||||
void MainWindow::onChangeShowOSD(bool checked)
|
||||
{
|
||||
Config::ShowOSD = checked?1:0;
|
||||
}
|
||||
|
||||
void MainWindow::onChangeLimitFramerate(bool checked)
|
||||
{
|
||||
Config::LimitFPS = checked?1:0;
|
||||
@ -3088,19 +3174,20 @@ void MainWindow::onUpdateVideoSettings(bool glchange)
|
||||
if (glchange)
|
||||
{
|
||||
emuThread->emuPause();
|
||||
if (hasOGL) emuThread->deinitContext();
|
||||
|
||||
if (hasOGL)
|
||||
emuThread->deinitOpenGL();
|
||||
delete panel;
|
||||
createScreenPanel();
|
||||
connect(emuThread, SIGNAL(windowUpdate()), panelWidget, SLOT(repaint()));
|
||||
if (hasOGL) emuThread->initOpenGL();
|
||||
}
|
||||
|
||||
videoSettingsDirty = true;
|
||||
|
||||
if (glchange)
|
||||
{
|
||||
if (hasOGL) emuThread->initContext();
|
||||
emuThread->emuUnpause();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3137,6 +3224,8 @@ int main(int argc, char** argv)
|
||||
{
|
||||
srand(time(nullptr));
|
||||
|
||||
qputenv("QT_SCALE_FACTOR", "1");
|
||||
|
||||
printf("melonDS " MELONDS_VERSION "\n");
|
||||
printf(MELONDS_URL "\n");
|
||||
|
||||
@ -3191,14 +3280,6 @@ int main(int argc, char** argv)
|
||||
SANITIZE(Config::ScreenAspectBot, 0, 4);
|
||||
#undef SANITIZE
|
||||
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(24);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(3, 2);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setSwapInterval(0);
|
||||
QSurfaceFormat::setDefaultFormat(format);
|
||||
|
||||
audioMuted = false;
|
||||
audioSync = SDL_CreateCond();
|
||||
audioSyncLock = SDL_CreateMutex();
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <QWidget>
|
||||
@ -28,15 +30,15 @@
|
||||
#include <QActionGroup>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
#include <QScreen>
|
||||
#include <QCloseEvent>
|
||||
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLFunctions_3_2_Core>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <atomic>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "FrontendUtil.h"
|
||||
#include "duckstation/gl/context.h"
|
||||
|
||||
class EmuThread : public QThread
|
||||
{
|
||||
@ -46,9 +48,6 @@ class EmuThread : public QThread
|
||||
public:
|
||||
explicit EmuThread(QObject* parent = nullptr);
|
||||
|
||||
void initOpenGL();
|
||||
void deinitOpenGL();
|
||||
|
||||
void changeWindowTitle(char* title);
|
||||
|
||||
// to be called from the UI thread
|
||||
@ -61,11 +60,13 @@ public:
|
||||
bool emuIsRunning();
|
||||
bool emuIsActive();
|
||||
|
||||
void initContext();
|
||||
void deinitContext();
|
||||
|
||||
int FrontBuffer = 0;
|
||||
QMutex FrontBufferLock;
|
||||
|
||||
GLsync FrontBufferReverseSyncs[2] = {nullptr, nullptr};
|
||||
GLsync FrontBufferSyncs[2] = {nullptr, nullptr};
|
||||
void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix);
|
||||
|
||||
signals:
|
||||
void windowUpdate();
|
||||
@ -86,13 +87,31 @@ signals:
|
||||
void swapScreensToggle();
|
||||
|
||||
private:
|
||||
volatile int EmuStatus;
|
||||
void drawScreenGL();
|
||||
void initOpenGL();
|
||||
void deinitOpenGL();
|
||||
|
||||
std::atomic<int> EmuStatus;
|
||||
int PrevEmuStatus;
|
||||
int EmuRunning;
|
||||
int EmuPause;
|
||||
|
||||
QOffscreenSurface* oglSurface;
|
||||
QOpenGLContext* oglContext;
|
||||
std::atomic<int> ContextRequest = 0;
|
||||
|
||||
GL::Context* oglContext = nullptr;
|
||||
GLuint screenVertexBuffer, screenVertexArray;
|
||||
GLuint screenTexture;
|
||||
GLuint screenShaderProgram[3];
|
||||
GLuint screenShaderTransformULoc, screenShaderScreenSizeULoc;
|
||||
|
||||
QMutex screenSettingsLock;
|
||||
WindowInfo windowInfo;
|
||||
float screenMatrix[Frontend::MaxScreenTransforms][6];
|
||||
int screenKind[Frontend::MaxScreenTransforms];
|
||||
int numScreens;
|
||||
bool filter;
|
||||
|
||||
int lastScreenWidth = -1, lastScreenHeight = -1;
|
||||
};
|
||||
|
||||
|
||||
@ -158,7 +177,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class ScreenPanelGL : public QOpenGLWidget, public ScreenHandler, protected QOpenGLFunctions_3_2_Core
|
||||
class ScreenPanelGL : public QWidget, public ScreenHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -166,13 +185,22 @@ public:
|
||||
explicit ScreenPanelGL(QWidget* parent);
|
||||
virtual ~ScreenPanelGL();
|
||||
|
||||
protected:
|
||||
void initializeGL() override;
|
||||
std::optional<WindowInfo> getWindowInfo();
|
||||
|
||||
void paintGL() override;
|
||||
bool createContext();
|
||||
|
||||
GL::Context* getContext() { return glContext.get(); }
|
||||
|
||||
void transferLayout(EmuThread* thread);
|
||||
protected:
|
||||
|
||||
qreal devicePixelRatioFromScreen() const;
|
||||
int scaledWindowWidth() const;
|
||||
int scaledWindowHeight() const;
|
||||
|
||||
QPaintEngine* paintEngine() const override;
|
||||
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void resizeGL(int w, int h) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
@ -180,16 +208,14 @@ protected:
|
||||
|
||||
void tabletEvent(QTabletEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void onScreenLayoutChanged();
|
||||
|
||||
private:
|
||||
void setupScreenLayout();
|
||||
|
||||
QOpenGLShaderProgram* screenShader;
|
||||
GLuint screenVertexBuffer;
|
||||
GLuint screenVertexArray;
|
||||
GLuint screenTexture;
|
||||
std::unique_ptr<GL::Context> glContext;
|
||||
};
|
||||
|
||||
class MelonApplication : public QApplication
|
||||
@ -210,7 +236,7 @@ public:
|
||||
~MainWindow();
|
||||
|
||||
bool hasOGL;
|
||||
QOpenGLContext* getOGLContext();
|
||||
GL::Context* getOGLContext();
|
||||
|
||||
bool preloadROMs(QString filename, QString gbafilename);
|
||||
|
||||
@ -306,6 +332,8 @@ private slots:
|
||||
void onFullscreenToggled();
|
||||
|
||||
private:
|
||||
void closeEvent(QCloseEvent* event);
|
||||
|
||||
QStringList currentROM;
|
||||
QStringList currentGBAROM;
|
||||
QList<QString> recentFileList;
|
||||
|
@ -23,7 +23,6 @@ const char* kScreenVS = R"(#version 140
|
||||
|
||||
uniform vec2 uScreenSize;
|
||||
uniform mat2x3 uTransform;
|
||||
uniform float uScaleFactor;
|
||||
|
||||
in vec2 vPosition;
|
||||
in vec2 vTexcoord;
|
||||
@ -34,9 +33,9 @@ void main()
|
||||
{
|
||||
vec4 fpos;
|
||||
|
||||
fpos.xy = vec3(vPosition, 1.0) * uTransform * uScaleFactor;
|
||||
fpos.xy = vec3(vPosition, 1.0) * uTransform;
|
||||
|
||||
fpos.xy = ((fpos.xy * 2.0) / (uScreenSize * uScaleFactor)) - 1.0;
|
||||
fpos.xy = ((fpos.xy * 2.0) / uScreenSize) - 1.0;
|
||||
fpos.y *= -1;
|
||||
fpos.z = 0.0;
|
||||
fpos.w = 1.0;
|
||||
|
Loading…
Reference in New Issue
Block a user