diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index ae56511da0e..3d9fea73df0 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -62,6 +62,8 @@ jobs: arch: x86_64 - runs-on: macos-12-arm arch: arm64 + - runs-on: windows-2022 + arch: x86_64 continue-on-error: true env: BUILDTYPE: ${{github.ref == 'refs/heads/main' && 'Release' || 'Debug'}} @@ -72,21 +74,24 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 with: - submodules: recursive fetch-depth: 0 + - name: Setup submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c core.longpaths=true -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive || true + - name: Get OS Architecture + if: runner.os == 'MacOS' || runner.os == 'Linux' run: uname -m - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies macOS - if: runner.os == 'macOS' + - name: Install dependencies (MacOS) + if: runner.os == 'MacOS' env: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 @@ -98,7 +103,7 @@ jobs: brew list glfw || brew install glfw brew list libuv || brew install libuv - - name: Install dependencies Linux + - name: Install dependencies (Linux) if: runner.os == 'Linux' env: DEBIAN_FRONTEND: noninteractive @@ -118,63 +123,102 @@ jobs: libc++abi-9-dev /usr/sbin/update-ccache-symlinks + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: npm ci run: npm ci --ignore-scripts - - name: Prepare ccache - run: ccache --clear --set-config cache_dir=~/.ccache + - name: Set up msvc dev cmd (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 - - name: Cache ccache - uses: actions/cache@v3 - env: - cache-name: ccache-v1 + - name: Update ccache (Windows) + if: runner.os == 'Windows' + + run: | + choco.exe upgrade ccache + ccache.exe --version + echo "CCACHE_CONFIGPATH=C:/Users/runneradmin/AppData/Roaming/ccache/ccache.conf" >> $GITHUB_ENV + + - name: Set up ccache + uses: hendrikmuhs/ccache-action@v1 with: - path: ~/.ccache key: ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }}-${{ github.sha }}-${{ github.head_ref }} restore-keys: | ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }}-${{ github.sha }} ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }} ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }} - - name: Clear ccache statistics - run: | - ccache --zero-stats --set-config cache_dir=~/.ccache - ccache --max-size=2G --set-config cache_dir=~/.ccache - ccache --show-stats --set-config cache_dir=~/.ccache - - - name: CMake + - name: Configure maplibre-gl-native (MacOS) if: runner.os == 'MacOS' run: | - cmake . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - - name: CMake + - name: Configure maplibre-gl-native (Linux) if: runner.os == 'Linux' run: | - cmake . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_C_COMPILER=gcc-10 \ + -DCMAKE_CXX_COMPILER=g++-10 + + - name: Configure maplibre-gl-native (Windows) + if: runner.os == 'Windows' + run: | + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache.exe - - name: Build + - name: Build maplibre-gl-native (MacOS/Linux) + if: runner.os == 'MacOS' || runner.os == 'Linux' run: | cmake --build build -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null) + - name: Build maplibre-gl-native (Windows) + if: runner.os == 'Windows' + shell: cmd + run: | + cmake --build build + - name: Run render tests on macOS if: runner.os == 'macOS' run: set -o pipefail && ./build/mbgl-render-test-runner --manifestPath metrics/macos-xcode11-release-style.json - - name: Upload render test artifacts + - name: Upload render test artifacts (MacOS) + if: runner.os == 'MacOS' uses: actions/upload-artifact@v3 - if: always() with: name: render-query-test-results path: metrics/macos-xcode11-release-style.html - - name: Test + - name: Test (Linux) if: runner.os == 'Linux' run: xvfb-run --auto-servernum npm test - - name: Test - if: runner.os == 'macOS' + - name: Test (MacOS) + if: runner.os == 'MacOS' run: npm test + - name: Test (Windows) + if: runner.os == 'Windows' + shell: pwsh + env: + LIBGL_ALWAYS_SOFTWARE: true + GALLIUM_DRIVER: softpipe + run: | + Invoke-WebRequest https://github.com/pal1000/mesa-dist-win/releases/download/22.3.5/mesa3d-22.3.5-release-msvc.7z -OutFile mesa3d.7z + & 'C:\Program Files\7-Zip\7z.exe' e -olib\node-v108 .\mesa3d.7z x64\opengl32.dll x64\libgallium_wgl.dll x64\libGLESv2.dll x64\libglapi.dll + npm test + # On PRs make sure that the npm package can be packaged. - name: Pack if: github.ref != 'refs/heads/main' diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index 85a5872fd99..6e9acd32613 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -59,6 +59,8 @@ jobs: arch: x86_64 - runs-on: macos-12-arm arch: arm64 + - runs-on: windows-2022 + arch: x86_64 needs: bump_version continue-on-error: true env: @@ -70,24 +72,27 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 with: - submodules: recursive fetch-depth: 0 - name: Get Latest Version run: git pull + - name: Setup submodules + shell: bash + run: | + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c core.longpaths=true -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 || true + - name: Get OS Architecture + if: runner.os == 'MacOS' || runner.os == 'Linux' run: uname -m - - name: Setup node - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Install dependencies macOS - if: runner.os == 'macOS' + - name: Install dependencies (MacOS) + if: runner.os == 'MacOS' env: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 @@ -99,7 +104,7 @@ jobs: brew list glfw || brew install glfw brew list libuv || brew install libuv - - name: Install dependencies Linux + - name: Install dependencies (Linux) if: runner.os == 'Linux' env: DEBIAN_FRONTEND: noninteractive @@ -119,68 +124,70 @@ jobs: libc++abi-9-dev /usr/sbin/update-ccache-symlinks + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: npm ci run: npm ci --ignore-scripts - - name: Prepare ccache - run: ccache --clear --set-config cache_dir=~/.ccache + - name: Set up msvc dev cmd (Windows) + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 - - name: Cache ccache - uses: actions/cache@v3 - env: - cache-name: ccache-v1 + - name: Update ccache (Windows) + if: runner.os == 'Windows' + run: | + choco.exe upgrade ccache + ccache.exe --version + echo "CCACHE_CONFIGPATH=C:/Users/runneradmin/AppData/Roaming/ccache/ccache.conf" >> $GITHUB_ENV + + - name: Set up ccache + uses: hendrikmuhs/ccache-action@v1 with: - path: ~/.ccache key: ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }}-${{ github.sha }}-${{ github.head_ref }} restore-keys: | ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }}-${{ github.sha }} ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ github.ref }} ${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }} - - name: Clear ccache statistics - run: | - ccache --zero-stats --set-config cache_dir=~/.ccache - ccache --max-size=2G --set-config cache_dir=~/.ccache - ccache --show-stats --set-config cache_dir=~/.ccache - - - name: CMake + - name: Configure maplibre-gl-native (MacOS) if: runner.os == 'MacOS' run: | - cmake . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - - name: CMake + - name: Configure maplibre-gl-native (Linux) if: runner.os == 'Linux' run: | - cmake . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_C_COMPILER=gcc-10 \ + -DCMAKE_CXX_COMPILER=g++-10 + + - name: Configure maplibre-gl-native (Windows) + if: runner.os == 'Windows' + run: | + cmake . -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache.exe - - name: Build + - name: Build maplibre-gl-native (MacOS/Linux) + if: runner.os == 'MacOS' || runner.os == 'Linux' run: | cmake --build build -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null) - #- name: Run render tests on macOS - # if: runner.os == 'macOS' - # run: ./build/mbgl-render-test-runner --manifestPath metrics/macos-xcode11-release-style.json - - #- name: Upload render test artifacts - # uses: actions/upload-artifact@v3 - # if: always() - # with: - # name: render-query-test-results - # path: metrics/macos-xcode11-release-style.html - - #- name: Test - # if: runner.os == 'Linux' - # run: xvfb-run --auto-servernum npm test - - #- name: Test - # if: runner.os == 'macOS' && matrix.arch != 'arm64' - # run: npm test - - # On PRs make sure that the npm package can be packaged. - #- name: Pack - # if: github.ref != 'refs/heads/main' - # run: | - # npm pack --dry-run + - name: Build maplibre-gl-native (Windows) + if: runner.os == 'Windows' + shell: cmd + run: | + cmake --build build - name: Publish X64 Release to Github if: github.ref == 'refs/heads/main' && matrix.arch == 'x86_64' diff --git a/.gitignore b/.gitignore index a752ed2606f..85003020043 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ /platform/android/build /platform/android/MapboxGLAndroidSDK/src/main/assets/sdk_versions/com.mapbox.mapboxsdk /platform/ios/platform/ios/Mapbox.playground/build/ +/platform/windows/vendor/mesa3d/ *.code-workspace .DS_Store diff --git a/.gitmodules b/.gitmodules index a50231c5e47..e91d2c31721 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,3 +52,6 @@ [submodule "docs/doxygen/doxygen-awesome-css"] path = docs/doxygen/doxygen-awesome-css url = https://github.com/jothepro/doxygen-awesome-css.git +[submodule "platform/windows/vendor/vcpkg"] + path = platform/windows/vendor/vcpkg + url = https://github.com/microsoft/vcpkg.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c58a0b8fe2..713508f77d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,17 @@ option(MBGL_WITH_SANITIZER "Use [address|thread|undefined] here" OFF) option(MBGL_WITH_RTTI "Compile with runtime type information" OFF) option(MBGL_WITH_OPENGL "Build with OpenGL renderer" ON) option(MBGL_WITH_EGL "Build with EGL renderer" OFF) +option(MBGL_WITH_OSMESA "Build with OSMesa (Software) renderer" OFF) option(MBGL_WITH_WERROR "Make all compilation warnings errors" ON) if (MBGL_WITH_QT AND NOT CMAKE_OSX_DEPLOYMENT_TARGET) set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0) endif() +if(WIN32 AND NOT MBGL_WITH_QT) + set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/platform/windows/custom-toolchain.cmake) +endif() + project("Mapbox GL Native" LANGUAGES CXX C) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -1097,6 +1102,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL Linux) include(${PROJECT_SOURCE_DIR}/platform/linux/linux.cmake) elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) include(${PROJECT_SOURCE_DIR}/platform/macos/macos.cmake) +elseif(WIN32) + include(${PROJECT_SOURCE_DIR}/platform/windows/windows.cmake) else() message(FATAL_ERROR "Unsupported target platform: " ${CMAKE_SYSTEM_NAME}) endif() diff --git a/README.md b/README.md index 9504ee1fb30..5f595f096b8 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,10 @@ The documentation of MapLibre GL Native is a work in progress. To get an archite - [⭐️ iOS](platform/ios/platform/ios/README.md) - [GLFW](platform/glfw) - [Linux](platform/linux/README.md) -- [macOS](platform/ios/platform/macos/README.md) - [Node.js](platform/node/README.md) - [Qt](platform/qt/README.md) +- [Windows](platform/windows/README.md) +- [macOS](platform/ios/platform/macos/README.md) Platforms with a ⭐️ are **MapLibre Core Projects** and have a substantial amount of financial resources allocated to them. Learn about the different [project tiers](https://github.com/maplibre/maplibre/blob/main/PROJECT_TIERS.md#project-tiers). diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 842a91e7292..bda272e451c 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -32,6 +32,22 @@ target_link_libraries( PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core ) +if(WIN32) + find_package(libuv REQUIRED) + + target_link_libraries( + mbgl-cache PRIVATE uv_a + ) + + target_link_libraries( + mbgl-offline PRIVATE uv_a + ) + + target_link_libraries( + mbgl-render PRIVATE uv_a + ) +endif() + install(TARGETS mbgl-offline mbgl-render RUNTIME DESTINATION bin) # FIXME: CI must have a valid token diff --git a/expression-test/expression_test_parser.cpp b/expression-test/expression_test_parser.cpp index ff0cc10ba49..c2c61b3fad1 100644 --- a/expression-test/expression_test_parser.cpp +++ b/expression-test/expression_test_parser.cpp @@ -1,5 +1,9 @@ #include "expression_test_parser.hpp" +#if defined(WIN32) && defined(GetObject) +#undef GetObject +#endif + #include #include #include diff --git a/platform/default/src/mbgl/storage/http_file_source.cpp b/platform/default/src/mbgl/storage/http_file_source.cpp index ac2acd3bee9..e16ed4fd32d 100644 --- a/platform/default/src/mbgl/storage/http_file_source.cpp +++ b/platform/default/src/mbgl/storage/http_file_source.cpp @@ -280,6 +280,11 @@ HTTPRequest::HTTPRequest(HTTPFileSource::Impl* context_, Resource resource_, Fil curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); } +#ifdef WIN32 + // Windows has issues with TLSv1.3, so we limit to TLSv1.2. Should be resolved in a later cURL release + // https://github.com/curl/curl/issues/9431 + handleError(curl_easy_setopt(handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2)); +#endif handleError(curl_easy_setopt(handle, CURLOPT_PRIVATE, this)); handleError(curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error)); handleError(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1)); diff --git a/platform/default/src/mbgl/test/main.cpp b/platform/default/src/mbgl/test/main.cpp index d01cf75ffc1..d6bc14889ac 100644 --- a/platform/default/src/mbgl/test/main.cpp +++ b/platform/default/src/mbgl/test/main.cpp @@ -1,5 +1,9 @@ #include +#ifdef WIN32 +#include +#else #include +#endif #include #include #include @@ -9,7 +13,11 @@ int main(int argc, char *argv[]) { #ifdef WORK_DIRECTORY +#ifdef WIN32 + const int result = _chdir(xstr(WORK_DIRECTORY)); +#else const int result = chdir(xstr(WORK_DIRECTORY)); +#endif if (result != 0) { fprintf(stderr, "failed to change directory: %s\n", strerror(errno)); return errno; diff --git a/platform/default/src/mbgl/util/run_loop.cpp b/platform/default/src/mbgl/util/run_loop.cpp index 6ea999e80b6..8e8eb35052a 100644 --- a/platform/default/src/mbgl/util/run_loop.cpp +++ b/platform/default/src/mbgl/util/run_loop.cpp @@ -162,7 +162,11 @@ void RunLoop::addWatch(int fd, Event event, std::function&& ca watch = watchPtr.get(); impl->watchPoll[fd] = std::move(watchPtr); +#ifdef WIN32 + if (uv_poll_init_socket(impl->loop, &watch->poll, fd)) { +#else if (uv_poll_init(impl->loop, &watch->poll, fd)) { +#endif throw std::runtime_error("Failed to init poll on file descriptor."); } } else { diff --git a/platform/glfw/CMakeLists.txt b/platform/glfw/CMakeLists.txt index d2eeac92535..1b4d8a8e23b 100644 --- a/platform/glfw/CMakeLists.txt +++ b/platform/glfw/CMakeLists.txt @@ -1,7 +1,18 @@ find_package(OpenGL REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_search_module(GLFW glfw3 REQUIRED) +if(WIN32) + if(MBGL_WITH_OSMESA) + message(WARNING "mbgl-glfw does not work with -DMBGL_WITH_OSMESA=ON. If you want to build this target, don't use this option.") + return() + endif() + + find_package(glfw3 REQUIRED) + find_package(libuv REQUIRED) +else() + find_package(PkgConfig REQUIRED) + + pkg_search_module(GLFW glfw3 REQUIRED) +endif() add_executable( mbgl-glfw @@ -50,10 +61,32 @@ target_link_libraries( PRIVATE $<$:-L${GLFW_LIBRARY_DIRS}> ) +if(WIN32) + target_compile_definitions( + mbgl-glfw + PRIVATE + _USE_MATH_DEFINES + NOMINMAX + CURL_STATICLIB + ) + + target_link_libraries( + mbgl-glfw + PRIVATE + glfw + uv_a + ) +else() + target_link_libraries( + mbgl-glfw + PRIVATE + ${GLFW_LIBRARIES} + ) +endif() + target_link_libraries( mbgl-glfw PRIVATE - ${GLFW_LIBRARIES} Mapbox::Base::Extras::args Mapbox::Base::Extras::filesystem Mapbox::Base::Extras::rapidjson @@ -62,7 +95,7 @@ target_link_libraries( Mapbox::Base::cheap-ruler-cpp ) -if(MBGL_WITH_OPENGL) +if(NOT WIN32 AND MBGL_WITH_OPENGL) target_link_libraries( mbgl-glfw PRIVATE OpenGL::GL diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index e311e598198..e2ebcd5f3f3 100644 --- a/platform/glfw/main.cpp +++ b/platform/glfw/main.cpp @@ -85,11 +85,15 @@ int main(int argc, char *argv[]) { const std::string cacheDB = cacheDBValue ? args::get(cacheDBValue) : "/tmp/mbgl-cache.db"; // sigint handling +#ifdef WIN32 + signal(SIGINT, &quit_handler); +#else struct sigaction sigIntHandler; sigIntHandler.sa_handler = quit_handler; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, nullptr); +#endif if (benchmark) { mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); diff --git a/platform/node/CMakeLists.txt b/platform/node/CMakeLists.txt index 0e41189ea17..ce58a72e3e4 100644 --- a/platform/node/CMakeLists.txt +++ b/platform/node/CMakeLists.txt @@ -12,8 +12,13 @@ add_node_module( 48 51 ) -find_package(PkgConfig REQUIRED) -pkg_search_module(LIBUV libuv REQUIRED) + +if(WIN32) + find_package(LIBUV REQUIRED) +else() + find_package(PkgConfig REQUIRED) + pkg_search_module(LIBUV libuv REQUIRED) +endif() add_library(mbgl-node-loop STATIC) diff --git a/platform/node/cmake/module.cmake b/platform/node/cmake/module.cmake index 6cbc24db054..414ba29dba0 100644 --- a/platform/node/cmake/module.cmake +++ b/platform/node/cmake/module.cmake @@ -120,6 +120,22 @@ function(add_node_module NAME) ) endif() + if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_ARCH x64) + else() + set(_ARCH x86) + endif() + + # Download the win-${_ARCH} libraries if we are compiling on Windows and don't have them yet + if(NOT EXISTS "${_CACHE_DIR}/lib/node/${_NODE_VERSION}/win-${_ARCH}/node.lib") + _node_module_download( + "win-${_ARCH} library for Node ${_NODE_VERSION}" + "https://nodejs.org/download/release/${_NODE_VERSION}/win-${_ARCH}/node.lib" + "${_CACHE_DIR}/lib/node/${_NODE_VERSION}/win-${_ARCH}/node.lib" + ) + endif() + endif() # Generate the library set(_TARGET "${NAME}.abi-${_ABI}") @@ -162,6 +178,12 @@ function(add_node_module NAME) target_link_libraries(${_TARGET} PRIVATE ${NAME} mbgl-compiler-options) + if(WIN32) + target_include_directories(${_TARGET} SYSTEM PRIVATE "${PROJECT_SOURCE_DIR}/platform/windows/include") + target_compile_definitions(${_TARGET} PRIVATE _USE_MATH_DEFINES NOMINMAX) + target_link_libraries(${_TARGET} PRIVATE "${_CACHE_DIR}/lib/node/${_NODE_VERSION}/win-${_ARCH}/node.lib") + endif() + if(APPLE) # Ensures that linked symbols are loaded when the module is loaded instead of causing # unresolved symbol errors later during runtime. @@ -171,6 +193,8 @@ function(add_node_module NAME) target_compile_definitions(${_TARGET} PRIVATE "_DARWIN_USE_64_BIT_INODE=1" ) + elseif(WIN32) + # Do nothing here else() # Ensures that linked symbols are loaded when the module is loaded instead of causing # unresolved symbol errors later during runtime. @@ -187,6 +211,22 @@ function(add_node_module NAME) POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "${_OUTPUT_PATH}" ) + + if(WIN32) + if(MBGL_WITH_OSMESA) + get_filename_component(_OUTPUT_PATH "${_OUTPUT_PATH}" DIRECTORY "${CMAKE_CURRENT_SOURCE_PATH}") + + add_custom_command( + TARGET ${_TARGET} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/platform/windows/vendor/mesa3d/${_ARCH}/libglapi.dll" "${_OUTPUT_PATH}" + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/platform/windows/vendor/mesa3d/${_ARCH}/libGLESv2.dll" "${_OUTPUT_PATH}" + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/platform/windows/vendor/mesa3d/${_ARCH}/osmesa.dll" "${_OUTPUT_PATH}" + ) + endif() + + unset(_ARCH) + endif() endforeach() # Add a target that builds all Node ABIs. diff --git a/platform/windows/FindOSMesa.cmake b/platform/windows/FindOSMesa.cmake new file mode 100644 index 00000000000..66f8eca4033 --- /dev/null +++ b/platform/windows/FindOSMesa.cmake @@ -0,0 +1,65 @@ +# Standard FIND_PACKAGE module for OSMesa, sets the following variables: +# - OSMesa_FOUND +# - OSMesa_INCLUDE_DIRS (only if OSMesa_FOUND) +# - OSMesa_LIBRARIES (only if OSMesa_FOUND) + +# Try to find the header +find_path(OSMesa_INCLUDE_DIR NAMES GL/osmesa.h) + +get_filename_component(OSMesa_DIR ${OSMesa_INCLUDE_DIR}/../ ABSOLUTE) + +# Try to find the library +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_ARCH x64) +else() + set(_ARCH x86) +endif() + +find_library(OSMesa_osmesa_LIBRARY NAMES osmesa PATHS ${OSMesa_DIR}/lib PATH_SUFFIXES ${_ARCH} NO_DEFAULT_PATH) +find_library(OSMesa_libGLESv2_LIBRARY NAMES libGLESv2 PATHS ${OSMesa_DIR}/lib PATH_SUFFIXES ${_ARCH} NO_DEFAULT_PATH) + +find_file(OSMesa_osmesa_LIBRARY_DLL NAMES osmesa.dll PATHS ${OSMesa_DIR} PATH_SUFFIXES ${_ARCH} NO_DEFAULT_PATH) +find_file(OSMesa_libGLESv2_LIBRARY_DLL NAMES libGLESv2.dll PATHS ${OSMesa_DIR} PATH_SUFFIXES ${_ARCH} NO_DEFAULT_PATH) + +unset(_ARCH) + +# Handle the QUIETLY/REQUIRED arguments, set OSMesa_FOUND if all variables are +# found +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OSMesa + REQUIRED_VARS + OSMesa_osmesa_LIBRARY + OSMesa_libGLESv2_LIBRARY + OSMesa_INCLUDE_DIR) + +# Hide internal variables +mark_as_advanced(OSMesa_INCLUDE_DIR OSMesa_osmesa_LIBRARY OSMesa_libGLESv2_LIBRARY) + +# Set standard variables +if(OSMesa_FOUND) + set(OSMesa_INCLUDE_DIRS "${OSMesa_INCLUDE_DIR}") + set(OSMesa_LIBRARIES + "${OSMesa_osmesa_LIBRARY}" + "${OSMesa_libGLESv2_LIBRARY}" + ) + + add_library(OSMesa::osmesa SHARED IMPORTED) + + set_target_properties( + OSMesa::osmesa + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${OSMesa_INCLUDE_DIRS} + IMPORTED_IMPLIB ${OSMesa_osmesa_LIBRARY} + IMPORTED_LOCATION ${OSMesa_osmesa_LIBRARY_DLL} + ) + + add_library(OSMesa::libGLESv2 SHARED IMPORTED) + + set_target_properties( + OSMesa::libGLESv2 + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${OSMesa_INCLUDE_DIRS} + IMPORTED_IMPLIB ${OSMesa_libGLESv2_LIBRARY} + IMPORTED_LOCATION ${OSMesa_libGLESv2_LIBRARY_DLL} + ) +endif() diff --git a/platform/windows/Get-VendorPackages.ps1 b/platform/windows/Get-VendorPackages.ps1 new file mode 100644 index 00000000000..c37a64d1d7c --- /dev/null +++ b/platform/windows/Get-VendorPackages.ps1 @@ -0,0 +1,44 @@ +param( + [Parameter(Mandatory=$true)][string]$Triplet, + [Parameter(Mandatory=$true)][string]$Renderer +) + +Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent) + +$vcpkg_temp_dir = '***' + +foreach($letter in [byte][char]'Z'..[byte][char]'A') +{ + $vcpkg_temp_dir = '{0}:' -f [char]$letter + + if(-not (Test-Path $vcpkg_temp_dir)) + { + & subst $vcpkg_temp_dir ([System.IO.Path]::Combine($PWD.Path, 'vendor', 'vcpkg')) + break + } +} + +switch($Renderer) +{ + 'EGL' { $renderer_packages = @('egl', 'opengl-registry'); break } + 'OSMesa' { $renderer_packages = @(''); break } + 'OpenGL' { $renderer_packages = @('opengl-registry'); break } +} + +if(-not (Test-Path "$vcpkg_temp_dir\vcpkg.exe")) +{ + & "$vcpkg_temp_dir\bootstrap-vcpkg.bat" +} + +& "$vcpkg_temp_dir\vcpkg.exe" --disable-metrics --overlay-triplets=$([System.IO.Path]::Combine($PWD.Path, 'vendor', 'vcpkg-custom-triplets')) --triplet=$($Triplet) --clean-after-build install curl dlfcn-win32 glfw3 icu libuv libjpeg-turbo libpng $($renderer_packages) + +subst $vcpkg_temp_dir /D + +if($Renderer -eq 'OSMesa' -and -not (Test-Path ([System.IO.Path]::Combine($PWD.Path, 'vendor', 'mesa3d')))) +{ + New-Item -Name temp -Type Directory | Out-Null + Invoke-WebRequest https://www.7-zip.org/a/7zr.exe -OutFile ([System.IO.Path]::Combine($PWD.Path, 'temp', '7zr.exe')) + (Invoke-WebRequest https://api.github.com/repos/pal1000/mesa-dist-win/releases | ConvertFrom-Json)[0].assets | Where-Object name -match 'mesa3d-.+-(release|development-pack)-msvc\.7z' | foreach { Invoke-WebRequest $_.browser_download_url -OutFile ([System.IO.Path]::Combine($PWD.Path, 'temp', $_.name)) } + Get-ChildItem 'temp\*.7z' | foreach { .\temp\7zr.exe x -ovendor\mesa3d $_.FullName } + Remove-Item temp -Recurse +} diff --git a/platform/windows/README.md b/platform/windows/README.md new file mode 100644 index 00000000000..4452b390b9a --- /dev/null +++ b/platform/windows/README.md @@ -0,0 +1,183 @@ +# Windows + +This is a port to add Windows support on other targets (Node, GLFW, etc). + +The files produced by building mbgl-core target can be reused as libraries in other projects. + +## Prerequisites + +The Windows port, for while, relies on `Microsoft Visual Studio` to build Maplibre GL Native, either using `Ninja` or `Microsoft Visual Studio`. The build was tested with `Microsoft Visual Studio 2022 Community Edition`. Other 2022 editions might work as well. Earlier versions are not guaranteed to work, but `Microsoft Visual Studio 2019` might work. + +To install the required Visual Studio components, open Visual Studio Installer and check `Desktop Development with C++` option. Make sure `C++ CMake tools for Windows` is selected in the right pane. If `git` is not already installed, select `Git for Windows` option in `Individual Components`. When Visual Studio finishes the install process, everything is ready to start. + +## Downloading sources + +Open `x64 Native Tools Command Prompt for VS 2022` and then clone the repository: + +```cmd +git clone --recurse-submodules -j8 https://github.com/maplibre/maplibre-gl-native.git +cd maplibre-gl-native +``` + +## Configuring + +Configure the build with the following command: + +```cmd +cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release +``` + +It will take some time to build and install all components on which Maplibre depends. + +## Alternative configure commands + +To configure build with EGL support (ANGLE libraries will be build), use the following command: + +```cmd +cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DMBGL_WITH_EGL=ON +``` + +To configure build with OSMesa (software rendering), use the following command: + +``` +cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DMBGL_WITH_OSMESA=ON +``` + +**WARNING:** as OSMesa doesn't have static libraries, it's necessary to copy `libglapi.dll`, `libGLESv2.dll` and `osmesa.dll` from `platform\windows\vendor\mesa3d\` to executable/dll directory you want to use, otherwise it won't run. + +## Building + +Finally, build the project with the following command: + +```cmd +cmake --build build +``` + +## Building with Microsoft Visual Studio + +Just omit the `-G Ninja` option from the configure command: + +```cmd +cmake . -B build +``` + +The same can be done with alternative configure commands: + +```cmd +cmake . -B build -DMBGL_WITH_EGL=ON +``` +or +```cmd +cmake . -B build -DMBGL_WITH_OSMESA=ON +``` + +Once configure is done, open the file `build\Mapbox GL Native.sln`. Build the target `ALL_BUILD` to build all targets, or pick a specific target. Don't forget to pick a build configuration (`Release`, `RelWithDebInfo`, `MinSizeRel` or `Debug`), otherwise the project will be built with default configuration (`Debug`). + +## Testing + +If all went well and target `mbgl-render` or `ALL_BUILD` was chosen, there should now be a `maplibre-gl-native\build\bin\mbgl-render.exe` binary that you can run to generate map tile images. To test that it is working properly, run the following command. + +```cmd +.\build\bin\mbgl-render.exe --style https://raw.githubusercontent.com/maplibre/demotiles/gh-pages/style.json --output out.png +``` + +This should produce an `out.png` map tile image with the default MapLibre styling from [the MapLibre demo](https://maplibre.org/). + +![Sample image of world from mbgl-render command](/misc/sample-maplibre-style-mbgl-render-out.png) + +### Using your own style/tiles + +You can also use the `mbgl-render` command to render images from your own style or tile set. To do so, you will need a data source and a style JSON file. + +For the purposes of this exercise, you can use the `zurich_switzerland.mbtiles` from [here](https://github.com/acalcutt/tileserver-gl/releases/download/test_data/zurich_switzerland.mbtiles), and the following `style.json` file. + +```json +{ + "version": 8, + "name": "Test style", + "center": [ + 8.54806714892635, + 47.37180823552663 + ], + "sources": { + "test": { + "type": "vector", + "url": "mbtiles:///path/to/zurich_switzerland.mbtiles" + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "hsl(47, 26%, 88%)" + } + }, + { + "id": "water", + "type": "fill", + "source": "test", + "source-layer": "water", + "filter": [ + "==", + "$type", + "Polygon" + ], + "paint": { + "fill-color": "hsl(205, 56%, 73%)" + } + }, + { + "id": "admin_country", + "type": "line", + "source": "test", + "source-layer": "boundary", + "filter": [ + "all", + [ + "<=", + "admin_level", + 2 + ], + [ + "==", + "$type", + "LineString" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsla(0, 8%, 22%, 0.51)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 3, + 0.5 + ], + [ + 22, + 15 + ] + ] + } + } + } + ] +} +``` + +Note that this style is totally inadequate for any real use beyond testing your custom setup. Don't forget to replace the source URL `"mbtiles:///path/to/zurich_switzerland.mbtiles"` with the actual path to your mbtiles file. + +From your `maplibre-gl-native/` dir, run the following command. + +```cmd +.\build\bin\mbgl-render --style path\to\style.json --output out.png +``` + +This should produce an `out.png` image in your current directory with a barebones image of the world. + +![Sample image of world from mbgl-render command](/misc/sample-barebones-mbgl-render-out.png) diff --git a/platform/windows/custom-toolchain.cmake b/platform/windows/custom-toolchain.cmake new file mode 100644 index 00000000000..589cee3bdf1 --- /dev/null +++ b/platform/windows/custom-toolchain.cmake @@ -0,0 +1,7 @@ +if(DEFINED ENV{VCINSTALLDIR}) + set(VCPKG_OVERLAY_TRIPLETS ${CMAKE_CURRENT_LIST_DIR}/vendor/vcpkg-custom-triplets) + set(VCPKG_DEFAULT_TRIPLET $ENV{VSCMD_ARG_TGT_ARCH}-windows) + set(VCPKG_TARGET_TRIPLET $ENV{VSCMD_ARG_TGT_ARCH}-windows) + + include(${CMAKE_CURRENT_LIST_DIR}/vendor/vcpkg/scripts/buildsystems/vcpkg.cmake) +endif() diff --git a/platform/windows/include/gl_functions_wgl.h b/platform/windows/include/gl_functions_wgl.h new file mode 100644 index 00000000000..dd8bc4fe413 --- /dev/null +++ b/platform/windows/include/gl_functions_wgl.h @@ -0,0 +1,509 @@ +#pragma once + +#include + +#ifndef _gl_functions_wgl_ +#define _gl_functions_wgl_ 1 + +#ifndef WINAPI +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif +#endif + +#define GL_GLEXT_PROTOTYPES + +#ifdef MBGL_USE_GLES2 +#include +#include +#else +#include +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PFNGLACTIVETEXTUREPROC wgl_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC wgl_glAttachShader = NULL; +PFNGLBINDATTRIBLOCATIONPROC wgl_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC wgl_glBindBuffer = NULL; +PFNGLBINDFRAMEBUFFERPROC wgl_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC wgl_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC wgl_glBindTexture = NULL; +PFNGLBLENDCOLORPROC wgl_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC wgl_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC wgl_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC wgl_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC wgl_glBlendFuncSeparate = NULL; +PFNGLBUFFERDATAPROC wgl_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC wgl_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC wgl_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC wgl_glClear = NULL; +PFNGLCLEARCOLORPROC wgl_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC wgl_glClearDepthf = NULL; +PFNGLCLEARSTENCILPROC wgl_glClearStencil = NULL; +PFNGLCOLORMASKPROC wgl_glColorMask = NULL; +PFNGLCOMPILESHADERPROC wgl_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC wgl_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC wgl_glCompressedTexSubImage2D = NULL; +PFNGLCOPYTEXIMAGE2DPROC wgl_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC wgl_glCopyTexSubImage2D = NULL; +PFNGLCREATEPROGRAMPROC wgl_glCreateProgram = NULL; +PFNGLCREATESHADERPROC wgl_glCreateShader = NULL; +PFNGLCULLFACEPROC wgl_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC wgl_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC wgl_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC wgl_glDeleteProgram = NULL; +PFNGLDELETERENDERBUFFERSPROC wgl_glDeleteRenderbuffers = NULL; +PFNGLDELETESHADERPROC wgl_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC wgl_glDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC wgl_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC wgl_glDepthMask = NULL; +PFNGLDEPTHRANGEFPROC wgl_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC wgl_glDetachShader = NULL; +PFNGLDISABLEPROC wgl_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC wgl_glDisableVertexAttribArray = NULL; +PFNGLDRAWARRAYSPROC wgl_glDrawArrays = NULL; +PFNGLDRAWELEMENTSPROC wgl_glDrawElements = NULL; +PFNGLENABLEPROC wgl_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC wgl_glEnableVertexAttribArray = NULL; +PFNGLFINISHPROC wgl_glFinish = NULL; +PFNGLFLUSHPROC wgl_glFlush = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC wgl_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC wgl_glFramebufferTexture2D = NULL; +PFNGLFRONTFACEPROC wgl_glFrontFace = NULL; +PFNGLGENBUFFERSPROC wgl_glGenBuffers = NULL; +PFNGLGENERATEMIPMAPPROC wgl_glGenerateMipmap = NULL; +PFNGLGENFRAMEBUFFERSPROC wgl_glGenFramebuffers = NULL; +PFNGLGENRENDERBUFFERSPROC wgl_glGenRenderbuffers = NULL; +PFNGLGENTEXTURESPROC wgl_glGenTextures = NULL; +PFNGLGETACTIVEATTRIBPROC wgl_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC wgl_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC wgl_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC wgl_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC wgl_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC wgl_glGetBufferParameteriv = NULL; +PFNGLGETERRORPROC wgl_glGetError = NULL; +PFNGLGETFLOATVPROC wgl_glGetFloatv = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC wgl_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGERVPROC wgl_glGetIntegerv = NULL; +PFNGLGETPROGRAMINFOLOGPROC wgl_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC wgl_glGetProgramiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC wgl_glGetRenderbufferParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC wgl_glGetShaderInfoLog = NULL; +PFNGLGETSHADERIVPROC wgl_glGetShaderiv = NULL; +PFNGLGETSHADERSOURCEPROC wgl_glGetShaderSource = NULL; +PFNGLGETSTRINGPROC wgl_glGetString = NULL; +PFNGLGETTEXPARAMETERFVPROC wgl_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC wgl_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMFVPROC wgl_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC wgl_glGetUniformiv = NULL; +PFNGLGETUNIFORMLOCATIONPROC wgl_glGetUniformLocation = NULL; +PFNGLGETVERTEXATTRIBFVPROC wgl_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC wgl_glGetVertexAttribiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC wgl_glGetVertexAttribPointerv = NULL; +PFNGLHINTPROC wgl_glHint = NULL; +PFNGLISBUFFERPROC wgl_glIsBuffer = NULL; +PFNGLISENABLEDPROC wgl_glIsEnabled = NULL; +PFNGLISFRAMEBUFFERPROC wgl_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC wgl_glIsProgram = NULL; +PFNGLISRENDERBUFFERPROC wgl_glIsRenderbuffer = NULL; +PFNGLISSHADERPROC wgl_glIsShader = NULL; +PFNGLISTEXTUREPROC wgl_glIsTexture = NULL; +PFNGLLINEWIDTHPROC wgl_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC wgl_glLinkProgram = NULL; +PFNGLPIXELSTOREIPROC wgl_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC wgl_glPolygonOffset = NULL; +PFNGLREADPIXELSPROC wgl_glReadPixels = NULL; +PFNGLRENDERBUFFERSTORAGEPROC wgl_glRenderbufferStorage = NULL; +PFNGLSAMPLECOVERAGEPROC wgl_glSampleCoverage = NULL; +PFNGLSCISSORPROC wgl_glScissor = NULL; +PFNGLSHADERSOURCEPROC wgl_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC wgl_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC wgl_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC wgl_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC wgl_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC wgl_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC wgl_glStencilOpSeparate = NULL; +PFNGLTEXIMAGE2DPROC wgl_glTexImage2D = NULL; +PFNGLTEXPARAMETERFPROC wgl_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC wgl_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC wgl_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC wgl_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE2DPROC wgl_glTexSubImage2D = NULL; +PFNGLUNIFORM1FPROC wgl_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC wgl_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC wgl_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC wgl_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC wgl_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC wgl_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC wgl_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC wgl_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC wgl_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC wgl_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC wgl_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC wgl_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC wgl_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC wgl_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC wgl_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC wgl_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC wgl_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC wgl_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC wgl_glUniformMatrix4fv = NULL; +PFNGLUSEPROGRAMPROC wgl_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC wgl_glValidateProgram = NULL; +PFNGLVERTEXATTRIB1FPROC wgl_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC wgl_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC wgl_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC wgl_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC wgl_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC wgl_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC wgl_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC wgl_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC wgl_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC wgl_glViewport = NULL; + +PFNWGLCHOOSEPIXELFORMATARBPROC wgl_wglChoosePixelFormatARB = NULL; +PFNWGLCREATECONTEXTATTRIBSARBPROC wgl_wglCreateContextAttribsARB = NULL; +PFNWGLGETEXTENSIONSSTRINGARBPROC wgl_wglGetExtensionsStringARB = NULL; +PFNWGLGETEXTENSIONSSTRINGEXTPROC wgl_wglGetExtensionsStringEXT = NULL; + +HMODULE opengl32 = NULL; + +typedef PROC (WINAPI * PFNWGLLOADERWGLGETPROCADDRESSPROC) (LPCSTR lpszProc); +PFNWGLLOADERWGLGETPROCADDRESSPROC wgl_wglGetProcAddress = NULL; + +PROC WINAPI wgl_GetProcAddress(LPCSTR procName) { + PROC proc = NULL; + proc = wgl_wglGetProcAddress(procName); + + if (!proc) { + proc = GetProcAddress(opengl32, procName); + } + + return proc; +} + +void loadWGL() { + if(opengl32) { + return; + } + + opengl32 = LoadLibraryA("opengl32.dll"); + wgl_wglGetProcAddress = (PFNWGLLOADERWGLGETPROCADDRESSPROC)GetProcAddress(opengl32, "wglGetProcAddress"); + + wgl_glActiveTexture = (PFNGLACTIVETEXTUREPROC)wgl_GetProcAddress("glActiveTexture"); + wgl_glAttachShader = (PFNGLATTACHSHADERPROC)wgl_GetProcAddress("glAttachShader"); + wgl_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)wgl_GetProcAddress("glBindAttribLocation"); + wgl_glBindBuffer = (PFNGLBINDBUFFERPROC)wgl_GetProcAddress("glBindBuffer"); + wgl_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wgl_GetProcAddress("glBindFramebuffer"); + wgl_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wgl_GetProcAddress("glBindRenderbuffer"); + wgl_glBindTexture = (PFNGLBINDTEXTUREPROC)wgl_GetProcAddress("glBindTexture"); + wgl_glBlendColor = (PFNGLBLENDCOLORPROC)wgl_GetProcAddress("glBlendColor"); + wgl_glBlendEquation = (PFNGLBLENDEQUATIONPROC)wgl_GetProcAddress("glBlendEquation"); + wgl_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)wgl_GetProcAddress("glBlendEquationSeparate"); + wgl_glBlendFunc = (PFNGLBLENDFUNCPROC)wgl_GetProcAddress("glBlendFunc"); + wgl_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)wgl_GetProcAddress("glBlendFuncSeparate"); + wgl_glBufferData = (PFNGLBUFFERDATAPROC)wgl_GetProcAddress("glBufferData"); + wgl_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)wgl_GetProcAddress("glBufferSubData"); + wgl_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wgl_GetProcAddress("glCheckFramebufferStatus"); + wgl_glClear = (PFNGLCLEARPROC)wgl_GetProcAddress("glClear"); + wgl_glClearColor = (PFNGLCLEARCOLORPROC)wgl_GetProcAddress("glClearColor"); + wgl_glClearDepthf = (PFNGLCLEARDEPTHFPROC)wgl_GetProcAddress("glClearDepthf"); + wgl_glClearStencil = (PFNGLCLEARSTENCILPROC)wgl_GetProcAddress("glClearStencil"); + wgl_glColorMask = (PFNGLCOLORMASKPROC)wgl_GetProcAddress("glColorMask"); + wgl_glCompileShader = (PFNGLCOMPILESHADERPROC)wgl_GetProcAddress("glCompileShader"); + wgl_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)wgl_GetProcAddress("glCompressedTexImage2D"); + wgl_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)wgl_GetProcAddress("glCompressedTexSubImage2D"); + wgl_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)wgl_GetProcAddress("glCopyTexImage2D"); + wgl_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)wgl_GetProcAddress("glCopyTexSubImage2D"); + wgl_glCreateProgram = (PFNGLCREATEPROGRAMPROC)wgl_GetProcAddress("glCreateProgram"); + wgl_glCreateShader = (PFNGLCREATESHADERPROC)wgl_GetProcAddress("glCreateShader"); + wgl_glCullFace = (PFNGLCULLFACEPROC)wgl_GetProcAddress("glCullFace"); + wgl_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wgl_GetProcAddress("glDeleteBuffers"); + wgl_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wgl_GetProcAddress("glDeleteFramebuffers"); + wgl_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wgl_GetProcAddress("glDeleteProgram"); + wgl_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wgl_GetProcAddress("glDeleteRenderbuffers"); + wgl_glDeleteShader = (PFNGLDELETESHADERPROC)wgl_GetProcAddress("glDeleteShader"); + wgl_glDeleteTextures = (PFNGLDELETETEXTURESPROC)wgl_GetProcAddress("glDeleteTextures"); + wgl_glDepthFunc = (PFNGLDEPTHFUNCPROC)wgl_GetProcAddress("glDepthFunc"); + wgl_glDepthMask = (PFNGLDEPTHMASKPROC)wgl_GetProcAddress("glDepthMask"); + wgl_glDepthRangef = (PFNGLDEPTHRANGEFPROC)wgl_GetProcAddress("glDepthRangef"); + wgl_glDetachShader = (PFNGLDETACHSHADERPROC)wgl_GetProcAddress("glDetachShader"); + wgl_glDisable = (PFNGLDISABLEPROC)wgl_GetProcAddress("glDisable"); + wgl_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wgl_GetProcAddress("glDisableVertexAttribArray"); + wgl_glDrawArrays = (PFNGLDRAWARRAYSPROC)wgl_GetProcAddress("glDrawArrays"); + wgl_glDrawElements = (PFNGLDRAWELEMENTSPROC)wgl_GetProcAddress("glDrawElements"); + wgl_glEnable = (PFNGLENABLEPROC)wgl_GetProcAddress("glEnable"); + wgl_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wgl_GetProcAddress("glEnableVertexAttribArray"); + wgl_glFinish = (PFNGLFINISHPROC)wgl_GetProcAddress("glFinish"); + wgl_glFlush = (PFNGLFLUSHPROC)wgl_GetProcAddress("glFlush"); + wgl_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wgl_GetProcAddress("glFramebufferRenderbuffer"); + wgl_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wgl_GetProcAddress("glFramebufferTexture2D"); + wgl_glFrontFace = (PFNGLFRONTFACEPROC)wgl_GetProcAddress("glFrontFace"); + wgl_glGenBuffers = (PFNGLGENBUFFERSPROC)wgl_GetProcAddress("glGenBuffers"); + wgl_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)wgl_GetProcAddress("glGenerateMipmap"); + wgl_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wgl_GetProcAddress("glGenFramebuffers"); + wgl_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wgl_GetProcAddress("glGenRenderbuffers"); + wgl_glGenTextures = (PFNGLGENTEXTURESPROC)wgl_GetProcAddress("glGenTextures"); + wgl_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)wgl_GetProcAddress("glGetActiveAttrib"); + wgl_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)wgl_GetProcAddress("glGetActiveUniform"); + wgl_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)wgl_GetProcAddress("glGetAttachedShaders"); + wgl_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)wgl_GetProcAddress("glGetAttribLocation"); + wgl_glGetBooleanv = (PFNGLGETBOOLEANVPROC)wgl_GetProcAddress("glGetBooleanv"); + wgl_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)wgl_GetProcAddress("glGetBufferParameteriv"); + wgl_glGetError = (PFNGLGETERRORPROC)wgl_GetProcAddress("glGetError"); + wgl_glGetFloatv = (PFNGLGETFLOATVPROC)wgl_GetProcAddress("glGetFloatv"); + wgl_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)wgl_GetProcAddress("glGetFramebufferAttachmentParameteriv"); + wgl_glGetIntegerv = (PFNGLGETINTEGERVPROC)wgl_GetProcAddress("glGetIntegerv"); + wgl_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wgl_GetProcAddress("glGetProgramInfoLog"); + wgl_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wgl_GetProcAddress("glGetProgramiv"); + wgl_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)wgl_GetProcAddress("glGetRenderbufferParameteriv"); + wgl_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wgl_GetProcAddress("glGetShaderInfoLog"); + wgl_glGetShaderiv = (PFNGLGETSHADERIVPROC)wgl_GetProcAddress("glGetShaderiv"); + wgl_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)wgl_GetProcAddress("glGetShaderSource"); + wgl_glGetString = (PFNGLGETSTRINGPROC)wgl_GetProcAddress("glGetString"); + wgl_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)wgl_GetProcAddress("glGetTexParameterfv"); + wgl_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)wgl_GetProcAddress("glGetTexParameteriv"); + wgl_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)wgl_GetProcAddress("glGetUniformfv"); + wgl_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)wgl_GetProcAddress("glGetUniformiv"); + wgl_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wgl_GetProcAddress("glGetUniformLocation"); + wgl_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)wgl_GetProcAddress("glGetVertexAttribfv"); + wgl_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)wgl_GetProcAddress("glGetVertexAttribiv"); + wgl_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)wgl_GetProcAddress("glGetVertexAttribPointerv"); + wgl_glHint = (PFNGLHINTPROC)wgl_GetProcAddress("glHint"); + wgl_glIsBuffer = (PFNGLISBUFFERPROC)wgl_GetProcAddress("glIsBuffer"); + wgl_glIsEnabled = (PFNGLISENABLEDPROC)wgl_GetProcAddress("glIsEnabled"); + wgl_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)wgl_GetProcAddress("glIsFramebuffer"); + wgl_glIsProgram = (PFNGLISPROGRAMPROC)wgl_GetProcAddress("glIsProgram"); + wgl_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)wgl_GetProcAddress("glIsRenderbuffer"); + wgl_glIsShader = (PFNGLISSHADERPROC)wgl_GetProcAddress("glIsShader"); + wgl_glIsTexture = (PFNGLISTEXTUREPROC)wgl_GetProcAddress("glIsTexture"); + wgl_glLineWidth = (PFNGLLINEWIDTHPROC)wgl_GetProcAddress("glLineWidth"); + wgl_glLinkProgram = (PFNGLLINKPROGRAMPROC)wgl_GetProcAddress("glLinkProgram"); + wgl_glPixelStorei = (PFNGLPIXELSTOREIPROC)wgl_GetProcAddress("glPixelStorei"); + wgl_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)wgl_GetProcAddress("glPolygonOffset"); + wgl_glReadPixels = (PFNGLREADPIXELSPROC)wgl_GetProcAddress("glReadPixels"); + wgl_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wgl_GetProcAddress("glRenderbufferStorage"); + wgl_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)wgl_GetProcAddress("glSampleCoverage"); + wgl_glScissor = (PFNGLSCISSORPROC)wgl_GetProcAddress("glScissor"); + wgl_glShaderSource = (PFNGLSHADERSOURCEPROC)wgl_GetProcAddress("glShaderSource"); + wgl_glStencilFunc = (PFNGLSTENCILFUNCPROC)wgl_GetProcAddress("glStencilFunc"); + wgl_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)wgl_GetProcAddress("glStencilFuncSeparate"); + wgl_glStencilMask = (PFNGLSTENCILMASKPROC)wgl_GetProcAddress("glStencilMask"); + wgl_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)wgl_GetProcAddress("glStencilMaskSeparate"); + wgl_glStencilOp = (PFNGLSTENCILOPPROC)wgl_GetProcAddress("glStencilOp"); + wgl_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)wgl_GetProcAddress("glStencilOpSeparate"); + wgl_glTexImage2D = (PFNGLTEXIMAGE2DPROC)wgl_GetProcAddress("glTexImage2D"); + wgl_glTexParameterf = (PFNGLTEXPARAMETERFPROC)wgl_GetProcAddress("glTexParameterf"); + wgl_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)wgl_GetProcAddress("glTexParameterfv"); + wgl_glTexParameteri = (PFNGLTEXPARAMETERIPROC)wgl_GetProcAddress("glTexParameteri"); + wgl_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)wgl_GetProcAddress("glTexParameteriv"); + wgl_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)wgl_GetProcAddress("glTexSubImage2D"); + wgl_glUniform1f = (PFNGLUNIFORM1FPROC)wgl_GetProcAddress("glUniform1f"); + wgl_glUniform1fv = (PFNGLUNIFORM1FVPROC)wgl_GetProcAddress("glUniform1fv"); + wgl_glUniform1i = (PFNGLUNIFORM1IPROC)wgl_GetProcAddress("glUniform1i"); + wgl_glUniform1iv = (PFNGLUNIFORM1IVPROC)wgl_GetProcAddress("glUniform1iv"); + wgl_glUniform2f = (PFNGLUNIFORM2FPROC)wgl_GetProcAddress("glUniform2f"); + wgl_glUniform2fv = (PFNGLUNIFORM2FVPROC)wgl_GetProcAddress("glUniform2fv"); + wgl_glUniform2i = (PFNGLUNIFORM2IPROC)wgl_GetProcAddress("glUniform2i"); + wgl_glUniform2iv = (PFNGLUNIFORM2IVPROC)wgl_GetProcAddress("glUniform2iv"); + wgl_glUniform3f = (PFNGLUNIFORM3FPROC)wgl_GetProcAddress("glUniform3f"); + wgl_glUniform3fv = (PFNGLUNIFORM3FVPROC)wgl_GetProcAddress("glUniform3fv"); + wgl_glUniform3i = (PFNGLUNIFORM3IPROC)wgl_GetProcAddress("glUniform3i"); + wgl_glUniform3iv = (PFNGLUNIFORM3IVPROC)wgl_GetProcAddress("glUniform3iv"); + wgl_glUniform4f = (PFNGLUNIFORM4FPROC)wgl_GetProcAddress("glUniform4f"); + wgl_glUniform4fv = (PFNGLUNIFORM4FVPROC)wgl_GetProcAddress("glUniform4fv"); + wgl_glUniform4i = (PFNGLUNIFORM4IPROC)wgl_GetProcAddress("glUniform4i"); + wgl_glUniform4iv = (PFNGLUNIFORM4IVPROC)wgl_GetProcAddress("glUniform4iv"); + wgl_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)wgl_GetProcAddress("glUniformMatrix2fv"); + wgl_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)wgl_GetProcAddress("glUniformMatrix3fv"); + wgl_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wgl_GetProcAddress("glUniformMatrix4fv"); + wgl_glUseProgram = (PFNGLUSEPROGRAMPROC)wgl_GetProcAddress("glUseProgram"); + wgl_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)wgl_GetProcAddress("glValidateProgram"); + wgl_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)wgl_GetProcAddress("glVertexAttrib1f"); + wgl_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)wgl_GetProcAddress("glVertexAttrib1fv"); + wgl_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)wgl_GetProcAddress("glVertexAttrib2f"); + wgl_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)wgl_GetProcAddress("glVertexAttrib2fv"); + wgl_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)wgl_GetProcAddress("glVertexAttrib3f"); + wgl_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)wgl_GetProcAddress("glVertexAttrib3fv"); + wgl_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)wgl_GetProcAddress("glVertexAttrib4f"); + wgl_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)wgl_GetProcAddress("glVertexAttrib4fv"); + wgl_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wgl_GetProcAddress("glVertexAttribPointer"); + wgl_glViewport = (PFNGLVIEWPORTPROC)wgl_GetProcAddress("glViewport"); + + wgl_wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wgl_GetProcAddress("wglChoosePixelFormatARB"); + wgl_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wgl_GetProcAddress("wglCreateContextAttribsARB"); + wgl_wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wgl_GetProcAddress("wglGetExtensionsStringARB"); + wgl_wglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wgl_GetProcAddress("wglGetExtensionsStringEXT"); +} + +#ifdef __cplusplus +} +#endif + +namespace mbgl { +namespace platform { + +void (* const glActiveTexture)(GLenum) = [](GLenum texture) { if (!opengl32) loadWGL(); ::wgl_glActiveTexture(texture); }; +void (* const glAttachShader)(GLuint, GLuint) = [](GLuint program, GLuint shader) { if (!opengl32) loadWGL(); ::wgl_glAttachShader(program, shader); }; +void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar*) = [](GLuint program, GLuint index, const GLchar* name) { if (!opengl32) loadWGL(); ::wgl_glBindAttribLocation(program, index, name); }; +void (* const glBindBuffer)(GLenum, GLuint) = [](GLenum target, GLuint buffer) { if (!opengl32) loadWGL(); ::wgl_glBindBuffer(target, buffer); }; +void (* const glBindFramebuffer)(GLenum, GLuint) = [](GLenum target, GLuint framebuffer) { if (!opengl32) loadWGL(); ::wgl_glBindFramebuffer(target, framebuffer); }; +void (* const glBindRenderbuffer)(GLenum, GLuint) = [](GLenum target, GLuint renderbuffer) { if (!opengl32) loadWGL(); ::wgl_glBindRenderbuffer(target, renderbuffer); }; +void (* const glBindTexture)(GLenum, GLuint) = [](GLenum target, GLuint texture) { if (!opengl32) loadWGL(); ::wgl_glBindTexture(target, texture); }; +void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat) = [](GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { if (!opengl32) loadWGL(); ::wgl_glBlendColor(red, green, blue, alpha); }; +void (* const glBlendEquation)(GLenum) = [](GLenum mode) { if (!opengl32) loadWGL(); ::wgl_glBlendEquation(mode); }; +void (* const glBlendEquationSeparate)(GLenum, GLenum) = [](GLenum modeRGB, GLenum modeAlpha) { if (!opengl32) loadWGL(); ::wgl_glBlendEquationSeparate(modeRGB, modeAlpha); }; +void (* const glBlendFunc)(GLenum, GLenum) = [](GLenum sfactor, GLenum dfactor) { if (!opengl32) loadWGL(); ::wgl_glBlendFunc(sfactor, dfactor); }; +void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum) = [](GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) { if (!opengl32) loadWGL(); ::wgl_glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); }; +void (* const glBufferData)(GLenum, GLsizeiptr, const void*, GLenum) = [](GLenum target, GLsizeiptr size, const void* data, GLenum usage) { if (!opengl32) loadWGL(); ::wgl_glBufferData(target, size, data, usage); }; +void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void*) = [](GLenum target, GLintptr offset, GLsizeiptr size, const void* data) { if (!opengl32) loadWGL(); ::wgl_glBufferSubData(target, offset, size, data); }; +GLenum(* const glCheckFramebufferStatus)(GLenum) = [](GLenum target) { if (!opengl32) loadWGL(); return ::wgl_glCheckFramebufferStatus(target); }; +void (* const glClear)(GLbitfield) = [](GLbitfield mask) { if (!opengl32) loadWGL(); ::wgl_glClear(mask); }; +void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat) = [](GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { if (!opengl32) loadWGL(); ::wgl_glClearColor(red, green, blue, alpha); }; +void (* const glClearDepthf)(GLfloat) = [](GLfloat d) { if (!opengl32) loadWGL(); ::wgl_glClearDepthf(d); }; +void (* const glClearStencil)(GLint) = [](GLint s) { if (!opengl32) loadWGL(); ::wgl_glClearStencil(s); }; +void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean) = [](GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { if (!opengl32) loadWGL(); ::wgl_glColorMask(red, green, blue, alpha); }; +void (* const glCompileShader)(GLuint) = [](GLuint shader) { if (!opengl32) loadWGL(); ::wgl_glCompileShader(shader); }; +void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void*) = [](GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) { if (!opengl32) loadWGL(); ::wgl_glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); }; +void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void*) = [](GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) { if (!opengl32) loadWGL(); ::wgl_glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); }; +void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) = [](GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { if (!opengl32) loadWGL(); ::wgl_glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); }; +void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) = [](GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { if (!opengl32) loadWGL(); ::wgl_glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); }; +GLuint(* const glCreateProgram)() = [](void) { if (!opengl32) loadWGL(); return ::wgl_glCreateProgram(); }; +GLuint(* const glCreateShader)(GLenum) = [](GLenum type) { if (!opengl32) loadWGL(); return ::wgl_glCreateShader(type); }; +void (* const glCullFace)(GLenum) = [](GLenum mode) { if (!opengl32) loadWGL(); ::wgl_glCullFace(mode); }; +void (* const glDeleteBuffers)(GLsizei, const GLuint*) = [](GLsizei n, const GLuint* buffers) { if (!opengl32) loadWGL(); ::wgl_glDeleteBuffers(n, buffers); }; +void (* const glDeleteFramebuffers)(GLsizei, const GLuint*) = [](GLsizei n, const GLuint* framebuffers) { if (!opengl32) loadWGL(); ::wgl_glDeleteFramebuffers(n, framebuffers); }; +void (* const glDeleteProgram)(GLuint) = [](GLuint program) { if (!opengl32) loadWGL(); ::wgl_glDeleteProgram(program); }; +void (* const glDeleteRenderbuffers)(GLsizei, const GLuint*) = [](GLsizei n, const GLuint* renderbuffers) { if (!opengl32) loadWGL(); ::wgl_glDeleteRenderbuffers(n, renderbuffers); }; +void (* const glDeleteShader)(GLuint) = [](GLuint shader) { if (!opengl32) loadWGL(); ::wgl_glDeleteShader(shader); }; +void (* const glDeleteTextures)(GLsizei, const GLuint*) = [](GLsizei n, const GLuint* textures) { if (!opengl32) loadWGL(); ::wgl_glDeleteTextures(n, textures); }; +void (* const glDepthFunc)(GLenum) = [](GLenum func) { if (!opengl32) loadWGL(); ::wgl_glDepthFunc(func); }; +void (* const glDepthMask)(GLboolean) = [](GLboolean flag) { if (!opengl32) loadWGL(); ::wgl_glDepthMask(flag); }; +void (* const glDepthRangef)(GLfloat, GLfloat) = [](GLfloat n, GLfloat f) { if (!opengl32) loadWGL(); ::wgl_glDepthRangef(n, f); }; +void (* const glDetachShader)(GLuint, GLuint) = [](GLuint program, GLuint shader) { if (!opengl32) loadWGL(); ::wgl_glDetachShader(program, shader); }; +void (* const glDisable)(GLenum) = [](GLenum cap) { if (!opengl32) loadWGL(); ::wgl_glDisable(cap); }; +void (* const glDisableVertexAttribArray)(GLuint) = [](GLuint index) { if (!opengl32) loadWGL(); ::wgl_glDisableVertexAttribArray(index); }; +void (* const glDrawArrays)(GLenum, GLint, GLsizei) = [](GLenum mode, GLint first, GLsizei count) { if (!opengl32) loadWGL(); ::wgl_glDrawArrays(mode, first, count); }; +void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void*) = [](GLenum mode, GLsizei count, GLenum type, const void* indices) { if (!opengl32) loadWGL(); ::wgl_glDrawElements(mode, count, type, indices); }; +void (* const glEnable)(GLenum) = [](GLenum cap) { if (!opengl32) loadWGL(); ::wgl_glEnable(cap); }; +void (* const glEnableVertexAttribArray)(GLuint) = [](GLuint index) { if (!opengl32) loadWGL(); ::wgl_glEnableVertexAttribArray(index); }; +void (* const glFinish)() = [](void) { if (!opengl32) loadWGL(); ::wgl_glFinish(); }; +void (* const glFlush)() = [](void) { if (!opengl32) loadWGL(); ::wgl_glFlush(); }; +void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint) = [](GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { if (!opengl32) loadWGL(); ::wgl_glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); }; +void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint) = [](GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { if (!opengl32) loadWGL(); ::wgl_glFramebufferTexture2D(target, attachment, textarget, texture, level); }; +void (* const glFrontFace)(GLenum) = [](GLenum mode) { if (!opengl32) loadWGL(); ::wgl_glFrontFace(mode); }; +void (* const glGenBuffers)(GLsizei, GLuint*) = [](GLsizei n, GLuint* buffers) { if (!opengl32) loadWGL(); ::wgl_glGenBuffers(n, buffers); }; +void (* const glGenerateMipmap)(GLenum) = [](GLenum target) { if (!opengl32) loadWGL(); ::wgl_glGenerateMipmap(target); }; +void (* const glGenFramebuffers)(GLsizei, GLuint*) = [](GLsizei n, GLuint* framebuffers) { if (!opengl32) loadWGL(); ::wgl_glGenFramebuffers(n, framebuffers); }; +void (* const glGenRenderbuffers)(GLsizei, GLuint*) = [](GLsizei n, GLuint* renderbuffers) { if (!opengl32) loadWGL(); ::wgl_glGenRenderbuffers(n, renderbuffers); }; +void (* const glGenTextures)(GLsizei, GLuint*) = [](GLsizei n, GLuint* textures) { if (!opengl32) loadWGL(); ::wgl_glGenTextures(n, textures); }; +void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*) = [](GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { if (!opengl32) loadWGL(); ::wgl_glGetActiveAttrib(program, index, bufSize, length, size, type, name); }; +void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*) = [](GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { if (!opengl32) loadWGL(); ::wgl_glGetActiveUniform(program, index, bufSize, length, size, type, name); }; +void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei*, GLuint*) = [](GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) { if (!opengl32) loadWGL(); ::wgl_glGetAttachedShaders(program, maxCount, count, shaders); }; +GLint(* const glGetAttribLocation)(GLuint, const GLchar*) = [](GLuint program, const GLchar* name) { if (!opengl32) loadWGL(); return ::wgl_glGetAttribLocation(program, name); }; +void (* const glGetBooleanv)(GLenum, GLboolean*) = [](GLenum pname, GLboolean* data) { if (!opengl32) loadWGL(); ::wgl_glGetBooleanv(pname, data); }; +void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint*) = [](GLenum target, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetBufferParameteriv(target, pname, params); }; +GLenum(* const glGetError)() = [](void) { if (!opengl32) loadWGL(); return ::wgl_glGetError(); }; +void (* const glGetFloatv)(GLenum, GLfloat*) = [](GLenum pname, GLfloat* data) { if (!opengl32) loadWGL(); ::wgl_glGetFloatv(pname, data); }; +void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint*) = [](GLenum target, GLenum attachment, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); }; +void (* const glGetIntegerv)(GLenum, GLint*) = [](GLenum pname, GLint* data) { if (!opengl32) loadWGL(); ::wgl_glGetIntegerv(pname, data); }; +void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*) = [](GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { if (!opengl32) loadWGL(); ::wgl_glGetProgramInfoLog(program, bufSize, length, infoLog); }; +void (* const glGetProgramiv)(GLuint, GLenum, GLint*) = [](GLuint program, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetProgramiv(program, pname, params); }; +void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint*) = [](GLenum target, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetRenderbufferParameteriv(target, pname, params); }; +void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*) = [](GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { if (!opengl32) loadWGL(); ::wgl_glGetShaderInfoLog(shader, bufSize, length, infoLog); }; +void (* const glGetShaderiv)(GLuint, GLenum, GLint*) = [](GLuint shader, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetShaderiv(shader, pname, params); }; +void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei*, GLchar*) = [](GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source) { if (!opengl32) loadWGL(); ::wgl_glGetShaderSource(shader, bufSize, length, source); }; +const GLubyte* (* const glGetString)(GLenum) = [](GLenum name) { if (!opengl32) loadWGL(); return ::wgl_glGetString(name); }; +void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat*) = [](GLenum target, GLenum pname, GLfloat* params) { if (!opengl32) loadWGL(); ::wgl_glGetTexParameterfv(target, pname, params); }; +void (* const glGetTexParameteriv)(GLenum, GLenum, GLint*) = [](GLenum target, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetTexParameteriv(target, pname, params); }; +void (* const glGetUniformfv)(GLuint, GLint, GLfloat*) = [](GLuint program, GLint location, GLfloat* params) { if (!opengl32) loadWGL(); ::wgl_glGetUniformfv(program, location, params); }; +void (* const glGetUniformiv)(GLuint, GLint, GLint*) = [](GLuint program, GLint location, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetUniformiv(program, location, params); }; +GLint(* const glGetUniformLocation)(GLuint, const GLchar*) = [](GLuint program, const GLchar* name) { if (!opengl32) loadWGL(); return ::wgl_glGetUniformLocation(program, name); }; +void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat*) = [](GLuint index, GLenum pname, GLfloat* params) { if (!opengl32) loadWGL(); ::wgl_glGetVertexAttribfv(index, pname, params); }; +void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint*) = [](GLuint index, GLenum pname, GLint* params) { if (!opengl32) loadWGL(); ::wgl_glGetVertexAttribiv(index, pname, params); }; +void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void**) = [](GLuint index, GLenum pname, void** pointer) { if (!opengl32) loadWGL(); ::wgl_glGetVertexAttribPointerv(index, pname, pointer); }; +void (* const glHint)(GLenum, GLenum) = [](GLenum target, GLenum mode) { if (!opengl32) loadWGL(); ::wgl_glHint(target, mode); }; +GLboolean(* const glIsBuffer)(GLuint) = [](GLuint buffer) { if (!opengl32) loadWGL(); return ::wgl_glIsBuffer(buffer); }; +GLboolean(* const glIsEnabled)(GLenum) = [](GLenum cap) { if (!opengl32) loadWGL(); return ::wgl_glIsEnabled(cap); }; +GLboolean(* const glIsFramebuffer)(GLuint) = [](GLuint framebuffer) { if (!opengl32) loadWGL(); return ::wgl_glIsFramebuffer(framebuffer); }; +GLboolean(* const glIsProgram)(GLuint) = [](GLuint program) { if (!opengl32) loadWGL(); return ::wgl_glIsProgram(program); }; +GLboolean(* const glIsRenderbuffer)(GLuint) = [](GLuint renderbuffer) { if (!opengl32) loadWGL(); return ::wgl_glIsRenderbuffer(renderbuffer); }; +GLboolean(* const glIsShader)(GLuint) = [](GLuint shader) { if (!opengl32) loadWGL(); return ::wgl_glIsShader(shader); }; +GLboolean(* const glIsTexture)(GLuint) = [](GLuint texture) { if (!opengl32) loadWGL(); return ::wgl_glIsTexture(texture); }; +void (* const glLineWidth)(GLfloat) = [](GLfloat width) { if (!opengl32) loadWGL(); ::wgl_glLineWidth(width); }; +void (* const glLinkProgram)(GLuint) = [](GLuint program) { if (!opengl32) loadWGL(); ::wgl_glLinkProgram(program); }; +void (* const glPixelStorei)(GLenum, GLint) = [](GLenum pname, GLint param) { if (!opengl32) loadWGL(); ::wgl_glPixelStorei(pname, param); }; +void (* const glPolygonOffset)(GLfloat, GLfloat) = [](GLfloat factor, GLfloat units) { if (!opengl32) loadWGL(); ::wgl_glPolygonOffset(factor, units); }; +void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*) = [](GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { if (!opengl32) loadWGL(); ::wgl_glReadPixels(x, y, width, height, format, type, pixels); }; +void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei) = [](GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { if (!opengl32) loadWGL(); ::wgl_glRenderbufferStorage(target, internalformat, width, height); }; +void (* const glSampleCoverage)(GLfloat, GLboolean) = [](GLfloat value, GLboolean invert) { if (!opengl32) loadWGL(); ::wgl_glSampleCoverage(value, invert); }; +void (* const glScissor)(GLint, GLint, GLsizei, GLsizei) = [](GLint x, GLint y, GLsizei width, GLsizei height) { if (!opengl32) loadWGL(); ::wgl_glScissor(x, y, width, height); }; +void (* const glShaderSource)(GLuint, GLsizei, const GLchar* const*, const GLint*) = [](GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) { if (!opengl32) loadWGL(); ::wgl_glShaderSource(shader, count, string, length); }; +void (* const glStencilFunc)(GLenum, GLint, GLuint) = [](GLenum func, GLint ref, GLuint mask) { if (!opengl32) loadWGL(); ::wgl_glStencilFunc(func, ref, mask); }; +void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint) = [](GLenum face, GLenum func, GLint ref, GLuint mask) { if (!opengl32) loadWGL(); ::wgl_glStencilFuncSeparate(face, func, ref, mask); }; +void (* const glStencilMask)(GLuint) = [](GLuint mask) { if (!opengl32) loadWGL(); ::wgl_glStencilMask(mask); }; +void (* const glStencilMaskSeparate)(GLenum, GLuint) = [](GLenum face, GLuint mask) { if (!opengl32) loadWGL(); ::wgl_glStencilMaskSeparate(face, mask); }; +void (* const glStencilOp)(GLenum, GLenum, GLenum) = [](GLenum fail, GLenum zfail, GLenum zpass) { if (!opengl32) loadWGL(); ::wgl_glStencilOp(fail, zfail, zpass); }; +void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum) = [](GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) { if (!opengl32) loadWGL(); ::wgl_glStencilOpSeparate(face, sfail, dpfail, dppass); }; +void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*) = [](GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) { if (!opengl32) loadWGL(); ::wgl_glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); }; +void (* const glTexParameterf)(GLenum, GLenum, GLfloat) = [](GLenum target, GLenum pname, GLfloat param) { if (!opengl32) loadWGL(); ::wgl_glTexParameterf(target, pname, param); }; +void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat*) = [](GLenum target, GLenum pname, const GLfloat* params) { if (!opengl32) loadWGL(); ::wgl_glTexParameterfv(target, pname, params); }; +void (* const glTexParameteri)(GLenum, GLenum, GLint) = [](GLenum target, GLenum pname, GLint param) { if (!opengl32) loadWGL(); ::wgl_glTexParameteri(target, pname, param); }; +void (* const glTexParameteriv)(GLenum, GLenum, const GLint*) = [](GLenum target, GLenum pname, const GLint* params) { if (!opengl32) loadWGL(); ::wgl_glTexParameteriv(target, pname, params); }; +void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*) = [](GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) { if (!opengl32) loadWGL(); ::wgl_glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); }; +void (* const glUniform1f)(GLint, GLfloat) = [](GLint location, GLfloat v0) { if (!opengl32) loadWGL(); ::wgl_glUniform1f(location, v0); }; +void (* const glUniform1fv)(GLint, GLsizei, const GLfloat*) = [](GLint location, GLsizei count, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniform1fv(location, count, value); }; +void (* const glUniform1i)(GLint, GLint) = [](GLint location, GLint v0) { if (!opengl32) loadWGL(); ::wgl_glUniform1i(location, v0); }; +void (* const glUniform1iv)(GLint, GLsizei, const GLint*) = [](GLint location, GLsizei count, const GLint* value) { if (!opengl32) loadWGL(); ::wgl_glUniform1iv(location, count, value); }; +void (* const glUniform2f)(GLint, GLfloat, GLfloat) = [](GLint location, GLfloat v0, GLfloat v1) { if (!opengl32) loadWGL(); ::wgl_glUniform2f(location, v0, v1); }; +void (* const glUniform2fv)(GLint, GLsizei, const GLfloat*) = [](GLint location, GLsizei count, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniform2fv(location, count, value); }; +void (* const glUniform2i)(GLint, GLint, GLint) = [](GLint location, GLint v0, GLint v1) { if (!opengl32) loadWGL(); ::wgl_glUniform2i(location, v0, v1); }; +void (* const glUniform2iv)(GLint, GLsizei, const GLint*) = [](GLint location, GLsizei count, const GLint* value) { if (!opengl32) loadWGL(); ::wgl_glUniform2iv(location, count, value); }; +void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat) = [](GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { if (!opengl32) loadWGL(); ::wgl_glUniform3f(location, v0, v1, v2); }; +void (* const glUniform3fv)(GLint, GLsizei, const GLfloat*) = [](GLint location, GLsizei count, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniform3fv(location, count, value); }; +void (* const glUniform3i)(GLint, GLint, GLint, GLint) = [](GLint location, GLint v0, GLint v1, GLint v2) { if (!opengl32) loadWGL(); ::wgl_glUniform3i(location, v0, v1, v2); }; +void (* const glUniform3iv)(GLint, GLsizei, const GLint*) = [](GLint location, GLsizei count, const GLint* value) { if (!opengl32) loadWGL(); ::wgl_glUniform3iv(location, count, value); }; +void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat) = [](GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { if (!opengl32) loadWGL(); ::wgl_glUniform4f(location, v0, v1, v2, v3); }; +void (* const glUniform4fv)(GLint, GLsizei, const GLfloat*) = [](GLint location, GLsizei count, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniform4fv(location, count, value); }; +void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint) = [](GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { if (!opengl32) loadWGL(); ::wgl_glUniform4i(location, v0, v1, v2, v3); }; +void (* const glUniform4iv)(GLint, GLsizei, const GLint*) = [](GLint location, GLsizei count, const GLint* value) { if (!opengl32) loadWGL(); ::wgl_glUniform4iv(location, count, value); }; +void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat*) = [](GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniformMatrix2fv(location, count, transpose, value); }; +void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*) = [](GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniformMatrix3fv(location, count, transpose, value); }; +void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*) = [](GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { if (!opengl32) loadWGL(); ::wgl_glUniformMatrix4fv(location, count, transpose, value); }; +void (* const glUseProgram)(GLuint) = [](GLuint program) { if (!opengl32) loadWGL(); ::wgl_glUseProgram(program); }; +void (* const glValidateProgram)(GLuint) = [](GLuint program) { if (!opengl32) loadWGL(); ::wgl_glValidateProgram(program); }; +void (* const glVertexAttrib1f)(GLuint, GLfloat) = [](GLuint index, GLfloat x) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib1f(index, x); }; +void (* const glVertexAttrib1fv)(GLuint, const GLfloat*) = [](GLuint index, const GLfloat* v) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib1fv(index, v); }; +void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat) = [](GLuint index, GLfloat x, GLfloat y) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib2f(index, x, y); }; +void (* const glVertexAttrib2fv)(GLuint, const GLfloat*) = [](GLuint index, const GLfloat* v) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib2fv(index, v); }; +void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat) = [](GLuint index, GLfloat x, GLfloat y, GLfloat z) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib3f(index, x, y, z); }; +void (* const glVertexAttrib3fv)(GLuint, const GLfloat*) = [](GLuint index, const GLfloat* v) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib3fv(index, v); }; +void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat) = [](GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib4f(index, x, y, z, w); }; +void (* const glVertexAttrib4fv)(GLuint, const GLfloat*) = [](GLuint index, const GLfloat* v) { if (!opengl32) loadWGL(); ::wgl_glVertexAttrib4fv(index, v); }; +void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*) = [](GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) { if (!opengl32) loadWGL(); ::wgl_glVertexAttribPointer(index, size, type, normalized, stride, pointer); }; +void (* const glViewport)(GLint, GLint, GLsizei, GLsizei) = [](GLint x, GLint y, GLsizei width, GLsizei height) { if (!opengl32) loadWGL(); ::wgl_glViewport(x, y, width, height); }; + +BOOL(* const wglChoosePixelFormatARB)(HDC, const int*, const FLOAT*, UINT, int*, UINT*) = [](HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats) { if (!opengl32) loadWGL(); return ::wgl_wglChoosePixelFormatARB(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); }; +HGLRC(* const wglCreateContextAttribsARB)(HDC, HGLRC, const int*) = [](HDC hDC, HGLRC hShareContext, const int* attribList) { if (!opengl32) loadWGL(); return ::wgl_wglCreateContextAttribsARB(hDC, hShareContext, attribList); }; +const char* (* const wglGetExtensionsStringARB)(HDC) = [](HDC hdc) { if (!opengl32) loadWGL(); return ::wgl_wglGetExtensionsStringARB(hdc); }; +const char* (* const wglGetExtensionsStringEXT)() = [](void) { if (!opengl32) loadWGL(); return ::wgl_wglGetExtensionsStringEXT(); }; + +#ifndef MBGL_USE_GLES2 +void (* const glDrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *) = ::glDrawPixels; +void (* const glGetDoublev)(GLenum, GLdouble *) = ::glGetDoublev; +void (* const glPixelTransferf)(GLenum, GLfloat) = ::glPixelTransferf; +void (* const glPixelZoom)(GLfloat, GLfloat) = ::glPixelZoom; +void (* const glPointSize)(GLfloat) = ::glPointSize; +void (* const glRasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble) = ::glRasterPos4d; +#endif + +} // namespace platform +} // namespace mbgl +#endif diff --git a/platform/windows/include/thread.h b/platform/windows/include/thread.h new file mode 100644 index 00000000000..b701c2e8802 --- /dev/null +++ b/platform/windows/include/thread.h @@ -0,0 +1,72 @@ +#pragma once + +#ifndef _thread_h_ +#define _thread_h_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2022 +// +// Usage: SetThreadName (-1, "MainThread"); +// +// +// Usage: SetThreadName ((DWORD)-1, "MainThread"); +// +const DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(DWORD dwThreadID, const char* threadName); + +typedef struct structTHREAD_INFO { + DWORD id; + DWORD key; + char* name; +} THREAD_INFO; + +#ifdef __cplusplus +} +#endif + +extern DWORD selfThreadKey; + +class DummyClassThread { +public: + DummyClassThread() { + selfThreadKey = TlsAlloc(); + } + + ~DummyClassThread() { + TlsFree(selfThreadKey); + } +}; + +extern DummyClassThread dummyClassThread; + +THREAD_INFO* GetCurrentThreadInfo(); + +namespace mbgl { +namespace platform { +std::string getCurrentThreadName(); +void setCurrentThreadName(const std::string& name); +void makeThreadLowPriority(); +void setCurrentThreadPriority(double priority); +} +} + +#endif diff --git a/platform/windows/src/gl_functions.cpp b/platform/windows/src/gl_functions.cpp new file mode 100644 index 00000000000..fea7b9f7100 --- /dev/null +++ b/platform/windows/src/gl_functions.cpp @@ -0,0 +1,170 @@ +#pragma once + +#include + +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES +#endif + +#ifndef MBGL_USE_GLES2 +#include +#include +#else +#include +#include +#endif + +namespace mbgl { +namespace platform { + +void (* const glActiveTexture)(GLenum) = ::glActiveTexture; +void (* const glAttachShader)(GLuint, GLuint) = ::glAttachShader; +void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar *) = ::glBindAttribLocation; +void (* const glBindBuffer)(GLenum, GLuint) = ::glBindBuffer; +void (* const glBindFramebuffer)(GLenum, GLuint) = ::glBindFramebuffer; +void (* const glBindRenderbuffer)(GLenum, GLuint) = ::glBindRenderbuffer; +void (* const glBindTexture)(GLenum, GLuint) = ::glBindTexture; +void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glBlendColor; +void (* const glBlendEquation)(GLenum) = ::glBlendEquation; +void (* const glBlendEquationSeparate)(GLenum, GLenum) = ::glBlendEquationSeparate; +void (* const glBlendFunc)(GLenum, GLenum) = ::glBlendFunc; +void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glBlendFuncSeparate; +void (* const glBufferData)(GLenum, GLsizeiptr, const void *, GLenum) = ::glBufferData; +void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void *) = ::glBufferSubData; +GLenum (* const glCheckFramebufferStatus)(GLenum) = ::glCheckFramebufferStatus; +void (* const glClear)(GLbitfield) = ::glClear; +void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat) = ::glClearColor; +void (* const glClearDepthf)(GLfloat) = ::glClearDepthf; +void (* const glClearStencil)(GLint) = ::glClearStencil; +void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean) = ::glColorMask; +void (* const glCompileShader)(GLuint) = ::glCompileShader; +void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void *) = ::glCompressedTexImage2D; +void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void *) = ::glCompressedTexSubImage2D; +void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) = ::glCopyTexImage2D; +void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) = ::glCopyTexSubImage2D; +GLuint (* const glCreateProgram)() = ::glCreateProgram; +GLuint (* const glCreateShader)(GLenum) = ::glCreateShader; +void (* const glCullFace)(GLenum) = ::glCullFace; +void (* const glDeleteBuffers)(GLsizei, const GLuint *) = ::glDeleteBuffers; +void (* const glDeleteFramebuffers)(GLsizei, const GLuint *) = ::glDeleteFramebuffers; +void (* const glDeleteProgram)(GLuint) = ::glDeleteProgram; +void (* const glDeleteRenderbuffers)(GLsizei, const GLuint *) = ::glDeleteRenderbuffers; +void (* const glDeleteShader)(GLuint) = ::glDeleteShader; +void (* const glDeleteTextures)(GLsizei, const GLuint *) = ::glDeleteTextures; +void (* const glDepthFunc)(GLenum) = ::glDepthFunc; +void (* const glDepthMask)(GLboolean) = ::glDepthMask; +void (* const glDepthRangef)(GLfloat, GLfloat) = ::glDepthRangef; +void (* const glDetachShader)(GLuint, GLuint) = ::glDetachShader; +void (* const glDisable)(GLenum) = ::glDisable; +void (* const glDisableVertexAttribArray)(GLuint) = ::glDisableVertexAttribArray; +void (* const glDrawArrays)(GLenum, GLint, GLsizei) = ::glDrawArrays; +void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void *) = ::glDrawElements; +void (* const glEnable)(GLenum) = ::glEnable; +void (* const glEnableVertexAttribArray)(GLuint) = ::glEnableVertexAttribArray; +void (* const glFinish)() = ::glFinish; +void (* const glFlush)() = ::glFlush; +void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint) = ::glFramebufferRenderbuffer; +void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint) = ::glFramebufferTexture2D; +void (* const glFrontFace)(GLenum) = ::glFrontFace; +void (* const glGenBuffers)(GLsizei, GLuint *) = ::glGenBuffers; +void (* const glGenerateMipmap)(GLenum) = ::glGenerateMipmap; +void (* const glGenFramebuffers)(GLsizei, GLuint *) = ::glGenFramebuffers; +void (* const glGenRenderbuffers)(GLsizei, GLuint *) = ::glGenRenderbuffers; +void (* const glGenTextures)(GLsizei, GLuint *) = ::glGenTextures; +void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveAttrib; +void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *) = ::glGetActiveUniform; +void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei *, GLuint *) = ::glGetAttachedShaders; +GLint (* const glGetAttribLocation)(GLuint, const GLchar *) = ::glGetAttribLocation; +void (* const glGetBooleanv)(GLenum, GLboolean *) = ::glGetBooleanv; +void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetBufferParameteriv; +GLenum (* const glGetError)() = ::glGetError; +void (* const glGetFloatv)(GLenum, GLfloat *) = ::glGetFloatv; +void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint *) = ::glGetFramebufferAttachmentParameteriv; +void (* const glGetIntegerv)(GLenum, GLint *) = ::glGetIntegerv; +void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetProgramInfoLog; +void (* const glGetProgramiv)(GLuint, GLenum, GLint *) = ::glGetProgramiv; +void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint *) = ::glGetRenderbufferParameteriv; +void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderInfoLog; +void (* const glGetShaderiv)(GLuint, GLenum, GLint *) = ::glGetShaderiv; +void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei *, GLchar *) = ::glGetShaderSource; +const GLubyte *(* const glGetString)(GLenum) = ::glGetString; +void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat *) = ::glGetTexParameterfv; +void (* const glGetTexParameteriv)(GLenum, GLenum, GLint *) = ::glGetTexParameteriv; +void (* const glGetUniformfv)(GLuint, GLint, GLfloat *) = ::glGetUniformfv; +void (* const glGetUniformiv)(GLuint, GLint, GLint *) = ::glGetUniformiv; +GLint (* const glGetUniformLocation)(GLuint, const GLchar *) = ::glGetUniformLocation; +void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat *) = ::glGetVertexAttribfv; +void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint *) = ::glGetVertexAttribiv; +void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void **) = ::glGetVertexAttribPointerv; +void (* const glHint)(GLenum, GLenum) = ::glHint; +GLboolean (* const glIsBuffer)(GLuint) = ::glIsBuffer; +GLboolean (* const glIsEnabled)(GLenum) = ::glIsEnabled; +GLboolean (* const glIsFramebuffer)(GLuint) = ::glIsFramebuffer; +GLboolean (* const glIsProgram)(GLuint) = ::glIsProgram; +GLboolean (* const glIsRenderbuffer)(GLuint) = ::glIsRenderbuffer; +GLboolean (* const glIsShader)(GLuint) = ::glIsShader; +GLboolean (* const glIsTexture)(GLuint) = ::glIsTexture; +void (* const glLineWidth)(GLfloat) = ::glLineWidth; +void (* const glLinkProgram)(GLuint) = ::glLinkProgram; +void (* const glPixelStorei)(GLenum, GLint) = ::glPixelStorei; +void (* const glPolygonOffset)(GLfloat, GLfloat) = ::glPolygonOffset; +void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void *) = ::glReadPixels; +void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei) = ::glRenderbufferStorage; +void (* const glSampleCoverage)(GLfloat, GLboolean) = ::glSampleCoverage; +void (* const glScissor)(GLint, GLint, GLsizei, GLsizei) = ::glScissor; +void (* const glShaderSource)(GLuint, GLsizei, const GLchar * const*, const GLint *) = ::glShaderSource; +void (* const glStencilFunc)(GLenum, GLint, GLuint) = ::glStencilFunc; +void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint) = ::glStencilFuncSeparate; +void (* const glStencilMask)(GLuint) = ::glStencilMask; +void (* const glStencilMaskSeparate)(GLenum, GLuint) = ::glStencilMaskSeparate; +void (* const glStencilOp)(GLenum, GLenum, GLenum) = ::glStencilOp; +void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum) = ::glStencilOpSeparate; +void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *) = ::glTexImage2D; +void (* const glTexParameterf)(GLenum, GLenum, GLfloat) = ::glTexParameterf; +void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat *) = ::glTexParameterfv; +void (* const glTexParameteri)(GLenum, GLenum, GLint) = ::glTexParameteri; +void (* const glTexParameteriv)(GLenum, GLenum, const GLint *) = ::glTexParameteriv; +void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *) = ::glTexSubImage2D; +void (* const glUniform1f)(GLint, GLfloat) = ::glUniform1f; +void (* const glUniform1fv)(GLint, GLsizei, const GLfloat *) = ::glUniform1fv; +void (* const glUniform1i)(GLint, GLint) = ::glUniform1i; +void (* const glUniform1iv)(GLint, GLsizei, const GLint *) = ::glUniform1iv; +void (* const glUniform2f)(GLint, GLfloat, GLfloat) = ::glUniform2f; +void (* const glUniform2fv)(GLint, GLsizei, const GLfloat *) = ::glUniform2fv; +void (* const glUniform2i)(GLint, GLint, GLint) = ::glUniform2i; +void (* const glUniform2iv)(GLint, GLsizei, const GLint *) = ::glUniform2iv; +void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat) = ::glUniform3f; +void (* const glUniform3fv)(GLint, GLsizei, const GLfloat *) = ::glUniform3fv; +void (* const glUniform3i)(GLint, GLint, GLint, GLint) = ::glUniform3i; +void (* const glUniform3iv)(GLint, GLsizei, const GLint *) = ::glUniform3iv; +void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glUniform4f; +void (* const glUniform4fv)(GLint, GLsizei, const GLfloat *) = ::glUniform4fv; +void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint) = ::glUniform4i; +void (* const glUniform4iv)(GLint, GLsizei, const GLint *) = ::glUniform4iv; +void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix2fv; +void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix3fv; +void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *) = ::glUniformMatrix4fv; +void (* const glUseProgram)(GLuint) = ::glUseProgram; +void (* const glValidateProgram)(GLuint) = ::glValidateProgram; +void (* const glVertexAttrib1f)(GLuint, GLfloat) = ::glVertexAttrib1f; +void (* const glVertexAttrib1fv)(GLuint, const GLfloat *) = ::glVertexAttrib1fv; +void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat) = ::glVertexAttrib2f; +void (* const glVertexAttrib2fv)(GLuint, const GLfloat *) = ::glVertexAttrib2fv; +void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib3f; +void (* const glVertexAttrib3fv)(GLuint, const GLfloat *) = ::glVertexAttrib3fv; +void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat) = ::glVertexAttrib4f; +void (* const glVertexAttrib4fv)(GLuint, const GLfloat *) = ::glVertexAttrib4fv; +void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *) = ::glVertexAttribPointer; +void (* const glViewport)(GLint, GLint, GLsizei, GLsizei) = ::glViewport; + +#ifndef MBGL_USE_GLES2 +void (* const glDrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *) = ::glDrawPixels; +void (* const glGetDoublev)(GLenum, GLdouble *) = ::glGetDoublev; +void (* const glPixelTransferf)(GLenum, GLfloat) = ::glPixelTransferf; +void (* const glPixelZoom)(GLfloat, GLfloat) = ::glPixelZoom; +void (* const glPointSize)(GLfloat) = ::glPointSize; +void (* const glRasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble) = ::glRasterPos4d; +#endif + +} // namespace platform +} // namespace mbgl diff --git a/platform/windows/src/headless_backend_egl.cpp b/platform/windows/src/headless_backend_egl.cpp new file mode 100644 index 00000000000..21db012510f --- /dev/null +++ b/platform/windows/src/headless_backend_egl.cpp @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include + +#include + +namespace mbgl { +namespace gl { + +// This class provides a singleton that contains information about the configuration used for +// instantiating new headless rendering contexts. +class EGLDisplayConfig { +private: + // Key for singleton construction. + struct Key { explicit Key() = default; }; + +public: + EGLDisplayConfig(Key) { + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + throw std::runtime_error("Failed to obtain a valid EGL display.\n"); + } + + EGLint major, minor, numConfigs; + if (!eglInitialize(display, &major, &minor)) { + throw std::runtime_error("eglInitialize() failed.\n"); + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglBindAPI(EGL_OPENGL_ES_API) returned error %d", + eglGetError()); + throw std::runtime_error("eglBindAPI() failed"); + } + + const EGLint attribs[] = { +#if MBGL_USE_GLES2 + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +#endif + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_NONE + }; + + // Note: we're choosing an arbitrary pixel format, since we're not using the default surface + // anyway; all rendering will be directed to framebuffers which have their own configuration. + if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs) || numConfigs != 1) { + throw std::runtime_error("Failed to choose ARGB config.\n"); + } + } + + ~EGLDisplayConfig() { + eglTerminate(display); + } + + static std::shared_ptr create() { + static std::weak_ptr instance; + auto shared = instance.lock(); + if (!shared) { + instance = shared = std::make_shared(Key{}); + } + return shared; + } + +public: + EGLDisplay display = EGL_NO_DISPLAY; + EGLConfig config = 0; +}; + +class EGLBackendImpl : public HeadlessBackend::Impl { +public: + EGLBackendImpl() { + // EGL initializes the context client version to 1 by default. We want to + // use OpenGL ES 2.0 which has the ability to create shader and program + // objects and also to write vertex and fragment shaders in the OpenGL ES + // Shading Language. + const EGLint attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + eglContext = eglCreateContext(eglDisplay->display, eglDisplay->config, EGL_NO_CONTEXT, attribs); + if (eglContext == EGL_NO_CONTEXT) { + mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error 0x%04x", + eglGetError()); + throw std::runtime_error("Error creating the EGL context object.\n"); + } + + // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to + // activate the context. + // Note that to be able to create pbuffer surfaces, we need to choose a config that + // includes EGL_SURFACE_TYPE, EGL_PBUFFER_BIT in HeadlessDisplay. + const EGLint surfAttribs[] = { + EGL_WIDTH, 8, + EGL_HEIGHT, 8, + EGL_LARGEST_PBUFFER, EGL_TRUE, + EGL_NONE + }; + + eglSurface = eglCreatePbufferSurface(eglDisplay->display, eglDisplay->config, surfAttribs); + if (eglSurface == EGL_NO_SURFACE) { + throw std::runtime_error("Could not create surface: " + util::toString(eglGetError())); + } + } + + ~EGLBackendImpl() final { + if (eglSurface != EGL_NO_SURFACE) { + if (!eglDestroySurface(eglDisplay->display, eglSurface)) { + Log::Error(Event::OpenGL, "Failed to destroy EGL surface."); + } + eglSurface = EGL_NO_SURFACE; + } + if (!eglDestroyContext(eglDisplay->display, eglContext)) { + Log::Error(Event::OpenGL, "Failed to destroy EGL context."); + } + } + + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { + return eglGetProcAddress(name); + } + + void activateContext() final { + if (!eglMakeCurrent(eglDisplay->display, eglSurface, eglSurface, eglContext)) { + throw std::runtime_error("Switching OpenGL context failed.\n"); + } + } + + void deactivateContext() final { + if (!eglMakeCurrent(eglDisplay->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + throw std::runtime_error("Removing OpenGL context failed.\n"); + } + } + +private: + const std::shared_ptr eglDisplay = EGLDisplayConfig::create(); + EGLContext eglContext = EGL_NO_CONTEXT; + EGLSurface eglSurface = EGL_NO_SURFACE; +}; + +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/windows/src/headless_backend_osmesa.cpp b/platform/windows/src/headless_backend_osmesa.cpp new file mode 100644 index 00000000000..1484fcdd596 --- /dev/null +++ b/platform/windows/src/headless_backend_osmesa.cpp @@ -0,0 +1,53 @@ +#include + +#include + +#include + +#include + +namespace mbgl { +namespace gl { + +// This class provides a singleton that contains information about the configuration used for +// instantiating new headless rendering contexts. + +class OSMesaBackendImpl final : public HeadlessBackend::Impl { +public: + OSMesaBackendImpl() { + context = OSMesaCreateContextAttribs(std::initializer_list({ + OSMESA_FORMAT, OSMESA_RGBA, + OSMESA_DEPTH_BITS, 24, + OSMESA_STENCIL_BITS, 8, + OSMESA_PROFILE, OSMESA_COMPAT_PROFILE, + NULL + }).begin(), NULL); + } + + ~OSMesaBackendImpl() final { + OSMesaDestroyContext(context); + } + + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { + return (ProcAddress)::OSMesaGetProcAddress(name); + } + + void activateContext() final { + OSMesaMakeCurrent(context, buffer.get(), GL_UNSIGNED_BYTE, 2048, 2048); + } + + void deactivateContext() final { + } + +private: + std::unique_ptr buffer = std::make_unique(2048 * 2048 * 4); + OSMesaContext context = NULL; +}; + +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/windows/src/headless_backend_wgl.cpp b/platform/windows/src/headless_backend_wgl.cpp new file mode 100644 index 00000000000..36a9ae4f029 --- /dev/null +++ b/platform/windows/src/headless_backend_wgl.cpp @@ -0,0 +1,423 @@ +#pragma once + +#include + +#include + +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#include "gl_functions_wgl.h" + +namespace mbgl { +namespace gl { + +// This class provides a singleton that contains information about the configuration used for +// instantiating new headless rendering contexts. +class WGLDisplayConfig { +private: + // Key for singleton construction. + struct Key { explicit Key() = default; }; + + WNDCLASSEXA helperWindowClass = { sizeof(WNDCLASSEXA) }; + HWND helperWindowHandle = NULL; + HDC helperWindowDeviceContext = NULL; + HGLRC helperWindowRenderingContext = NULL; + +private: + void CreateHelperWindow() { + MSG message; + + helperWindowClass.style = CS_OWNDC; + helperWindowClass.lpfnWndProc = [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hWnd, uMsg, wParam, lParam); }; + helperWindowClass.lpszClassName = "WGL Helper Window"; + GetModuleHandleExA(0, NULL, &helperWindowClass.hInstance); + + if (!RegisterClassExA(&helperWindowClass)) { + Log::Error(Event::OpenGL, "Failed to register helper window class"); + throw std::runtime_error("Failed to register helper window class"); + } + + helperWindowHandle = CreateWindowExA( + 0, + helperWindowClass.lpszClassName, + "WGL Helper Window", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + NULL, + NULL, + helperWindowClass.hInstance, + NULL + ); + + if (!helperWindowHandle) { + Log::Error(Event::OpenGL, "Failed to create helper window"); + throw std::runtime_error("Failed to create helper window"); + } + + ShowWindow(helperWindowHandle, SW_HIDE); + + while (PeekMessage(&message, helperWindowHandle, 0, 0, PM_REMOVE)) { + DispatchMessage(&message); + } + } + + void DestroyHelperWindow() { + if (helperWindowDeviceContext) { + ReleaseDC(helperWindowHandle, helperWindowDeviceContext); + DeleteDC(helperWindowDeviceContext); + } + + DestroyWindow(helperWindowHandle); + UnregisterClassA(helperWindowClass.lpszClassName, helperWindowClass.hInstance); + } + + bool StringInExtensionString(const char* string, const char* extensions) { + const char* start = extensions; + + while(true) { + const char* where; + const char* terminator; + + where = strstr(start, string); + if (!where) + return false; + + terminator = where + strlen(string); + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') + break; + } + + start = terminator; + } + + return true; + } + + bool extensionSupportedWGL(const char* extension) { + const char* extensions = NULL; + + extensions = mbgl::platform::wglGetExtensionsStringARB(wglGetCurrentDC()); + + if(!extensions || !StringInExtensionString(extension, extensions)) + extensions = mbgl::platform::wglGetExtensionsStringEXT(); + + if(!extensions || !StringInExtensionString(extension, extensions)) + extensions = (const char *)wgl_glGetString(GL_EXTENSIONS); + + if (!extensions) + return false; + + return StringInExtensionString(extension, extensions); + } +public: + explicit WGLDisplayConfig(Key) { + HDC dummyDC, previousDC; + HGLRC dummyRC, previousRC; + PIXELFORMATDESCRIPTOR pfd; + + CreateHelperWindow(); + + dummyDC = GetDC(helperWindowHandle); + + ZeroMemory(&pfd, sizeof(pfd)); + + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_GENERIC_ACCELERATED | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 24; + pfd.cAlphaBits = 8; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + + // Note: we're choosing an arbitrary pixel format, since we're not using the default surface + // anyway; all rendering will be directed to framebuffers which have their own configuration. + if (!SetPixelFormat(dummyDC, ChoosePixelFormat(dummyDC, &pfd), &pfd)) { + Log::Error(Event::OpenGL, "Failed to set pixel format for dummy context"); + throw std::runtime_error("Failed to set pixel format for dummy context"); + } + + dummyRC = wglCreateContext(dummyDC); + + if (!dummyRC) { + Log::Error(Event::OpenGL, "Failed to create dummy context"); + throw std::runtime_error("Failed to create dummy context"); + } + + previousDC = wglGetCurrentDC(); + previousRC = wglGetCurrentContext(); + + if (!wglMakeCurrent(dummyDC, dummyRC)) { + wglMakeCurrent(previousDC, previousRC); + wglDeleteContext(dummyRC); + + DestroyHelperWindow(); + + Log::Error(Event::OpenGL, "Failed to make dummy context current"); + throw std::runtime_error("Failed to make dummy context current"); + } + + ARB_multisample = extensionSupportedWGL("WGL_ARB_multisample"); + ARB_create_context = extensionSupportedWGL("WGL_ARB_create_context"); + ARB_create_context_profile = extensionSupportedWGL("WGL_ARB_create_context_profile"); + EXT_create_context_es2_profile = extensionSupportedWGL("WGL_EXT_create_context_es2_profile"); + EXT_colorspace = extensionSupportedWGL("WGL_EXT_colorspace"); + ARB_pixel_format = extensionSupportedWGL("WGL_ARB_pixel_format"); + ARB_ES2_compatibility = extensionSupportedWGL("GL_ARB_ES2_compatibility"); + + if (!ARB_create_context || !ARB_create_context_profile || !(EXT_create_context_es2_profile || ARB_ES2_compatibility)) { + Log::Error(Event::OpenGL, "OpenGL ES 2.0 is unavailable"); + throw std::runtime_error("OpenGL ES 2.0 is unavailable"); + } + + DestroyHelperWindow(); + + renderingWindowClass.style = CS_OWNDC; + renderingWindowClass.lpfnWndProc = [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hWnd, uMsg, wParam, lParam); }; + renderingWindowClass.lpszClassName = "WGL Rendering Window"; + GetModuleHandleExA(0, NULL, &renderingWindowClass.hInstance); + + if (!RegisterClassExA(&renderingWindowClass)) { + Log::Error(Event::OpenGL, "Failed to register rendering window class"); + throw std::runtime_error("Failed to register rendering window class"); + } + } + + ~WGLDisplayConfig() { + UnregisterClassA(renderingWindowClass.lpszClassName, renderingWindowClass.hInstance); + } + + static std::shared_ptr create() { + static std::weak_ptr instance; + auto shared = instance.lock(); + + if (!shared) { + instance = shared = std::make_shared(Key{}); + } + + return shared; + } +public: + bool ARB_multisample = false; + bool ARB_create_context = false; + bool ARB_create_context_profile = false; + bool EXT_create_context_es2_profile = false; + bool EXT_colorspace = false; + bool ARB_pixel_format = false; + bool ARB_ES2_compatibility = false; + WNDCLASSEXA renderingWindowClass = { sizeof(WNDCLASSEXA) }; +}; + +class WGLBackendImpl final : public HeadlessBackend::Impl { +private: + std::shared_ptr wglDisplayConfig = WGLDisplayConfig::create(); + + HWND renderingWindowHandle = NULL; + HDC renderingWindowDeviceContext = NULL; + HGLRC renderingWindowRenderingContext = NULL; +private: + void CreateRenderingWindow() { + MSG message; + + renderingWindowHandle = CreateWindowExA( + 0, + wglDisplayConfig->renderingWindowClass.lpszClassName, + "WGL Render Window", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, 1, 1, + NULL, + NULL, + wglDisplayConfig->renderingWindowClass.hInstance, + NULL + ); + + if (!renderingWindowHandle) { + Log::Error(Event::OpenGL, "Failed to create helper window"); + throw std::runtime_error("Failed to create helper window"); + } + + ShowWindow(renderingWindowHandle, SW_HIDE); + + while (PeekMessage(&message, renderingWindowHandle, 0, 0, PM_REMOVE)) { + DispatchMessage(&message); + } + } + + void DestroyRenderingWindow() { + if (renderingWindowDeviceContext && renderingWindowHandle) { + ReleaseDC(renderingWindowHandle, renderingWindowDeviceContext); + DeleteDC(renderingWindowDeviceContext); + renderingWindowDeviceContext = NULL; + } + + if (renderingWindowHandle) { + DestroyWindow(renderingWindowHandle); + renderingWindowHandle = NULL; + } + } + + HGLRC GetContext() { + if (!(renderingWindowRenderingContext || CreateRenderingContext())) { + Log::Error(Event::OpenGL, "Failed to create rendering context"); + throw std::runtime_error("Failed to create rendering context"); + } + + return renderingWindowRenderingContext; + } + + bool CreateRenderingContext() { + PIXELFORMATDESCRIPTOR pfd; + int pixelFormat; + UINT numFormats; + + if (!renderingWindowHandle) { + CreateRenderingWindow(); + } + + if (!renderingWindowDeviceContext) { + renderingWindowDeviceContext = GetDC(renderingWindowHandle); + } + + if (!mbgl::platform::wglChoosePixelFormatARB(renderingWindowDeviceContext, std::initializer_list({ + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 24, + WGL_ALPHA_BITS_ARB, 8, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + NULL + }).begin(), NULL, 1, &pixelFormat, &numFormats)) { + Log::Error(Event::OpenGL, "Failed to choose pixel format for context"); + throw std::runtime_error("Failed to choose pixel format for context"); + } + + ZeroMemory(&pfd, sizeof(pfd)); + + pfd.nSize = sizeof(pfd); + + if (!DescribePixelFormat(renderingWindowDeviceContext, pixelFormat, sizeof(pfd), &pfd)) { + Log::Error(Event::OpenGL, "Failed to retrieve pixel format for context"); + throw std::runtime_error("Failed to retrieve pixel format for context"); + } + + if (!SetPixelFormat(renderingWindowDeviceContext, pixelFormat, &pfd)) { + Log::Error(Event::OpenGL, "Failed to set pixel format for context"); + throw std::runtime_error("Failed to set pixel format for context"); + } + + if (wglDisplayConfig->ARB_create_context) { + renderingWindowRenderingContext = mbgl::platform::wglCreateContextAttribsARB(renderingWindowDeviceContext, NULL, + std::initializer_list({ + WGL_CONTEXT_MAJOR_VERSION_ARB, 2, + WGL_CONTEXT_MINOR_VERSION_ARB, 0, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + NULL + }).begin()); + + if (!renderingWindowRenderingContext) { + const DWORD error = GetLastError(); + + if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { + Log::Error(Event::OpenGL, "Driver does not support OpenGL ES version 2.0"); + throw std::runtime_error("Driver does not support OpenGL ES version 2.0"); + } + else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) { + Log::Error(Event::OpenGL, "Driver does not support the requested OpenGL profile"); + throw std::runtime_error("Driver does not support the requested OpenGL profile"); + } + else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) { + Log::Error(Event::OpenGL, "The share context is not compatible with the requested context"); + throw std::runtime_error("The share context is not compatible with the requested context"); + } + else { + Log::Error(Event::OpenGL, "Failed to create OpenGL ES context"); + throw std::runtime_error("Failed to create OpenGL ES context"); + } + + return false; + } + } + else { + renderingWindowRenderingContext = wglCreateContext(renderingWindowDeviceContext); + + if (!renderingWindowRenderingContext) { + Log::Error(Event::OpenGL, "Failed to create OpenGL context"); + throw std::runtime_error("Failed to create OpenGL context"); + } + } + + HGLRC currentRenderingContext = wglGetCurrentContext(); + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(currentRenderingContext); + + wglMakeCurrent(renderingWindowDeviceContext, renderingWindowRenderingContext); + + return true; + } + + bool DestroyRenderingContext() { + if (renderingWindowRenderingContext && !wglMakeCurrent(renderingWindowDeviceContext, NULL)) { + Log::Error(Event::OpenGL, "Failed to make context current"); + //throw std::runtime_error("Failed to make context current"); + return false; + } + + if (renderingWindowRenderingContext && !wglDeleteContext(renderingWindowRenderingContext)) { + Log::Error(Event::OpenGL, "Failed to delete current context"); + //throw std::runtime_error("Failed to delete current context"); + return false; + } + + renderingWindowRenderingContext = NULL; + + return true; + } + +public: + WGLBackendImpl() { + auto renderingContext = GetContext(); + } + + ~WGLBackendImpl() final { + if (renderingWindowRenderingContext) { + DestroyRenderingContext(); + } + + DestroyRenderingWindow(); + } + + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { + return (ProcAddress)::wgl_GetProcAddress(name); + } + + void activateContext() final { + if (renderingWindowRenderingContext && !wglMakeCurrent(renderingWindowDeviceContext, renderingWindowRenderingContext)) { + Log::Error(Event::OpenGL, "Switching OpenGL context failed"); + //throw std::runtime_error("Switching OpenGL context failed"); + } + } + + void deactivateContext() final { + if (renderingWindowRenderingContext && !wglMakeCurrent(NULL, NULL)) { + Log::Error(Event::OpenGL, "Removing OpenGL context failed"); + //throw std::runtime_error("Removing OpenGL context failed"); + } + } +}; + +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/windows/src/thread.cpp b/platform/windows/src/thread.cpp new file mode 100644 index 00000000000..22405dcfcd8 --- /dev/null +++ b/platform/windows/src/thread.cpp @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include + +#include + +#include "thread.h" + +DWORD selfThreadKey; +DummyClassThread dummyClassThread; + +// https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2022 +void SetThreadName(DWORD dwThreadID, const char* threadName) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; +#pragma warning(push) + +#pragma warning(disable: 6320 6322) + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER){ + } +#pragma warning(pop) +} + +THREAD_INFO* GetCurrentThreadInfo() { + THREAD_INFO* info = (THREAD_INFO*)TlsGetValue(selfThreadKey); + + if (!info) { + info = (THREAD_INFO*)calloc(1, sizeof(THREAD_INFO)); + info->id = GetCurrentThreadId(); + info->key = selfThreadKey; + info->name = NULL; + + TlsSetValue(selfThreadKey, info); + } + + return info; +} + +namespace mbgl { +namespace platform { + +std::string getCurrentThreadName() { + THREAD_INFO* info = GetCurrentThreadInfo(); + + if (info && info->name) + { + return std::string(info->name); + } + + return std::string(); +} + +void setCurrentThreadName(const std::string& name) { + THREAD_INFO* info = GetCurrentThreadInfo(); + + if (info && info->name) + { + free(info->name); + info->name = new char[name.length() + 1]; + std::strcpy(info->name, name.c_str()); + } + + SetThreadName(-1, name.c_str()); +} + +void makeThreadLowPriority() { + if (!SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN)) { + Log::Warning(Event::General, "Couldn't set thread scheduling policy"); + } +} + +void setCurrentThreadPriority(double priority) { + if (!SetThreadPriority(GetCurrentThread(), int(priority))) { + Log::Warning(Event::General, "Couldn't set thread priority"); + } +} + +void attachThread() {} + +void detachThread() {} + +} // namespace platform +} // namespace mbgl diff --git a/platform/windows/src/thread_local.cpp b/platform/windows/src/thread_local.cpp new file mode 100644 index 00000000000..dba1f1275cd --- /dev/null +++ b/platform/windows/src/thread_local.cpp @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include "thread.h" + +#define StorageToThreadInfo reinterpret_cast(storage) + +namespace mbgl { +namespace util { +namespace impl { + +ThreadLocalBase::ThreadLocalBase() { + static_assert(sizeof(storage) >= sizeof(THREAD_INFO*), "storage is too small"); + static_assert(alignof(decltype(storage)) % alignof(THREAD_INFO*) == 0, "storage is incorrectly aligned"); + + THREAD_INFO* info = GetCurrentThreadInfo(); + THREAD_INFO* threadLocalInfo = (THREAD_INFO*)calloc(1, sizeof(THREAD_INFO)); + threadLocalInfo->id = info->id; + threadLocalInfo->name = info->name; + + if (threadLocalInfo == NULL || (threadLocalInfo->key = TlsAlloc()) == TLS_OUT_OF_INDEXES) { + Log::Error(Event::General, "Failed to initialize thread-specific storage key"); + abort(); + } + + StorageToThreadInfo = threadLocalInfo; +} + +ThreadLocalBase::~ThreadLocalBase() { + // ThreadLocal will not take ownership of the pointer it is managing. The pointer + // needs to be explicitly cleared before we destroy this object. + assert(!get()); + + DWORD key = StorageToThreadInfo->key; + + free(StorageToThreadInfo); + + if (!TlsFree(key)) { + Log::Error(Event::General, "Failed to delete thread-specific storage key"); + abort(); + } +} + +void* ThreadLocalBase::get() { + return TlsGetValue(StorageToThreadInfo->key); +} + +void ThreadLocalBase::set(void* ptr) { + if (!TlsSetValue(StorageToThreadInfo->key, ptr)) { + Log::Error(Event::General, "Failed to set thread-specific storage"); + abort(); + } +} + +} // namespace impl +} // namespace util +} // namespace mbgl diff --git a/platform/windows/vendor/vcpkg b/platform/windows/vendor/vcpkg new file mode 160000 index 00000000000..37fce29a263 --- /dev/null +++ b/platform/windows/vendor/vcpkg @@ -0,0 +1 @@ +Subproject commit 37fce29a263a1546262eaed6af7ccac53b0094cd diff --git a/platform/windows/vendor/vcpkg-custom-triplets/x64-windows.cmake b/platform/windows/vendor/vcpkg-custom-triplets/x64-windows.cmake new file mode 100644 index 00000000000..7f709cad6a0 --- /dev/null +++ b/platform/windows/vendor/vcpkg-custom-triplets/x64-windows.cmake @@ -0,0 +1,4 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +#set(VCPKG_BUILD_TYPE release) diff --git a/platform/windows/vendor/vcpkg-custom-triplets/x86-windows.cmake b/platform/windows/vendor/vcpkg-custom-triplets/x86-windows.cmake new file mode 100644 index 00000000000..79f48d9635c --- /dev/null +++ b/platform/windows/vendor/vcpkg-custom-triplets/x86-windows.cmake @@ -0,0 +1,4 @@ +set(VCPKG_TARGET_ARCHITECTURE x86) +set(VCPKG_CRT_LINKAGE static) +set(VCPKG_LIBRARY_LINKAGE static) +#set(VCPKG_BUILD_TYPE release) diff --git a/platform/windows/windows.cmake b/platform/windows/windows.cmake new file mode 100644 index 00000000000..b5f614fa205 --- /dev/null +++ b/platform/windows/windows.cmake @@ -0,0 +1,251 @@ +if(MBGL_WITH_EGL) + set(_RENDERER EGL) +elseif(MBGL_WITH_OSMESA) + set(_RENDERER OSMesa) +else() + set(_RENDERER OpenGL) +endif() + +execute_process(COMMAND powershell -ExecutionPolicy Bypass -File ${CMAKE_CURRENT_LIST_DIR}/Get-VendorPackages.ps1 -Triplet ${VCPKG_TARGET_TRIPLET} -Renderer ${_RENDERER}) +unset(_RENDERER) + +add_compile_definitions(NOMINMAX _USE_MATH_DEFINES GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) + +target_compile_options( + mbgl-compiler-options + INTERFACE + $<$:/MP> +) + +find_package(CURL REQUIRED) +find_package(dlfcn-win32 REQUIRED) +find_package(ICU OPTIONAL_COMPONENTS i18n uc) +find_package(JPEG REQUIRED) +find_package(libuv REQUIRED) +find_package(PNG REQUIRED) +find_path(DLFCN_INCLUDE_DIRS dlfcn.h) +find_path(LIBUV_INCLUDE_DIRS uv.h) + +target_sources( + mbgl-core + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/gfx/headless_backend.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/gfx/headless_frontend.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/gl/headless_backend.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/i18n/collator.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/i18n/number_format.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/layermanager/layer_manager.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/platform/time.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/asset_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/database_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/file_source_manager.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/file_source_request.cpp + $<$:${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/http_file_source.cpp> + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/local_file_request.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/local_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/mbtiles_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/main_resource_loader.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_database.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_download.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/online_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/sqlite3.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/text/bidi.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/text/local_glyph_rasterizer.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/async_task.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/compression.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/image.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/jpeg_reader.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/logging_stderr.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/monotonic_timer.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/png_reader.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/png_writer.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/run_loop.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/string_stdlib.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/timer.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/utf.cpp + ${PROJECT_SOURCE_DIR}/platform/windows/src/thread.cpp + ${PROJECT_SOURCE_DIR}/platform/windows/src/thread_local.cpp +) + +target_compile_definitions( + mbgl-core + PRIVATE + CURL_STATICLIB + PUBLIC + MBGL_USE_GLES2 +) + +if(MBGL_WITH_EGL) + find_package(unofficial-angle CONFIG REQUIRED) + target_sources( + mbgl-core + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/windows/src/headless_backend_egl.cpp + ${PROJECT_SOURCE_DIR}/platform/windows/src/gl_functions.cpp + ) + target_compile_definitions( + mbgl-core + PRIVATE + KHRONOS_STATIC + ) + target_link_libraries( + mbgl-core + PRIVATE + unofficial::angle::libEGL + unofficial::angle::libGLESv2 + ) +elseif(MBGL_WITH_OSMESA) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + list(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR}/vendor/mesa3d) + + find_package(OSMesa REQUIRED) + target_sources( + mbgl-core + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/windows/src/headless_backend_osmesa.cpp + ${PROJECT_SOURCE_DIR}/platform/windows/src/gl_functions.cpp + ) + + set_property( + SOURCE ${PROJECT_SOURCE_DIR}/platform/windows/src/headless_backend_osmesa.cpp + PROPERTY INCLUDE_DIRECTORIES ${OSMesa_INCLUDE_DIRS} + ) + + target_link_libraries( + mbgl-core + PRIVATE + OSMesa::osmesa + OSMesa::libGLESv2 + ) +else() + find_package(OpenGL REQUIRED) + target_sources( + mbgl-core + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/windows/src/headless_backend_wgl.cpp + ) + target_compile_definitions( + mbgl-core + PRIVATE + KHRONOS_STATIC + ) + target_link_libraries( + mbgl-core + PRIVATE + OpenGL::GL + ) +endif() + +# FIXME: Should not be needed, but now needed by node because of the headless frontend. +target_include_directories( + mbgl-core + PUBLIC ${PROJECT_SOURCE_DIR}/platform/default/include + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/windows/include + ${CURL_INCLUDE_DIRS} + ${DLFCN_INCLUDE_DIRS} + ${JPEG_INCLUDE_DIRS} + ${LIBUV_INCLUDE_DIRS} +) + +include(${PROJECT_SOURCE_DIR}/vendor/nunicode.cmake) +include(${PROJECT_SOURCE_DIR}/vendor/sqlite.cmake) + +if(NOT ${ICU_FOUND} OR "${ICU_VERSION}" VERSION_LESS 62.0) + message(STATUS "ICU not found or too old, using builtin.") + + set(MBGL_USE_BUILTIN_ICU TRUE) + include(${PROJECT_SOURCE_DIR}/vendor/icu.cmake) + + set_source_files_properties( + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/i18n/number_format.cpp + PROPERTIES + COMPILE_DEFINITIONS + MBGL_USE_BUILTIN_ICU + ) +endif() + +target_link_libraries( + mbgl-core + PRIVATE + ${CURL_LIBRARIES} + ${JPEG_LIBRARIES} + ${LIBUV_LIBRARIES} + dlfcn-win32::dl + $<$>:ICU::data> + $<$>:ICU::i18n> + $<$>:ICU::uc> + $<$:mbgl-vendor-icu> + PNG::PNG + mbgl-vendor-nunicode + mbgl-vendor-sqlite +) + +add_subdirectory(${PROJECT_SOURCE_DIR}/bin) +add_subdirectory(${PROJECT_SOURCE_DIR}/expression-test) +add_subdirectory(${PROJECT_SOURCE_DIR}/platform/glfw) +add_subdirectory(${PROJECT_SOURCE_DIR}/platform/node) + +add_executable( + mbgl-test-runner + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/test/main.cpp +) + +target_compile_definitions( + mbgl-test-runner + PRIVATE MBGL_BUILDING_LIB WORK_DIRECTORY=${PROJECT_SOURCE_DIR} +) + +target_include_directories( + mbgl-test-runner + PRIVATE + ${PROJECT_SOURCE_DIR}/platform/windows/include +) + +target_link_libraries( + mbgl-test-runner + PRIVATE + mbgl-compiler-options + -Wl,--whole-archive + mbgl-test + -Wl,--no-whole-archive +) + +add_executable( + mbgl-benchmark-runner + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/benchmark/main.cpp +) + +target_link_libraries( + mbgl-benchmark-runner + PRIVATE + mbgl-compiler-options + mbgl-benchmark + -WHOLEARCHIVE:mbgl-benchmark + uv_a + shlwapi +) + +add_executable( + mbgl-render-test-runner + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/render-test/main.cpp +) + +target_compile_definitions( + mbgl-render-test-runner + PRIVATE MBGL_BUILDING_LIB +) + +target_link_libraries( + mbgl-render-test-runner + PRIVATE mbgl-compiler-options mbgl-render-test uv_a +) + +# Disable benchmarks in CI as they run in VM environment +if(NOT DEFINED ENV{CI}) + add_test(NAME mbgl-benchmark-runner COMMAND mbgl-benchmark-runner WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) +endif() +add_test(NAME mbgl-test-runner COMMAND mbgl-test-runner WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + +install(TARGETS mbgl-render-test-runner RUNTIME DESTINATION bin) diff --git a/render-test/manifest_parser.cpp b/render-test/manifest_parser.cpp index 0597240eb8b..1fc58196cf6 100644 --- a/render-test/manifest_parser.cpp +++ b/render-test/manifest_parser.cpp @@ -7,6 +7,10 @@ #include #include +#if defined(WIN32) && defined(GetObject) +#undef GetObject +#endif + Manifest::Manifest() { const char* envApiKey = getenv("MGL_API_KEY"); if (envApiKey != nullptr) { diff --git a/render-test/parser.cpp b/render-test/parser.cpp index f364810c181..4a039cf405b 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -6,6 +6,10 @@ #include "metadata.hpp" #include "runner.hpp" +#if defined(WIN32) && defined(GetObject) +#undef GetObject +#endif + #include #include #include diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp index c5dd529a919..c7edc2d4efe 100644 --- a/test/util/memory.test.cpp +++ b/test/util/memory.test.cpp @@ -1,4 +1,6 @@ +#ifndef NOMINMAX #define NOMINMAX +#endif #include #include