Gut the rest of graphicsdev and inputdev

This commit is contained in:
Luke Street 2022-03-09 00:04:40 -05:00
parent 94d11cb328
commit 33cfcd8b63
92 changed files with 2 additions and 86460 deletions

11
.gitmodules vendored
View File

@ -1,11 +0,0 @@
[submodule "glslang"]
path = glslang
url = https://github.com/KhronosGroup/glslang.git
branch = master
[submodule "logvisor"]
path = logvisor
url = ../logvisor.git
branch = master
[submodule "optick"]
path = optick
url = https://github.com/AxioDL/optick.git

View File

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
project(boo)
cmake_policy(SET CMP0074 NEW)
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
if (MSVC)
# Shaddup MSVC
add_compile_definitions(UNICODE=1 _UNICODE=1 __SSE__=1
@ -68,12 +69,10 @@ else ()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif ()
endif ()
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
if (NOT TARGET logvisor)
add_subdirectory(logvisor)
endif()
add_subdirectory(soxr/src)
add_library(boo
@ -93,20 +92,6 @@ add_library(boo
lib/audiodev/MIDIEncoder.cpp
lib/audiodev/WAVOut.cpp
lib/Common.hpp
# lib/graphicsdev/Common.cpp
# lib/graphicsdev/Common.hpp
# lib/inputdev/DeviceBase.cpp include/boo/inputdev/DeviceBase.hpp
# lib/inputdev/CafeProPad.cpp include/boo/inputdev/CafeProPad.hpp
# lib/inputdev/RevolutionPad.cpp include/boo/inputdev/RevolutionPad.hpp
# lib/inputdev/DolphinSmashAdapter.cpp include/boo/inputdev/DolphinSmashAdapter.hpp
# lib/inputdev/NintendoPowerA.cpp include/boo/inputdev/NintendoPowerA.hpp
# lib/inputdev/DualshockPad.cpp include/boo/inputdev/DualshockPad.hpp
# lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp
# lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp
# lib/inputdev/DeviceFinder.cpp include/boo/inputdev/DeviceFinder.hpp
# lib/inputdev/HIDParser.cpp include/boo/inputdev/HIDParser.hpp
# lib/inputdev/IHIDDevice.hpp
# include/boo/IGraphicsContext.hpp
include/boo/audiodev/IAudioSubmix.hpp
include/boo/audiodev/IAudioVoice.hpp
include/boo/audiodev/IAudioVoiceEngine.hpp
@ -114,30 +99,14 @@ add_library(boo
include/boo/audiodev/IMIDIReader.hpp
include/boo/audiodev/MIDIDecoder.hpp
include/boo/audiodev/MIDIEncoder.hpp
# include/boo/graphicsdev/IGraphicsDataFactory.hpp
# include/boo/graphicsdev/IGraphicsCommandQueue.hpp
# include/boo/inputdev/IHIDListener.hpp
# include/boo/inputdev/XInputPad.hpp
include/boo/boo.hpp
include/boo/BooObject.hpp
include/boo/DeferredWindowEvents.hpp
include/boo/IApplication.hpp
include/boo/IWindow.hpp
include/boo/System.hpp
include/boo/ThreadLocalPtr.hpp
# InputDeviceClasses.cpp
)
if (NOT MSVC)
target_compile_options(boo PRIVATE -Wno-narrowing)
endif()
option(BOO_GRAPHICS_DEBUG_GROUPS "Enable Debug Groups for labeling graphics passes within backend API." OFF)
if (BOO_GRAPHICS_DEBUG_GROUPS)
message(STATUS "Enabling graphics debug groups")
target_compile_definitions(boo PUBLIC -DBOO_GRAPHICS_DEBUG_GROUPS=1)
endif()
find_package(IPP)
if (IPP_FOUND)
target_compile_definitions(boo PUBLIC -DINTEL_IPP=1)
@ -154,29 +123,6 @@ target_include_directories(boo PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
#if(NOT GEKKO AND NOT CAFE AND NOT WINDOWS_STORE AND NOT NX)
# add_library(glew lib/graphicsdev/glew.c)
# # For some reason, clang takes forever if glew.c is not built with -Os
# if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
# set_source_files_properties(lib/graphicsdev/glew.c PROPERTIES COMPILE_FLAGS -Os)
# endif()
# target_include_directories(glew PUBLIC include/boo/graphicsdev)
# target_compile_definitions(glew PUBLIC -DGLEW_NO_GLU=1)
#endif()
#
#if(NOT GEKKO AND NOT CAFE AND NOT WINDOWS_STORE AND NOT NX AND NOT APPLE)
# target_sources(boo PRIVATE lib/graphicsdev/GL.cpp)
# target_compile_definitions(boo PUBLIC -DBOO_HAS_GL=1)
# target_link_libraries(boo PUBLIC glew)
#
# target_sources(boo PRIVATE
# include/boo/graphicsdev/GL.hpp
# include/boo/graphicsdev/GLSLMacros.hpp
# include/boo/graphicsdev/Vulkan.hpp
# include/boo/graphicsdev/VulkanDispatchTable.hpp
# )
#endif()
set(AudioMatrix_SRC lib/audiodev/AudioMatrix.cpp)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64
OR CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64
@ -189,17 +135,7 @@ if(WINDOWS_STORE)
target_sources(boo PRIVATE
${AudioMatrix_SRC}
lib/audiodev/WASAPI.cpp
# lib/inputdev/HIDDeviceUWP.cpp
# lib/inputdev/HIDListenerUWP.cpp
# lib/graphicsdev/D3D11.cpp
# lib/graphicsdev/D3D12.cpp
# lib/win/ApplicationUWP.cpp
# lib/win/UWPCommon.hpp
# lib/win/WinCommon.hpp
# lib/win/WindowUWP.cpp
include/boo/UWPViewProvider.hpp
# include/boo/graphicsdev/D3D.hpp
)
target_compile_definitions(boo PUBLIC
@ -208,33 +144,11 @@ if(WINDOWS_STORE)
)
target_link_libraries(boo PUBLIC
Hid
Imm32
opengl32
Setupapi
Shlwapi
Winmm
Winusb
Xinput
)
elseif(WIN32)
# unset(VULKAN_SDK_DIRS CACHE)
# get_filename_component(VULKAN_SDK_DIRS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\LunarG\\VulkanSDK;VK_SDK_PATHs]" ABSOLUTE CACHE)
# if (NOT "${VULKAN_SDK_DIRS}" STREQUAL "/registry")
# message(STATUS "Enabling Vulkan support")
# list(GET VULKAN_SDK_DIRS 0 VULKAN_SDK_DIR)
# target_include_directories(boo PUBLIC "${VULKAN_SDK_DIR}/Include")
# target_compile_definitions(boo PUBLIC
# -DBOO_HAS_VULKAN=1
# -DVK_USE_PLATFORM_WIN32_KHR=1
# )
# target_sources(boo PRIVATE
# lib/graphicsdev/Vulkan.cpp
# lib/graphicsdev/VulkanDispatchTable.cpp
# )
# set(BOO_ENABLE_VULKAN_IN_OPTICK TRUE)
# endif()
find_file(TE_VIRTUAL_MIDI_H teVirtualMIDI.h PATHS
"$ENV{PROGRAMFILES\(X86\)}/Tobias Erichsen/teVirtualMIDISDK/C-Binding")
find_file(TE_VIRTUAL_MIDI_H teVirtualMIDI.h
@ -251,15 +165,6 @@ elseif(WIN32)
target_sources(boo PRIVATE
${AudioMatrix_SRC}
lib/audiodev/WASAPI.cpp
# lib/graphicsdev/D3D11.cpp
# lib/inputdev/HIDListenerWinUSB.cpp
# lib/inputdev/HIDDeviceWinUSB.cpp
# lib/win/ApplicationWin32.cpp
# lib/win/WindowWin32.cpp
# lib/win/WinCommon.hpp
# lib/win/Win32Common.hpp
# include/boo/graphicsdev/D3D.hpp
)
target_compile_definitions(boo PUBLIC
@ -280,27 +185,14 @@ elseif(APPLE)
target_sources(boo PRIVATE
lib/audiodev/AQS.cpp
${AudioMatrix_SRC}
# lib/inputdev/HIDListenerIOKit.cpp
# lib/inputdev/HIDDeviceIOKit.cpp
# lib/mac/ApplicationCocoa.mm
# lib/mac/WindowCocoa.mm
# lib/mac/CocoaCommon.hpp
# lib/graphicsdev/Metal.mm
lib/CFPointer.hpp
# lib/inputdev/IOKitPointer.hpp
# include/boo/graphicsdev/Metal.hpp
)
set_source_files_properties(
# lib/mac/ApplicationCocoa.mm
# lib/mac/WindowCocoa.mm
# lib/graphicsdev/Metal.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc
)
find_library(APPKIT_LIBRARY AppKit)
find_library(IOKIT_LIBRARY IOKit)
unset(BOO_HAS_METAL CACHE)
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER 10.11)
set(BOO_HAS_METAL ON CACHE BOOL "Metal is available in this OS X version" FORCE)
@ -309,8 +201,6 @@ elseif(APPLE)
else()
set(METAL_LIBRARY "")
endif()
find_library(QUARTZCORE_LIBRARY QuartzCore)
find_library(COREVIDEO_LIBRARY CoreVideo)
find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
find_library(COREAUDIO_LIBRARY CoreAudio)
find_library(COREMIDI_LIBRARY CoreMIDI)
@ -321,72 +211,11 @@ elseif(APPLE)
${COREAUDIO_LIBRARY}
${COREMIDI_LIBRARY}
${COREVIDEO_LIBRARY}
${IOKIT_LIBRARY}
${METAL_LIBRARY}
${QUARTZCORE_LIBRARY}
)
else(NOT GEKKO)
target_sources(boo PRIVATE
lib/audiodev/LinuxMidi.hpp
# lib/graphicsdev/GL.cpp
# lib/graphicsdev/GLX.cpp
# lib/x11/XlibCommon.hpp
# lib/x11/ApplicationUnix.cpp
# lib/x11/ApplicationWayland.hpp
# lib/x11/ApplicationXlib.hpp
# lib/x11/WindowWayland.cpp
# lib/x11/WindowXlib.cpp
)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(dbus_pkg QUIET libdbus dbus-1)
endif()
find_path(DBUS_INCLUDE_DIR
NAMES
dbus/dbus.h
HINTS
${dbus_pkg_INCLUDE_DIRS}
PATH_SUFFIXES
include/
include/dbus-1.0/
dbus-1.0/
)
find_path(DBUS_ARCH_INCLUDE_DIR
NAMES
dbus/dbus-arch-deps.h
HINTS
${dbus_pkg_INCLUDE_DIRS}
PATHS
# TODO use CMAKE_SYSTEM_PROCESSOR or similar?
/usr/lib/dbus-1.0/include
/usr/lib64/dbus-1.0/include
/usr/local/lib/dbus-1.0/include
/usr/lib/x86_64-linux-gnu/dbus-1.0/include
/usr/lib/aarch64-linux-gnu/dbus-1.0/include
PATH_SUFFIXES
dbus-1.0/include/
)
find_library(DBUS_LIBRARY
NAMES
dbus
dbus-1
HINTS
${dbus_pkg_LIBRARY_DIRS}
PATH_SUFFIXES
lib
lib32
lib64
)
find_path(PULSEAUDIO_INCLUDE_DIR
@ -399,59 +228,23 @@ else(NOT GEKKO)
target_sources(boo PRIVATE lib/audiodev/PulseAudio.cpp)
target_link_libraries(boo PUBLIC pulse)
if(DBUS_INCLUDE_DIR-NOTFOUND)
message(FATAL_ERROR "Unix build of boo requires dbus")
endif()
target_include_directories(boo PRIVATE
${DBUS_ARCH_INCLUDE_DIR}
${DBUS_INCLUDE_DIR}
)
target_link_libraries(boo
PUBLIC
asound
${DBUS_LIBRARY}
GL
pthread
X11
Xi
Xrandr
)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
# find_path(VULKAN_INCLUDE_DIR
# NAMES vulkan/vulkan.h
# )
# if(VULKAN_INCLUDE_DIR)
# message(STATUS "Enabling Vulkan support")
# target_sources(boo PRIVATE
# lib/graphicsdev/Vulkan.cpp
# lib/graphicsdev/VulkanDispatchTable.cpp
# )
# target_compile_definitions(boo
# PUBLIC
# -DBOO_HAS_VULKAN=1
# -DVK_USE_PLATFORM_XCB_KHR=1
# )
# set(BOO_ENABLE_VULKAN_IN_OPTICK TRUE)
# endif()
target_sources(boo PRIVATE
${AudioMatrix_SRC}
# lib/inputdev/HIDDeviceUdev.cpp
# lib/inputdev/HIDListenerUdev.cpp
)
target_link_libraries(boo
PUBLIC
dl
xcb
X11-xcb
udev
)
else()
target_sources(boo PRIVATE
${AudioMatrix_SRC}
# lib/inputdev/HIDDeviceBSD.cpp
# lib/inputdev/HIDListenerBSD.cpp
)
target_link_libraries(boo
PUBLIC
@ -462,64 +255,18 @@ else(NOT GEKKO)
endif()
if(NOT NX)
# Empty link args for boo's use
function(glslang_set_link_args TARGET)
endfunction(glslang_set_link_args)
# Disable PCH for now
function(glslang_pch SRCS PCHCPP)
endfunction(glslang_pch)
set(ENABLE_SPVREMAPPER On)
add_definitions("-DENABLE_OPT=0")
add_subdirectory(glslang/glslang)
add_subdirectory(glslang/OGLCompilersDLL)
add_subdirectory(glslang/SPIRV)
add_subdirectory(glslang/StandAlone)
if (NOT MSVC)
target_compile_options(glslang PRIVATE -Wno-implicit-fallthrough -Wno-strict-aliasing)
target_compile_options(SPIRV PRIVATE -Wno-implicit-fallthrough -Wno-strict-aliasing)
endif()
target_include_directories(glslang-default-resource-limits
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/glslang
)
target_link_libraries(boo
PUBLIC
glslang
glslang-default-resource-limits
OGLCompiler
OSDependent
soxr
SPIRV
)
endif()
# Include Optick and change the default value of some options
option(OPTICK_ENABLED "Enable profiling with Optick" OFF)
set(OPTICK_USE_VULKAN ${BOO_ENABLE_VULKAN_IN_OPTICK} CACHE BOOL "Built-in support for Vulkan" FORCE)
set(OPTICK_INSTALL_TARGETS OFF CACHE BOOL "Should optick be installed? Set to OFF if you use add_subdirectory to include Optick." FORCE)
add_subdirectory(optick)
target_link_libraries(boo PUBLIC logvisor OptickCore)
target_include_directories(boo
PUBLIC
include
PRIVATE
glslang
soxr/src
${CMAKE_CURRENT_SOURCE_DIR}
)
if(COMMAND add_sanitizers)
add_sanitizers(boo)
endif()
add_subdirectory(test)
if(WINDOWS_STORE)
set_property(TARGET boo booTest PROPERTY VS_WINRT_COMPONENT TRUE)
endif()

View File

@ -1,74 +0,0 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

View File

@ -1,17 +0,0 @@
#include "boo/inputdev/DeviceSignature.hpp"
#include "boo/inputdev/DolphinSmashAdapter.hpp"
#include "boo/inputdev/DualshockPad.hpp"
#include "boo/inputdev/GenericPad.hpp"
#include "boo/inputdev/XInputPad.hpp"
#include "boo/inputdev/NintendoPowerA.hpp"
namespace boo {
const DeviceSignature BOO_DEVICE_SIGS[] = {DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337, DeviceType::USB),
DEVICE_SIG(DualshockPad, 0x54c, 0x268, DeviceType::HID),
DEVICE_SIG(GenericPad, 0, 0, DeviceType::HID),
DEVICE_SIG(NintendoPowerA, 0x20D6, 0xA711, DeviceType::USB),
DEVICE_SIG(XInputPad, 0, 0, DeviceType::XInput),
DEVICE_SIG_SENTINEL()};
}

@ -1 +0,0 @@
Subproject commit 02c70ad10e1f9dc88ae4ee509f26fe5f9fb31843

View File

@ -1,248 +0,0 @@
#pragma once
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <vector>
#include "boo/IWindow.hpp"
namespace boo {
template <class Receiver>
struct DeferredWindowEvents : public IWindowCallback {
Receiver& m_rec;
std::mutex m_mt;
std::condition_variable m_resizeCv;
DeferredWindowEvents(Receiver& rec) : m_rec(rec) {}
bool m_destroyed = false;
void destroyed() override { m_destroyed = true; }
bool m_hasResize = false;
SWindowRect m_latestResize;
void resized(const SWindowRect& rect, bool sync) override {
std::unique_lock<std::mutex> lk(m_mt);
m_latestResize = rect;
m_hasResize = true;
if (sync)
m_resizeCv.wait_for(lk, std::chrono::milliseconds(500));
}
struct Command {
enum class Type {
MouseDown,
MouseUp,
MouseMove,
MouseEnter,
MouseLeave,
Scroll,
TouchDown,
TouchUp,
TouchMove,
CharKeyDown,
CharKeyUp,
SpecialKeyDown,
SpecialKeyUp,
ModKeyDown,
ModKeyUp
} m_type;
SWindowCoord m_coord;
EMouseButton m_button;
EModifierKey m_mods;
SScrollDelta m_scroll;
STouchCoord m_tCoord;
uintptr_t m_tid;
unsigned long m_charcode;
ESpecialKey m_special;
bool m_isRepeat;
void dispatch(Receiver& rec) const {
switch (m_type) {
case Type::MouseDown:
rec.mouseDown(m_coord, m_button, m_mods);
break;
case Type::MouseUp:
rec.mouseUp(m_coord, m_button, m_mods);
break;
case Type::MouseMove:
rec.mouseMove(m_coord);
break;
case Type::MouseEnter:
rec.mouseEnter(m_coord);
break;
case Type::MouseLeave:
rec.mouseLeave(m_coord);
break;
case Type::Scroll:
rec.scroll(m_coord, m_scroll);
break;
case Type::TouchDown:
rec.touchDown(m_tCoord, m_tid);
break;
case Type::TouchUp:
rec.touchUp(m_tCoord, m_tid);
break;
case Type::TouchMove:
rec.touchMove(m_tCoord, m_tid);
break;
case Type::CharKeyDown:
rec.charKeyDown(m_charcode, m_mods, m_isRepeat);
break;
case Type::CharKeyUp:
rec.charKeyUp(m_charcode, m_mods);
break;
case Type::SpecialKeyDown:
rec.specialKeyDown(m_special, m_mods, m_isRepeat);
break;
case Type::SpecialKeyUp:
rec.specialKeyUp(m_special, m_mods);
break;
case Type::ModKeyDown:
rec.modKeyDown(m_mods, m_isRepeat);
break;
case Type::ModKeyUp:
rec.modKeyUp(m_mods);
break;
default:
break;
}
}
Command(Type tp) : m_type(tp) {}
};
std::vector<Command> m_cmds;
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseDown);
m_cmds.back().m_coord = coord;
m_cmds.back().m_button = button;
m_cmds.back().m_mods = mods;
}
void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseUp);
m_cmds.back().m_coord = coord;
m_cmds.back().m_button = button;
m_cmds.back().m_mods = mods;
}
void mouseMove(const SWindowCoord& coord) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseMove);
m_cmds.back().m_coord = coord;
}
void mouseEnter(const SWindowCoord& coord) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseEnter);
m_cmds.back().m_coord = coord;
}
void mouseLeave(const SWindowCoord& coord) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseLeave);
m_cmds.back().m_coord = coord;
}
void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::Scroll);
m_cmds.back().m_coord = coord;
m_cmds.back().m_scroll = scroll;
}
void touchDown(const STouchCoord& coord, uintptr_t tid) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchDown);
m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid;
}
void touchUp(const STouchCoord& coord, uintptr_t tid) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchUp);
m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid;
}
void touchMove(const STouchCoord& coord, uintptr_t tid) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchMove);
m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid;
}
void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::CharKeyDown);
m_cmds.back().m_charcode = charCode;
m_cmds.back().m_mods = mods;
m_cmds.back().m_isRepeat = isRepeat;
}
void charKeyUp(unsigned long charCode, EModifierKey mods) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::CharKeyUp);
m_cmds.back().m_charcode = charCode;
m_cmds.back().m_mods = mods;
}
void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::SpecialKeyDown);
m_cmds.back().m_special = key;
m_cmds.back().m_mods = mods;
m_cmds.back().m_isRepeat = isRepeat;
}
void specialKeyUp(ESpecialKey key, EModifierKey mods) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::SpecialKeyUp);
m_cmds.back().m_special = key;
m_cmds.back().m_mods = mods;
}
void modKeyDown(EModifierKey mod, bool isRepeat) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::ModKeyDown);
m_cmds.back().m_mods = mod;
m_cmds.back().m_isRepeat = isRepeat;
}
void modKeyUp(EModifierKey mod) override {
std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::ModKeyUp);
m_cmds.back().m_mods = mod;
}
ITextInputCallback* getTextInputCallback() override { return m_rec.getTextInputCallback(); }
void dispatchEvents() {
std::unique_lock<std::mutex> lk(m_mt);
bool destroyed = m_destroyed;
bool hasResize = m_hasResize;
if (hasResize)
m_hasResize = false;
SWindowRect latestResize = m_latestResize;
std::vector<Command> cmds;
m_cmds.swap(cmds);
lk.unlock();
if (destroyed) {
m_rec.destroyed();
return;
}
if (hasResize)
m_rec.resized(latestResize, false);
for (const Command& cmd : cmds)
cmd.dispatch(m_rec);
}
};
} // namespace boo

View File

@ -1,75 +0,0 @@
#pragma once
#include <memory>
#include <string_view>
#include <vector>
#include "boo/IWindow.hpp"
#include "boo/System.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
namespace boo {
class IApplication;
struct IApplicationCallback {
virtual int appMain(IApplication*) = 0;
virtual void appQuitting(IApplication*) = 0;
virtual void appFilesOpen(IApplication*, const std::vector<std::string>&) {}
};
class IApplication {
friend class WindowCocoa;
friend class WindowWayland;
friend class WindowXlib;
friend class WindowWin32;
virtual void _deletedWindow(IWindow* window) = 0;
public:
virtual ~IApplication() = default;
enum class EPlatformType {
Auto = 0,
Wayland = 1,
Xlib = 2,
Android = 3,
Cocoa = 4,
CocoaTouch = 5,
Win32 = 6,
UWP = 7,
Revolution = 8,
Cafe = 9,
NX = 10,
Qt = 11
};
virtual EPlatformType getPlatformType() const = 0;
virtual int run() = 0;
virtual std::string_view getUniqueName() const = 0;
virtual std::string_view getFriendlyName() const = 0;
virtual std::string_view getProcessName() const = 0;
virtual const std::vector<std::string>& getArgs() const = 0;
/* Constructors/initializers for sub-objects */
virtual std::shared_ptr<IWindow> newWindow(std::string_view title) = 0;
};
int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, std::string_view uniqueName,
std::string_view friendlyName, std::string_view pname, const std::vector<std::string>& args,
std::string_view gfxApi = {}, uint32_t samples = 1, uint32_t anisotropy = 1, bool deepColor = false,
bool singleInstance = true);
extern IApplication* APP;
static inline int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb,
std::string_view uniqueName, std::string_view friendlyName, int argc,
char** argv, std::string_view gfxApi = {}, uint32_t samples = 1,
uint32_t anisotropy = 1, bool deepColor = false, bool singleInstance = true) {
if (APP)
return 1;
std::vector<std::string> args;
for (int i = 1; i < argc; ++i)
args.push_back(argv[i]);
return ApplicationRun(platform, cb, uniqueName, friendlyName, argv[0], args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
}
} // namespace boo

View File

@ -1,57 +0,0 @@
#pragma once
#include <cstdint>
#include <memory>
namespace boo {
struct IGraphicsCommandQueue;
struct IGraphicsDataFactory;
class IGraphicsContext {
friend class WindowCocoa;
friend class WindowXCB;
virtual void _setCallback([[maybe_unused]] class IWindowCallback* cb) {}
public:
enum class EGraphicsAPI {
Invalid = 0,
OpenGL3_3 = 1,
OpenGL4_2 = 2,
Vulkan = 3,
D3D11 = 4,
Metal = 6,
GX = 7,
GX2 = 8,
NX = 9
};
enum class EPixelFormat {
Invalid = 0,
RGBA8 = 1, /* Default */
RGBA16 = 2,
RGBA8_Z24 = 3,
RGBAF32 = 4,
RGBAF32_Z24 = 5
};
virtual ~IGraphicsContext() = default;
virtual EGraphicsAPI getAPI() const = 0;
virtual EPixelFormat getPixelFormat() const = 0;
virtual void setPixelFormat(EPixelFormat pf) = 0;
virtual bool initializeContext(void* handle) = 0;
virtual void makeCurrent() = 0;
virtual void postInit() = 0;
virtual void present() = 0;
virtual IGraphicsCommandQueue* getCommandQueue() = 0;
virtual IGraphicsDataFactory* getDataFactory() = 0;
/* Creates a new context on current thread!! Call from main client thread */
virtual IGraphicsDataFactory* getMainContextDataFactory() = 0;
/* Creates a new context on current thread!! Call from client loading thread */
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
};
} // namespace boo

View File

@ -1,272 +0,0 @@
#pragma once
#include <algorithm>
#include <array>
#include <memory>
#include "boo/System.hpp"
#undef min
#undef max
namespace boo {
struct IGraphicsCommandQueue;
struct IGraphicsDataFactory;
struct IAudioVoiceEngine;
enum class EMouseButton { None = 0, Primary = 1, Secondary = 2, Middle = 3, Aux1 = 4, Aux2 = 5 };
struct SWindowCoord {
std::array<int, 2> pixel;
std::array<int, 2> virtualPixel;
std::array<float, 2> norm;
};
struct SWindowRect {
std::array<int, 2> location{};
std::array<int, 2> size{};
constexpr SWindowRect() noexcept = default;
constexpr SWindowRect(int x, int y, int w, int h) noexcept : location{x, y}, size{w, h} {}
constexpr bool operator==(const SWindowRect& other) const noexcept {
return location[0] == other.location[0] && location[1] == other.location[1] && size[0] == other.size[0] &&
size[1] == other.size[1];
}
constexpr bool operator!=(const SWindowRect& other) const noexcept { return !operator==(other); }
constexpr bool coordInRect(const SWindowCoord& coord) const noexcept {
return coord.pixel[0] >= location[0] && coord.pixel[0] < location[0] + size[0] && coord.pixel[1] >= location[1] &&
coord.pixel[1] < location[1] + size[1];
}
constexpr SWindowRect intersect(const SWindowRect& other) const noexcept {
if (location[0] < other.location[0] + other.size[0] && location[0] + size[0] > other.location[0] &&
location[1] < other.location[1] + other.size[1] && location[1] + size[1] > other.location[1]) {
SWindowRect ret;
ret.location[0] = std::max(location[0], other.location[0]);
ret.location[1] = std::max(location[1], other.location[1]);
ret.size[0] = std::min(location[0] + size[0], other.location[0] + other.size[0]) - ret.location[0];
ret.size[1] = std::min(location[1] + size[1], other.location[1] + other.size[1]) - ret.location[1];
return ret;
}
return {};
}
};
struct STouchCoord {
std::array<double, 2> coord;
};
struct SScrollDelta {
std::array<double, 2> delta{};
bool isFine = false; /* Use system-scale fine-scroll (for scrollable-trackpads) */
bool isAccelerated = false; /* System performs acceleration computation */
constexpr SScrollDelta operator+(const SScrollDelta& other) const noexcept {
SScrollDelta ret;
ret.delta[0] = delta[0] + other.delta[0];
ret.delta[1] = delta[1] + other.delta[1];
ret.isFine = isFine || other.isFine;
ret.isAccelerated = isAccelerated || other.isAccelerated;
return ret;
}
constexpr SScrollDelta operator-(const SScrollDelta& other) const noexcept {
SScrollDelta ret;
ret.delta[0] = delta[0] - other.delta[0];
ret.delta[1] = delta[1] - other.delta[1];
ret.isFine = isFine || other.isFine;
ret.isAccelerated = isAccelerated || other.isAccelerated;
return ret;
}
constexpr SScrollDelta& operator+=(const SScrollDelta& other) noexcept {
delta[0] += other.delta[0];
delta[1] += other.delta[1];
isFine |= other.isFine;
isAccelerated |= other.isAccelerated;
return *this;
}
constexpr void zeroOut() noexcept { delta = {}; }
constexpr bool isZero() const noexcept { return delta[0] == 0.0 && delta[1] == 0.0; }
};
enum class ESpecialKey {
None = 0,
F1 = 1,
F2 = 2,
F3 = 3,
F4 = 4,
F5 = 5,
F6 = 6,
F7 = 7,
F8 = 8,
F9 = 9,
F10 = 10,
F11 = 11,
F12 = 12,
Esc = 13,
Enter = 14,
Backspace = 15,
Insert = 16,
Delete = 17,
Home = 18,
End = 19,
PgUp = 20,
PgDown = 21,
Left = 22,
Right = 23,
Up = 24,
Down = 25,
Tab = 26,
MAX = 27,
};
enum class EModifierKey {
None = 0,
Ctrl = 1 << 0,
Alt = 1 << 2,
Shift = 1 << 3,
Command = 1 << 4,
CtrlCommand = EModifierKey::Ctrl | EModifierKey::Command
};
ENABLE_BITWISE_ENUM(EModifierKey)
struct ITextInputCallback {
virtual bool hasMarkedText() const = 0;
virtual std::pair<int, int> markedRange() const = 0;
virtual std::pair<int, int> selectedRange() const = 0;
virtual void setMarkedText(std::string_view str, const std::pair<int, int>& selectedRange,
const std::pair<int, int>& replacementRange) = 0;
virtual void unmarkText() = 0;
virtual std::string substringForRange(const std::pair<int, int>& range, std::pair<int, int>& actualRange) const = 0;
virtual void insertText(std::string_view str, const std::pair<int, int>& range = {-1, 0}) = 0;
virtual int characterIndexAtPoint(const SWindowCoord& point) const = 0;
virtual SWindowRect rectForCharacterRange(const std::pair<int, int>& range,
std::pair<int, int>& actualRange) const = 0;
};
class IWindowCallback {
public:
virtual void resized([[maybe_unused]] const SWindowRect& rect, [[maybe_unused]] bool sync) {}
virtual void mouseDown([[maybe_unused]] const SWindowCoord& coord, [[maybe_unused]] EMouseButton button,
[[maybe_unused]] EModifierKey mods) {}
virtual void mouseUp([[maybe_unused]] const SWindowCoord& coord, [[maybe_unused]] EMouseButton button,
[[maybe_unused]] EModifierKey mods) {}
virtual void mouseMove([[maybe_unused]] const SWindowCoord& coord) {}
virtual void mouseEnter([[maybe_unused]] const SWindowCoord& coord) {}
virtual void mouseLeave([[maybe_unused]] const SWindowCoord& coord) {}
virtual void scroll([[maybe_unused]] const SWindowCoord& coord, [[maybe_unused]] const SScrollDelta& scroll) {}
virtual void touchDown([[maybe_unused]] const STouchCoord& coord, [[maybe_unused]] uintptr_t tid) {}
virtual void touchUp([[maybe_unused]] const STouchCoord& coord, [[maybe_unused]] uintptr_t tid) {}
virtual void touchMove([[maybe_unused]] const STouchCoord& coord, [[maybe_unused]] uintptr_t tid) {}
virtual void charKeyDown([[maybe_unused]] unsigned long charCode, [[maybe_unused]] EModifierKey mods,
[[maybe_unused]] bool isRepeat) {}
virtual void charKeyUp([[maybe_unused]] unsigned long charCode, [[maybe_unused]] EModifierKey mods) {}
virtual void specialKeyDown([[maybe_unused]] ESpecialKey key, [[maybe_unused]] EModifierKey mods,
[[maybe_unused]] bool isRepeat) {}
virtual void specialKeyUp([[maybe_unused]] ESpecialKey key, [[maybe_unused]] EModifierKey mods) {}
virtual void modKeyDown([[maybe_unused]] EModifierKey mod, [[maybe_unused]] bool isRepeat) {}
virtual void modKeyUp([[maybe_unused]] EModifierKey mod) {}
virtual ITextInputCallback* getTextInputCallback() { return nullptr; }
virtual void focusLost() {}
virtual void focusGained() {}
virtual void windowMoved([[maybe_unused]] const SWindowRect& rect) {}
virtual void destroyed() {}
};
enum class ETouchType { None = 0, Display = 1, Trackpad = 2 };
enum class EWindowStyle {
None = 0,
Titlebar = 1 << 0,
Resize = 1 << 1,
Close = 1 << 2,
Default = Titlebar | Resize | Close
};
ENABLE_BITWISE_ENUM(EWindowStyle)
enum class EMouseCursor {
None = 0,
Pointer = 1,
HorizontalArrow = 2,
VerticalArrow = 3,
IBeam = 4,
Crosshairs = 5,
BottomRightArrow = 6,
BottomLeftArrow = 7,
Hand = 8,
NotAllowed = 9,
};
enum class EClipboardType { None = 0, String = 1, UTF8String = 2, PNGImage = 3 };
class IWindow : public std::enable_shared_from_this<IWindow> {
public:
virtual ~IWindow() = default;
virtual void setCallback(IWindowCallback* cb) = 0;
virtual void closeWindow() = 0;
virtual void showWindow() = 0;
virtual void hideWindow() = 0;
virtual std::string getTitle() = 0;
virtual void setTitle(std::string_view title) = 0;
virtual void setCursor(EMouseCursor cursor) = 0;
virtual void setWaitCursor(bool wait) = 0;
virtual double getWindowRefreshRate() const = 0;
virtual void setWindowFrameDefault() = 0;
virtual void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const = 0;
virtual void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const = 0;
virtual SWindowRect getWindowFrame() const {
SWindowRect retval;
getWindowFrame(retval.location[0], retval.location[1], retval.size[0], retval.size[1]);
return retval;
}
virtual void setWindowFrame(float x, float y, float w, float h) = 0;
virtual void setWindowFrame(int x, int y, int w, int h) = 0;
virtual void setWindowFrame(const SWindowRect& rect) {
setWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]);
}
virtual float getVirtualPixelFactor() const = 0;
virtual bool isFullscreen() const = 0;
virtual void setFullscreen(bool fs) = 0;
virtual void claimKeyboardFocus(const int coord[2]) = 0;
virtual bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) = 0;
virtual std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz) = 0;
virtual int waitForRetrace() = 0;
virtual uintptr_t getPlatformHandle() const = 0;
virtual bool _incomingEvent([[maybe_unused]] void* event) { return false; }
virtual void _cleanup() {}
virtual ETouchType getTouchType() const = 0;
virtual void setStyle(EWindowStyle style) = 0;
virtual EWindowStyle getStyle() const = 0;
virtual void setTouchBarProvider([[maybe_unused]] void* provider) {}
virtual IGraphicsCommandQueue* getCommandQueue() = 0;
virtual IGraphicsDataFactory* getDataFactory() = 0;
/* Creates a new context on current thread!! Call from main client thread */
virtual IGraphicsDataFactory* getMainContextDataFactory() = 0;
/* Creates a new context on current thread!! Call from client loading thread */
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
};
} // namespace boo

View File

@ -1,33 +0,0 @@
#pragma once
#ifndef __SWITCH__
#if _WIN32
#else
#include <pthread.h>
#endif
/** Multiplatform TLS-pointer wrapper (for compilers without proper thread_local support) */
template <class T>
class ThreadLocalPtr {
#if _WIN32
DWORD m_key;
public:
ThreadLocalPtr() { m_key = TlsAlloc(); }
~ThreadLocalPtr() { TlsFree(m_key); }
T* get() const { return static_cast<T*>(TlsGetValue(m_key)); }
void reset(T* v = nullptr) { TlsSetValue(m_key, LPVOID(v)); }
#else
pthread_key_t m_key;
public:
ThreadLocalPtr() { pthread_key_create(&m_key, nullptr); }
~ThreadLocalPtr() { pthread_key_delete(m_key); }
T* get() const { return static_cast<T*>(pthread_getspecific(m_key)); }
void reset(T* v = nullptr) { pthread_setspecific(m_key, v); }
#endif
T* operator->() { return get(); }
};
#endif

View File

@ -1,38 +0,0 @@
#pragma once
#include "boo/IApplication.hpp"
namespace boo {
#if WINDOWS_STORE
using namespace Windows::ApplicationModel::Core;
ref struct ViewProvider sealed : IFrameworkViewSource {
internal : ViewProvider(boo::IApplicationCallback& appCb, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, Platform::Array<Platform::String ^> ^ params, bool singleInstance)
: m_appCb(appCb)
, m_uniqueName(uniqueName)
, m_friendlyName(friendlyName)
, m_pname(pname)
, m_singleInstance(singleInstance) {
char selfPath[1024];
GetModuleFileNameW(nullptr, selfPath, 1024);
m_args.reserve(params->Length + 1);
m_args.emplace_back(selfPath);
for (Platform::String ^ str : params)
m_args.emplace_back(str->Data());
}
public:
virtual IFrameworkView ^ CreateView();
internal : boo::IApplicationCallback& m_appCb;
std::string m_uniqueName;
std::string m_friendlyName;
std::string m_pname;
std::vector<std::string> m_args;
bool m_singleInstance;
};
#endif
} // namespace boo

View File

@ -1,72 +0,0 @@
#pragma once
#if _WIN32
#include <cstddef>
#include <vector>
#include "boo/BooObject.hpp"
#include "boo/System.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
using pD3DCreateBlob = HRESULT(WINAPI*)(SIZE_T Size, ID3DBlob** ppBlob);
extern pD3DCreateBlob D3DCreateBlobPROC;
namespace boo {
struct BaseGraphicsData;
class D3D11DataFactory : public IGraphicsDataFactory {
public:
~D3D11DataFactory() override = default;
Platform platform() const override { return Platform::D3D11; }
const char* platformName() const override { return "D3D11"; }
class Context final : public IGraphicsDataFactory::Context {
friend class D3D11DataFactoryImpl;
D3D11DataFactory& m_parent;
ObjToken<BaseGraphicsData> m_data;
Context(D3D11DataFactory& parent __BooTraceArgs);
~Context();
public:
Platform platform() const override { return Platform::D3D11; }
const char* platformName() const override { return "D3D11"; }
ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) override;
ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count) override;
ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz) override;
ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz) override;
ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode) override;
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t colorBindCount,
size_t depthBindCount) override;
ObjToken<ITextureCubeR> newCubeRenderTexture(size_t width, size_t mips) override;
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) override;
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo,
bool asynchronous = true) override;
ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount,
const ObjToken<ITexture>* texs, const int* bindIdxs, const bool* bindDepth,
size_t baseVert = 0, size_t baseInst = 0) override;
};
static std::vector<uint8_t> CompileHLSL(const char* source, PipelineStage stage);
};
} // namespace boo
#endif // _WIN32

View File

@ -1,66 +0,0 @@
#pragma once
#if BOO_HAS_GL
#include <cstdint>
#include "boo/BooObject.hpp"
#include "boo/graphicsdev/IGraphicsCommandQueue.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace boo {
struct BaseGraphicsData;
struct GLContext {
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
bool m_deepColor = false;
};
class GLDataFactory : public IGraphicsDataFactory {
public:
class Context final : public IGraphicsDataFactory::Context {
friend class GLDataFactoryImpl;
GLDataFactory& m_parent;
ObjToken<BaseGraphicsData> m_data;
Context(GLDataFactory& parent __BooTraceArgs);
~Context();
public:
Platform platform() const override { return Platform::OpenGL; }
const char* platformName() const override { return "OpenGL"; }
ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) override;
ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count) override;
ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz) override;
ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz) override;
ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode) override;
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount) override;
ObjToken<ITextureCubeR> newCubeRenderTexture(size_t width, size_t mips) override;
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) override;
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo,
bool asynchronous = true) override;
ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount,
const ObjToken<ITexture>* texs, const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0) override;
};
};
} // namespace boo
#endif

View File

@ -1,57 +0,0 @@
#pragma once
#define BOO_GLSL_MAX_UNIFORM_COUNT 8
#define BOO_GLSL_MAX_TEXTURE_COUNT 12
#define BOO_GLSL_BINDING_HEAD \
"#ifdef VULKAN\n" \
"#define gl_VertexID gl_VertexIndex\n" \
"#extension GL_ARB_separate_shader_objects: enable\n" \
"#define SBINDING(idx) layout(location=idx)\n" \
"#else\n" \
"#define SBINDING(idx)\n" \
"#endif\n" \
"#extension GL_ARB_shading_language_420pack: enable\n" \
"#ifdef GL_ARB_shading_language_420pack\n" \
"#define UBINDING0 layout(binding=0)\n" \
"#define UBINDING1 layout(binding=1)\n" \
"#define UBINDING2 layout(binding=2)\n" \
"#define UBINDING3 layout(binding=3)\n" \
"#define UBINDING4 layout(binding=4)\n" \
"#define UBINDING5 layout(binding=5)\n" \
"#define UBINDING6 layout(binding=6)\n" \
"#define UBINDING7 layout(binding=7)\n" \
"#define TBINDING0 layout(binding=8)\n" \
"#define TBINDING1 layout(binding=9)\n" \
"#define TBINDING2 layout(binding=10)\n" \
"#define TBINDING3 layout(binding=11)\n" \
"#define TBINDING4 layout(binding=12)\n" \
"#define TBINDING5 layout(binding=13)\n" \
"#define TBINDING6 layout(binding=14)\n" \
"#define TBINDING7 layout(binding=15)\n" \
"#define TBINDING8 layout(binding=16)\n" \
"#define TBINDING9 layout(binding=17)\n" \
"#define TBINDING10 layout(binding=18)\n" \
"#define TBINDING11 layout(binding=19)\n" \
"#else\n" \
"#define UBINDING0\n" \
"#define UBINDING1\n" \
"#define UBINDING2\n" \
"#define UBINDING3\n" \
"#define UBINDING4\n" \
"#define UBINDING5\n" \
"#define UBINDING6\n" \
"#define UBINDING7\n" \
"#define TBINDING0\n" \
"#define TBINDING1\n" \
"#define TBINDING2\n" \
"#define TBINDING3\n" \
"#define TBINDING4\n" \
"#define TBINDING5\n" \
"#define TBINDING6\n" \
"#define TBINDING7\n" \
"#define TBINDING8\n" \
"#define TBINDING9\n" \
"#define TBINDING10\n" \
"#define TBINDING11\n" \
"#endif\n"

View File

@ -1,53 +0,0 @@
#pragma once
#include <array>
#include <cstddef>
#include <functional>
#include "boo/BooObject.hpp"
#include "boo/IWindow.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace boo {
struct IGraphicsCommandQueue {
virtual ~IGraphicsCommandQueue() = default;
using Platform = IGraphicsDataFactory::Platform;
virtual Platform platform() const = 0;
virtual const char* platformName() const = 0;
virtual void setShaderDataBinding(const ObjToken<IShaderDataBinding>& binding) = 0;
virtual void setRenderTarget(const ObjToken<ITextureR>& target) = 0;
virtual void setRenderTarget(const ObjToken<ITextureCubeR>& target, int face) = 0;
virtual void setViewport(const SWindowRect& rect, float znear = 0.f, float zfar = 1.f) = 0;
virtual void setScissor(const SWindowRect& rect) = 0;
virtual void resizeRenderTexture(const ObjToken<ITextureR>& tex, size_t width, size_t height) = 0;
virtual void resizeRenderTexture(const ObjToken<ITextureCubeR>& tex, size_t width, size_t mips) = 0;
virtual void generateMipmaps(const ObjToken<ITextureCubeR>& tex) = 0;
virtual void schedulePostFrameHandler(std::function<void(void)>&& func) = 0;
virtual void setClearColor(const float rgba[4]) = 0;
virtual void clearTarget(bool render = true, bool depth = true) = 0;
virtual void draw(size_t start, size_t count) = 0;
virtual void drawIndexed(size_t start, size_t count, size_t baseVertex = 0) = 0;
virtual void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0;
virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0;
virtual void resolveBindTexture(const ObjToken<ITextureR>& texture, const SWindowRect& rect, bool tlOrigin,
int bindIdx, bool color, bool depth, bool clearDepth = false) = 0;
virtual void resolveDisplay(const ObjToken<ITextureR>& source) = 0;
virtual void execute() = 0;
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
virtual void pushDebugGroup(const char* name, const std::array<float, 4>& color = {1.f, 1.f, 1.f, 1.f}) = 0;
virtual void popDebugGroup() = 0;
#endif
virtual void startRenderer() = 0;
virtual void stopRenderer() = 0;
};
} // namespace boo

View File

@ -1,294 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <vector>
#include "boo/BooObject.hpp"
#include "boo/System.hpp"
#ifdef __SWITCH__
#include <ctype.h>
#endif
namespace boo {
struct IGraphicsCommandQueue;
/** Supported buffer uses */
enum class BufferUse { Null, Vertex, Index, Uniform };
/** Typeless graphics buffer */
struct IGraphicsBuffer : IObj {
bool dynamic() const { return m_dynamic; }
protected:
bool m_dynamic;
explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {}
};
/** Static resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferS : IGraphicsBuffer {
protected:
IGraphicsBufferS() : IGraphicsBuffer(false) {}
};
/** Dynamic resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferD : IGraphicsBuffer {
virtual void load(const void* data, size_t sz) = 0;
virtual void* map(size_t sz) = 0;
virtual void unmap() = 0;
protected:
IGraphicsBufferD() : IGraphicsBuffer(true) {}
};
/** Texture access types */
enum class TextureType { Static, StaticArray, Dynamic, Render, CubeRender };
/** Supported texture formats */
enum class TextureFormat { RGBA8, I8, I16, DXT1, DXT3, DXT5, BPTC };
/** Supported texture clamp modes */
enum class TextureClampMode { Invalid = -1, Repeat, ClampToWhite, ClampToBlack, ClampToEdge, ClampToEdgeNearest };
/** Typeless texture */
struct ITexture : IObj {
TextureType type() const { return m_type; }
/* Only applies on GL and Vulkan. Use shader semantics on other platforms */
virtual void setClampMode(TextureClampMode mode) {}
protected:
TextureType m_type;
explicit ITexture(TextureType type) : m_type(type) {}
};
/** Static resource buffer for textures */
struct ITextureS : ITexture {
protected:
ITextureS() : ITexture(TextureType::Static) {}
};
/** Static-array resource buffer for array textures */
struct ITextureSA : ITexture {
protected:
ITextureSA() : ITexture(TextureType::StaticArray) {}
};
/** Dynamic resource buffer for textures */
struct ITextureD : ITexture {
virtual void load(const void* data, size_t sz) = 0;
virtual void* map(size_t sz) = 0;
virtual void unmap() = 0;
protected:
ITextureD() : ITexture(TextureType::Dynamic) {}
};
/** Resource buffer for render-target textures */
struct ITextureR : ITexture {
protected:
ITextureR() : ITexture(TextureType::Render) {}
};
/** Resource buffer for cube render-target textures */
struct ITextureCubeR : ITexture {
protected:
ITextureCubeR() : ITexture(TextureType::CubeRender) {}
};
/** Types of vertex attributes */
enum class VertexSemantic {
None = 0,
Position3,
Position4,
Normal3,
Normal4,
Color,
ColorUNorm,
UV2,
UV4,
Weight,
ModelView,
Position2,
SemanticMask = 0xf,
Instanced = 0x10
};
ENABLE_BITWISE_ENUM(VertexSemantic)
/** Used to create IVertexFormat */
struct VertexElementDescriptor {
VertexSemantic semantic{};
int semanticIdx = 0;
VertexElementDescriptor() = default;
VertexElementDescriptor(VertexSemantic s, int idx = 0) : semantic(s), semanticIdx(idx) {}
};
/** Structure for passing vertex format info for pipeline construction */
struct VertexFormatInfo {
size_t elementCount = 0;
const VertexElementDescriptor* elements = nullptr;
VertexFormatInfo() = default;
VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem) : elementCount(sz), elements(elem) {}
template <typename T>
VertexFormatInfo(const T& tp) : elementCount(std::extent_v<T>), elements(tp) {}
VertexFormatInfo(std::initializer_list<VertexElementDescriptor> l)
: elementCount(l.size()), elements(std::move(l.begin())) {}
};
/** Opaque token for referencing a shader stage usable in a graphics pipeline */
struct IShaderStage : IObj {};
/** Opaque token for referencing a complete graphics pipeline state necessary
* to rasterize geometry (shaders and blending modes mainly) */
struct IShaderPipeline : IObj {
virtual bool isReady() const = 0;
};
/** Opaque token serving as indirection table for shader resources
* and IShaderPipeline reference. Each renderable surface-material holds one
* as a reference */
struct IShaderDataBinding : IObj {};
/** Used wherever distinction of pipeline stages is needed */
enum class PipelineStage { Null, Vertex, Fragment, Geometry, Control, Evaluation };
/** Used by platform shader pipeline constructors */
enum class Primitive { Triangles, TriStrips, Patches };
/** Used by platform shader pipeline constructors */
enum class CullMode { None, Backface, Frontface };
/** Used by platform shader pipeline constructors */
enum class ZTest {
None,
LEqual, /* Flipped on Vulkan, D3D, Metal */
Greater,
GEqual,
Equal
};
/** Used by platform shader pipeline constructors */
enum class BlendFactor {
Zero,
One,
SrcColor,
InvSrcColor,
DstColor,
InvDstColor,
SrcAlpha,
InvSrcAlpha,
DstAlpha,
InvDstAlpha,
SrcColor1,
InvSrcColor1,
/* Special value that activates DstColor - SrcColor blending */
Subtract
};
/** Structure for passing additional pipeline construction information */
struct AdditionalPipelineInfo {
BlendFactor srcFac = BlendFactor::One;
BlendFactor dstFac = BlendFactor::Zero;
Primitive prim = Primitive::TriStrips;
ZTest depthTest = ZTest::LEqual;
bool depthWrite = true;
bool colorWrite = true;
bool alphaWrite = false;
CullMode culling = CullMode::Backface;
uint32_t patchSize = 0;
bool overwriteAlpha = false;
bool depthAttachment = true;
};
/** Factory object for creating batches of resources as an IGraphicsData token */
struct IGraphicsDataFactory {
virtual ~IGraphicsDataFactory() = default;
enum class Platform { Null, OpenGL, D3D11, Metal, Vulkan, GX, NX };
virtual Platform platform() const = 0;
virtual const char* platformName() const = 0;
struct Context {
virtual Platform platform() const = 0;
virtual const char* platformName() const = 0;
virtual ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride,
size_t count) = 0;
virtual ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count) = 0;
virtual ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz) = 0;
virtual ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz) = 0;
virtual ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode) = 0;
virtual ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount) = 0;
virtual ObjToken<ITextureCubeR> newCubeRenderTexture(size_t width, size_t mips) = 0;
virtual ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) = 0;
ObjToken<IShaderStage> newShaderStage(const std::vector<uint8_t>& data, PipelineStage stage) {
return newShaderStage(data.data(), data.size(), stage);
}
virtual ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation,
const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo,
bool asynchronous = true) = 0;
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo,
bool asynchronous = true) {
return newShaderPipeline(std::move(vertex), std::move(fragment), {}, {}, {}, vtxFmt, additionalInfo,
asynchronous);
}
virtual ObjToken<IShaderDataBinding> newShaderDataBinding(
const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const size_t* ubufSizes, size_t texCount, const ObjToken<ITexture>* texs, const int* texBindIdx,
const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0) = 0;
ObjToken<IShaderDataBinding> newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>* ubufs,
const PipelineStage* ubufStages, size_t texCount,
const ObjToken<ITexture>* texs, const int* texBindIdx,
const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0) {
return newShaderDataBinding(pipeline, vbo, instVbo, ibo, ubufCount, ubufs, ubufStages, nullptr, nullptr, texCount,
texs, texBindIdx, depthBind, baseVert, baseInst);
}
};
virtual void commitTransaction(const std::function<bool(Context& ctx)>& __BooTraceArgs) = 0;
virtual void lazyCommitTransaction(const std::function<bool(Context& ctx)>& f __BooTraceArgs) {
commitTransaction(f __BooTraceArgsUse);
}
virtual void commitPendingTransaction() {}
virtual ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) = 0;
virtual void setDisplayGamma(float gamma) = 0;
virtual bool isTessellationSupported(uint32_t& maxPatchSizeOut) = 0;
virtual void waitUntilShadersReady() = 0;
virtual bool areShadersReady() = 0;
};
using GraphicsDataFactoryContext = IGraphicsDataFactory::Context;
using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>;
} // namespace boo

View File

@ -1,61 +0,0 @@
#pragma once
#ifdef __APPLE__
#if BOO_HAS_METAL
#include "boo/BooObject.hpp"
#include "boo/IGraphicsContext.hpp"
#include "boo/System.hpp"
#include "boo/graphicsdev/IGraphicsCommandQueue.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace boo {
struct BaseGraphicsData;
class MetalDataFactory : public IGraphicsDataFactory {
public:
class Context final : public IGraphicsDataFactory::Context {
friend class MetalDataFactoryImpl;
MetalDataFactory& m_parent;
ObjToken<BaseGraphicsData> m_data;
Context(MetalDataFactory& parent __BooTraceArgs);
~Context();
public:
Platform platform() const { return Platform::Metal; }
const char* platformName() const { return "Metal"; }
ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz);
ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz);
ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode);
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t colorBindCount,
size_t depthBindCount);
ObjToken<ITextureCubeR> newCubeRenderTexture(size_t width, size_t mips);
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo, bool asynchronous = true);
ObjToken<IShaderDataBinding> newShaderDataBinding(
const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const size_t* ubufSizes, size_t texCount, const ObjToken<ITexture>* texs, const int* texBindIdxs,
const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0);
};
static std::vector<uint8_t> CompileMetal(const char* source, PipelineStage stage);
};
} // namespace boo
#endif
#endif // __APPLE__

View File

@ -1,88 +0,0 @@
#pragma once
#if BOO_HAS_NX
#include <unordered_map>
#include "boo/BooObject.hpp"
#include "boo/graphicsdev/IGraphicsCommandQueue.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "boo/graphicsdev/nx_compiler.hpp"
#include <switch/nvidia/fence.h>
struct pipe_screen;
struct pipe_context;
struct st_context;
struct pipe_surface;
namespace boo {
struct BaseGraphicsData;
struct NXContext {
struct pipe_surface* m_windowSurfaces[2];
NvFence m_fences[2];
bool m_fence_swap;
bool initialize();
bool terminate();
bool _resizeWindowSurfaces();
unsigned m_sampleCount = 1;
struct pipe_screen* m_screen = nullptr;
struct pipe_context* m_pctx = nullptr;
struct st_context* m_st = nullptr;
nx_compiler m_compiler;
std::unordered_map<uint32_t, void*> m_samplers;
std::unordered_map<uint32_t, void*> m_blendStates;
std::unordered_map<uint32_t, void*> m_rasStates;
std::unordered_map<uint32_t, void*> m_dsStates;
std::unordered_map<uint64_t, void*> m_vtxElemStates;
};
class NXDataFactory : public IGraphicsDataFactory {
public:
class Context final : public IGraphicsDataFactory::Context {
friend class NXDataFactoryImpl;
NXDataFactory& m_parent;
boo::ObjToken<BaseGraphicsData> m_data;
Context(NXDataFactory& parent __BooTraceArgs);
~Context();
public:
Platform platform() const { return Platform::NX; }
const char* platformName() const { return "NX"; }
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz);
boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz);
boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode);
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount);
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo);
boo::ObjToken<IShaderDataBinding> newShaderDataBinding(
const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const size_t* ubufSizes, size_t texCount, const boo::ObjToken<ITexture>* texs, const int* bindIdxs,
const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0);
};
};
} // namespace boo
#endif

View File

@ -1,174 +0,0 @@
#pragma once
#if BOO_HAS_VULKAN
#include <mutex>
#include <queue>
#include <unordered_map>
#include <vector>
#include "boo/BooObject.hpp"
#include "boo/IGraphicsContext.hpp"
#include "boo/IWindow.hpp"
#include "boo/System.hpp"
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "boo/graphicsdev/VulkanDispatchTable.hpp"
/* Forward-declare handle type for Vulkan Memory Allocator */
struct VmaAllocator_T;
namespace boo {
struct BaseGraphicsData;
struct VulkanContext {
struct LayerProperties {
VkLayerProperties properties;
std::vector<VkExtensionProperties> extensions;
};
#ifndef NDEBUG
PFN_vkDestroyDebugReportCallbackEXT m_destroyDebugReportCallback = nullptr;
VkDebugReportCallbackEXT m_debugReportCallback = VK_NULL_HANDLE;
#endif
std::vector<LayerProperties> m_instanceLayerProperties;
std::vector<const char*> m_layerNames;
std::vector<const char*> m_instanceExtensionNames;
VkInstance m_instance = VK_NULL_HANDLE;
std::vector<const char*> m_deviceExtensionNames;
std::vector<VkPhysicalDevice> m_gpus;
VkPhysicalDeviceFeatures m_features;
VkPhysicalDeviceProperties m_gpuProps;
VkPhysicalDeviceMemoryProperties m_memoryProperties;
VkDevice m_dev = VK_NULL_HANDLE;
VmaAllocator_T* m_allocator = VK_NULL_HANDLE;
uint32_t m_queueCount;
uint32_t m_graphicsQueueFamilyIndex = UINT32_MAX;
std::vector<VkQueueFamilyProperties> m_queueProps;
VkQueue m_queue = VK_NULL_HANDLE;
std::mutex m_queueLock;
VkDescriptorSetLayout m_descSetLayout = VK_NULL_HANDLE;
VkPipelineLayout m_pipelinelayout = VK_NULL_HANDLE;
VkRenderPass m_pass = VK_NULL_HANDLE;
VkRenderPass m_passOneSample = VK_NULL_HANDLE;
VkRenderPass m_passColorOnly = VK_NULL_HANDLE;
VkCommandPool m_loadPool = VK_NULL_HANDLE;
VkCommandBuffer m_loadCmdBuf = VK_NULL_HANDLE;
VkFormat m_displayFormat;
VkFormat m_internalFormat;
struct Window {
struct SwapChain {
VkFormat m_format = VK_FORMAT_UNDEFINED;
VkSwapchainKHR m_swapChain = VK_NULL_HANDLE;
struct Buffer {
VkImage m_image = VK_NULL_HANDLE;
VkImageView m_colorView = VK_NULL_HANDLE;
VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
VkRenderPassBeginInfo m_passBeginInfo = {};
void setImage(VulkanContext* ctx, VkImage image, uint32_t width, uint32_t height);
void destroy(VkDevice dev);
};
std::vector<Buffer> m_bufs;
uint32_t m_backBuf = 0;
void destroy(VkDevice dev) {
for (Buffer& buf : m_bufs)
buf.destroy(dev);
m_bufs.clear();
if (m_swapChain) {
vk::DestroySwapchainKHR(dev, m_swapChain, nullptr);
m_swapChain = VK_NULL_HANDLE;
}
m_backBuf = 0;
}
} m_swapChains[2];
uint32_t m_activeSwapChain = 0;
#if _WIN32
HWND m_hwnd = 0;
bool m_fs = false;
LONG_PTR m_fsStyle;
LONG_PTR m_fsExStyle;
RECT m_fsRect;
int m_fsCountDown = 0;
#endif
};
std::unordered_map<const boo::IWindow*, std::unique_ptr<Window>> m_windows;
VkSampleCountFlags m_sampleCountColor = VK_SAMPLE_COUNT_1_BIT;
VkSampleCountFlags m_sampleCountDepth = VK_SAMPLE_COUNT_1_BIT;
float m_anisotropy = 1.f;
bool m_deepColor = false;
std::unordered_map<uint32_t, VkSampler> m_samplers;
bool initVulkan(std::string_view appName, PFN_vkGetInstanceProcAddr getVkProc);
bool enumerateDevices();
void initDevice();
void destroyDevice();
void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);
struct SwapChainResize {
Window& m_windowCtx;
VkSurfaceKHR m_surface;
VkFormat m_format;
VkColorSpaceKHR m_colorspace;
SWindowRect m_rect;
SwapChainResize(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect)
: m_windowCtx(windowCtx), m_surface(surface), m_format(format), m_colorspace(colorspace), m_rect(rect) {}
};
std::queue<SwapChainResize> m_deferredResizes;
std::mutex m_resizeLock;
void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect);
bool _resizeSwapChains();
};
extern VulkanContext g_VulkanContext;
class VulkanDataFactory : public IGraphicsDataFactory {
public:
class Context final : public IGraphicsDataFactory::Context {
friend class VulkanDataFactoryImpl;
VulkanDataFactory& m_parent;
boo::ObjToken<BaseGraphicsData> m_data;
public:
Context(VulkanDataFactory& parent __BooTraceArgs);
~Context();
Platform platform() const { return Platform::Vulkan; }
const char* platformName() const { return "Vulkan"; }
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz);
boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz);
boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode);
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount);
ObjToken<ITextureCubeR> newCubeRenderTexture(size_t width, size_t mips);
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo, bool asynchronous = true);
boo::ObjToken<IShaderDataBinding> newShaderDataBinding(
const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const size_t* ubufSizes, size_t texCount, const boo::ObjToken<ITexture>* texs, const int* bindIdxs,
const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0);
};
static std::vector<uint8_t> CompileGLSL(const char* source, PipelineStage stage);
};
} // namespace boo
#endif

View File

@ -1,223 +0,0 @@
// This file is generated.
#pragma once
#include <vulkan/vulkan.h>
namespace vk {
// VK_core
extern PFN_vkCreateInstance CreateInstance;
extern PFN_vkDestroyInstance DestroyInstance;
extern PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
extern PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
extern PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;
extern PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;
extern PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties;
extern PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
extern PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
extern PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
extern PFN_vkCreateDevice CreateDevice;
extern PFN_vkDestroyDevice DestroyDevice;
extern PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
extern PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
extern PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties;
extern PFN_vkGetDeviceQueue GetDeviceQueue;
extern PFN_vkQueueSubmit QueueSubmit;
extern PFN_vkQueueWaitIdle QueueWaitIdle;
extern PFN_vkDeviceWaitIdle DeviceWaitIdle;
extern PFN_vkAllocateMemory AllocateMemory;
extern PFN_vkFreeMemory FreeMemory;
extern PFN_vkMapMemory MapMemory;
extern PFN_vkUnmapMemory UnmapMemory;
extern PFN_vkFlushMappedMemoryRanges FlushMappedMemoryRanges;
extern PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges;
extern PFN_vkGetDeviceMemoryCommitment GetDeviceMemoryCommitment;
extern PFN_vkBindBufferMemory BindBufferMemory;
extern PFN_vkBindImageMemory BindImageMemory;
extern PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements;
extern PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements;
extern PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements;
extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
extern PFN_vkQueueBindSparse QueueBindSparse;
extern PFN_vkCreateFence CreateFence;
extern PFN_vkDestroyFence DestroyFence;
extern PFN_vkResetFences ResetFences;
extern PFN_vkGetFenceStatus GetFenceStatus;
extern PFN_vkWaitForFences WaitForFences;
extern PFN_vkCreateSemaphore CreateSemaphore;
extern PFN_vkDestroySemaphore DestroySemaphore;
extern PFN_vkCreateEvent CreateEvent;
extern PFN_vkDestroyEvent DestroyEvent;
extern PFN_vkGetEventStatus GetEventStatus;
extern PFN_vkSetEvent SetEvent;
extern PFN_vkResetEvent ResetEvent;
extern PFN_vkCreateQueryPool CreateQueryPool;
extern PFN_vkDestroyQueryPool DestroyQueryPool;
extern PFN_vkGetQueryPoolResults GetQueryPoolResults;
extern PFN_vkCreateBuffer CreateBuffer;
extern PFN_vkDestroyBuffer DestroyBuffer;
extern PFN_vkCreateBufferView CreateBufferView;
extern PFN_vkDestroyBufferView DestroyBufferView;
extern PFN_vkCreateImage CreateImage;
extern PFN_vkDestroyImage DestroyImage;
extern PFN_vkGetImageSubresourceLayout GetImageSubresourceLayout;
extern PFN_vkCreateImageView CreateImageView;
extern PFN_vkDestroyImageView DestroyImageView;
extern PFN_vkCreateShaderModule CreateShaderModule;
extern PFN_vkDestroyShaderModule DestroyShaderModule;
extern PFN_vkCreatePipelineCache CreatePipelineCache;
extern PFN_vkDestroyPipelineCache DestroyPipelineCache;
extern PFN_vkGetPipelineCacheData GetPipelineCacheData;
extern PFN_vkMergePipelineCaches MergePipelineCaches;
extern PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines;
extern PFN_vkCreateComputePipelines CreateComputePipelines;
extern PFN_vkDestroyPipeline DestroyPipeline;
extern PFN_vkCreatePipelineLayout CreatePipelineLayout;
extern PFN_vkDestroyPipelineLayout DestroyPipelineLayout;
extern PFN_vkCreateSampler CreateSampler;
extern PFN_vkDestroySampler DestroySampler;
extern PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout;
extern PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout;
extern PFN_vkCreateDescriptorPool CreateDescriptorPool;
extern PFN_vkDestroyDescriptorPool DestroyDescriptorPool;
extern PFN_vkResetDescriptorPool ResetDescriptorPool;
extern PFN_vkAllocateDescriptorSets AllocateDescriptorSets;
extern PFN_vkFreeDescriptorSets FreeDescriptorSets;
extern PFN_vkUpdateDescriptorSets UpdateDescriptorSets;
extern PFN_vkCreateFramebuffer CreateFramebuffer;
extern PFN_vkDestroyFramebuffer DestroyFramebuffer;
extern PFN_vkCreateRenderPass CreateRenderPass;
extern PFN_vkDestroyRenderPass DestroyRenderPass;
extern PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity;
extern PFN_vkCreateCommandPool CreateCommandPool;
extern PFN_vkDestroyCommandPool DestroyCommandPool;
extern PFN_vkResetCommandPool ResetCommandPool;
extern PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
extern PFN_vkFreeCommandBuffers FreeCommandBuffers;
extern PFN_vkBeginCommandBuffer BeginCommandBuffer;
extern PFN_vkEndCommandBuffer EndCommandBuffer;
extern PFN_vkResetCommandBuffer ResetCommandBuffer;
extern PFN_vkCmdBindPipeline CmdBindPipeline;
extern PFN_vkCmdSetViewport CmdSetViewport;
extern PFN_vkCmdSetScissor CmdSetScissor;
extern PFN_vkCmdSetLineWidth CmdSetLineWidth;
extern PFN_vkCmdSetDepthBias CmdSetDepthBias;
extern PFN_vkCmdSetBlendConstants CmdSetBlendConstants;
extern PFN_vkCmdSetDepthBounds CmdSetDepthBounds;
extern PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask;
extern PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask;
extern PFN_vkCmdSetStencilReference CmdSetStencilReference;
extern PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets;
extern PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer;
extern PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers;
extern PFN_vkCmdDraw CmdDraw;
extern PFN_vkCmdDrawIndexed CmdDrawIndexed;
extern PFN_vkCmdDrawIndirect CmdDrawIndirect;
extern PFN_vkCmdDrawIndexedIndirect CmdDrawIndexedIndirect;
extern PFN_vkCmdDispatch CmdDispatch;
extern PFN_vkCmdDispatchIndirect CmdDispatchIndirect;
extern PFN_vkCmdCopyBuffer CmdCopyBuffer;
extern PFN_vkCmdCopyImage CmdCopyImage;
extern PFN_vkCmdBlitImage CmdBlitImage;
extern PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage;
extern PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer;
extern PFN_vkCmdUpdateBuffer CmdUpdateBuffer;
extern PFN_vkCmdFillBuffer CmdFillBuffer;
extern PFN_vkCmdClearColorImage CmdClearColorImage;
extern PFN_vkCmdClearDepthStencilImage CmdClearDepthStencilImage;
extern PFN_vkCmdClearAttachments CmdClearAttachments;
extern PFN_vkCmdResolveImage CmdResolveImage;
extern PFN_vkCmdSetEvent CmdSetEvent;
extern PFN_vkCmdResetEvent CmdResetEvent;
extern PFN_vkCmdWaitEvents CmdWaitEvents;
extern PFN_vkCmdPipelineBarrier CmdPipelineBarrier;
extern PFN_vkCmdBeginQuery CmdBeginQuery;
extern PFN_vkCmdEndQuery CmdEndQuery;
extern PFN_vkCmdResetQueryPool CmdResetQueryPool;
extern PFN_vkCmdWriteTimestamp CmdWriteTimestamp;
extern PFN_vkCmdCopyQueryPoolResults CmdCopyQueryPoolResults;
extern PFN_vkCmdPushConstants CmdPushConstants;
extern PFN_vkCmdBeginRenderPass CmdBeginRenderPass;
extern PFN_vkCmdNextSubpass CmdNextSubpass;
extern PFN_vkCmdEndRenderPass CmdEndRenderPass;
extern PFN_vkCmdExecuteCommands CmdExecuteCommands;
// VK_KHR_surface
extern PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
// VK_KHR_swapchain
extern PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
extern PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
extern PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
extern PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
extern PFN_vkQueuePresentKHR QueuePresentKHR;
// VK_KHR_display
extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR;
extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR;
extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR;
extern PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR;
extern PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR;
extern PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR;
extern PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR;
// VK_KHR_display_swapchain
extern PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;
#ifdef VK_USE_PLATFORM_XLIB_KHR
// VK_KHR_xlib_surface
extern PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR;
extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR GetPhysicalDeviceXlibPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
// VK_KHR_xcb_surface
extern PFN_vkCreateXcbSurfaceKHR CreateXcbSurfaceKHR;
extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR GetPhysicalDeviceXcbPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
// VK_KHR_wayland_surface
extern PFN_vkCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR;
extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWaylandPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
// VK_KHR_mir_surface
extern PFN_vkCreateMirSurfaceKHR CreateMirSurfaceKHR;
extern PFN_vkGetPhysicalDeviceMirPresentationSupportKHR GetPhysicalDeviceMirPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
// VK_KHR_android_surface
extern PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
// VK_KHR_win32_surface
extern PFN_vkCreateWin32SurfaceKHR CreateWin32SurfaceKHR;
extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR;
#endif
// VK_EXT_debug_report
extern PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
extern PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
extern PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
// VK_EXT_debug_marker
extern PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
extern PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
extern PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;
extern PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;
extern PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
void init_dispatch_table_middle(VkInstance instance, bool include_bottom);
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev);
} // namespace vk

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
#pragma once
#include <memory>
#include <string>
/* These match mesa's internal stages */
enum class nx_shader_stage {
NONE = -1,
VERTEX = 0,
TESS_CTRL = 1,
TESS_EVAL = 2,
GEOMETRY = 3,
FRAGMENT = 4,
COMPUTE = 5,
};
struct standalone_options {
int glsl_version;
int dump_ast;
int dump_hir;
int dump_lir;
int dump_builder;
int do_link;
int just_log;
};
class nx_compiler;
class nx_shader_stage_object {
friend class nx_compiler;
nx_compiler* m_parent = nullptr;
struct gl_shader* m_shader = nullptr;
nx_shader_stage_object(nx_compiler& parent) : m_parent(&parent) {}
public:
nx_shader_stage_object() = default;
nx_shader_stage_object(const nx_shader_stage_object&);
nx_shader_stage_object& operator=(const nx_shader_stage_object&);
~nx_shader_stage_object() { reset(); }
void reset();
operator bool() const;
nx_shader_stage stage() const;
const char* info_log() const;
};
class nx_linked_shader {
friend class nx_compiler;
nx_compiler* m_parent = nullptr;
struct gl_shader_program* m_program = nullptr;
nx_linked_shader(nx_compiler& parent) : m_parent(&parent) {}
public:
nx_linked_shader() = default;
nx_linked_shader(const nx_linked_shader&);
nx_linked_shader& operator=(const nx_linked_shader&);
~nx_linked_shader() { reset(); }
void reset();
operator bool() const { return m_program != nullptr; }
const struct gl_shader_program* program() const { return m_program; }
};
class nx_compiler {
friend class nx_shader_stage_object;
friend class nx_linked_shader;
struct pipe_screen* m_screen = nullptr;
struct st_context* m_st = nullptr;
struct standalone_options m_options = {};
bool m_ownsCtx = false;
void compile_shader(struct gl_context* ctx, struct gl_shader* shader);
public:
nx_compiler();
~nx_compiler();
bool initialize(struct pipe_screen* screen, struct st_context* st, const struct standalone_options* o = nullptr);
bool initialize(const struct standalone_options* o = nullptr);
nx_shader_stage_object compile(nx_shader_stage type, const char* source);
nx_linked_shader link(unsigned num_stages, const nx_shader_stage_object** stages, std::string* infoLog = nullptr);
std::pair<std::shared_ptr<uint8_t[]>, size_t> offline_link(unsigned num_stages, const nx_shader_stage_object** stages,
std::string* infoLog = nullptr);
};

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
#pragma once
//#include "DeferredWindowEvents.hpp"
//#include "IApplication.hpp"
//#include "IWindow.hpp"
#include "inputdev/DeviceFinder.hpp"
#include "inputdev/DolphinSmashAdapter.hpp"
#include "inputdev/DualshockPad.hpp"
#include "inputdev/GenericPad.hpp"
#include "inputdev/NintendoPowerA.hpp"
//#include "graphicsdev/IGraphicsCommandQueue.hpp"
//#include "graphicsdev/IGraphicsDataFactory.hpp"

View File

@ -1,3 +0,0 @@
#pragma once
namespace boo {}

View File

@ -1,91 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <memory>
#include <mutex>
#include <vector>
#include "boo/System.hpp"
#if _WIN32
#include <hidsdi.h>
#endif
namespace boo {
class DeviceToken;
class IHIDDevice;
enum class HIDReportType { Input, Output, Feature };
class DeviceBase : public std::enable_shared_from_this<DeviceBase> {
friend class DeviceToken;
friend struct DeviceSignature;
friend class HIDDeviceIOKit;
uint64_t m_typeHash;
class DeviceToken* m_token;
std::shared_ptr<IHIDDevice> m_hidDev;
void _deviceDisconnected();
public:
DeviceBase(uint64_t typeHash, DeviceToken* token);
virtual ~DeviceBase() = default;
uint64_t getTypeHash() const { return m_typeHash; }
void closeDevice();
/* Callbacks */
virtual void deviceDisconnected() = 0;
virtual void vdeviceError(fmt::string_view error, fmt::format_args args);
template <typename S, typename... Args, typename Char = fmt::char_t<S>>
void deviceError(const S& format, Args&&... args) {
vdeviceError(fmt::to_string_view<Char>(format),
fmt::basic_format_args<fmt::buffer_context<Char>>(
fmt::make_args_checked<Args...>(format, args...)));
}
virtual void initialCycle() {}
virtual void transferCycle() {}
virtual void finalCycle() {}
/* Low-Level API */
bool sendUSBInterruptTransfer(const uint8_t* data, size_t length);
size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length);
inline unsigned getVendorId() const;
inline unsigned getProductId() const;
inline std::string_view getVendorName() const;
inline std::string_view getProductName() const;
/* High-Level API */
#if _WIN32
#if !WINDOWS_STORE
PHIDP_PREPARSED_DATA getReportDescriptor() const;
#endif
#else
std::vector<uint8_t> getReportDescriptor() const;
#endif
bool sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message = 0);
size_t receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp,
uint32_t message = 0); // Prefer callback version
virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/,
uint32_t /*message*/) {}
};
template <class CB>
class TDeviceBase : public DeviceBase {
protected:
std::mutex m_callbackLock;
CB* m_callback = nullptr;
public:
TDeviceBase(uint64_t typeHash, DeviceToken* token) : DeviceBase(typeHash, token) {}
void setCallback(CB* cb) {
std::lock_guard<std::mutex> lk(m_callbackLock);
m_callback = cb;
}
};
} // namespace boo

View File

@ -1,91 +0,0 @@
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <unordered_set>
#include "boo/inputdev/DeviceSignature.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/IHIDListener.hpp"
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace boo {
class DeviceFinder {
public:
friend class HIDListenerIOKit;
friend class HIDListenerUdev;
friend class HIDListenerWinUSB;
static inline DeviceFinder* instance() { return skDevFinder; }
private:
static class DeviceFinder* skDevFinder;
/* Types this finder is interested in (immutable) */
DeviceSignature::TDeviceSignatureSet m_types;
/* Platform-specific USB event registration
* (for auto-scanning, NULL if not registered) */
std::unique_ptr<IHIDListener> m_listener;
/* Set of presently-connected device tokens */
TDeviceTokens m_tokens;
std::mutex m_tokensLock;
/* Friend methods for platform-listener to find/insert/remove
* tokens with type-filtering */
bool _hasToken(const std::string& path) const {
return m_tokens.find(path) != m_tokens.end();
}
bool _insertToken(std::unique_ptr<DeviceToken>&& token);
void _removeToken(const std::string& path);
public:
class CDeviceTokensHandle {
DeviceFinder& m_finder;
public:
CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) { m_finder.m_tokensLock.lock(); }
~CDeviceTokensHandle() { m_finder.m_tokensLock.unlock(); }
TDeviceTokens::iterator begin() noexcept { return m_finder.m_tokens.begin(); }
TDeviceTokens::iterator end() noexcept { return m_finder.m_tokens.end(); }
TDeviceTokens::const_iterator begin() const noexcept { return m_finder.m_tokens.begin(); }
TDeviceTokens::const_iterator end() const noexcept { return m_finder.m_tokens.end(); }
};
/* Application must specify its interested device-types */
DeviceFinder(std::unordered_set<uint64_t> types);
virtual ~DeviceFinder();
/* Get interested device-type mask */
const DeviceSignature::TDeviceSignatureSet& getTypes() const { return m_types; }
/* Iterable set of tokens */
CDeviceTokensHandle getTokens() { return CDeviceTokensHandle(*this); }
/* Automatic device scanning */
bool startScanning();
bool stopScanning();
/* Manual device scanning */
bool scanNow();
virtual void deviceConnected(DeviceToken&) {}
virtual void deviceDisconnected(DeviceToken&, DeviceBase*) {}
#if _WIN32
/* Windows-specific WM_DEVICECHANGED handler */
static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam);
#endif
};
} // namespace boo

View File

@ -1,44 +0,0 @@
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <typeindex>
#include <vector>
namespace boo {
enum class DeviceType { None = 0, USB = 1, Bluetooth = 2, HID = 3, XInput = 4 };
class DeviceToken;
class DeviceBase;
#define dev_typeid(type) std::hash<std::string>()(#type)
struct DeviceSignature {
using TDeviceSignatureSet = std::vector<const DeviceSignature*>;
using TFactoryLambda = std::function<std::shared_ptr<DeviceBase>(DeviceToken*)>;
const char* m_name = nullptr;
uint64_t m_typeHash = 0;
unsigned m_vid = 0;
unsigned m_pid = 0;
TFactoryLambda m_factory;
DeviceType m_type{};
DeviceSignature() : m_typeHash(dev_typeid(DeviceSignature)) {} /* Sentinel constructor */
DeviceSignature(const char* name, uint64_t typeHash, unsigned vid, unsigned pid, TFactoryLambda&& factory,
DeviceType type = DeviceType::None)
: m_name(name), m_typeHash(typeHash), m_vid(vid), m_pid(pid), m_factory(factory), m_type(type) {}
static bool DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet);
static std::shared_ptr<DeviceBase> DeviceNew(DeviceToken& token);
};
#define DEVICE_SIG(name, vid, pid, type) \
DeviceSignature(#name, dev_typeid(name), vid, pid, \
[](DeviceToken* tok) -> std::shared_ptr<DeviceBase> { return std::make_shared<name>(tok); }, type)
#define DEVICE_SIG_SENTINEL() DeviceSignature()
extern const DeviceSignature BOO_DEVICE_SIGS[];
} // namespace boo

View File

@ -1,62 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/DeviceSignature.hpp"
namespace boo {
class DeviceToken {
friend struct DeviceSignature;
friend class HIDListenerWinUSB;
DeviceType m_devType;
unsigned m_vendorId;
unsigned m_productId;
std::string m_vendorName;
std::string m_productName;
std::string m_devPath;
friend class DeviceBase;
std::shared_ptr<DeviceBase> m_connectedDev;
friend class DeviceFinder;
void _deviceClose() {
if (m_connectedDev)
m_connectedDev->_deviceDisconnected();
m_connectedDev = NULL;
}
public:
DeviceToken(const DeviceToken&) = delete;
DeviceToken(DeviceToken&& other) noexcept = default;
DeviceToken(DeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path)
: m_devType(devType), m_vendorId(vid), m_productId(pid), m_devPath(path), m_connectedDev(NULL) {
if (vname)
m_vendorName = vname;
if (pname)
m_productName = pname;
}
DeviceToken& operator=(const DeviceToken&) = delete;
DeviceToken& operator=(DeviceToken&&) noexcept = default;
bool operator==(const DeviceToken& rhs) const { return m_devPath == rhs.m_devPath; }
bool operator<(const DeviceToken& rhs) const { return m_devPath < rhs.m_devPath; }
DeviceType getDeviceType() const { return m_devType; }
unsigned getVendorId() const { return m_vendorId; }
unsigned getProductId() const { return m_productId; }
std::string_view getVendorName() const { return m_vendorName; }
std::string_view getProductName() const { return m_productName; }
std::string_view getDevicePath() const { return m_devPath; }
bool isDeviceOpen() const { return (m_connectedDev != NULL); }
std::shared_ptr<DeviceBase> openAndGetDevice() {
if (!m_connectedDev)
m_connectedDev = DeviceSignature::DeviceNew(*this);
return m_connectedDev;
}
};
} // namespace boo

View File

@ -1,96 +0,0 @@
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include "boo/System.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo {
enum class EDolphinControllerType {
None = 0,
Normal = 0x10,
Wavebird = 0x20,
};
ENABLE_BITWISE_ENUM(EDolphinControllerType)
enum class EDolphinControllerButtons {
Start = 1 << 0,
Z = 1 << 1,
R = 1 << 2,
L = 1 << 3,
A = 1 << 8,
B = 1 << 9,
X = 1 << 10,
Y = 1 << 11,
Left = 1 << 12,
Right = 1 << 13,
Down = 1 << 14,
Up = 1 << 15
};
ENABLE_BITWISE_ENUM(EDolphinControllerButtons)
struct DolphinControllerState {
std::array<int16_t, 2> m_leftStick{};
std::array<int16_t, 2> m_rightStick{};
std::array<int16_t, 2> m_analogTriggers{};
uint16_t m_btns = 0;
void reset() {
m_leftStick = {};
m_rightStick = {};
m_analogTriggers = {};
m_btns = 0;
}
void clamp();
};
struct IDolphinSmashAdapterCallback {
virtual void controllerConnected([[maybe_unused]] unsigned idx, [[maybe_unused]] EDolphinControllerType type) {}
virtual void controllerDisconnected([[maybe_unused]] unsigned idx) {}
virtual void controllerUpdate([[maybe_unused]] unsigned idx, [[maybe_unused]] EDolphinControllerType type,
[[maybe_unused]] const DolphinControllerState& state) {}
};
class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallback> {
std::array<int16_t, 2> m_leftStickCal{0x7f, 0};
std::array<int16_t, 2> m_rightStickCal{0x7f, 0};
std::array<int16_t, 2> m_triggersCal{};
uint8_t m_knownControllers = 0;
uint8_t m_rumbleRequest = 0;
std::array<bool, 4> m_hardStop{};
uint8_t m_rumbleState = 0xf; /* Force initial send of stop-rumble command */
void deviceDisconnected() override;
void initialCycle() override;
void transferCycle() override;
void finalCycle() override;
public:
DolphinSmashAdapter(DeviceToken* token);
~DolphinSmashAdapter() override;
void setCallback(IDolphinSmashAdapterCallback* cb) {
TDeviceBase<IDolphinSmashAdapterCallback>::setCallback(cb);
m_knownControllers = 0;
}
void startRumble(size_t idx) {
if (idx >= m_hardStop.size()) {
return;
}
m_rumbleRequest |= 1U << idx;
}
void stopRumble(size_t idx, bool hard = false) {
if (idx >= m_hardStop.size()) {
return;
}
m_rumbleRequest &= ~(1U << idx);
m_hardStop[idx] = hard;
}
};
} // namespace boo

View File

@ -1,157 +0,0 @@
#pragma once
#include <cstdint>
#include "boo/System.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo {
struct DualshockLED {
uint8_t timeEnabled;
uint8_t dutyLength;
uint8_t enabled;
uint8_t dutyOff;
uint8_t dutyOn;
};
struct DualshockRumble {
uint8_t padding;
uint8_t rightDuration;
bool rightOn;
uint8_t leftDuration;
uint8_t leftForce;
};
union DualshockOutReport {
struct {
uint8_t reportId;
DualshockRumble rumble;
uint8_t gyro1;
uint8_t gyro2;
uint8_t padding[2];
uint8_t leds;
DualshockLED led[4];
DualshockLED reserved;
};
uint8_t buf[49];
};
enum class EDualshockPadButtons {
Select = 1 << 0,
L3 = 1 << 1,
R3 = 1 << 2,
Start = 1 << 3,
Up = 1 << 4,
Right = 1 << 5,
Down = 1 << 6,
Left = 1 << 7,
L2 = 1 << 8,
R2 = 1 << 9,
L1 = 1 << 10,
R1 = 1 << 11,
Triangle = 1 << 12,
Circle = 1 << 13,
Cross = 1 << 14,
Square = 1 << 15
};
enum class EDualshockMotor : uint8_t {
None = 0,
Right = 1 << 0,
Left = 1 << 1,
};
ENABLE_BITWISE_ENUM(EDualshockMotor)
enum class EDualshockLED { LED_OFF = 0, LED_1 = 1 << 1, LED_2 = 1 << 2, LED_3 = 1 << 3, LED_4 = 1 << 4 };
ENABLE_BITWISE_ENUM(EDualshockLED)
struct DualshockPadState {
uint8_t m_reportType;
uint8_t m_reserved1;
uint16_t m_buttonState;
uint8_t m_psButtonState;
uint8_t m_reserved2;
uint8_t m_leftStick[2];
uint8_t m_rightStick[2];
uint8_t m_reserved3[4];
uint8_t m_pressureUp;
uint8_t m_pressureRight;
uint8_t m_pressureDown;
uint8_t m_pressureLeft;
uint8_t m_pressureL2;
uint8_t m_pressureR2;
uint8_t m_pressureL1;
uint8_t m_pressureR1;
uint8_t m_pressureTriangle;
uint8_t m_pressureCircle;
uint8_t m_pressureCross;
uint8_t m_pressureSquare;
uint8_t m_reserved4[3];
uint8_t m_charge;
uint8_t m_power;
uint8_t m_connection;
uint8_t m_reserved5[9];
uint16_t m_accelerometer[3];
uint16_t m_gyrometerZ;
// INTERNAL, set by libBoo, do not modify directly!
float accPitch;
float accYaw;
float gyroZ;
};
class DualshockPad;
struct IDualshockPadCallback {
virtual void controllerDisconnected() {}
virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {}
};
class DualshockPad final : public TDeviceBase<IDualshockPadCallback> {
EDualshockMotor m_rumbleRequest;
EDualshockMotor m_rumbleState;
uint8_t m_rumbleDuration[2];
uint8_t m_rumbleIntensity[2];
EDualshockLED m_led;
DualshockOutReport m_report;
void deviceDisconnected() override;
void initialCycle() override;
void transferCycle() override;
void finalCycle() override;
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override;
public:
DualshockPad(DeviceToken* token);
~DualshockPad() override;
void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity = 255) {
m_rumbleRequest |= motor;
if (True(EDualshockMotor(motor) & EDualshockMotor::Left)) {
m_rumbleDuration[0] = duration;
m_rumbleIntensity[0] = intensity;
}
if (True(EDualshockMotor(motor) & EDualshockMotor::Right)) {
m_rumbleDuration[1] = duration;
m_rumbleIntensity[1] = intensity;
}
}
void stopRumble(int motor) { m_rumbleRequest &= ~EDualshockMotor(motor); }
EDualshockLED getLED() const { return m_led; }
void setLED(EDualshockLED led, bool on = true) {
if (on)
m_led |= led;
else
m_led &= ~led;
setRawLED(int(led));
}
void setRawLED(int led) {
m_report.leds = led;
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
}
};
} // namespace boo

View File

@ -1,30 +0,0 @@
#pragma once
#include <functional>
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/HIDParser.hpp"
namespace boo {
struct IGenericPadCallback {
virtual void controllerConnected() {}
virtual void controllerDisconnected() {}
virtual void valueUpdate(const HIDMainItem& item, int32_t value) {}
};
class GenericPad final : public TDeviceBase<IGenericPadCallback> {
HIDParser m_parser;
public:
GenericPad(DeviceToken* token);
~GenericPad() override;
void deviceDisconnected() override;
void initialCycle() override;
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override;
void enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
};
} // namespace boo

View File

@ -1,210 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <stack>
#include <utility>
#include <vector>
#include "boo/System.hpp"
#if _WIN32
#include <hidsdi.h>
#endif
namespace boo {
struct HIDItemState;
struct HIDCollectionItem;
struct HIDReports;
enum class HIDUsagePage : uint8_t {
Undefined = 0,
GenericDesktop = 1,
Simulation = 2,
VR = 3,
Sport = 4,
Game = 5,
GenericDevice = 6,
Keyboard = 7,
LEDs = 8,
Button = 9,
Ordinal = 10,
Telephony = 11,
Consumer = 12,
Digitizer = 13
};
enum class HIDUsage : uint8_t {
Undefined = 0,
/* Generic Desktop */
Pointer = 1,
Mouse = 2,
Reserved = 3,
Joystick = 4,
GamePad = 5,
Keyboard = 6,
Keypad = 7,
MultiAxis = 8,
TabletPC = 9,
X = 0x30,
Y = 0x31,
Z = 0x32,
Rx = 0x33,
Ry = 0x34,
Rz = 0x35,
Slider = 0x36,
Dial = 0x37,
Wheel = 0x38,
HatSwitch = 0x39,
CountedBuffer = 0x3a,
ByteCount = 0x3b,
MotionWakeup = 0x3c,
Start = 0x3d,
Select = 0x3e,
Vx = 0x40,
Vy = 0x41,
Vz = 0x42,
Vbrx = 0x43,
Vbry = 0x44,
Vbrz = 0x45,
Vno = 0x46,
FeatureNotification = 0x47,
ResolutionMultiplier = 0x48,
SystemControl = 0x80,
SystemPowerDown = 0x81,
SystemSleep = 0x82,
SystemWakeUp = 0x83,
SystemContextMenu = 0x84,
SystemMainMenu = 0x85,
SystemAppMenu = 0x86,
SystemMenuHelp = 0x87,
SystemMenuExit = 0x88,
SystemMenuSelect = 0x89,
SystemMenuRight = 0x8a,
SystemMenuLeft = 0x8b,
SystemMenuUp = 0x8c,
SystemMenuDown = 0x8d,
SystemColdRestart = 0x8e,
SystemWarmRestart = 0x8f,
DPadUp = 0x90,
DPadDown = 0x91,
DPadRight = 0x92,
DPadLeft = 0x93,
SystemDock = 0xa0,
SystemUndock = 0xa1,
SystemSetup = 0xa2,
SystemBreak = 0xa3,
SystemDebuggerBreak = 0xa4,
ApplicationBreak = 0xa5,
ApplicationDebuggerBreak = 0xa6,
SystemSpeakerMute = 0xa7,
SystemHibernate = 0xa8,
SystemDisplayInvert = 0xb0,
SystemDisplayInternal = 0xb1,
SystemDisplayExternal = 0xb2,
SystemDisplayBoth = 0xb3,
SystemDisplayDual = 0xb4,
SystemDisplayToggleIntExt = 0xb5,
/* Game Controls */
_3DGameController = 0x1,
PinballDevice = 0x2,
GunDevice = 0x3,
PointOfView = 0x20,
TurnLeftRight = 0x21,
PitchForwardBackward = 0x22,
RollRightLeft = 0x23,
MoveRightLeft = 0x24,
MoveForwardBackward = 0x25,
MoveUpDown = 0x26,
LeanLeftRight = 0x27,
LeanForwardBackward = 0x28,
HeightOfPOV = 0x29,
Flipper = 0x2a,
SecondaryFlipper = 0x2b,
Bump = 0x2c,
NewGame = 0x2d,
ShootBall = 0x2e,
Player = 0x2f,
GunBolt = 0x30,
GunClip = 0x31,
GunSelector = 0x32,
GunSingleShot = 0x33,
GunBurst = 0x34,
GunAutomatic = 0x35,
GunSafety = 0x36,
GamepadFireJump = 0x37,
GamepadTrigger = 0x39,
};
using HIDRange = std::pair<int32_t, int32_t>;
/* [6.2.2.5] Input, Output, and Feature Items */
struct HIDMainItem {
uint16_t m_flags;
HIDUsagePage m_usagePage;
HIDUsage m_usage;
HIDRange m_logicalRange;
int32_t m_reportSize;
bool IsConstant() const { return (m_flags & 0x1) != 0; }
bool IsVariable() const { return (m_flags & 0x2) != 0; }
bool IsRelative() const { return (m_flags & 0x4) != 0; }
bool IsWrap() const { return (m_flags & 0x8) != 0; }
bool IsNonlinear() const { return (m_flags & 0x10) != 0; }
bool IsNoPreferred() const { return (m_flags & 0x20) != 0; }
bool IsNullState() const { return (m_flags & 0x40) != 0; }
bool IsVolatile() const { return (m_flags & 0x80) != 0; }
bool IsBufferedBytes() const { return (m_flags & 0x100) != 0; }
HIDMainItem() = default;
HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx);
HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDRange logicalRange, int32_t reportSize);
const char* GetUsagePageName() const;
const char* GetUsageName() const;
};
class HIDParser {
public:
enum class ParserStatus { OK, Done, Error };
private:
ParserStatus m_status = ParserStatus::OK;
#if _WIN32
#if !WINDOWS_STORE
std::vector<HIDMainItem> m_itemPool;
mutable std::vector<HIDP_DATA> m_dataList;
PHIDP_PREPARSED_DATA m_descriptorData = nullptr;
#endif
#else
std::unique_ptr<HIDMainItem[]> m_itemPool;
using Report = std::pair<uint32_t, std::pair<uint32_t, uint32_t>>;
std::unique_ptr<Report[]> m_reportPool;
std::pair<uint32_t, uint32_t> m_inputReports = {};
std::pair<uint32_t, uint32_t> m_outputReports = {};
std::pair<uint32_t, uint32_t> m_featureReports = {};
bool m_multipleReports = false;
static ParserStatus ParseItem(HIDReports& reportsOut, std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& collectionStack, const uint8_t*& it, const uint8_t* end,
bool& multipleReports);
#endif
public:
#if _WIN32
#if !WINDOWS_STORE
ParserStatus Parse(const PHIDP_PREPARSED_DATA descriptorData);
#endif
#else
ParserStatus Parse(const uint8_t* descriptorData, size_t len);
static size_t CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len);
static std::pair<HIDUsagePage, HIDUsage> GetApplicationUsage(const uint8_t* descriptorData, size_t len);
#endif
operator bool() const { return m_status == ParserStatus::Done; }
void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
void ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB, const uint8_t* data,
size_t len) const;
};
} // namespace boo

View File

@ -1,37 +0,0 @@
#pragma once
#include <memory>
#include <mutex>
#include <unordered_map>
#include <utility>
#include "boo/inputdev/DeviceToken.hpp"
namespace boo {
class DeviceFinder;
using TDeviceTokens = std::unordered_map<std::string, std::unique_ptr<DeviceToken>>;
using TInsertedDeviceToken = std::pair<TDeviceTokens::iterator, bool>;
class IHIDListener {
public:
virtual ~IHIDListener() = default;
/* Automatic device scanning */
virtual bool startScanning() = 0;
virtual bool stopScanning() = 0;
/* Manual device scanning */
virtual bool scanNow() = 0;
#if _WIN32 && !WINDOWS_STORE
/* External listener implementation (for Windows) */
virtual bool _extDevConnect(const char* path) = 0;
virtual bool _extDevDisconnect(const char* path) = 0;
#endif
};
/* Platform-specific constructor */
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder);
} // namespace boo

View File

@ -1,48 +0,0 @@
#pragma once
#include "DeviceBase.hpp"
#include "boo/System.hpp"
namespace boo {
struct NintendoPowerAState {
uint8_t y : 1;
uint8_t b : 1;
uint8_t a : 1;
uint8_t x : 1;
uint8_t l : 1;
uint8_t r : 1;
uint8_t zl : 1;
uint8_t zr : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t stickL : 1;
uint8_t stickR : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t dPad;
uint8_t leftX;
uint8_t leftY;
uint8_t rightX;
uint8_t rightY;
bool operator==(const NintendoPowerAState& other) const;
bool operator!=(const NintendoPowerAState& other) const;
};
class NintendoPowerA;
struct INintendoPowerACallback {
virtual void controllerDisconnected() {}
virtual void controllerUpdate(const NintendoPowerAState& state) {}
};
class NintendoPowerA final : public TDeviceBase<INintendoPowerACallback> {
NintendoPowerAState m_last{};
void deviceDisconnected() override;
void initialCycle() override;
void transferCycle() override;
void finalCycle() override;
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override;
public:
explicit NintendoPowerA(DeviceToken*);
~NintendoPowerA() override;
};
} // namespace boo

View File

@ -1,3 +0,0 @@
#pragma once
namespace boo {}

View File

@ -1,60 +0,0 @@
#pragma once
#include <cstdint>
#include "boo/System.hpp"
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/DeviceSignature.hpp"
namespace boo {
struct XInputPadState {
uint16_t wButtons;
uint8_t bLeftTrigger;
uint8_t bRightTrigger;
int16_t sThumbLX;
int16_t sThumbLY;
int16_t sThumbRX;
int16_t sThumbRY;
};
enum class EXInputMotor : uint8_t {
None = 0,
Right = 1 << 0,
Left = 1 << 1,
};
ENABLE_BITWISE_ENUM(EXInputMotor)
class XInputPad;
struct IXInputPadCallback {
virtual void controllerDisconnected() {}
virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {}
};
class XInputPad final : public TDeviceBase<IXInputPadCallback> {
friend class HIDListenerWinUSB;
uint16_t m_rumbleRequest[2] = {};
uint16_t m_rumbleState[2] = {};
public:
XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(dev_typeid(XInputPad), token) {}
void deviceDisconnected() override {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void startRumble(EXInputMotor motors, uint16_t intensity) {
if (True(motors & EXInputMotor::Left))
m_rumbleRequest[0] = intensity;
if (True(motors & EXInputMotor::Right))
m_rumbleRequest[1] = intensity;
}
void stopRumble(EXInputMotor motors) {
if (True(motors & EXInputMotor::Left))
m_rumbleRequest[0] = 0;
if (True(motors & EXInputMotor::Right))
m_rumbleRequest[1] = 0;
}
};
} // namespace boo

View File

@ -1,6 +1,5 @@
#include "lib/audiodev/AudioVoiceEngine.hpp"
#include "boo/IApplication.hpp"
#include "lib/CFPointer.hpp"
#include <AudioToolbox/AudioToolbox.h>

View File

@ -1,6 +1,4 @@
#include "lib/audiodev/AudioVoiceEngine.hpp"
#include "boo/boo.hpp"
#include "lib/audiodev/LinuxMidi.hpp"
#include <logvisor/logvisor.hpp>

View File

@ -1,18 +0,0 @@
#include "Common.hpp"
#include <cmath>
#include <numeric>
#include <thread>
namespace boo {
void UpdateGammaLUT(ITextureD* tex, float gamma) {
void* data = tex->map(65536 * 2);
for (int i = 0; i < 65536; ++i) {
float level = std::pow(i / 65535.f, gamma);
reinterpret_cast<uint16_t*>(data)[i] = level * 65535.f;
}
tex->unmap();
}
} // namespace boo

View File

@ -1,288 +0,0 @@
#pragma once
/* Private header for managing shader data
* binding lifetimes through rendering cycle */
#include <array>
#include <atomic>
#include <cassert>
#include <condition_variable>
#include <chrono>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
#include <optick.h>
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "boo/graphicsdev/IGraphicsCommandQueue.hpp"
#include "lib/Common.hpp"
namespace boo {
struct BaseGraphicsData;
struct BaseGraphicsPool;
template <class NodeCls, class DataCls = BaseGraphicsData>
struct GraphicsDataNode;
/** Inherited by data factory implementations to track the head data and pool nodes */
struct GraphicsDataFactoryHead {
std::recursive_mutex m_dataMutex;
BaseGraphicsData* m_dataHead = nullptr;
BaseGraphicsPool* m_poolHead = nullptr;
~GraphicsDataFactoryHead() {
assert(m_dataHead == nullptr && "Dangling graphics data pools detected");
assert(m_poolHead == nullptr && "Dangling graphics data pools detected");
}
};
/** Private generalized data container class.
* Keeps head pointers to all graphics objects by type
*/
struct BaseGraphicsData : ListNode<BaseGraphicsData, GraphicsDataFactoryHead*> {
static BaseGraphicsData*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_dataHead; }
static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) {
return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
}
__BooTraceFields
GraphicsDataNode<IShaderStage, BaseGraphicsData>* m_Ss = nullptr;
GraphicsDataNode<IShaderPipeline, BaseGraphicsData>* m_SPs = nullptr;
GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>* m_SBinds = nullptr;
GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>* m_SBufs = nullptr;
GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>* m_DBufs = nullptr;
GraphicsDataNode<ITextureS, BaseGraphicsData>* m_STexs = nullptr;
GraphicsDataNode<ITextureSA, BaseGraphicsData>* m_SATexs = nullptr;
GraphicsDataNode<ITextureD, BaseGraphicsData>* m_DTexs = nullptr;
GraphicsDataNode<ITextureR, BaseGraphicsData>* m_RTexs = nullptr;
GraphicsDataNode<ITextureCubeR, BaseGraphicsData>* m_CubeRTexs = nullptr;
template <class T>
GraphicsDataNode<T, BaseGraphicsData>*& getHead();
template <class T>
size_t countForward() {
auto* head = getHead<T>();
return head ? head->countForward() : 0;
}
explicit BaseGraphicsData(GraphicsDataFactoryHead& head __BooTraceArgs)
: ListNode<BaseGraphicsData, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer {}
};
template <>
inline GraphicsDataNode<IShaderStage, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderStage>() {
return m_Ss;
}
template <>
inline GraphicsDataNode<IShaderPipeline, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderPipeline>() {
return m_SPs;
}
template <>
inline GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderDataBinding>() {
return m_SBinds;
}
template <>
inline GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>*& BaseGraphicsData::getHead<IGraphicsBufferS>() {
return m_SBufs;
}
template <>
inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>*& BaseGraphicsData::getHead<IGraphicsBufferD>() {
return m_DBufs;
}
template <>
inline GraphicsDataNode<ITextureS, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureS>() {
return m_STexs;
}
template <>
inline GraphicsDataNode<ITextureSA, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureSA>() {
return m_SATexs;
}
template <>
inline GraphicsDataNode<ITextureD, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureD>() {
return m_DTexs;
}
template <>
inline GraphicsDataNode<ITextureR, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureR>() {
return m_RTexs;
}
template <>
inline GraphicsDataNode<ITextureCubeR, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureCubeR>() {
return m_CubeRTexs;
}
/** Private generalized pool container class.
* Keeps head pointer to exactly one dynamic buffer while otherwise conforming to BaseGraphicsData
*/
struct BaseGraphicsPool : ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*> {
static BaseGraphicsPool*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_poolHead; }
static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) {
return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
}
__BooTraceFields
GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>* m_DBufs = nullptr;
template <class T>
GraphicsDataNode<T, BaseGraphicsPool>*& getHead();
template <class T>
size_t countForward() {
auto* head = getHead<T>();
return head ? head->countForward() : 0;
}
explicit BaseGraphicsPool(GraphicsDataFactoryHead& head __BooTraceArgs)
: ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer {}
};
template <>
inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>*& BaseGraphicsPool::getHead<IGraphicsBufferD>() {
return m_DBufs;
}
/** Private generalised graphics object node.
* Keeps a strong reference to the data pool that it's a member of;
* as well as doubly-linked pointers to same-type sibling objects
*/
template <class NodeCls, class DataCls>
struct GraphicsDataNode : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls> {
using base = ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>;
static GraphicsDataNode<NodeCls, DataCls>*& _getHeadPtr(ObjToken<DataCls>& head) {
return head->template getHead<NodeCls>();
}
static std::unique_lock<std::recursive_mutex> _getHeadLock(ObjToken<DataCls>& head) {
return std::unique_lock<std::recursive_mutex>{head->m_head->m_dataMutex};
}
explicit GraphicsDataNode(const ObjToken<DataCls>& data)
: ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>(data) {}
class iterator {
GraphicsDataNode<NodeCls, DataCls>* m_node;
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = NodeCls;
using difference_type = std::ptrdiff_t;
using pointer = NodeCls*;
using reference = NodeCls&;
explicit iterator(GraphicsDataNode<NodeCls, DataCls>* node) : m_node(node) {}
NodeCls& operator*() const { return *m_node; }
bool operator!=(const iterator& other) const { return m_node != other.m_node; }
iterator& operator++() {
m_node = m_node->m_next;
return *this;
}
iterator& operator--() {
m_node = m_node->m_prev;
return *this;
}
};
iterator begin() { return iterator(this); }
iterator end() { return iterator(nullptr); }
size_t countForward() {
size_t ret = 0;
for (auto& n : *this)
++ret;
return ret;
}
};
void UpdateGammaLUT(ITextureD* tex, float gamma);
/** Generic work-queue for asynchronously building shader pipelines on supported backends
*/
template <class ShaderPipelineType>
class PipelineCompileQueue {
struct Task {
ObjToken<IShaderPipeline> m_pipeline;
explicit Task(ObjToken<IShaderPipeline> pipeline) : m_pipeline(pipeline) {}
void run() {
m_pipeline.cast<ShaderPipelineType>()->compile();
}
};
std::queue<Task> m_tasks;
std::atomic_size_t m_outstandingTasks = 0;
std::vector<std::thread> m_threads;
std::mutex m_mt;
std::condition_variable m_cv, m_backcv;
std::atomic_bool m_running = true;
void worker() {
std::unique_lock<std::mutex> lk(m_mt);
while (m_running) {
m_cv.wait(lk, [this]() { return !m_tasks.empty() || !m_running; });
if (!m_running)
break;
Task t = std::move(m_tasks.front());
m_tasks.pop();
lk.unlock();
t.run();
lk.lock();
--m_outstandingTasks;
m_backcv.notify_all();
}
}
public:
void addPipeline(ObjToken<IShaderPipeline> pipeline) {
std::lock_guard<std::mutex> lk(m_mt);
m_tasks.emplace(pipeline);
++m_outstandingTasks;
m_cv.notify_one();
}
void waitUntilReady() {
std::unique_lock<std::mutex> lk(m_mt);
m_backcv.wait(lk, [this]() { return m_outstandingTasks == 0 || !m_running; });
}
bool isReady() const {
return m_outstandingTasks == 0 || !m_running;
}
PipelineCompileQueue() {
unsigned int numThreads = std::thread::hardware_concurrency();
if (numThreads > 1)
--numThreads;
m_threads.reserve(numThreads);
for (unsigned int i = 0; i < numThreads; ++i)
m_threads.emplace_back(std::bind(&PipelineCompileQueue::worker, this));
}
~PipelineCompileQueue() {
m_running = false;
m_cv.notify_all();
for (auto& t : m_threads) t.join();
}
};
#ifdef BOO_GRAPHICS_DEBUG_GROUPS
template <typename CommandQueue>
class GraphicsDebugGroup {
/* Stack only */
void* operator new(size_t);
void operator delete(void*);
void* operator new[](size_t);
void operator delete[](void*);
CommandQueue* m_q;
public:
explicit GraphicsDebugGroup(CommandQueue* q, const char* name,
const std::array<float, 4>& color = {1.f, 1.f, 1.f, 1.f}) : m_q(q) {
m_q->pushDebugGroup(name, color);
}
~GraphicsDebugGroup() {
m_q->popDebugGroup();
}
};
#define SCOPED_GRAPHICS_DEBUG_GROUP(...) GraphicsDebugGroup _GfxDbg_(__VA_ARGS__);
#else
#define SCOPED_GRAPHICS_DEBUG_GROUP(_, name, ...) OPTICK_EVENT(name)
#endif
} // namespace boo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
#include "boo/graphicsdev/glxew.h"
#include <logvisor/logvisor.hpp>
namespace boo {
static logvisor::Module Log("boo::GLX");
void GLXExtensionCheck() {
if (!GLXEW_SGI_video_sync)
Log.report(logvisor::Fatal, FMT_STRING("GLX_SGI_video_sync not available"));
if (!GLXEW_EXT_swap_control && !GLXEW_MESA_swap_control && !GLXEW_SGI_swap_control)
Log.report(logvisor::Fatal, FMT_STRING("swap_control not available"));
}
void GLXEnableVSync(Display* disp, GLXWindow drawable) {
if (GLXEW_EXT_swap_control)
glXSwapIntervalEXT(disp, drawable, 1);
else if (GLXEW_MESA_swap_control)
glXSwapIntervalMESA(1);
else if (GLXEW_SGI_swap_control)
glXSwapIntervalSGI(1);
}
} // namespace boo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,657 +0,0 @@
// This file is generated.
#include "boo/graphicsdev/VulkanDispatchTable.hpp"
namespace vk {
PFN_vkCreateInstance CreateInstance;
PFN_vkDestroyInstance DestroyInstance;
PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;
PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
PFN_vkCreateDevice CreateDevice;
PFN_vkDestroyDevice DestroyDevice;
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties;
PFN_vkGetDeviceQueue GetDeviceQueue;
PFN_vkQueueSubmit QueueSubmit;
PFN_vkQueueWaitIdle QueueWaitIdle;
PFN_vkDeviceWaitIdle DeviceWaitIdle;
PFN_vkAllocateMemory AllocateMemory;
PFN_vkFreeMemory FreeMemory;
PFN_vkMapMemory MapMemory;
PFN_vkUnmapMemory UnmapMemory;
PFN_vkFlushMappedMemoryRanges FlushMappedMemoryRanges;
PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges;
PFN_vkGetDeviceMemoryCommitment GetDeviceMemoryCommitment;
PFN_vkBindBufferMemory BindBufferMemory;
PFN_vkBindImageMemory BindImageMemory;
PFN_vkGetBufferMemoryRequirements GetBufferMemoryRequirements;
PFN_vkGetImageMemoryRequirements GetImageMemoryRequirements;
PFN_vkGetImageSparseMemoryRequirements GetImageSparseMemoryRequirements;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
PFN_vkQueueBindSparse QueueBindSparse;
PFN_vkCreateFence CreateFence;
PFN_vkDestroyFence DestroyFence;
PFN_vkResetFences ResetFences;
PFN_vkGetFenceStatus GetFenceStatus;
PFN_vkWaitForFences WaitForFences;
PFN_vkCreateSemaphore CreateSemaphore;
PFN_vkDestroySemaphore DestroySemaphore;
PFN_vkCreateEvent CreateEvent;
PFN_vkDestroyEvent DestroyEvent;
PFN_vkGetEventStatus GetEventStatus;
PFN_vkSetEvent SetEvent;
PFN_vkResetEvent ResetEvent;
PFN_vkCreateQueryPool CreateQueryPool;
PFN_vkDestroyQueryPool DestroyQueryPool;
PFN_vkGetQueryPoolResults GetQueryPoolResults;
PFN_vkCreateBuffer CreateBuffer;
PFN_vkDestroyBuffer DestroyBuffer;
PFN_vkCreateBufferView CreateBufferView;
PFN_vkDestroyBufferView DestroyBufferView;
PFN_vkCreateImage CreateImage;
PFN_vkDestroyImage DestroyImage;
PFN_vkGetImageSubresourceLayout GetImageSubresourceLayout;
PFN_vkCreateImageView CreateImageView;
PFN_vkDestroyImageView DestroyImageView;
PFN_vkCreateShaderModule CreateShaderModule;
PFN_vkDestroyShaderModule DestroyShaderModule;
PFN_vkCreatePipelineCache CreatePipelineCache;
PFN_vkDestroyPipelineCache DestroyPipelineCache;
PFN_vkGetPipelineCacheData GetPipelineCacheData;
PFN_vkMergePipelineCaches MergePipelineCaches;
PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines;
PFN_vkCreateComputePipelines CreateComputePipelines;
PFN_vkDestroyPipeline DestroyPipeline;
PFN_vkCreatePipelineLayout CreatePipelineLayout;
PFN_vkDestroyPipelineLayout DestroyPipelineLayout;
PFN_vkCreateSampler CreateSampler;
PFN_vkDestroySampler DestroySampler;
PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout;
PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout;
PFN_vkCreateDescriptorPool CreateDescriptorPool;
PFN_vkDestroyDescriptorPool DestroyDescriptorPool;
PFN_vkResetDescriptorPool ResetDescriptorPool;
PFN_vkAllocateDescriptorSets AllocateDescriptorSets;
PFN_vkFreeDescriptorSets FreeDescriptorSets;
PFN_vkUpdateDescriptorSets UpdateDescriptorSets;
PFN_vkCreateFramebuffer CreateFramebuffer;
PFN_vkDestroyFramebuffer DestroyFramebuffer;
PFN_vkCreateRenderPass CreateRenderPass;
PFN_vkDestroyRenderPass DestroyRenderPass;
PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity;
PFN_vkCreateCommandPool CreateCommandPool;
PFN_vkDestroyCommandPool DestroyCommandPool;
PFN_vkResetCommandPool ResetCommandPool;
PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
PFN_vkFreeCommandBuffers FreeCommandBuffers;
PFN_vkBeginCommandBuffer BeginCommandBuffer;
PFN_vkEndCommandBuffer EndCommandBuffer;
PFN_vkResetCommandBuffer ResetCommandBuffer;
PFN_vkCmdBindPipeline CmdBindPipeline;
PFN_vkCmdSetViewport CmdSetViewport;
PFN_vkCmdSetScissor CmdSetScissor;
PFN_vkCmdSetLineWidth CmdSetLineWidth;
PFN_vkCmdSetDepthBias CmdSetDepthBias;
PFN_vkCmdSetBlendConstants CmdSetBlendConstants;
PFN_vkCmdSetDepthBounds CmdSetDepthBounds;
PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask;
PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask;
PFN_vkCmdSetStencilReference CmdSetStencilReference;
PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets;
PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer;
PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers;
PFN_vkCmdDraw CmdDraw;
PFN_vkCmdDrawIndexed CmdDrawIndexed;
PFN_vkCmdDrawIndirect CmdDrawIndirect;
PFN_vkCmdDrawIndexedIndirect CmdDrawIndexedIndirect;
PFN_vkCmdDispatch CmdDispatch;
PFN_vkCmdDispatchIndirect CmdDispatchIndirect;
PFN_vkCmdCopyBuffer CmdCopyBuffer;
PFN_vkCmdCopyImage CmdCopyImage;
PFN_vkCmdBlitImage CmdBlitImage;
PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage;
PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer;
PFN_vkCmdUpdateBuffer CmdUpdateBuffer;
PFN_vkCmdFillBuffer CmdFillBuffer;
PFN_vkCmdClearColorImage CmdClearColorImage;
PFN_vkCmdClearDepthStencilImage CmdClearDepthStencilImage;
PFN_vkCmdClearAttachments CmdClearAttachments;
PFN_vkCmdResolveImage CmdResolveImage;
PFN_vkCmdSetEvent CmdSetEvent;
PFN_vkCmdResetEvent CmdResetEvent;
PFN_vkCmdWaitEvents CmdWaitEvents;
PFN_vkCmdPipelineBarrier CmdPipelineBarrier;
PFN_vkCmdBeginQuery CmdBeginQuery;
PFN_vkCmdEndQuery CmdEndQuery;
PFN_vkCmdResetQueryPool CmdResetQueryPool;
PFN_vkCmdWriteTimestamp CmdWriteTimestamp;
PFN_vkCmdCopyQueryPoolResults CmdCopyQueryPoolResults;
PFN_vkCmdPushConstants CmdPushConstants;
PFN_vkCmdBeginRenderPass CmdBeginRenderPass;
PFN_vkCmdNextSubpass CmdNextSubpass;
PFN_vkCmdEndRenderPass CmdEndRenderPass;
PFN_vkCmdExecuteCommands CmdExecuteCommands;
PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
PFN_vkQueuePresentKHR QueuePresentKHR;
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR GetPhysicalDeviceDisplayPropertiesKHR;
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR GetPhysicalDeviceDisplayPlanePropertiesKHR;
PFN_vkGetDisplayPlaneSupportedDisplaysKHR GetDisplayPlaneSupportedDisplaysKHR;
PFN_vkGetDisplayModePropertiesKHR GetDisplayModePropertiesKHR;
PFN_vkCreateDisplayModeKHR CreateDisplayModeKHR;
PFN_vkGetDisplayPlaneCapabilitiesKHR GetDisplayPlaneCapabilitiesKHR;
PFN_vkCreateDisplayPlaneSurfaceKHR CreateDisplayPlaneSurfaceKHR;
PFN_vkCreateSharedSwapchainsKHR CreateSharedSwapchainsKHR;
#ifdef VK_USE_PLATFORM_XLIB_KHR
PFN_vkCreateXlibSurfaceKHR CreateXlibSurfaceKHR;
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR GetPhysicalDeviceXlibPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
PFN_vkCreateXcbSurfaceKHR CreateXcbSurfaceKHR;
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR GetPhysicalDeviceXcbPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
PFN_vkCreateWaylandSurfaceKHR CreateWaylandSurfaceKHR;
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWaylandPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
PFN_vkCreateMirSurfaceKHR CreateMirSurfaceKHR;
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR GetPhysicalDeviceMirPresentationSupportKHR;
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
PFN_vkCreateWin32SurfaceKHR CreateWin32SurfaceKHR;
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR;
#endif
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
PFN_vkDebugMarkerSetObjectTagEXT DebugMarkerSetObjectTagEXT;
PFN_vkDebugMarkerSetObjectNameEXT DebugMarkerSetObjectNameEXT;
PFN_vkCmdDebugMarkerBeginEXT CmdDebugMarkerBeginEXT;
PFN_vkCmdDebugMarkerEndEXT CmdDebugMarkerEndEXT;
PFN_vkCmdDebugMarkerInsertEXT CmdDebugMarkerInsertEXT;
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) {
GetInstanceProcAddr = get_instance_proc_addr;
CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance"));
EnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"));
EnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties"));
}
void init_dispatch_table_middle(VkInstance instance, bool include_bottom) {
GetInstanceProcAddr =
reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(instance, "vkGetInstanceProcAddr"));
DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(GetInstanceProcAddr(instance, "vkDestroyInstance"));
EnumeratePhysicalDevices =
reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
GetPhysicalDeviceFeatures =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures"));
GetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties"));
GetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties"));
GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
GetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties"));
CreateDevice = reinterpret_cast<PFN_vkCreateDevice>(GetInstanceProcAddr(instance, "vkCreateDevice"));
EnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties"));
GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties"));
DestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(GetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
GetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
GetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
GetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
GetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
GetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
GetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
GetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
GetDisplayModePropertiesKHR = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
CreateDisplayModeKHR =
reinterpret_cast<PFN_vkCreateDisplayModeKHR>(GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
GetDisplayPlaneCapabilitiesKHR = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
CreateDisplayPlaneSurfaceKHR = reinterpret_cast<PFN_vkCreateDisplayPlaneSurfaceKHR>(
GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR"));
#ifdef VK_USE_PLATFORM_XLIB_KHR
CreateXlibSurfaceKHR =
reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
GetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"));
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
CreateXcbSurfaceKHR =
reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
GetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"));
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
CreateWaylandSurfaceKHR =
reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
GetPhysicalDeviceWaylandPresentationSupportKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"));
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
CreateMirSurfaceKHR =
reinterpret_cast<PFN_vkCreateMirSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_MIR_KHR
GetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceMirPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"));
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
CreateAndroidSurfaceKHR =
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
CreateWin32SurfaceKHR =
reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"));
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
GetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"));
#endif
CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
DebugReportMessageEXT =
reinterpret_cast<PFN_vkDebugReportMessageEXT>(GetInstanceProcAddr(instance, "vkDebugReportMessageEXT"));
if (!include_bottom)
return;
GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(GetInstanceProcAddr(instance, "vkDestroyDevice"));
GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(GetInstanceProcAddr(instance, "vkGetDeviceQueue"));
QueueSubmit = reinterpret_cast<PFN_vkQueueSubmit>(GetInstanceProcAddr(instance, "vkQueueSubmit"));
QueueWaitIdle = reinterpret_cast<PFN_vkQueueWaitIdle>(GetInstanceProcAddr(instance, "vkQueueWaitIdle"));
DeviceWaitIdle = reinterpret_cast<PFN_vkDeviceWaitIdle>(GetInstanceProcAddr(instance, "vkDeviceWaitIdle"));
AllocateMemory = reinterpret_cast<PFN_vkAllocateMemory>(GetInstanceProcAddr(instance, "vkAllocateMemory"));
FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetInstanceProcAddr(instance, "vkFreeMemory"));
MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetInstanceProcAddr(instance, "vkMapMemory"));
UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetInstanceProcAddr(instance, "vkUnmapMemory"));
FlushMappedMemoryRanges =
reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges"));
InvalidateMappedMemoryRanges = reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(
GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges"));
GetDeviceMemoryCommitment =
reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment"));
BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetInstanceProcAddr(instance, "vkBindBufferMemory"));
BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetInstanceProcAddr(instance, "vkBindImageMemory"));
GetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(
GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements"));
GetImageMemoryRequirements =
reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(
GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements"));
QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetInstanceProcAddr(instance, "vkQueueBindSparse"));
CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetInstanceProcAddr(instance, "vkCreateFence"));
DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetInstanceProcAddr(instance, "vkDestroyFence"));
ResetFences = reinterpret_cast<PFN_vkResetFences>(GetInstanceProcAddr(instance, "vkResetFences"));
GetFenceStatus = reinterpret_cast<PFN_vkGetFenceStatus>(GetInstanceProcAddr(instance, "vkGetFenceStatus"));
WaitForFences = reinterpret_cast<PFN_vkWaitForFences>(GetInstanceProcAddr(instance, "vkWaitForFences"));
CreateSemaphore = reinterpret_cast<PFN_vkCreateSemaphore>(GetInstanceProcAddr(instance, "vkCreateSemaphore"));
DestroySemaphore = reinterpret_cast<PFN_vkDestroySemaphore>(GetInstanceProcAddr(instance, "vkDestroySemaphore"));
CreateEvent = reinterpret_cast<PFN_vkCreateEvent>(GetInstanceProcAddr(instance, "vkCreateEvent"));
DestroyEvent = reinterpret_cast<PFN_vkDestroyEvent>(GetInstanceProcAddr(instance, "vkDestroyEvent"));
GetEventStatus = reinterpret_cast<PFN_vkGetEventStatus>(GetInstanceProcAddr(instance, "vkGetEventStatus"));
SetEvent = reinterpret_cast<PFN_vkSetEvent>(GetInstanceProcAddr(instance, "vkSetEvent"));
ResetEvent = reinterpret_cast<PFN_vkResetEvent>(GetInstanceProcAddr(instance, "vkResetEvent"));
CreateQueryPool = reinterpret_cast<PFN_vkCreateQueryPool>(GetInstanceProcAddr(instance, "vkCreateQueryPool"));
DestroyQueryPool = reinterpret_cast<PFN_vkDestroyQueryPool>(GetInstanceProcAddr(instance, "vkDestroyQueryPool"));
GetQueryPoolResults =
reinterpret_cast<PFN_vkGetQueryPoolResults>(GetInstanceProcAddr(instance, "vkGetQueryPoolResults"));
CreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(GetInstanceProcAddr(instance, "vkCreateBuffer"));
DestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(GetInstanceProcAddr(instance, "vkDestroyBuffer"));
CreateBufferView = reinterpret_cast<PFN_vkCreateBufferView>(GetInstanceProcAddr(instance, "vkCreateBufferView"));
DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetInstanceProcAddr(instance, "vkDestroyBufferView"));
CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetInstanceProcAddr(instance, "vkCreateImage"));
DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetInstanceProcAddr(instance, "vkDestroyImage"));
GetImageSubresourceLayout =
reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout"));
CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetInstanceProcAddr(instance, "vkCreateImageView"));
DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetInstanceProcAddr(instance, "vkDestroyImageView"));
CreateShaderModule =
reinterpret_cast<PFN_vkCreateShaderModule>(GetInstanceProcAddr(instance, "vkCreateShaderModule"));
DestroyShaderModule =
reinterpret_cast<PFN_vkDestroyShaderModule>(GetInstanceProcAddr(instance, "vkDestroyShaderModule"));
CreatePipelineCache =
reinterpret_cast<PFN_vkCreatePipelineCache>(GetInstanceProcAddr(instance, "vkCreatePipelineCache"));
DestroyPipelineCache =
reinterpret_cast<PFN_vkDestroyPipelineCache>(GetInstanceProcAddr(instance, "vkDestroyPipelineCache"));
GetPipelineCacheData =
reinterpret_cast<PFN_vkGetPipelineCacheData>(GetInstanceProcAddr(instance, "vkGetPipelineCacheData"));
MergePipelineCaches =
reinterpret_cast<PFN_vkMergePipelineCaches>(GetInstanceProcAddr(instance, "vkMergePipelineCaches"));
CreateGraphicsPipelines =
reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines"));
CreateComputePipelines =
reinterpret_cast<PFN_vkCreateComputePipelines>(GetInstanceProcAddr(instance, "vkCreateComputePipelines"));
DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetInstanceProcAddr(instance, "vkDestroyPipeline"));
CreatePipelineLayout =
reinterpret_cast<PFN_vkCreatePipelineLayout>(GetInstanceProcAddr(instance, "vkCreatePipelineLayout"));
DestroyPipelineLayout =
reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetInstanceProcAddr(instance, "vkDestroyPipelineLayout"));
CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetInstanceProcAddr(instance, "vkCreateSampler"));
DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetInstanceProcAddr(instance, "vkDestroySampler"));
CreateDescriptorSetLayout =
reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout"));
DestroyDescriptorSetLayout =
reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout"));
CreateDescriptorPool =
reinterpret_cast<PFN_vkCreateDescriptorPool>(GetInstanceProcAddr(instance, "vkCreateDescriptorPool"));
DestroyDescriptorPool =
reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetInstanceProcAddr(instance, "vkDestroyDescriptorPool"));
ResetDescriptorPool =
reinterpret_cast<PFN_vkResetDescriptorPool>(GetInstanceProcAddr(instance, "vkResetDescriptorPool"));
AllocateDescriptorSets =
reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetInstanceProcAddr(instance, "vkAllocateDescriptorSets"));
FreeDescriptorSets =
reinterpret_cast<PFN_vkFreeDescriptorSets>(GetInstanceProcAddr(instance, "vkFreeDescriptorSets"));
UpdateDescriptorSets =
reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetInstanceProcAddr(instance, "vkUpdateDescriptorSets"));
CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetInstanceProcAddr(instance, "vkCreateFramebuffer"));
DestroyFramebuffer =
reinterpret_cast<PFN_vkDestroyFramebuffer>(GetInstanceProcAddr(instance, "vkDestroyFramebuffer"));
CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetInstanceProcAddr(instance, "vkCreateRenderPass"));
DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetInstanceProcAddr(instance, "vkDestroyRenderPass"));
GetRenderAreaGranularity =
reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity"));
CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetInstanceProcAddr(instance, "vkCreateCommandPool"));
DestroyCommandPool =
reinterpret_cast<PFN_vkDestroyCommandPool>(GetInstanceProcAddr(instance, "vkDestroyCommandPool"));
ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetInstanceProcAddr(instance, "vkResetCommandPool"));
AllocateCommandBuffers =
reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetInstanceProcAddr(instance, "vkAllocateCommandBuffers"));
FreeCommandBuffers =
reinterpret_cast<PFN_vkFreeCommandBuffers>(GetInstanceProcAddr(instance, "vkFreeCommandBuffers"));
BeginCommandBuffer =
reinterpret_cast<PFN_vkBeginCommandBuffer>(GetInstanceProcAddr(instance, "vkBeginCommandBuffer"));
EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetInstanceProcAddr(instance, "vkEndCommandBuffer"));
ResetCommandBuffer =
reinterpret_cast<PFN_vkResetCommandBuffer>(GetInstanceProcAddr(instance, "vkResetCommandBuffer"));
CmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(GetInstanceProcAddr(instance, "vkCmdBindPipeline"));
CmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(GetInstanceProcAddr(instance, "vkCmdSetViewport"));
CmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(GetInstanceProcAddr(instance, "vkCmdSetScissor"));
CmdSetLineWidth = reinterpret_cast<PFN_vkCmdSetLineWidth>(GetInstanceProcAddr(instance, "vkCmdSetLineWidth"));
CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetInstanceProcAddr(instance, "vkCmdSetDepthBias"));
CmdSetBlendConstants =
reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetInstanceProcAddr(instance, "vkCmdSetBlendConstants"));
CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetInstanceProcAddr(instance, "vkCmdSetDepthBounds"));
CmdSetStencilCompareMask =
reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask"));
CmdSetStencilWriteMask =
reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask"));
CmdSetStencilReference =
reinterpret_cast<PFN_vkCmdSetStencilReference>(GetInstanceProcAddr(instance, "vkCmdSetStencilReference"));
CmdBindDescriptorSets =
reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets"));
CmdBindIndexBuffer =
reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer"));
CmdBindVertexBuffers =
reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers"));
CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetInstanceProcAddr(instance, "vkCmdDraw"));
CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetInstanceProcAddr(instance, "vkCmdDrawIndexed"));
CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndirect"));
CmdDrawIndexedIndirect =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect"));
CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetInstanceProcAddr(instance, "vkCmdDispatch"));
CmdDispatchIndirect =
reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetInstanceProcAddr(instance, "vkCmdDispatchIndirect"));
CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyBuffer"));
CmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(GetInstanceProcAddr(instance, "vkCmdCopyImage"));
CmdBlitImage = reinterpret_cast<PFN_vkCmdBlitImage>(GetInstanceProcAddr(instance, "vkCmdBlitImage"));
CmdCopyBufferToImage =
reinterpret_cast<PFN_vkCmdCopyBufferToImage>(GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage"));
CmdCopyImageToBuffer =
reinterpret_cast<PFN_vkCmdCopyImageToBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer"));
CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetInstanceProcAddr(instance, "vkCmdUpdateBuffer"));
CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetInstanceProcAddr(instance, "vkCmdFillBuffer"));
CmdClearColorImage =
reinterpret_cast<PFN_vkCmdClearColorImage>(GetInstanceProcAddr(instance, "vkCmdClearColorImage"));
CmdClearDepthStencilImage =
reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage"));
CmdClearAttachments =
reinterpret_cast<PFN_vkCmdClearAttachments>(GetInstanceProcAddr(instance, "vkCmdClearAttachments"));
CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetInstanceProcAddr(instance, "vkCmdResolveImage"));
CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetInstanceProcAddr(instance, "vkCmdSetEvent"));
CmdResetEvent = reinterpret_cast<PFN_vkCmdResetEvent>(GetInstanceProcAddr(instance, "vkCmdResetEvent"));
CmdWaitEvents = reinterpret_cast<PFN_vkCmdWaitEvents>(GetInstanceProcAddr(instance, "vkCmdWaitEvents"));
CmdPipelineBarrier =
reinterpret_cast<PFN_vkCmdPipelineBarrier>(GetInstanceProcAddr(instance, "vkCmdPipelineBarrier"));
CmdBeginQuery = reinterpret_cast<PFN_vkCmdBeginQuery>(GetInstanceProcAddr(instance, "vkCmdBeginQuery"));
CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetInstanceProcAddr(instance, "vkCmdEndQuery"));
CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetInstanceProcAddr(instance, "vkCmdResetQueryPool"));
CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetInstanceProcAddr(instance, "vkCmdWriteTimestamp"));
CmdCopyQueryPoolResults =
reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults"));
CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetInstanceProcAddr(instance, "vkCmdPushConstants"));
CmdBeginRenderPass =
reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetInstanceProcAddr(instance, "vkCmdBeginRenderPass"));
CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetInstanceProcAddr(instance, "vkCmdNextSubpass"));
CmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(GetInstanceProcAddr(instance, "vkCmdEndRenderPass"));
CmdExecuteCommands =
reinterpret_cast<PFN_vkCmdExecuteCommands>(GetInstanceProcAddr(instance, "vkCmdExecuteCommands"));
CreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetInstanceProcAddr(instance, "vkCreateSwapchainKHR"));
DestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetInstanceProcAddr(instance, "vkDestroySwapchainKHR"));
GetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR"));
AcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetInstanceProcAddr(instance, "vkAcquireNextImageKHR"));
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetInstanceProcAddr(instance, "vkQueuePresentKHR"));
CreateSharedSwapchainsKHR =
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR"));
}
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) {
GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr(dev, "vkGetDeviceProcAddr"));
DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(GetDeviceProcAddr(dev, "vkDestroyDevice"));
GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(GetDeviceProcAddr(dev, "vkGetDeviceQueue"));
QueueSubmit = reinterpret_cast<PFN_vkQueueSubmit>(GetDeviceProcAddr(dev, "vkQueueSubmit"));
QueueWaitIdle = reinterpret_cast<PFN_vkQueueWaitIdle>(GetDeviceProcAddr(dev, "vkQueueWaitIdle"));
DeviceWaitIdle = reinterpret_cast<PFN_vkDeviceWaitIdle>(GetDeviceProcAddr(dev, "vkDeviceWaitIdle"));
AllocateMemory = reinterpret_cast<PFN_vkAllocateMemory>(GetDeviceProcAddr(dev, "vkAllocateMemory"));
FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetDeviceProcAddr(dev, "vkFreeMemory"));
MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetDeviceProcAddr(dev, "vkMapMemory"));
UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetDeviceProcAddr(dev, "vkUnmapMemory"));
FlushMappedMemoryRanges =
reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkFlushMappedMemoryRanges"));
InvalidateMappedMemoryRanges =
reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkInvalidateMappedMemoryRanges"));
GetDeviceMemoryCommitment =
reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceProcAddr(dev, "vkGetDeviceMemoryCommitment"));
BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetDeviceProcAddr(dev, "vkBindBufferMemory"));
BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetDeviceProcAddr(dev, "vkBindImageMemory"));
GetBufferMemoryRequirements =
reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetBufferMemoryRequirements"));
GetImageMemoryRequirements =
reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetImageMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(
GetDeviceProcAddr(dev, "vkGetImageSparseMemoryRequirements"));
QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetDeviceProcAddr(dev, "vkQueueBindSparse"));
CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetDeviceProcAddr(dev, "vkCreateFence"));
DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetDeviceProcAddr(dev, "vkDestroyFence"));
ResetFences = reinterpret_cast<PFN_vkResetFences>(GetDeviceProcAddr(dev, "vkResetFences"));
GetFenceStatus = reinterpret_cast<PFN_vkGetFenceStatus>(GetDeviceProcAddr(dev, "vkGetFenceStatus"));
WaitForFences = reinterpret_cast<PFN_vkWaitForFences>(GetDeviceProcAddr(dev, "vkWaitForFences"));
CreateSemaphore = reinterpret_cast<PFN_vkCreateSemaphore>(GetDeviceProcAddr(dev, "vkCreateSemaphore"));
DestroySemaphore = reinterpret_cast<PFN_vkDestroySemaphore>(GetDeviceProcAddr(dev, "vkDestroySemaphore"));
CreateEvent = reinterpret_cast<PFN_vkCreateEvent>(GetDeviceProcAddr(dev, "vkCreateEvent"));
DestroyEvent = reinterpret_cast<PFN_vkDestroyEvent>(GetDeviceProcAddr(dev, "vkDestroyEvent"));
GetEventStatus = reinterpret_cast<PFN_vkGetEventStatus>(GetDeviceProcAddr(dev, "vkGetEventStatus"));
SetEvent = reinterpret_cast<PFN_vkSetEvent>(GetDeviceProcAddr(dev, "vkSetEvent"));
ResetEvent = reinterpret_cast<PFN_vkResetEvent>(GetDeviceProcAddr(dev, "vkResetEvent"));
CreateQueryPool = reinterpret_cast<PFN_vkCreateQueryPool>(GetDeviceProcAddr(dev, "vkCreateQueryPool"));
DestroyQueryPool = reinterpret_cast<PFN_vkDestroyQueryPool>(GetDeviceProcAddr(dev, "vkDestroyQueryPool"));
GetQueryPoolResults = reinterpret_cast<PFN_vkGetQueryPoolResults>(GetDeviceProcAddr(dev, "vkGetQueryPoolResults"));
CreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(GetDeviceProcAddr(dev, "vkCreateBuffer"));
DestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(GetDeviceProcAddr(dev, "vkDestroyBuffer"));
CreateBufferView = reinterpret_cast<PFN_vkCreateBufferView>(GetDeviceProcAddr(dev, "vkCreateBufferView"));
DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetDeviceProcAddr(dev, "vkDestroyBufferView"));
CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetDeviceProcAddr(dev, "vkCreateImage"));
DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetDeviceProcAddr(dev, "vkDestroyImage"));
GetImageSubresourceLayout =
reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetDeviceProcAddr(dev, "vkGetImageSubresourceLayout"));
CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetDeviceProcAddr(dev, "vkCreateImageView"));
DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetDeviceProcAddr(dev, "vkDestroyImageView"));
CreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(GetDeviceProcAddr(dev, "vkCreateShaderModule"));
DestroyShaderModule = reinterpret_cast<PFN_vkDestroyShaderModule>(GetDeviceProcAddr(dev, "vkDestroyShaderModule"));
CreatePipelineCache = reinterpret_cast<PFN_vkCreatePipelineCache>(GetDeviceProcAddr(dev, "vkCreatePipelineCache"));
DestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(GetDeviceProcAddr(dev, "vkDestroyPipelineCache"));
GetPipelineCacheData = reinterpret_cast<PFN_vkGetPipelineCacheData>(GetDeviceProcAddr(dev, "vkGetPipelineCacheData"));
MergePipelineCaches = reinterpret_cast<PFN_vkMergePipelineCaches>(GetDeviceProcAddr(dev, "vkMergePipelineCaches"));
CreateGraphicsPipelines =
reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetDeviceProcAddr(dev, "vkCreateGraphicsPipelines"));
CreateComputePipelines =
reinterpret_cast<PFN_vkCreateComputePipelines>(GetDeviceProcAddr(dev, "vkCreateComputePipelines"));
DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetDeviceProcAddr(dev, "vkDestroyPipeline"));
CreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(GetDeviceProcAddr(dev, "vkCreatePipelineLayout"));
DestroyPipelineLayout =
reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetDeviceProcAddr(dev, "vkDestroyPipelineLayout"));
CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetDeviceProcAddr(dev, "vkCreateSampler"));
DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetDeviceProcAddr(dev, "vkDestroySampler"));
CreateDescriptorSetLayout =
reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkCreateDescriptorSetLayout"));
DestroyDescriptorSetLayout =
reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkDestroyDescriptorSetLayout"));
CreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(GetDeviceProcAddr(dev, "vkCreateDescriptorPool"));
DestroyDescriptorPool =
reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetDeviceProcAddr(dev, "vkDestroyDescriptorPool"));
ResetDescriptorPool = reinterpret_cast<PFN_vkResetDescriptorPool>(GetDeviceProcAddr(dev, "vkResetDescriptorPool"));
AllocateDescriptorSets =
reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetDeviceProcAddr(dev, "vkAllocateDescriptorSets"));
FreeDescriptorSets = reinterpret_cast<PFN_vkFreeDescriptorSets>(GetDeviceProcAddr(dev, "vkFreeDescriptorSets"));
UpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetDeviceProcAddr(dev, "vkUpdateDescriptorSets"));
CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetDeviceProcAddr(dev, "vkCreateFramebuffer"));
DestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(GetDeviceProcAddr(dev, "vkDestroyFramebuffer"));
CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetDeviceProcAddr(dev, "vkCreateRenderPass"));
DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetDeviceProcAddr(dev, "vkDestroyRenderPass"));
GetRenderAreaGranularity =
reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetDeviceProcAddr(dev, "vkGetRenderAreaGranularity"));
CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetDeviceProcAddr(dev, "vkCreateCommandPool"));
DestroyCommandPool = reinterpret_cast<PFN_vkDestroyCommandPool>(GetDeviceProcAddr(dev, "vkDestroyCommandPool"));
ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetDeviceProcAddr(dev, "vkResetCommandPool"));
AllocateCommandBuffers =
reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetDeviceProcAddr(dev, "vkAllocateCommandBuffers"));
FreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(GetDeviceProcAddr(dev, "vkFreeCommandBuffers"));
BeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(GetDeviceProcAddr(dev, "vkBeginCommandBuffer"));
EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetDeviceProcAddr(dev, "vkEndCommandBuffer"));
ResetCommandBuffer = reinterpret_cast<PFN_vkResetCommandBuffer>(GetDeviceProcAddr(dev, "vkResetCommandBuffer"));
CmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(GetDeviceProcAddr(dev, "vkCmdBindPipeline"));
CmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(GetDeviceProcAddr(dev, "vkCmdSetViewport"));
CmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(GetDeviceProcAddr(dev, "vkCmdSetScissor"));
CmdSetLineWidth = reinterpret_cast<PFN_vkCmdSetLineWidth>(GetDeviceProcAddr(dev, "vkCmdSetLineWidth"));
CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetDeviceProcAddr(dev, "vkCmdSetDepthBias"));
CmdSetBlendConstants = reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetDeviceProcAddr(dev, "vkCmdSetBlendConstants"));
CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetDeviceProcAddr(dev, "vkCmdSetDepthBounds"));
CmdSetStencilCompareMask =
reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilCompareMask"));
CmdSetStencilWriteMask =
reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilWriteMask"));
CmdSetStencilReference =
reinterpret_cast<PFN_vkCmdSetStencilReference>(GetDeviceProcAddr(dev, "vkCmdSetStencilReference"));
CmdBindDescriptorSets =
reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetDeviceProcAddr(dev, "vkCmdBindDescriptorSets"));
CmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetDeviceProcAddr(dev, "vkCmdBindIndexBuffer"));
CmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetDeviceProcAddr(dev, "vkCmdBindVertexBuffers"));
CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetDeviceProcAddr(dev, "vkCmdDraw"));
CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetDeviceProcAddr(dev, "vkCmdDrawIndexed"));
CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndirect"));
CmdDrawIndexedIndirect =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndexedIndirect"));
CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetDeviceProcAddr(dev, "vkCmdDispatch"));
CmdDispatchIndirect = reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetDeviceProcAddr(dev, "vkCmdDispatchIndirect"));
CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetDeviceProcAddr(dev, "vkCmdCopyBuffer"));
CmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(GetDeviceProcAddr(dev, "vkCmdCopyImage"));
CmdBlitImage = reinterpret_cast<PFN_vkCmdBlitImage>(GetDeviceProcAddr(dev, "vkCmdBlitImage"));
CmdCopyBufferToImage = reinterpret_cast<PFN_vkCmdCopyBufferToImage>(GetDeviceProcAddr(dev, "vkCmdCopyBufferToImage"));
CmdCopyImageToBuffer = reinterpret_cast<PFN_vkCmdCopyImageToBuffer>(GetDeviceProcAddr(dev, "vkCmdCopyImageToBuffer"));
CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetDeviceProcAddr(dev, "vkCmdUpdateBuffer"));
CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetDeviceProcAddr(dev, "vkCmdFillBuffer"));
CmdClearColorImage = reinterpret_cast<PFN_vkCmdClearColorImage>(GetDeviceProcAddr(dev, "vkCmdClearColorImage"));
CmdClearDepthStencilImage =
reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetDeviceProcAddr(dev, "vkCmdClearDepthStencilImage"));
CmdClearAttachments = reinterpret_cast<PFN_vkCmdClearAttachments>(GetDeviceProcAddr(dev, "vkCmdClearAttachments"));
CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetDeviceProcAddr(dev, "vkCmdResolveImage"));
CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetDeviceProcAddr(dev, "vkCmdSetEvent"));
CmdResetEvent = reinterpret_cast<PFN_vkCmdResetEvent>(GetDeviceProcAddr(dev, "vkCmdResetEvent"));
CmdWaitEvents = reinterpret_cast<PFN_vkCmdWaitEvents>(GetDeviceProcAddr(dev, "vkCmdWaitEvents"));
CmdPipelineBarrier = reinterpret_cast<PFN_vkCmdPipelineBarrier>(GetDeviceProcAddr(dev, "vkCmdPipelineBarrier"));
CmdBeginQuery = reinterpret_cast<PFN_vkCmdBeginQuery>(GetDeviceProcAddr(dev, "vkCmdBeginQuery"));
CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetDeviceProcAddr(dev, "vkCmdEndQuery"));
CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetDeviceProcAddr(dev, "vkCmdResetQueryPool"));
CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetDeviceProcAddr(dev, "vkCmdWriteTimestamp"));
CmdCopyQueryPoolResults =
reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetDeviceProcAddr(dev, "vkCmdCopyQueryPoolResults"));
CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetDeviceProcAddr(dev, "vkCmdPushConstants"));
CmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetDeviceProcAddr(dev, "vkCmdBeginRenderPass"));
CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetDeviceProcAddr(dev, "vkCmdNextSubpass"));
CmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(GetDeviceProcAddr(dev, "vkCmdEndRenderPass"));
CmdExecuteCommands = reinterpret_cast<PFN_vkCmdExecuteCommands>(GetDeviceProcAddr(dev, "vkCmdExecuteCommands"));
CreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetDeviceProcAddr(dev, "vkCreateSwapchainKHR"));
DestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetDeviceProcAddr(dev, "vkDestroySwapchainKHR"));
GetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetDeviceProcAddr(dev, "vkGetSwapchainImagesKHR"));
AcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetDeviceProcAddr(dev, "vkAcquireNextImageKHR"));
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetDeviceProcAddr(dev, "vkQueuePresentKHR"));
CreateSharedSwapchainsKHR =
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR"));
DebugMarkerSetObjectTagEXT = reinterpret_cast<PFN_vkDebugMarkerSetObjectTagEXT>(
GetDeviceProcAddr(dev, "vkDebugMarkerSetObjectTagEXT"));
DebugMarkerSetObjectNameEXT = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(
GetDeviceProcAddr(dev, "vkDebugMarkerSetObjectNameEXT"));
CmdDebugMarkerBeginEXT = reinterpret_cast<PFN_vkCmdDebugMarkerBeginEXT>(
GetDeviceProcAddr(dev, "vkCmdDebugMarkerBeginEXT"));
CmdDebugMarkerEndEXT = reinterpret_cast<PFN_vkCmdDebugMarkerEndEXT>(
GetDeviceProcAddr(dev, "vkCmdDebugMarkerEndEXT"));
CmdDebugMarkerInsertEXT = reinterpret_cast<PFN_vkCmdDebugMarkerInsertEXT>(
GetDeviceProcAddr(dev, "vkCmdDebugMarkerInsertEXT"));
}
} // namespace vk

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
#include "boo/inputdev/CafeProPad.hpp"

View File

@ -1,91 +0,0 @@
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "lib/inputdev/IHIDDevice.hpp"
namespace boo {
DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token) : m_typeHash(typeHash), m_token(token) {}
void DeviceBase::_deviceDisconnected() {
deviceDisconnected();
m_token = nullptr;
if (m_hidDev) {
m_hidDev->_deviceDisconnected();
m_hidDev.reset();
}
}
void DeviceBase::closeDevice() {
if (m_token)
m_token->_deviceClose();
}
void DeviceBase::vdeviceError(fmt::string_view error, fmt::format_args args) {
fmt::vprint(error, args);
}
bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(data, length);
return false;
}
size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(data, length);
return false;
}
unsigned DeviceBase::getVendorId() const {
if (m_token)
return m_token->getVendorId();
return -1;
}
unsigned DeviceBase::getProductId() const {
if (m_token)
return m_token->getProductId();
return -1;
}
std::string_view DeviceBase::getVendorName() const {
if (m_token)
return m_token->getVendorName();
return {};
}
std::string_view DeviceBase::getProductName() const {
if (m_token)
return m_token->getProductName();
return {};
}
#if _WIN32
#if !WINDOWS_STORE
PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() const {
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
}
#endif
#else
std::vector<uint8_t> DeviceBase::getReportDescriptor() const {
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
}
#endif
bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_hidDev)
return m_hidDev->_sendHIDReport(data, length, tp, message);
return false;
}
size_t DeviceBase::receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_hidDev)
return m_hidDev->_receiveHIDReport(data, length, tp, message);
return 0;
}
} // namespace boo

View File

@ -1,140 +0,0 @@
#include "boo/inputdev/DeviceFinder.hpp"
#include <cstdio>
#include <cstdlib>
#if _WIN32
#include <Dbt.h>
#include <hidclass.h>
#include <usbiodef.h>
#endif
namespace boo {
DeviceFinder* DeviceFinder::skDevFinder = nullptr;
DeviceFinder::DeviceFinder(std::unordered_set<uint64_t> types) {
if (skDevFinder) {
fmt::print(stderr, FMT_STRING("only one instance of CDeviceFinder may be constructed"));
std::abort();
}
skDevFinder = this;
for (const uint64_t& typeHash : types) {
const DeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name) {
if (sigIter->m_typeHash == typeHash)
m_types.push_back(sigIter);
++sigIter;
}
}
}
DeviceFinder::~DeviceFinder() {
if (m_listener)
m_listener->stopScanning();
skDevFinder = nullptr;
}
bool DeviceFinder::_insertToken(std::unique_ptr<DeviceToken>&& token) {
if (!DeviceSignature::DeviceMatchToken(*token, m_types)) {
return false;
}
m_tokensLock.lock();
const TInsertedDeviceToken insertedTok = m_tokens.emplace(token->getDevicePath(), std::move(token));
m_tokensLock.unlock();
deviceConnected(*insertedTok.first->second);
return true;
}
void DeviceFinder::_removeToken(const std::string& path) {
const auto preCheck = m_tokens.find(path);
if (preCheck == m_tokens.end()) {
return;
}
DeviceToken& tok = *preCheck->second;
std::shared_ptr<DeviceBase> dev = tok.m_connectedDev;
tok._deviceClose();
deviceDisconnected(tok, dev.get());
m_tokensLock.lock();
m_tokens.erase(preCheck);
m_tokensLock.unlock();
}
bool DeviceFinder::startScanning() {
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->startScanning();
return false;
}
bool DeviceFinder::stopScanning() {
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->stopScanning();
return false;
}
bool DeviceFinder::scanNow() {
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->scanNow();
return false;
}
#if _WIN32 && !WINDOWS_STORE
/* Windows-specific WM_DEVICECHANGED handler */
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam) {
PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam;
PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
DeviceFinder* finder = instance();
if (!finder)
return 0;
if (wParam == DBT_DEVICEARRIVAL) {
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None) {
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevConnect(devPath);
#else
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
#endif
}
}
} else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None) {
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevDisconnect(devPath);
#else
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
#endif
}
}
}
return 0;
}
#endif
} // namespace boo

View File

@ -1,77 +0,0 @@
#include "boo/inputdev/DeviceSignature.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/GenericPad.hpp"
#include "lib/inputdev/IHIDDevice.hpp"
namespace boo {
extern const DeviceSignature BOO_DEVICE_SIGS[];
bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet) {
if (token.getDeviceType() == DeviceType::HID) {
uint64_t genPadHash = dev_typeid(GenericPad);
bool hasGenericPad = false;
for (const DeviceSignature* sig : sigSet) {
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId() && sig->m_type != DeviceType::HID)
return false;
if (sig->m_typeHash == genPadHash)
hasGenericPad = true;
}
return hasGenericPad;
}
for (const DeviceSignature* sig : sigSet) {
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
}
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp);
std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token) {
std::shared_ptr<DeviceBase> retval;
/* Perform signature-matching to find the appropriate device-factory */
const DeviceSignature* foundSig = nullptr;
const DeviceSignature* sigIter = BOO_DEVICE_SIGS;
unsigned targetVid = token.getVendorId();
unsigned targetPid = token.getProductId();
while (sigIter->m_name) {
if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid) {
foundSig = sigIter;
break;
}
++sigIter;
}
if (!foundSig) {
/* Try Generic HID devices */
if (token.getDeviceType() == DeviceType::HID) {
retval = std::make_shared<GenericPad>(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
}
return nullptr;
}
if (foundSig->m_type != DeviceType::None && foundSig->m_type != token.getDeviceType())
return nullptr;
retval = foundSig->m_factory(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
}
} // namespace boo

View File

@ -1,235 +0,0 @@
#include "boo/inputdev/DolphinSmashAdapter.hpp"
#include "boo/inputdev/DeviceSignature.hpp"
namespace boo {
/*
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
*/
DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token)
: TDeviceBase<IDolphinSmashAdapterCallback>(dev_typeid(DolphinSmashAdapter), token) {}
DolphinSmashAdapter::~DolphinSmashAdapter() {}
static constexpr EDolphinControllerType parseType(unsigned char status) {
const auto type =
EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird);
switch (type) {
case EDolphinControllerType::Normal:
case EDolphinControllerType::Wavebird:
return type;
default:
return EDolphinControllerType::None;
}
}
static EDolphinControllerType parseState(DolphinControllerState* stateOut, const uint8_t* payload, bool& rumble) {
const unsigned char status = payload[0];
const EDolphinControllerType type = parseType(status);
rumble = ((status & 0x04) != 0) ? true : false;
stateOut->m_btns = static_cast<uint16_t>(payload[1]) << 8 | static_cast<uint16_t>(payload[2]);
stateOut->m_leftStick[0] = payload[3];
stateOut->m_leftStick[1] = payload[4];
stateOut->m_rightStick[0] = payload[5];
stateOut->m_rightStick[1] = payload[6];
stateOut->m_analogTriggers[0] = payload[7];
stateOut->m_analogTriggers[1] = payload[8];
return type;
}
void DolphinSmashAdapter::initialCycle() {
constexpr std::array<uint8_t, 1> handshakePayload{0x13};
sendUSBInterruptTransfer(handshakePayload.data(), handshakePayload.size());
}
void DolphinSmashAdapter::transferCycle() {
std::array<uint8_t, 37> payload;
const size_t recvSz = receiveUSBInterruptTransfer(payload.data(), payload.size());
if (recvSz != payload.size() || payload[0] != 0x21) {
return;
}
// fmt::print("RECEIVED DATA {} {:02X}\n", recvSz, payload[0]);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (!m_callback) {
return;
}
/* Parse controller states */
const uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0;
for (uint32_t i = 0; i < 4; i++, controller += 9) {
DolphinControllerState state;
bool rumble = false;
const EDolphinControllerType type = parseState(&state, controller, rumble);
if (True(type) && (m_knownControllers & (1U << i)) == 0) {
m_leftStickCal = state.m_leftStick;
m_rightStickCal = state.m_rightStick;
m_triggersCal = state.m_analogTriggers;
m_knownControllers |= 1U << i;
m_callback->controllerConnected(i, type);
} else if (False(type) && (m_knownControllers & (1U << i)) != 0) {
m_knownControllers &= ~(1U << i);
m_callback->controllerDisconnected(i);
}
if ((m_knownControllers & (1U << i)) != 0) {
state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0];
state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1];
state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0];
state.m_rightStick[1] = state.m_rightStick[1] - m_rightStickCal[1];
state.m_analogTriggers[0] = state.m_analogTriggers[0] - m_triggersCal[0];
state.m_analogTriggers[1] = state.m_analogTriggers[1] - m_triggersCal[1];
m_callback->controllerUpdate(i, type, state);
}
rumbleMask |= rumble ? 1U << i : 0;
}
/* Send rumble message (if needed) */
const uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
if (rumbleReq != m_rumbleState) {
std::array<uint8_t, 5> rumbleMessage{0x11, 0, 0, 0, 0};
for (size_t i = 0; i < 4; ++i) {
if ((rumbleReq & (1U << i)) != 0) {
rumbleMessage[i + 1] = 1;
} else if (m_hardStop[i]) {
rumbleMessage[i + 1] = 2;
} else {
rumbleMessage[i + 1] = 0;
}
}
sendUSBInterruptTransfer(rumbleMessage.data(), rumbleMessage.size());
m_rumbleState = rumbleReq;
}
}
void DolphinSmashAdapter::finalCycle() {
constexpr std::array<uint8_t, 5> rumbleMessage{0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(rumbleMessage.data(), sizeof(rumbleMessage));
}
void DolphinSmashAdapter::deviceDisconnected() {
for (uint32_t i = 0; i < 4; i++) {
if ((m_knownControllers & (1U << i)) != 0) {
m_knownControllers &= ~(1U << i);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) {
m_callback->controllerDisconnected(i);
}
}
}
}
/* The following code is derived from pad.c in libogc
*
* Copyright (C) 2004 - 2009
* Michael Wiedenbauer (shagkur)
* Dave Murphy (WinterMute)
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source
* distribution.
*/
constexpr std::array<int16_t, 8> pad_clampregion{
30, 180, 15, 72, 40, 15, 59, 31,
};
static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min) {
int x = px;
int y = py;
int signX;
if (x > 0) {
signX = 1;
} else {
signX = -1;
x = -x;
}
int signY;
if (y > 0) {
signY = 1;
} else {
signY = -1;
y = -y;
}
if (x <= min) {
x = 0;
} else {
x -= min;
}
if (y <= min) {
y = 0;
} else {
y -= min;
}
if (x == 0 && y == 0) {
px = py = 0;
return;
}
if (xy * y <= xy * x) {
const int d = xy * x + (max - xy) * y;
if (xy * max < d) {
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
} else {
const int d = xy * y + (max - xy) * x;
if (xy * max < d) {
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
}
px = int16_t(signX * x);
py = int16_t(signY * y);
}
static void pad_clamptrigger(int16_t& trigger) {
const int16_t min = pad_clampregion[0];
const int16_t max = pad_clampregion[1];
if (min > trigger) {
trigger = 0;
} else {
if (max < trigger) {
trigger = max;
}
trigger -= min;
}
}
void DolphinControllerState::clamp() {
pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]);
pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]);
pad_clamptrigger(m_analogTriggers[0]);
pad_clamptrigger(m_analogTriggers[1]);
}
} // namespace boo

View File

@ -1,123 +0,0 @@
#include "boo/inputdev/DualshockPad.hpp"
#include "boo/inputdev/DeviceSignature.hpp"
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#ifdef _MSC_VER
inline uint16_t bswap16(uint16_t val) { return _byteswap_ushort(val); }
#elif __GNUC__ && !defined(__FreeBSD__)
constexpr uint16_t bswap16(uint16_t val) { return __builtin_bswap16(val); }
#elif !defined(__FreeBSD__)
constexpr uint16_t bswap16(uint16_t val) { return __builtin_byteswap(val); }
#endif
#ifndef M_PIF
#define M_PIF 3.14159265358979323846f /* pi */
#endif
#define RAD_TO_DEG (180.f / M_PIF)
namespace boo {
static const uint8_t defaultReport[49] = {0x01, 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff,
0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10,
0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00};
DualshockPad::DualshockPad(DeviceToken* token)
: TDeviceBase<IDualshockPadCallback>(dev_typeid(DualshockPad), token)
, m_rumbleRequest(EDualshockMotor::None)
, m_rumbleState(EDualshockMotor::None) {
memcpy(m_report.buf, defaultReport, 49);
}
DualshockPad::~DualshockPad() {}
void DualshockPad::deviceDisconnected() {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void DualshockPad::initialCycle() {
#if 0
// Tells controller to start sending changes on in pipe
uint8_t setupCommand[5] = {0xF4, 0x42, 0x0c, 0x00, 0x00};
if (!sendHIDReport(setupCommand, 5, HIDReportType::Feature, 0xF4)) {
deviceError("Unable to send complete packet! Request size {:x}\n", sizeof(setupCommand));
return;
}
uint8_t btAddr[8];
receiveHIDReport(btAddr, sizeof(btAddr), HIDReportType::Feature, 0xF5);
for (int i = 0; i < 6; i++) {
// Copy into buffer reversed, so it is LSB first
m_btAddress[5 - i] = btAddr[i + 2];
}
#endif
}
void DualshockPad::transferCycle() {}
void DualshockPad::finalCycle() {
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
}
void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (message != 1 || length != 49 || tp != HIDReportType::Input)
return;
DualshockPadState state = *reinterpret_cast<const DualshockPadState*>(data);
for (int i = 0; i < 3; i++)
state.m_accelerometer[i] = bswap16(state.m_accelerometer[i]);
state.m_gyrometerZ = bswap16(state.m_gyrometerZ);
const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V);
float accXval = -((double)state.m_accelerometer[0] - zeroG);
float accYval = -((double)state.m_accelerometer[1] - zeroG);
float accZval = -((double)state.m_accelerometer[2] - zeroG);
state.accPitch = (atan2(accYval, accZval) + M_PIF) * RAD_TO_DEG;
state.accYaw = (atan2(accXval, accZval) + M_PIF) * RAD_TO_DEG;
state.gyroZ = (state.m_gyrometerZ / 1023.f);
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerUpdate(*this, state);
}
if (m_rumbleRequest != m_rumbleState) {
if (True(m_rumbleRequest & EDualshockMotor::Left)) {
m_report.rumble.leftDuration = m_rumbleDuration[0];
m_report.rumble.leftForce = m_rumbleIntensity[0];
} else {
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
}
if (True(m_rumbleRequest & EDualshockMotor::Right)) {
m_report.rumble.rightDuration = m_rumbleDuration[1];
m_report.rumble.rightOn = m_rumbleIntensity[1] > 0;
} else {
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
}
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
m_rumbleState = m_rumbleRequest;
} else {
if (state.m_reserved5[8] & 0x80)
m_rumbleRequest &= ~EDualshockMotor::Right;
if (state.m_reserved5[7] & 0x01)
m_rumbleRequest &= ~EDualshockMotor::Left;
m_rumbleState = m_rumbleRequest;
}
}
} // namespace boo

View File

@ -1,46 +0,0 @@
#include "boo/inputdev/GenericPad.hpp"
#include "boo/inputdev/DeviceToken.hpp"
namespace boo {
GenericPad::GenericPad(DeviceToken* token) : TDeviceBase<IGenericPadCallback>(dev_typeid(GenericPad), token) {}
GenericPad::~GenericPad() {}
void GenericPad::deviceDisconnected() {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void GenericPad::initialCycle() {
#if _WIN32
#if !WINDOWS_STORE
const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc);
#endif
#else
std::vector<uint8_t> reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc.data(), reportDesc.size());
#endif
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerConnected();
}
void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (length == 0 || tp != HIDReportType::Input || !m_callback)
return;
std::function<bool(const HIDMainItem&, int32_t)> func = [this](const HIDMainItem& item, int32_t value) {
m_callback->valueUpdate(item, value);
return true;
};
m_parser.ScanValues(func, data, length);
}
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
m_parser.EnumerateValues(valueCB);
}
} // namespace boo

View File

@ -1,20 +0,0 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
namespace boo {
class HIDListenerBSD final : public IHIDListener {
DeviceFinder& m_finder;
public:
HIDListenerBSD(DeviceFinder& finder) : m_finder(finder) {}
~HIDListenerBSD() override = default;
bool startScanning() override { return false; }
bool stopScanning() override { return false; }
bool scanNow() override { return false; }
};
IHIDListener* IHIDListenerNew(DeviceFinder& finder) { return new HIDListenerBSD(finder); }
} // namespace boo

View File

@ -1,312 +0,0 @@
#include "lib/inputdev/IHIDDevice.hpp"
#include <thread>
#include "lib/inputdev/IOKitPointer.hpp"
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDDevicePlugin.h>
#include <IOKit/usb/IOUSBLib.h>
namespace boo {
class HIDDeviceIOKit : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
IUnknownPointer<IOUSBInterfaceInterface> m_usbIntf;
uint8_t m_usbIntfInPipe = 0;
uint8_t m_usbIntfOutPipe = 0;
CFPointer<IOHIDDeviceRef> m_hidIntf;
bool m_runningTransferLoop = false;
bool m_isBt = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) override {
if (m_usbIntf) {
IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length);
return res == kIOReturnSuccess;
}
return false;
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) override {
if (m_usbIntf) {
UInt32 readSize = length;
IOReturn res = m_usbIntf->ReadPipe(m_usbIntf.storage(), m_usbIntfInPipe, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
return 0;
}
std::vector<uint8_t> _getReportDescriptor() override {
if (m_hidIntf) {
if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey))) {
CFIndex len = CFDataGetLength(CFDataRef(desc));
std::vector<uint8_t> ret(len, '\0');
CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]);
return ret;
}
}
return {};
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
/* HACK: A bug in IOBluetoothGamepadHIDDriver prevents raw output report transmission
* USB driver appears to work correctly */
if (m_hidIntf && !m_isBt) {
IOReturn res = IOHIDDeviceSetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, length);
return res == kIOReturnSuccess;
}
return false;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
if (m_hidIntf) {
CFIndex readSize = length;
IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceIOKit> device) {
pthread_setname_np(fmt::format(FMT_STRING("{} Transfer Thread"), device->m_token.getProductName()).c_str());
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Get the HID element's parent (USB interrupt transfer-interface) */
IOObjectPointer<io_iterator_t> devIter;
IOObjectPointer<io_registry_entry_t> devEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
IOObjectPointer<io_object_t> interfaceEntry;
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get())) {
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) {
interfaceEntry = obj;
break;
}
}
if (!interfaceEntry) {
device->m_devImp->deviceError(FMT_STRING("Unable to find interface for {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* IOKit Plugin COM interface (WTF Apple???) */
IOCFPluginPointer iodev;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID, &iodev, &score);
if (err) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* USB interface function-pointer table */
IUnknownPointer<IOUSBInterfaceInterface> intf;
err = iodev.As(&intf, kIOUSBInterfaceInterfaceID);
if (err) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Obtain exclusive lock on device */
device->m_usbIntf = intf;
err = intf->USBInterfaceOpen(intf.storage());
if (err != kIOReturnSuccess) {
if (err == kIOReturnExclusiveAccess) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: someone else using it\n"),
device->m_token.getProductName(), device->m_devPath);
} else {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Determine pipe indices for interrupt I/O */
UInt8 numEndpoints = 0;
err = intf->GetNumEndpoints(intf.storage(), &numEndpoints);
for (int i = 1; i < numEndpoints + 1; ++i) {
UInt8 dir, num, tType, interval;
UInt16 mPacketSz;
err = intf->GetPipeProperties(intf.storage(), i, &dir, &num, &tType, &mPacketSz, &interval);
if (tType == kUSBInterrupt) {
if (dir == kUSBIn)
device->m_usbIntfInPipe = num;
else if (dir == kUSBOut)
device->m_usbIntfOutPipe = num;
}
}
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
/* Cleanup */
intf->USBInterfaceClose(intf.storage());
device->m_usbIntf = nullptr;
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceIOKit> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
}
static void _hidRemoveCb(void* _Nullable context, IOReturn result, void* _Nullable sender) {
reinterpret_cast<HIDDeviceIOKit*>(context)->m_runningTransferLoop = false;
}
static void _hidReportCb(void* _Nullable context, IOReturn, void* _Nullable, IOHIDReportType type, uint32_t reportID,
uint8_t* report, CFIndex reportLength) {
reinterpret_cast<DeviceBase*>(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID);
}
static void _threadProcHID(std::shared_ptr<HIDDeviceIOKit> device) {
pthread_setname_np(fmt::format(FMT_STRING("{} Transfer Thread"), device->m_token.getProductName()).c_str());
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Get the HID element's object (HID device interface) */
IOObjectPointer<io_service_t> interfaceEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) {
device->m_devImp->deviceError(FMT_STRING("Unable to find interface for {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
lk.unlock();
device->m_initCond.notify_one();
return;
}
device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get());
if (!device->m_hidIntf) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Open device */
IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
if (err != kIOReturnSuccess) {
if (err == kIOReturnExclusiveAccess) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: someone else using it\n"),
device->m_token.getProductName(), device->m_devPath);
} else {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}\n"),
device->m_token.getProductName(), device->m_devPath);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Register removal callback */
IOHIDDeviceRegisterRemovalCallback(device->m_hidIntf.get(), _hidRemoveCb, device.get());
/* Make note if device uses bluetooth driver */
if (CFTypeRef transport = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDTransportKey)))
device->m_isBt =
CFStringCompare(CFStringRef(transport), CFSTR(kIOHIDTransportBluetoothValue), 0) == kCFCompareEqualTo;
/* Register input buffer */
std::unique_ptr<uint8_t[]> buffer;
int bufSize = 0;
if (CFTypeRef maxSize = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDMaxInputReportSizeKey)))
CFNumberGetValue(CFNumberRef(maxSize), kCFNumberIntType, &bufSize);
if (bufSize) {
buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufSize]);
IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize, _hidReportCb,
device->m_devImp.get());
IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.010, true);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
IOHIDDeviceClose(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
device->m_hidIntf.reset();
}
void _deviceDisconnected() override { m_runningTransferLoop = false; }
public:
HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
void _startThread() override {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else {
fmt::print(stderr, FMT_STRING("invalid token supplied to device constructor\n"));
return;
}
m_initCond.wait(lk);
}
~HIDDeviceIOKit() override {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceIOKit>(token, devImp);
}
} // namespace boo

View File

@ -1,26 +0,0 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "lib/inputdev/IHIDDevice.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo {
class HIDDeviceUWP : public IHIDDevice {
public:
HIDDeviceUWP(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {}
void _deviceDisconnected() override {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) override { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) override { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override { return false; }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override { return false; }
void _startThread() override {}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceUWP>(token, devImp);
}
} // namespace boo

View File

@ -1,292 +0,0 @@
#include "lib/inputdev/IHIDDevice.hpp"
#include <condition_variable>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <thread>
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/HIDParser.hpp"
#include <fcntl.h>
#include <libudev.h>
#include <linux/usb/ch9.h>
#include <linux/usbdevice_fs.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <unistd.h>
namespace boo {
udev* GetUdev();
/*
* Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html
*/
class HIDDeviceUdev final : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
int m_devFd = 0;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) override {
if (m_devFd) {
usbdevfs_bulktransfer xfer = {m_usbIntfOutPipe | USB_DIR_OUT, (unsigned)length, 30, (void*)data};
int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer);
if (ret != (int)length)
return false;
return true;
}
return false;
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) override {
if (m_devFd) {
usbdevfs_bulktransfer xfer = {m_usbIntfInPipe | USB_DIR_IN, (unsigned)length, 30, data};
return ioctl(m_devFd, USBDEVFS_BULK, &xfer);
}
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device) {
int i;
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR);
if (fd < 0) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), dp, strerror(errno));
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
}
device->m_devFd = fd;
usb_device_descriptor devDesc = {};
read(fd, &devDesc, 1);
read(fd, &devDesc.bDescriptorType, devDesc.bLength - 1);
if (devDesc.bNumConfigurations) {
usb_config_descriptor confDesc = {};
read(fd, &confDesc, 1);
read(fd, &confDesc.bDescriptorType, confDesc.bLength - 1);
if (confDesc.bNumInterfaces) {
usb_interface_descriptor intfDesc = {};
read(fd, &intfDesc, 1);
read(fd, &intfDesc.bDescriptorType, intfDesc.bLength - 1);
for (i = 0; i < intfDesc.bNumEndpoints + 1; ++i) {
usb_endpoint_descriptor endpDesc = {};
read(fd, &endpDesc, 1);
read(fd, &endpDesc.bDescriptorType, endpDesc.bLength - 1);
if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
device->m_usbIntfInPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
else if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
device->m_usbIntfOutPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
}
}
}
/* Request that kernel disconnects existing driver */
usbdevfs_ioctl disconnectReq = {0, USBDEVFS_DISCONNECT, nullptr};
ioctl(fd, USBDEVFS_IOCTL, &disconnectReq);
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
/* Cleanup */
close(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
udev_device_unref(udevDev);
}
static void _threadProcHID(std::shared_ptr<HIDDeviceUdev> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR | O_NONBLOCK);
if (fd < 0) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), dp, strerror(errno));
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
}
device->m_devFd = fd;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
device->m_devImp->deviceError(FMT_STRING("Unable to ioctl(HIDIOCGRDESCSIZE) {}@{}: {}\n"),
device->m_token.getProductName(), dp, strerror(errno));
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
device->m_devImp->deviceError(FMT_STRING("Unable to ioctl(HIDIOCGRDESC) {}@{}: {}\n"),
device->m_token.getProductName(), dp, strerror(errno));
close(fd);
return;
}
size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size);
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[readSz]);
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) {
fd_set readset;
FD_ZERO(&readset);
FD_SET(fd, &readset);
struct timeval timeout = {0, 10000};
if (select(fd + 1, &readset, nullptr, nullptr, &timeout) > 0) {
while (true) {
ssize_t sz = read(fd, readBuf.get(), readSz);
if (sz < 0)
break;
device->m_devImp->receivedHIDReport(readBuf.get(), sz, HIDReportType::Input, readBuf[0]);
}
}
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
close(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
}
void _deviceDisconnected() override { m_runningTransferLoop = false; }
std::vector<uint8_t> _getReportDescriptor() override {
/* Report descriptor size */
int reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
return {};
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESC, &reportDesc) == -1)
return {};
std::vector<uint8_t> ret(reportDesc.size, '\0');
memmove(ret.data(), reportDesc.value, reportDesc.size);
return ret;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
if (m_devFd) {
if (tp == HIDReportType::Feature) {
int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data);
if (ret < 0)
return false;
return true;
} else if (tp == HIDReportType::Output) {
ssize_t ret = write(m_devFd, data, length);
if (ret < 0)
return false;
return true;
}
}
return false;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
if (m_devFd) {
if (tp == HIDReportType::Feature) {
data[0] = message;
int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data);
if (ret < 0)
return 0;
return length;
}
}
return 0;
}
public:
HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
void _startThread() override {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else {
fmt::print(stderr, FMT_STRING("invalid token supplied to device constructor"));
abort();
}
m_initCond.wait(lk);
}
~HIDDeviceUdev() override {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceUdev>(token, devImp);
}
} // namespace boo

View File

@ -1,327 +0,0 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "lib/inputdev/IHIDDevice.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
#include <algorithm>
#include <condition_variable>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <thread>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#include <winusb.h>
#include <usb100.h>
#include <Winusbio.h>
#include <hidsdi.h>
#undef min
#undef max
namespace boo {
class HIDDeviceWinUSB final : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
HANDLE m_devHandle = nullptr;
HANDLE m_hidHandle = nullptr;
WINUSB_INTERFACE_HANDLE m_usbHandle = nullptr;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) override {
if (m_usbHandle) {
ULONG lengthTransferred = 0;
if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, nullptr) ||
lengthTransferred != length) {
return false;
}
return true;
}
return false;
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) override {
if (m_usbHandle) {
ULONG lengthTransferred = 0;
if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, nullptr))
return 0;
return lengthTransferred;
}
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceWinUSB> device) {
unsigned i;
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */
device->m_devHandle =
CreateFileA(device->m_devPath.data(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
if (INVALID_HANDLE_VALUE == device->m_devHandle) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), device->m_devPath, GetLastError());
lk.unlock();
device->m_initCond.notify_one();
return;
}
if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), device->m_devPath, GetLastError());
lk.unlock();
device->m_initCond.notify_one();
CloseHandle(device->m_devHandle);
return;
}
/* Enumerate device pipes */
USB_INTERFACE_DESCRIPTOR ifDesc = {0};
if (!WinUsb_QueryInterfaceSettings(device->m_usbHandle, 0, &ifDesc)) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), device->m_devPath, GetLastError());
lk.unlock();
device->m_initCond.notify_one();
CloseHandle(device->m_devHandle);
return;
}
for (i = 0; i < ifDesc.bNumEndpoints; ++i) {
WINUSB_PIPE_INFORMATION pipeDesc;
WinUsb_QueryPipe(device->m_usbHandle, 0, i, &pipeDesc);
if (pipeDesc.PipeType == UsbdPipeTypeInterrupt) {
if (USB_ENDPOINT_DIRECTION_IN(pipeDesc.PipeId))
device->m_usbIntfInPipe = pipeDesc.PipeId;
else
device->m_usbIntfOutPipe = pipeDesc.PipeId;
}
}
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
/* Cleanup */
WinUsb_Free(device->m_usbHandle);
CloseHandle(device->m_devHandle);
device->m_devHandle = 0;
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceWinUSB> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
}
size_t m_minFeatureSz = 0;
size_t m_minInputSz = 0;
size_t m_minOutputSz = 0;
PHIDP_PREPARSED_DATA m_preparsedData = nullptr;
static void _threadProcHID(std::shared_ptr<HIDDeviceWinUSB> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */
device->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
device->m_hidHandle =
CreateFileA(device->m_devPath.data(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
if (INVALID_HANDLE_VALUE == device->m_hidHandle) {
device->m_devImp->deviceError(FMT_STRING("Unable to open {}@{}: {}\n"),
device->m_token.getProductName(), device->m_devPath, GetLastError());
lk.unlock();
device->m_initCond.notify_one();
return;
}
if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) {
device->m_devImp->deviceError(FMT_STRING("Unable get preparsed data of {}@{}: {}\n"),
device->m_token.getProductName(), device->m_devPath, GetLastError());
lk.unlock();
device->m_initCond.notify_one();
return;
}
HIDP_CAPS caps;
HidP_GetCaps(device->m_preparsedData, &caps);
device->m_minFeatureSz = caps.FeatureReportByteLength;
device->m_minInputSz = caps.InputReportByteLength;
device->m_minOutputSz = caps.OutputReportByteLength;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Allocate read buffer */
size_t inBufferSz = device->m_minInputSz;
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[inBufferSz]);
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) {
device->ReadCycle(readBuf.get(), inBufferSz);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
CloseHandle(device->m_overlapped.hEvent);
CloseHandle(device->m_hidHandle);
HidD_FreePreparsedData(device->m_preparsedData);
device->m_hidHandle = nullptr;
}
void _deviceDisconnected() override { m_runningTransferLoop = false; }
std::vector<uint8_t> m_sendBuf;
std::vector<uint8_t> m_recvBuf;
const PHIDP_PREPARSED_DATA _getReportDescriptor() override { return m_preparsedData; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length));
if (m_sendBuf.size() < maxOut)
m_sendBuf.resize(maxOut);
if (maxOut > length)
memset(m_sendBuf.data() + length, 0, maxOut - length);
memmove(m_sendBuf.data(), data, length);
if (tp == HIDReportType::Output) {
DWORD useLength = DWORD(std::max(length, m_minOutputSz));
DWORD BytesWritten;
OVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped));
BOOL Result = WriteFile(m_hidHandle, m_sendBuf.data(), useLength, &BytesWritten, &Overlapped);
if (!Result) {
DWORD Error = GetLastError();
if (Error == ERROR_INVALID_USER_BUFFER) {
// std::cout << "Falling back to SetOutputReport" << std::endl;
if (!HidD_SetOutputReport(m_hidHandle, (PVOID)m_sendBuf.data(), useLength))
return false;
}
if (Error != ERROR_IO_PENDING) {
fmt::print(stderr, FMT_STRING("Write Failed {:08X}\n"), int(Error));
return false;
}
}
if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) {
DWORD Error = GetLastError();
fmt::print(stderr, FMT_STRING("Write Failed {:08X}\n"), int(Error));
return false;
}
} else if (tp == HIDReportType::Feature) {
DWORD useLength = DWORD(std::max(length, m_minFeatureSz));
if (!HidD_SetFeature(m_hidHandle, (PVOID)m_sendBuf.data(), useLength)) {
// int error = GetLastError();
return false;
}
}
return true;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) override {
size_t maxIn = std::max(m_minFeatureSz, std::max(m_minInputSz, length));
if (m_recvBuf.size() < maxIn)
m_recvBuf.resize(maxIn);
memset(m_recvBuf.data(), 0, length);
m_recvBuf[0] = message;
if (tp == HIDReportType::Input) {
if (!HidD_GetInputReport(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minInputSz, length))))
return 0;
} else if (tp == HIDReportType::Feature) {
if (!HidD_GetFeature(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minFeatureSz, length))))
return 0;
}
memmove(data, m_recvBuf.data(), length);
return length;
}
public:
HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
void _startThread() override {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else
throw std::runtime_error("invalid token supplied to device constructor");
m_initCond.wait(lk);
}
~HIDDeviceWinUSB() override {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
OVERLAPPED m_overlapped = {};
void ReadCycle(uint8_t* inBuffer, size_t inBufferSz) {
ResetEvent(m_overlapped.hEvent);
ZeroMemory(inBuffer, inBufferSz);
DWORD BytesRead = 0;
BOOL Result = ReadFile(m_hidHandle, inBuffer, DWORD(inBufferSz), &BytesRead, &m_overlapped);
if (!Result) {
DWORD Error = GetLastError();
if (Error == ERROR_DEVICE_NOT_CONNECTED) {
m_runningTransferLoop = false;
return;
} else if (Error != ERROR_IO_PENDING) {
fmt::print(stderr, FMT_STRING("Read Failed: {:08X}\n"), int(Error));
return;
} else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE)) {
return;
}
}
m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceWinUSB>(token, devImp);
}
} // namespace boo

View File

@ -1,25 +0,0 @@
#include "IHIDDevice.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo {
class HIDDeviceBSD final : public IHIDDevice {
DeviceToken& m_token;
DeviceBase& m_devImp;
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message) { return false; }
size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message) { return 0; }
public:
HIDDeviceBSD(DeviceToken& token, DeviceBase& devImp) : m_token(token), m_devImp(devImp) {}
~HIDDeviceBSD() override = default;
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceBSD>(token, devImp);
}
} // namespace boo

View File

@ -1,297 +0,0 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDDevicePlugin.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <sys/utsname.h>
#include "IOKitPointer.hpp"
#include "../CFPointer.hpp"
namespace boo {
/*
* Reference: http://oroboro.com/usb-serial-number-osx/
*/
static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182>& usbDevice, UInt8 idx, char* out) {
UInt16 buffer[128];
// wow... we're actually forced to make hard coded bus requests. Its like
// hard disk programming in the 80's!
IOUSBDevRequest request;
request.bmRequestType =
USBmakebmRequestType(static_cast<typeof kUSBRqDirnMask>(kUSBIn), static_cast<typeof kUSBRqTypeMask>(kUSBStandard),
static_cast<typeof kUSBRqRecipientMask>(kUSBDevice));
request.bRequest = kUSBRqGetDescriptor;
request.wValue = (kUSBStringDesc << 8) | idx;
request.wIndex = 0x409; // english
request.wLength = sizeof(buffer);
request.pData = buffer;
kern_return_t err = usbDevice->DeviceRequest(usbDevice.storage(), &request);
if (err != 0) {
// the request failed... fairly uncommon for the USB disk driver, but not
// so uncommon for other devices. This can also be less reliable if your
// disk is mounted through an external USB hub. At this level we actually
// have to worry about hardware issues like this.
return false;
}
// we're mallocing this string just as an example. But you probably will want
// to do something smarter, like pre-allocated buffers in the info class, or
// use a string class.
if (request.wLenDone == 0)
return false;
unsigned count = (request.wLenDone - 1) / 2;
unsigned i;
for (i = 0; i < count; ++i)
out[i] = buffer[i + 1];
out[i] = '\0';
return true;
}
class HIDListenerIOKit : public IHIDListener {
DeviceFinder& m_finder;
CFRunLoopRef m_listenerRunLoop;
IONotificationPortRef m_llPort;
IOObjectPointer<io_iterator_t> m_llAddNotif, m_llRemoveNotif;
IOObjectPointer<io_iterator_t> m_hidAddNotif, m_hidRemoveNotif;
const char* m_usbClass;
bool m_scanningEnabled;
static void devicesConnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
continue;
UInt16 vid, pid;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
&devServ, &score);
if (err != kIOReturnSuccess) {
fmt::print(stderr, FMT_STRING("unable to open IOKit plugin interface\n"));
continue;
}
IUnknownPointer<IOUSBDeviceInterface182> dev;
err = devServ.As(&dev, kIOUSBDeviceInterfaceID182);
if (err != kIOReturnSuccess) {
fmt::print(stderr, FMT_STRING("unable to open IOKit device interface\n"));
continue;
}
dev->GetDeviceVendor(dev.storage(), &vid);
dev->GetDeviceProduct(dev.storage(), &pid);
UInt8 vstridx, pstridx;
dev->USBGetManufacturerStringIndex(dev.storage(), &vstridx);
dev->USBGetProductStringIndex(dev.storage(), &pstridx);
getUSBStringDescriptor(dev, vstridx, vstr);
getUSBStringDescriptor(dev, pstridx, pstr);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB, vid, pid, vstr, pstr, devPath));
// fmt::print(FMT_STRING("ADDED {:08X} {}\n"), obj.get(), devPath);
}
}
static void devicesDisconnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
^{ devicesDisconnectedUSBLL(listener, iterator); });
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
// fmt::print(FMT_STRING("REMOVED {:08X} {}\n"), obj.get(), devPath);
}
}
static void devicesConnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
continue;
unsigned vidv, pidv;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err =
IOCreatePlugInInterfaceForService(obj.get(), kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
if (err != kIOReturnSuccess) {
fmt::print(stderr, FMT_STRING("unable to open IOKit plugin interface\n"));
continue;
}
IUnknownPointer<IOHIDDeviceDeviceInterface> dev;
err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID);
if (err != kIOReturnSuccess) {
fmt::print(stderr, FMT_STRING("unable to open IOKit device interface\n"));
continue;
}
/* Game controllers only */
CFPointer<CFNumberRef> usagePage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsagePageKey), (CFTypeRef*)&usagePage);
CFPointer<CFNumberRef> usage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsageKey), (CFTypeRef*)&usage);
int usagePageV, usageV;
CFNumberGetValue(usagePage.get(), kCFNumberIntType, &usagePageV);
CFNumberGetValue(usage.get(), kCFNumberIntType, &usageV);
if (usagePageV == kHIDPage_GenericDesktop) {
if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad)
continue;
} else {
continue;
}
CFPointer<CFNumberRef> vid, pid;
dev->getProperty(dev.storage(), CFSTR(kIOHIDVendorIDKey), (CFTypeRef*)&vid);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductIDKey), (CFTypeRef*)&pid);
CFNumberGetValue(vid.get(), kCFNumberIntType, &vidv);
CFNumberGetValue(pid.get(), kCFNumberIntType, &pidv);
CFPointer<CFStringRef> vstridx, pstridx;
dev->getProperty(dev.storage(), CFSTR(kIOHIDManufacturerKey), (CFTypeRef*)&vstridx);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductKey), (CFTypeRef*)&pstridx);
if (vstridx)
CFStringGetCString(vstridx.get(), vstr, 128, kCFStringEncodingUTF8);
if (pstridx)
CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID, vidv, pidv, vstr, pstr, devPath));
// fmt::print(FMT_STRING("ADDED {:08X} {}\n"), obj, devPath);
}
}
static void devicesDisconnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
^{ devicesDisconnectedHID(listener, iterator); });
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
// fmt::print(FMT_STRING("REMOVED {:08X} {}\n"), obj, devPath);
}
}
public:
HIDListenerIOKit(DeviceFinder& finder) : m_finder(finder) {
struct utsname kernInfo;
uname(&kernInfo);
int release = atoi(kernInfo.release);
m_usbClass = release >= 15 ? "IOUSBHostDevice" : kIOUSBDeviceClassName;
m_listenerRunLoop = CFRunLoopGetMain();
m_llPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort);
CFRunLoopAddSource(m_listenerRunLoop, rlSrc, kCFRunLoopDefaultMode);
m_scanningEnabled = true;
/* Register HID Matcher */
{
CFMutableDictionaryRef matchDict = IOServiceMatching("IOHIDDevice");
CFRetain(matchDict);
kern_return_t hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedHID, this, &m_hidAddNotif);
if (hidRet == kIOReturnSuccess)
devicesConnectedHID(this, m_hidAddNotif.get());
hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedHID, this, &m_hidRemoveNotif);
if (hidRet == kIOReturnSuccess)
devicesDisconnectedHID(this, m_hidRemoveNotif.get());
}
/* Register Low-Level USB Matcher */
{
CFMutableDictionaryRef matchDict = IOServiceMatching(m_usbClass);
CFRetain(matchDict);
kern_return_t llRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedUSBLL, this, &m_llAddNotif);
if (llRet == kIOReturnSuccess)
devicesConnectedUSBLL(this, m_llAddNotif.get());
llRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedUSBLL, this, &m_llRemoveNotif);
if (llRet == kIOReturnSuccess)
devicesDisconnectedUSBLL(this, m_llRemoveNotif.get());
}
m_scanningEnabled = false;
}
~HIDListenerIOKit() override {
// CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode);
IONotificationPortDestroy(m_llPort);
}
/* Automatic device scanning */
bool startScanning() override {
m_scanningEnabled = true;
return true;
}
bool stopScanning() override {
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow() override {
IOObjectPointer<io_iterator_t> iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) {
devicesConnectedUSBLL(this, iter.get());
}
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerIOKit>(finder);
}
} // namespace boo

View File

@ -1,22 +0,0 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
namespace boo {
class HIDListenerUWP : public IHIDListener {
public:
HIDListenerUWP(DeviceFinder& finder) {}
/* Automatic device scanning */
bool startScanning() override { return false; }
bool stopScanning() override { return false; }
/* Manual device scanning */
bool scanNow() override { return false; }
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) { return std::make_unique<HIDListenerUWP>(finder); }
} // namespace boo

View File

@ -1,232 +0,0 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
#include "boo/inputdev/HIDParser.hpp"
#include "logvisor/logvisor.hpp"
#include <libudev.h>
#include <cstring>
#include <cstdio>
#include <signal.h>
#include <fcntl.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <thread>
namespace boo {
static udev* UDEV_INST = nullptr;
udev* GetUdev() {
if (!UDEV_INST)
UDEV_INST = udev_new();
return UDEV_INST;
}
class HIDListenerUdev final : public IHIDListener {
DeviceFinder& m_finder;
udev_monitor* m_udevMon;
std::thread m_udevThread;
bool m_scanningEnabled;
void deviceConnected(udev_device* device) {
if (!m_scanningEnabled)
return;
/* Prevent redundant registration */
const char* devPath = udev_device_get_syspath(device);
if (m_finder._hasToken(devPath))
return;
/* Filter to USB/BT */
const char* dt = udev_device_get_devtype(device);
DeviceType type = DeviceType::None;
int vid = 0, pid = 0;
const char* manuf = nullptr;
const char* product = nullptr;
if (dt) {
if (!strcmp(dt, "usb_device"))
type = DeviceType::USB;
else if (!strcmp(dt, "bluetooth_device"))
type = DeviceType::Bluetooth;
else
return;
udev_list_entry* attrs = udev_device_get_properties_list_entry(device);
udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID");
if (vide)
vid = strtol(udev_list_entry_get_value(vide), nullptr, 16);
udev_list_entry* pide = udev_list_entry_get_by_name(attrs, "ID_MODEL_ID");
if (pide)
pid = strtol(udev_list_entry_get_value(pide), nullptr, 16);
udev_list_entry* manufe = udev_list_entry_get_by_name(attrs, "ID_VENDOR");
if (manufe)
manuf = udev_list_entry_get_value(manufe);
udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL");
if (producte)
product = udev_list_entry_get_value(producte);
} else if (!strcmp(udev_device_get_subsystem(device), "hidraw")) {
type = DeviceType::HID;
udev_device* parent = udev_device_get_parent(device);
udev_list_entry* attrs = udev_device_get_properties_list_entry(parent);
udev_list_entry* hidide = udev_list_entry_get_by_name(attrs, "HID_ID");
if (hidide) {
const char* hidid = udev_list_entry_get_value(hidide);
const char* vids = strchr(hidid, ':') + 1;
const char* pids = strchr(vids, ':') + 1;
vid = strtol(vids, nullptr, 16);
pid = strtol(pids, nullptr, 16);
}
udev_list_entry* hidnamee = udev_list_entry_get_by_name(attrs, "HID_NAME");
if (hidnamee) {
product = udev_list_entry_get_value(hidnamee);
manuf = product;
}
/* Get device file */
const char* dp = udev_device_get_devnode(device);
int fd = open(dp, O_RDWR);
if (fd < 0)
return;
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
// const char* err = strerror(errno);
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
// const char* err = strerror(errno);
close(fd);
return;
}
close(fd);
std::pair<HIDUsagePage, HIDUsage> usage = HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
if (usage.first != HIDUsagePage::GenericDesktop ||
(usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad))
return;
}
#if 0
udev_list_entry* att = nullptr;
udev_list_entry_foreach(att, attrs)
{
const char* name = udev_list_entry_get_name(att);
const char* val = udev_list_entry_get_value(att);
fmt::print(stderr, FMT_STRING("{} {}\n"), name, val);
}
std::fputs("\n\n", stderr);
#endif
m_finder._insertToken(std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath));
}
void deviceDisconnected(udev_device* device) {
const char* devPath = udev_device_get_syspath(device);
m_finder._removeToken(devPath);
}
void _udevProc() {
logvisor::RegisterThreadName("Boo udev");
udev_monitor_enable_receiving(m_udevMon);
int fd = udev_monitor_get_fd(m_udevMon);
while (true) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (pselect(fd + 1, &fds, nullptr, nullptr, nullptr, nullptr) < 0) {
/* SIGTERM handled here */
if (errno == EINTR)
break;
}
int oldtype;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype);
udev_device* dev = udev_monitor_receive_device(m_udevMon);
if (dev) {
const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add"))
deviceConnected(dev);
else if (!strcmp(action, "remove"))
deviceDisconnected(dev);
udev_device_unref(dev);
}
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldtype);
pthread_testcancel();
}
}
public:
HIDListenerUdev(DeviceFinder& finder) : m_finder(finder) {
/* Setup hotplug events */
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
if (!m_udevMon) {
fmt::print(stderr, FMT_STRING("unable to init udev_monitor"));
abort();
}
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "usb", "usb_device");
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "bluetooth", "bluetooth_device");
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "hidraw", nullptr);
udev_monitor_filter_update(m_udevMon);
/* Initial HID Device Add */
m_scanningEnabled = true;
scanNow();
m_scanningEnabled = false;
/* Start hotplug thread */
m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this);
}
~HIDListenerUdev() override {
pthread_cancel(m_udevThread.native_handle());
if (m_udevThread.joinable())
m_udevThread.join();
udev_monitor_unref(m_udevMon);
}
/* Automatic device scanning */
bool startScanning() override {
m_scanningEnabled = true;
return true;
}
bool stopScanning() override {
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow() override {
udev_enumerate* uenum = udev_enumerate_new(GetUdev());
udev_enumerate_add_match_subsystem(uenum, "usb");
udev_enumerate_add_match_subsystem(uenum, "bluetooth");
udev_enumerate_add_match_subsystem(uenum, "hidraw");
udev_enumerate_scan_devices(uenum);
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);
udev_list_entry* uenumItem;
udev_list_entry_foreach(uenumItem, uenumList) {
const char* devPath = udev_list_entry_get_name(uenumItem);
udev_device* dev = udev_device_new_from_syspath(UDEV_INST, devPath);
if (dev)
deviceConnected(dev);
udev_device_unref(dev);
}
udev_enumerate_unref(uenum);
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerUdev>(finder);
}
} // namespace boo

View File

@ -1,279 +0,0 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "boo/inputdev/IHIDListener.hpp"
#include <cstring>
#include <thread>
#include "boo/inputdev/DeviceFinder.hpp"
#include "boo/inputdev/XInputPad.hpp"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#include <initguid.h>
#include <SetupAPI.h>
#include <Cfgmgr32.h>
#include <Usbiodef.h>
#include <Devpkey.h>
#include <hidclass.h>
#include <Xinput.h>
namespace boo {
class HIDListenerWinUSB final : public IHIDListener {
DeviceFinder& m_finder;
bool m_scanningEnabled;
/*
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
*/
void _enumerate(DeviceType type, CONST GUID* TypeGUID, const char* pathFilter) {
/* Don't ask */
static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"};
unsigned i, j;
CONFIGRET r;
ULONG devpropType;
DWORD reg_type;
HDEVINFO hDevInfo = 0;
SP_DEVINFO_DATA DeviceInfoData = {0};
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = {0};
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
union {
SP_DEVICE_INTERFACE_DETAIL_DATA_A wtf;
CHAR alloc[2048];
} DeviceInterfaceDetailData; /* Stack allocation should be fine for this */
DeviceInterfaceDetailData.wtf.cbSize = sizeof(DeviceInterfaceDetailData);
CHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN];
LPSTR pszToken, pszNextToken;
CHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];
/* List all connected HID devices */
hDevInfo = SetupDiGetClassDevs(nullptr, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
return;
for (i = 0;; ++i) {
if (!SetupDiEnumDeviceInterfaces(hDevInfo, nullptr, TypeGUID, i, &DeviceInterfaceData))
break;
DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, &DeviceInterfaceData, &DeviceInterfaceDetailData.wtf,
sizeof(DeviceInterfaceDetailData), nullptr, &DeviceInfoData))
continue;
r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
if (r != CR_SUCCESS)
continue;
/* Retreive the device description as reported by the device itself */
pszToken = strtok_s(szDeviceInstanceID, "\\#&", &pszNextToken);
szVid[0] = '\0';
szPid[0] = '\0';
szMi[0] = '\0';
while (pszToken != nullptr) {
for (j = 0; j < 3; ++j) {
if (strncmp(pszToken, arPrefix[j], 4) == 0) {
switch (j) {
case 0:
strcpy_s(szVid, MAX_DEVICE_ID_LEN, pszToken);
break;
case 1:
strcpy_s(szPid, MAX_DEVICE_ID_LEN, pszToken);
break;
case 2:
strcpy_s(szMi, MAX_DEVICE_ID_LEN, pszToken);
break;
default:
break;
}
}
}
pszToken = strtok_s(nullptr, "\\#&", &pszNextToken);
}
if (!szVid[0] || !szPid[0])
continue;
unsigned vid = strtol(szVid + 4, nullptr, 16);
unsigned pid = strtol(szPid + 4, nullptr, 16);
CHAR productW[1024] = {0};
// CHAR product[1024] = {0};
DWORD productSz = 0;
if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devpropType,
(BYTE*)productW, 1024, &productSz, 0)) {
/* fallback to SPDRP_DEVICEDESC (USB hubs still use it) */
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, &reg_type, (BYTE*)productW, 1024,
&productSz);
}
/* DAFUQ??? Why isn't this really WCHAR??? */
// WideCharToMultiByte(CP_UTF8, 0, productW, -1, product, 1024, nullptr, nullptr);
WCHAR manufW[1024] = L"Someone"; /* Windows Vista and earlier will use this as the vendor */
CHAR manuf[1024] = {0};
DWORD manufSz = 0;
SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer, &devpropType, (BYTE*)manufW,
1024, &manufSz, 0);
WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr);
if (type == DeviceType::HID) {
HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
if (INVALID_HANDLE_VALUE == devHnd)
continue;
PHIDP_PREPARSED_DATA preparsedData;
if (!HidD_GetPreparsedData(devHnd, &preparsedData)) {
CloseHandle(devHnd);
continue;
}
HIDP_CAPS caps;
HidP_GetCaps(preparsedData, &caps);
HidD_FreePreparsedData(preparsedData);
CloseHandle(devHnd);
/* Filter non joysticks and gamepads */
if (caps.UsagePage != 1 || (caps.Usage != 4 && caps.Usage != 5))
continue;
}
/* Store as a shouting string (to keep hash-lookups consistent) */
CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath);
/* Filter to specific device (provided by hotplug event) */
if (pathFilter && strcmp(pathFilter, DeviceInterfaceDetailData.wtf.DevicePath))
continue;
if (!m_scanningEnabled || m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
continue;
/* Whew!! that's a single device enumerated!! */
m_finder._insertToken(
std::make_unique<DeviceToken>(type, vid, pid, manuf, productW, DeviceInterfaceDetailData.wtf.DevicePath));
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
void _pollDevices(const char* pathFilter) {
_enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter);
_enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter);
}
static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad) {
return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger, pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY};
}
std::thread m_xinputThread;
bool m_xinputRunning = true;
DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)};
std::vector<DeviceToken> m_xinputTokens;
void _xinputProc() {
m_xinputTokens.reserve(4);
for (int i = 0; i < 4; ++i)
m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", "");
while (m_xinputRunning) {
for (int i = 0; i < 4; ++i) {
DeviceToken& tok = m_xinputTokens[i];
XINPUT_STATE state;
if (XInputGetState(i, &state) == ERROR_SUCCESS) {
if (state.dwPacketNumber != m_xinputPackets[i]) {
if (m_xinputPackets[i] == -1)
m_finder.deviceConnected(tok);
m_xinputPackets[i] = state.dwPacketNumber;
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
std::lock_guard<std::mutex> lk(pad.m_callbackLock);
if (pad.m_callback)
pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad));
}
}
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
if (pad.m_rumbleRequest[0] != pad.m_rumbleState[0] || pad.m_rumbleRequest[1] != pad.m_rumbleState[1]) {
pad.m_rumbleState[0] = pad.m_rumbleRequest[0];
pad.m_rumbleState[1] = pad.m_rumbleRequest[1];
XINPUT_VIBRATION vibe = {pad.m_rumbleRequest[0], pad.m_rumbleRequest[1]};
XInputSetState(i, &vibe);
}
}
} else if (m_xinputPackets[i] != -1) {
m_xinputPackets[i] = -1;
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
pad.deviceDisconnected();
}
m_finder.deviceDisconnected(tok, tok.m_connectedDev.get());
}
}
Sleep(10);
}
}
public:
HIDListenerWinUSB(DeviceFinder& finder) : m_finder(finder) {
/* Initial HID Device Add */
m_scanningEnabled = true;
_pollDevices(nullptr);
m_scanningEnabled = false;
/* XInput arbitration thread */
for (const DeviceSignature* sig : m_finder.getTypes()) {
if (sig->m_type == DeviceType::XInput) {
m_xinputThread = std::thread(std::bind(&HIDListenerWinUSB::_xinputProc, this));
break;
}
}
}
~HIDListenerWinUSB() override {
m_xinputRunning = false;
if (m_xinputThread.joinable())
m_xinputThread.join();
}
/* Automatic device scanning */
bool startScanning() override {
m_scanningEnabled = true;
return true;
}
bool stopScanning() override {
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow() override {
_pollDevices(nullptr);
return true;
}
bool _extDevConnect(const char* path) override {
char upperPath[1024];
strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath);
if (m_scanningEnabled && !m_finder._hasToken(upperPath))
_pollDevices(upperPath);
return true;
}
bool _extDevDisconnect(const char* path) override {
char upperPath[1024];
strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath);
m_finder._removeToken(upperPath);
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerWinUSB>(finder);
}
} // namespace boo

View File

@ -1,902 +0,0 @@
#include "boo/inputdev/HIDParser.hpp"
#include <algorithm>
#include <array>
#include <map>
#undef min
#undef max
namespace boo {
/* Based on "Device Class Definition for Human Interface Devices (HID)"
* http://www.usb.org/developers/hidpage/HID1_11.pdf
*/
constexpr std::array<const char*, 14> UsagePageNames{
"Undefined", "Generic Desktop", "Simulation", "VR", "Sport",
"Game Controls", "Generic Device", "Keyboard", "LEDs", "Button",
"Ordinal", "Telephony", "Consumer", "Digitizer",
};
constexpr std::array<const char*, 182> GenericDesktopUsages{
"Undefined",
"Pointer",
"Mouse",
"Reserved",
"Joystick",
"Game Pad",
"Keyboard",
"Keypad",
"Multi-axis Controller",
"Tablet PC System Controls",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"X",
"Y",
"Z",
"Rx",
"Ry",
"Rz",
"Slider",
"Dial",
"Wheel",
"Hat Switch",
"Counted Buffer",
"Byte Count",
"Motion Wakeup",
"Start",
"Select",
"Reserved",
"Vx",
"Vy",
"Vz",
"Vbrx",
"Vbry",
"Vbrz",
"Vno",
"Feature Notification",
"Resolution Multiplier",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Control",
"System Power Down",
"System Sleep",
"System Wake Up",
"System Context Menu",
"System Main Menu",
"System App Menu",
"System Menu Help",
"System Menu Exit",
"System Menu Select",
"System Menu Right",
"System Menu Left",
"System Menu Up",
"System Menu Down",
"System Cold Restart",
"System Warm Restart",
"D-pad Up",
"D-pad Down",
"D-pad Right",
"D-pad Left",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Dock",
"System Undock",
"System Setup",
"System Break",
"System Debugger Break",
"Application Break",
"Application Debugger Break",
"System Speaker Mute",
"System Hibernate",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Display Invert",
"System Display Internal",
"System Display External",
"System Display Both",
"System Display Dual",
"System Display Toggle Int/Ext",
};
constexpr std::array<const char*, 58> GameUsages{
"Undefined",
"3D Game Controller",
"Pinball Device",
"Gun Device",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"Point of View",
"Turn Right/Left",
"Pitch Forward/Backward",
"Roll Right/Left",
"Move Right/Left",
"Move Forward/Backward",
"Move Up/Down",
"Lean Right/Left",
"Lean Forward/Backward",
"Height of POV",
"Flipper",
"Secondary Flipper",
"Bump",
"New Game",
"Shoot Ball",
"Player",
"Gun Bolt",
"Gun Clip",
"Gun Selector",
"Gun Single Shot",
"Gun Burst",
"Gun Automatic",
"Gun Safety",
"Gemepad Fire/Jump",
nullptr,
"Gamepad Trigger",
};
enum class HIDCollectionType : uint8_t {
Physical,
Application,
Logical,
Report,
NamedArray,
UsageSwitch,
UsageModifier
};
enum class HIDItemType : uint8_t { Main, Global, Local, Reserved };
enum class HIDItemTag : uint8_t {
/* [6.2.2.4] Main Items */
Input = 0b1000,
Output = 0b1001,
Feature = 0b1011,
Collection = 0b1010,
EndCollection = 0b1100,
/* [6.2.2.7] Global Items */
UsagePage = 0b0000,
LogicalMinimum = 0b0001,
LogicalMaximum = 0b0010,
PhysicalMinimum = 0b0011,
PhysicalMaximum = 0b0100,
UnitExponent = 0b0101,
Unit = 0b0110,
ReportSize = 0b0111,
ReportID = 0b1000,
ReportCount = 0b1001,
Push = 0b1010,
Pop = 0b1011,
/* [6.2.2.8] Local Items */
Usage = 0b0000,
UsageMinimum = 0b0001,
UsageMaximum = 0b0010,
DesignatorIndex = 0b0011,
DesignatorMinimum = 0b0100,
DesignatorMaximum = 0b0101,
StringIndex = 0b0111,
StringMinimum = 0b1000,
StringMaximum = 0b1001,
Delimiter = 0b1010,
};
struct HIDItemState {
/* [6.2.2.7] Global items */
HIDUsagePage m_usagePage = HIDUsagePage::Undefined;
HIDRange m_logicalRange = {};
HIDRange m_physicalRange = {};
int32_t m_unitExponent = 0;
uint32_t m_unit = 0;
uint32_t m_reportSize = 0; // In bits
uint32_t m_reportID = 0;
uint32_t m_reportCount = 0;
/* [6.2.2.8] Local Items */
std::vector<HIDUsage> m_usage;
HIDRange m_usageRange = {};
#if 0
std::vector<int32_t> m_designatorIndex;
std::vector<HIDRange> m_designatorRange;
std::vector<int32_t> m_stringIndex;
std::vector<HIDRange> m_stringRange;
std::vector<int32_t> m_delimiter;
#endif
void ResetLocalItems() {
m_usage.clear();
m_usageRange = HIDRange();
#if 0
m_designatorIndex.clear();
m_designatorRange.clear();
m_stringIndex.clear();
m_stringRange.clear();
m_delimiter.clear();
#endif
}
template <typename T>
static T _GetLocal(const std::vector<T>& v, uint32_t idx) {
if (v.empty())
return {};
if (idx >= v.size())
return v[0];
return v[idx];
}
HIDUsage GetUsage(uint32_t idx) const {
if (m_usageRange.second - m_usageRange.first != 0)
return HIDUsage(m_usageRange.first + idx);
return _GetLocal(m_usage, idx);
}
};
struct HIDCollectionItem {
/* [6.2.2.6] Collection, End Collection Items */
HIDCollectionType m_type;
HIDUsagePage m_usagePage;
HIDUsage m_usage;
HIDCollectionItem(HIDCollectionType type, const HIDItemState& state)
: m_type(type), m_usagePage(state.m_usagePage), m_usage(state.GetUsage(0)) {}
};
HIDMainItem::HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx) : m_flags(uint16_t(flags)) {
m_usagePage = state.m_usagePage;
m_usage = state.GetUsage(reportIdx);
m_logicalRange = state.m_logicalRange;
m_reportSize = state.m_reportSize;
}
HIDMainItem::HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDRange logicalRange,
int32_t reportSize)
: m_flags(uint16_t(flags))
, m_usagePage(usagePage)
, m_usage(usage)
, m_logicalRange(logicalRange)
, m_reportSize(reportSize) {}
const char* HIDMainItem::GetUsagePageName() const {
const auto index = size_t(m_usagePage);
if (index >= UsagePageNames.size()) {
return nullptr;
}
return UsagePageNames[index];
}
const char* HIDMainItem::GetUsageName() const {
const auto index = size_t(m_usage);
switch (m_usagePage) {
case HIDUsagePage::GenericDesktop:
if (index >= GenericDesktopUsages.size()) {
return nullptr;
}
return GenericDesktopUsages[index];
case HIDUsagePage::Game:
if (index >= GameUsages.size()) {
return nullptr;
}
return GameUsages[index];
default:
return nullptr;
}
}
struct HIDReports {
std::map<int32_t, std::vector<HIDMainItem>> m_inputReports;
std::map<int32_t, std::vector<HIDMainItem>> m_outputReports;
std::map<int32_t, std::vector<HIDMainItem>> m_featureReports;
static void _AddItem(std::map<int32_t, std::vector<HIDMainItem>>& m, uint32_t flags, const HIDItemState& state) {
std::vector<HIDMainItem>& report = m[state.m_reportID];
report.reserve(report.size() + state.m_reportCount);
for (uint32_t i = 0; i < state.m_reportCount; ++i)
report.emplace_back(flags, state, i);
}
void AddInputItem(uint32_t flags, const HIDItemState& state) { _AddItem(m_inputReports, flags, state); }
void AddOutputItem(uint32_t flags, const HIDItemState& state) { _AddItem(m_outputReports, flags, state); }
void AddFeatureItem(uint32_t flags, const HIDItemState& state) { _AddItem(m_featureReports, flags, state); }
};
#if _WIN32
#if !WINDOWS_STORE
HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorData) {
/* User mode HID report descriptor isn't available on Win32.
* Opaque preparsed data must be enumerated and sorted into
* iterable items.
*
* Wine's implementation has a good illustration of what's
* going on here:
* https://github.com/wine-mirror/wine/blob/master/dlls/hidclass.sys/descriptor.c
*
* (Thanks for this pointless pain-in-the-ass Microsoft)
*/
m_descriptorData = descriptorData;
HIDP_CAPS caps;
HidP_GetCaps(descriptorData, &caps);
m_dataList.resize(HidP_MaxDataListLength(HidP_Input, descriptorData));
std::map<uint32_t, HIDMainItem> inputItems;
{
/* First enumerate buttons */
USHORT length = caps.NumberInputButtonCaps;
std::vector<HIDP_BUTTON_CAPS> bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS());
HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData);
for (const HIDP_BUTTON_CAPS& buttonCaps : bCaps) {
if (buttonCaps.IsRange) {
int usage = buttonCaps.Range.UsageMin;
for (int i = buttonCaps.Range.DataIndexMin; i <= buttonCaps.Range.DataIndexMax; ++i, ++usage) {
inputItems.emplace(i, HIDMainItem(buttonCaps.BitField, HIDUsagePage(buttonCaps.UsagePage), HIDUsage(usage),
std::make_pair(0, 1), 1));
}
} else {
inputItems.emplace(buttonCaps.NotRange.DataIndex,
HIDMainItem(buttonCaps.BitField, HIDUsagePage(buttonCaps.UsagePage),
HIDUsage(buttonCaps.NotRange.Usage), std::make_pair(0, 1), 1));
}
}
}
{
/* Now enumerate values */
USHORT length = caps.NumberInputValueCaps;
std::vector<HIDP_VALUE_CAPS> vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS());
HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData);
for (const HIDP_VALUE_CAPS& valueCaps : vCaps) {
if (valueCaps.IsRange) {
int usage = valueCaps.Range.UsageMin;
for (int i = valueCaps.Range.DataIndexMin; i <= valueCaps.Range.DataIndexMax; ++i, ++usage) {
inputItems.emplace(i, HIDMainItem(valueCaps.BitField, HIDUsagePage(valueCaps.UsagePage), HIDUsage(usage),
std::make_pair(valueCaps.LogicalMin, valueCaps.LogicalMax),
valueCaps.BitSize));
}
} else {
inputItems.emplace(valueCaps.NotRange.DataIndex,
HIDMainItem(valueCaps.BitField, HIDUsagePage(valueCaps.UsagePage),
HIDUsage(valueCaps.NotRange.Usage),
HIDRange(valueCaps.LogicalMin, valueCaps.LogicalMax), valueCaps.BitSize));
}
}
}
m_itemPool.reserve(inputItems.size());
for (const auto& item : inputItems)
m_itemPool.push_back(item.second);
m_status = ParserStatus::Done;
return ParserStatus::Done;
}
#endif
#else
static HIDParser::ParserStatus AdvanceIt(const uint8_t*& it, const uint8_t* end, size_t adv) {
it += adv;
if (it > end) {
it = end;
return HIDParser::ParserStatus::Error;
} else if (it == end) {
return HIDParser::ParserStatus::Done;
}
return HIDParser::ParserStatus::OK;
}
static uint8_t GetByteValue(const uint8_t*& it, const uint8_t* end, HIDParser::ParserStatus& status) {
const uint8_t* oldIt = it;
status = AdvanceIt(it, end, 1);
if (status == HIDParser::ParserStatus::Error)
return 0;
return *oldIt;
}
static uint32_t GetShortValue(const uint8_t*& it, const uint8_t* end, int adv, HIDParser::ParserStatus& status) {
const uint8_t* oldIt = it;
switch (adv) {
case 1:
status = AdvanceIt(it, end, 1);
if (status == HIDParser::ParserStatus::Error)
return 0;
return *oldIt;
case 2:
status = AdvanceIt(it, end, 2);
if (status == HIDParser::ParserStatus::Error)
return 0;
return *reinterpret_cast<const uint16_t*>(&*oldIt);
case 3:
status = AdvanceIt(it, end, 4);
if (status == HIDParser::ParserStatus::Error)
return 0;
return *reinterpret_cast<const uint32_t*>(&*oldIt);
default:
break;
}
return 0;
}
HIDParser::ParserStatus HIDParser::ParseItem(HIDReports& reportsOut, std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& collectionStack, const uint8_t*& it,
const uint8_t* end, bool& multipleReports) {
ParserStatus status = ParserStatus::OK;
uint8_t head = *it++;
if (head == 0b11111110) {
/* Long item */
uint8_t bDataSize = GetByteValue(it, end, status);
if (status == ParserStatus::Error)
return ParserStatus::Error;
/*uint8_t bLongItemTag =*/GetByteValue(it, end, status);
if (status == ParserStatus::Error)
return ParserStatus::Error;
status = AdvanceIt(it, end, bDataSize);
if (status == ParserStatus::Error)
return ParserStatus::Error;
} else {
/* Short Item */
uint32_t data = GetShortValue(it, end, head & 0x3, status);
if (status == ParserStatus::Error)
return ParserStatus::Error;
switch (HIDItemType((head >> 2) & 0x3)) {
case HIDItemType::Main:
switch (HIDItemTag(head >> 4)) {
case HIDItemTag::Input:
reportsOut.AddInputItem(data, stateStack.top());
break;
case HIDItemTag::Output:
reportsOut.AddOutputItem(data, stateStack.top());
break;
case HIDItemTag::Feature:
reportsOut.AddFeatureItem(data, stateStack.top());
break;
case HIDItemTag::Collection:
collectionStack.emplace(HIDCollectionType(data), stateStack.top());
break;
case HIDItemTag::EndCollection:
if (collectionStack.empty())
return ParserStatus::Error;
collectionStack.pop();
break;
default:
return ParserStatus::Error;
}
stateStack.top().ResetLocalItems();
break;
case HIDItemType::Global:
switch (HIDItemTag(head >> 4)) {
case HIDItemTag::UsagePage:
stateStack.top().m_usagePage = HIDUsagePage(data);
break;
case HIDItemTag::LogicalMinimum:
stateStack.top().m_logicalRange.first = data;
break;
case HIDItemTag::LogicalMaximum:
stateStack.top().m_logicalRange.second = data;
break;
case HIDItemTag::PhysicalMinimum:
stateStack.top().m_physicalRange.first = data;
break;
case HIDItemTag::PhysicalMaximum:
stateStack.top().m_physicalRange.second = data;
break;
case HIDItemTag::UnitExponent:
stateStack.top().m_unitExponent = data;
break;
case HIDItemTag::Unit:
stateStack.top().m_unit = data;
break;
case HIDItemTag::ReportSize:
stateStack.top().m_reportSize = data;
break;
case HIDItemTag::ReportID:
multipleReports = true;
stateStack.top().m_reportID = data;
break;
case HIDItemTag::ReportCount:
stateStack.top().m_reportCount = data;
break;
case HIDItemTag::Push:
stateStack.push(stateStack.top());
break;
case HIDItemTag::Pop:
if (stateStack.empty())
return ParserStatus::Error;
stateStack.pop();
break;
default:
return ParserStatus::Error;
}
break;
case HIDItemType::Local:
switch (HIDItemTag(head >> 4)) {
case HIDItemTag::Usage:
stateStack.top().m_usage.push_back(HIDUsage(data));
break;
case HIDItemTag::UsageMinimum:
stateStack.top().m_usageRange.first = data;
break;
case HIDItemTag::UsageMaximum:
stateStack.top().m_usageRange.second = data;
break;
case HIDItemTag::DesignatorIndex:
case HIDItemTag::DesignatorMinimum:
case HIDItemTag::DesignatorMaximum:
case HIDItemTag::StringIndex:
case HIDItemTag::StringMinimum:
case HIDItemTag::StringMaximum:
case HIDItemTag::Delimiter:
break;
default:
return ParserStatus::Error;
}
break;
default:
return ParserStatus::Error;
}
}
return it == end ? ParserStatus::Done : ParserStatus::OK;
}
HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t len) {
std::stack<HIDItemState> stateStack;
stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack;
HIDReports reports;
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;)
if ((m_status = ParseItem(reports, stateStack, collectionStack, it, end, m_multipleReports)) != ParserStatus::OK)
break;
if (m_status != ParserStatus::Done)
return m_status;
uint32_t itemCount = 0;
uint32_t reportCount =
uint32_t(reports.m_inputReports.size() + reports.m_outputReports.size() + reports.m_featureReports.size());
for (const auto& rep : reports.m_inputReports)
itemCount += rep.second.size();
for (const auto& rep : reports.m_outputReports)
itemCount += rep.second.size();
for (const auto& rep : reports.m_featureReports)
itemCount += rep.second.size();
m_itemPool.reset(new HIDMainItem[itemCount]);
m_reportPool.reset(new Report[reportCount]);
uint32_t itemIndex = 0;
uint32_t reportIndex = 0;
auto func = [&](std::pair<uint32_t, uint32_t>& out, const std::map<int32_t, std::vector<HIDMainItem>>& in) {
out = std::make_pair(reportIndex, reportIndex + in.size());
for (const auto& rep : in) {
m_reportPool[reportIndex++] = std::make_pair(rep.first, std::make_pair(itemIndex, itemIndex + rep.second.size()));
for (const auto& item : rep.second)
m_itemPool[itemIndex++] = item;
}
};
func(m_inputReports, reports.m_inputReports);
func(m_outputReports, reports.m_outputReports);
func(m_featureReports, reports.m_featureReports);
return m_status;
}
size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len) {
std::stack<HIDItemState> stateStack;
stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack;
HIDReports reports;
ParserStatus status = ParserStatus::Done;
bool multipleReports = false;
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;)
if ((status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports)) != ParserStatus::OK)
break;
if (status != ParserStatus::Done)
return 0;
size_t maxSize = 0;
for (const auto& rep : reports.m_inputReports) {
size_t repSize = 0;
for (const auto& item : rep.second)
repSize += item.m_reportSize;
if (repSize > maxSize)
maxSize = repSize;
}
return (maxSize + 7) / 8 + multipleReports;
}
std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) {
std::stack<HIDItemState> stateStack;
stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack;
HIDReports reports;
ParserStatus status = ParserStatus::Done;
bool multipleReports = false;
const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;) {
status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports);
if (collectionStack.empty())
continue;
if (collectionStack.top().m_type == HIDCollectionType::Application)
return {collectionStack.top().m_usagePage, collectionStack.top().m_usage};
if (status != ParserStatus::OK)
break;
}
return {};
}
#endif
#if _WIN32
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
#if !WINDOWS_STORE
if (m_status != ParserStatus::Done)
return;
for (const HIDMainItem& item : m_itemPool) {
if (item.IsConstant())
continue;
if (!valueCB(item))
return;
}
#endif
}
#else
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
if (m_status != ParserStatus::Done)
return;
for (uint32_t i = m_inputReports.first; i < m_inputReports.second; ++i) {
const Report& rep = m_reportPool[i];
for (uint32_t j = rep.second.first; j < rep.second.second; ++j) {
const HIDMainItem& item = m_itemPool[j];
if (item.IsConstant())
continue;
if (!valueCB(item))
return;
}
}
}
#endif
#if _WIN32
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const {
#if !WINDOWS_STORE
if (m_status != ParserStatus::Done)
return;
ULONG dataLen = m_dataList.size();
if (HidP_GetData(HidP_Input, m_dataList.data(), &dataLen, m_descriptorData, PCHAR(data), len) != HIDP_STATUS_SUCCESS)
return;
int idx = 0;
auto it = m_dataList.begin();
auto end = m_dataList.begin() + dataLen;
for (const HIDMainItem& item : m_itemPool) {
if (item.IsConstant())
continue;
int32_t value = 0;
if (it != end) {
const HIDP_DATA& hidData = *it;
if (hidData.DataIndex == idx) {
value = hidData.RawValue;
++it;
}
}
if (!valueCB(item, value))
return;
++idx;
}
#endif
}
#else
class BitwiseIterator {
const uint8_t*& m_it;
const uint8_t* m_end;
int m_bit = 0;
public:
BitwiseIterator(const uint8_t*& it, const uint8_t* end) : m_it(it), m_end(end) {}
uint32_t GetUnsignedValue(int numBits, HIDParser::ParserStatus& status) {
uint32_t val = 0;
for (int i = 0; i < numBits;) {
if (m_it >= m_end) {
status = HIDParser::ParserStatus::Error;
return 0;
}
int remBits = std::min(8 - m_bit, numBits - i);
val |= uint32_t((*m_it >> m_bit) & ((1 << remBits) - 1)) << i;
i += remBits;
m_bit += remBits;
if (m_bit == 8) {
m_bit = 0;
AdvanceIt(m_it, m_end, 1);
}
}
return val;
}
};
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const {
if (m_status != ParserStatus::Done)
return;
auto it = data;
auto end = data + len;
ParserStatus status = ParserStatus::OK;
uint8_t reportId = 0;
if (m_multipleReports)
reportId = GetByteValue(it, end, status);
if (status == ParserStatus::Error)
return;
BitwiseIterator bitIt(it, end);
for (uint32_t i = m_inputReports.first; i < m_inputReports.second; ++i) {
const Report& rep = m_reportPool[i];
if (rep.first != reportId)
continue;
for (uint32_t j = rep.second.first; j < rep.second.second; ++j) {
const HIDMainItem& item = m_itemPool[j];
int32_t val = bitIt.GetUnsignedValue(item.m_reportSize, status);
if (status == ParserStatus::Error)
return;
if (item.IsConstant())
continue;
if (!valueCB(item, val))
return;
}
break;
}
}
#endif
} // namespace boo

View File

@ -1,35 +0,0 @@
#pragma once
#include <memory>
#include "boo/inputdev/DeviceBase.hpp"
#include "boo/inputdev/DeviceToken.hpp"
#if _WIN32
#include <hidsdi.h>
#endif
namespace boo {
class IHIDDevice : public std::enable_shared_from_this<IHIDDevice> {
friend class DeviceBase;
friend struct DeviceSignature;
virtual void _deviceDisconnected() = 0;
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) = 0;
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) = 0;
#if _WIN32
#if !WINDOWS_STORE
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor() = 0;
#endif
#else
virtual std::vector<uint8_t> _getReportDescriptor() = 0;
#endif
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual void _startThread() = 0;
public:
virtual ~IHIDDevice() = default;
};
} // namespace boo

View File

@ -1,103 +0,0 @@
#pragma once
#include "lib/CFPointer.hpp"
#include <IOKit/IOTypes.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <utility>
/// A smart pointer that can manage the lifecycle of IOKit objects.
template <typename T>
class IOObjectPointer {
public:
IOObjectPointer() : storage(0) {}
IOObjectPointer(T pointer) : storage(toStorageType(pointer)) {
if (storage) {
IOObjectRetain(storage);
}
}
IOObjectPointer(const IOObjectPointer& other) : storage(other.storage) {
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
}
IOObjectPointer& operator=(const IOObjectPointer& other) {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
storage = other.storage;
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
return *this;
}
IOObjectPointer(IOObjectPointer&& other) : storage(std::exchange(other.storage, 0)) {}
~IOObjectPointer() {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
}
static inline IOObjectPointer<T> adopt(T ptr) { return IOObjectPointer<T>(ptr, IOObjectPointer<T>::Adopt); }
T get() const { return fromStorageType(storage); }
io_object_t* operator&() {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
return &storage;
}
operator bool() const { return storage != 0; }
private:
io_object_t storage;
enum AdoptTag { Adopt };
IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {}
inline io_object_t toStorageType(io_object_t ptr) const { return (io_object_t)ptr; }
inline T fromStorageType(io_object_t pointer) const { return (T)pointer; }
void swap(IOObjectPointer& other) { std::swap(storage, other.storage); }
};
/// A smart pointer that can manage the lifecycle of IOKit plugin objects.
class IOCFPluginPointer {
public:
IOCFPluginPointer() : _storage(nullptr) {}
IOCFPluginPointer(const IOCFPluginPointer& other) = delete;
IOCFPluginPointer(IOCFPluginPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {}
~IOCFPluginPointer() {
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
}
IOCFPlugInInterface*** operator&() {
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
return &_storage;
}
HRESULT As(LPVOID* p, CFUUIDRef uuid) const {
(*_storage)->AddRef(_storage); // Needed for some reason
return (*_storage)->QueryInterface(_storage, CFUUIDGetUUIDBytes(uuid), p);
}
operator bool() const { return _storage != nullptr; }
IOCFPlugInInterface** storage() const { return _storage; }
private:
IOCFPlugInInterface** _storage;
void swap(IOCFPluginPointer& other) { std::swap(_storage, other._storage); }
};

View File

@ -1,50 +0,0 @@
#include "boo/inputdev/NintendoPowerA.hpp"
#include <array>
#include <cstring>
#include "boo/inputdev/DeviceSignature.hpp"
namespace boo {
NintendoPowerA::NintendoPowerA(DeviceToken* token)
: TDeviceBase<INintendoPowerACallback>(dev_typeid(NintendoPowerA), token) {}
NintendoPowerA::~NintendoPowerA() = default;
void NintendoPowerA::deviceDisconnected() {
std::lock_guard lk{m_callbackLock};
if (m_callback != nullptr) {
m_callback->controllerDisconnected();
}
}
void NintendoPowerA::initialCycle() {}
void NintendoPowerA::transferCycle() {
std::array<uint8_t, 8> payload;
const size_t recvSz = receiveUSBInterruptTransfer(payload.data(), payload.size());
if (recvSz != payload.size()) {
return;
}
NintendoPowerAState state;
std::memcpy(&state, payload.data(), sizeof(state));
std::lock_guard lk{m_callbackLock};
if (state != m_last && m_callback != nullptr) {
m_callback->controllerUpdate(state);
}
m_last = state;
}
void NintendoPowerA::finalCycle() {}
void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {}
bool NintendoPowerAState::operator==(const NintendoPowerAState& other) const {
return std::memcmp(this, &other, sizeof(NintendoPowerAState)) == 0;
}
bool NintendoPowerAState::operator!=(const NintendoPowerAState& other) const { return !operator==(other); }
} // namespace boo

View File

@ -1 +0,0 @@
#include "boo/inputdev/RevolutionPad.hpp"

View File

@ -1,301 +0,0 @@
#include <AppKit/AppKit.h>
#include <thread>
#include "boo/IApplication.hpp"
#include "boo/graphicsdev/Metal.hpp"
#include "lib/Common.hpp"
#include "lib/mac/CocoaCommon.hpp"
#include <logvisor/logvisor.hpp>
#if !__has_feature(objc_arc)
#error ARC Required
#endif
/* If set, application will terminate once client thread reaches end;
* main() will not get back control. Otherwise, main will get back control
* but App will not terminate in the normal Cocoa manner (possibly resulting
* in CoreAnimation warnings). */
#define COCOA_TERMINATE 1
namespace boo { class ApplicationCocoa; }
@interface AppDelegate : NSObject <NSApplicationDelegate> {
boo::ApplicationCocoa* m_app;
@public
}
- (id)initWithApp:(boo::ApplicationCocoa*)app;
@end
namespace boo {
static logvisor::Module Log("boo::ApplicationCocoa");
std::shared_ptr<IWindow> _WindowCocoaNew(std::string_view title, MetalContext* metalCtx);
class ApplicationCocoa : public IApplication {
public:
IApplicationCallback& m_callback;
AppDelegate* m_appDelegate;
private:
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
NSPanel* aboutPanel;
/* All windows */
std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows;
MetalContext m_metalCtx;
#if 0
GLContext m_glCtx;
#endif
void _deletedWindow(IWindow* window) override {
m_windows.erase(window->getPlatformHandle());
}
public:
ApplicationCocoa(IApplicationCallback& callback,
std::string_view uniqueName,
std::string_view friendlyName,
std::string_view pname,
const std::vector<std::string>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args) {
m_metalCtx.m_sampleCount = samples;
m_metalCtx.m_anisotropy = anisotropy;
m_metalCtx.m_pixelFormat = deepColor ? MTLPixelFormatRGBA16Float : MTLPixelFormatBGRA8Unorm;
#if 0
m_glCtx.m_sampleCount = samples;
m_glCtx.m_anisotropy = anisotropy;
m_glCtx.m_deepColor = deepColor;
#endif
[[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
/* Delegate (OS X callbacks) */
m_appDelegate = [[AppDelegate alloc] initWithApp:this];
[[NSApplication sharedApplication] setDelegate:m_appDelegate];
/* App menu */
NSMenu* rootMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]];
NSMenuItem* fsItem = [appMenu addItemWithTitle:@"Toggle Full Screen"
action:@selector(toggleFs:)
keyEquivalent:@"f"];
[fsItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
[appMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quitItem = [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()]
action:@selector(quitApp:)
keyEquivalent:@"q"];
[quitItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
[[rootMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]
action:nil keyEquivalent:@""] setSubmenu:appMenu];
[[NSApplication sharedApplication] setMainMenu:rootMenu];
m_metalCtx.m_dev = MTLCreateSystemDefaultDevice();
if (!m_metalCtx.m_dev)
Log.report(logvisor::Fatal, FMT_STRING("Unable to create metal device"));
m_metalCtx.m_q = [m_metalCtx.m_dev newCommandQueue];
while (![m_metalCtx.m_dev supportsTextureSampleCount:m_metalCtx.m_sampleCount])
m_metalCtx.m_sampleCount = flp2(m_metalCtx.m_sampleCount - 1);
Log.report(logvisor::Info, FMT_STRING("using Metal renderer"));
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
EPlatformType getPlatformType() const override {
return EPlatformType::Cocoa;
}
std::thread m_clientThread;
int m_clientReturn = 0;
bool m_terminateNow = false;
int run() override {
/* Spawn client thread */
m_clientThread = std::thread([&]() {
std::string thrName = std::string(getFriendlyName()) + " Client Thread";
logvisor::RegisterThreadName(thrName.c_str());
/* Run app */
m_clientReturn = m_callback.appMain(this);
/* Cleanup */
for (auto& w : m_windows)
if (std::shared_ptr<IWindow> window = w.second.lock())
window->closeWindow();
#if COCOA_TERMINATE
/* Continue termination */
dispatch_sync(dispatch_get_main_queue(),
^{
/* Ends modal run loop and continues Cocoa termination */
[NSApp replyToApplicationShouldTerminate:YES];
/* If this is reached, application didn't spawn any windows
* and must be explicitly terminated */
m_terminateNow = true;
[NSApp terminate:nil];
});
#else
/* Return control to main() */
dispatch_sync(dispatch_get_main_queue(),
^{
[[NSApplication sharedApplication] stop:nil];
});
#endif
});
/* Already in Cocoa's event loop; return now */
return 0;
}
void quit() {
[NSApp terminate:nil];
}
std::string_view getUniqueName() const override {
return m_uniqueName;
}
std::string_view getFriendlyName() const override {
return m_friendlyName;
}
std::string_view getProcessName() const override {
return m_pname;
}
const std::vector<std::string>& getArgs() const override {
return m_args;
}
std::shared_ptr<IWindow> newWindow(std::string_view title) override {
auto newWindow = _WindowCocoaNew(title, &m_metalCtx);
m_windows[newWindow->getPlatformHandle()] = newWindow;
return newWindow;
}
/* Last GL context */
#if 0
NSOpenGLContext* m_lastGLCtx = nullptr;
#endif
};
#if 0
void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx)
{
static_cast<ApplicationCocoa*>(APP)->m_lastGLCtx = lastGLCtx;
}
#endif
IApplication* APP = nullptr;
int ApplicationRun(IApplication::EPlatformType platform,
IApplicationCallback& cb,
std::string_view uniqueName,
std::string_view friendlyName,
std::string_view pname,
const std::vector<std::string>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor,
bool singleInstance) {
std::string thrName = std::string(friendlyName) + " Main Thread";
logvisor::RegisterThreadName(thrName.c_str());
@autoreleasepool {
if (!APP) {
if (platform != IApplication::EPlatformType::Cocoa &&
platform != IApplication::EPlatformType::Auto)
return 1;
/* Never deallocated to ensure window destructors have access */
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args,
gfxApi, samples, anisotropy, deepColor);
}
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if ([NSApp respondsToSelector:@selector(setAppearance:)])
[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]];
#endif
[NSApp run];
ApplicationCocoa* appCocoa = static_cast<ApplicationCocoa*>(APP);
if (appCocoa->m_clientThread.joinable())
appCocoa->m_clientThread.join();
return appCocoa->m_clientReturn;
}
}
}
@implementation AppDelegate
- (id)initWithApp:(boo::ApplicationCocoa*)app {
self = [super init];
m_app = app;
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification*)notification {
(void) notification;
m_app->run();
}
#if COCOA_TERMINATE
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app {
(void) app;
if (m_app->m_terminateNow)
return NSTerminateNow;
m_app->m_callback.appQuitting(m_app);
return NSTerminateLater;
}
#else
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app
{
(void)app;
m_app->m_callback.appQuitting(m_app);
return NSTerminateCancel;
}
#endif
- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename {
std::vector<std::string> strVec;
strVec.push_back(std::string([filename UTF8String]));
m_app->m_callback.appFilesOpen(boo::APP, strVec);
return true;
}
- (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames {
std::vector<std::string> strVec;
strVec.reserve([filenames count]);
for (NSString* str in filenames)
strVec.push_back(std::string([str UTF8String]));
m_app->m_callback.appFilesOpen(boo::APP, strVec);
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender {
(void) sender;
return YES;
}
- (IBAction)toggleFs:(id)sender {
(void) sender;
[[NSApp keyWindow] toggleFullScreen:nil];
}
- (IBAction)quitApp:(id)sender {
(void) sender;
[NSApp terminate:nil];
}
@end

View File

@ -1,40 +0,0 @@
#pragma once
#if __APPLE__
#if !__has_feature(objc_arc)
#error ARC Required
#endif
#if BOO_HAS_METAL
#include <Metal/Metal.h>
#include <QuartzCore/CAMetalLayer.h>
#include <mutex>
#include <unordered_map>
namespace boo {
class IWindow;
struct MetalContext {
id<MTLDevice> m_dev = nullptr;
id<MTLCommandQueue> m_q = nullptr;
struct Window {
CAMetalLayer* m_metalLayer = nullptr;
std::mutex m_resizeLock;
bool m_needsResize;
CGSize m_size;
};
std::unordered_map<IWindow*, Window> m_windows;
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
MTLPixelFormat m_pixelFormat = MTLPixelFormatBGRA8Unorm;
};
} // namespace boo
#else
namespace boo {
struct MetalContext {};
} // namespace boo
#endif
#endif // __APPLE__

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +0,0 @@
#include "lib/win/UWPCommon.hpp"
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::ApplicationModel::Core;
using namespace Platform;
#if _DEBUG
#define D3D11_CREATE_DEVICE_FLAGS D3D11_CREATE_DEVICE_DEBUG
#else
#define D3D11_CREATE_DEVICE_FLAGS 0
#endif
#include <cstdlib>
#include "boo/IApplication.hpp"
#include "boo/System.hpp"
#include "boo/UWPViewProvider.hpp"
#include "boo/graphicsdev/D3D.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
#include <logvisor/logvisor.hpp>
#if _WIN32_WINNT_WIN10
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignaturePROC = nullptr;
#endif
pD3DCompile D3DCompilePROC = nullptr;
pD3DCreateBlob D3DCreateBlobPROC = nullptr;
static bool FindBestD3DCompile() {
D3DCompilePROC = D3DCompile;
D3DCreateBlobPROC = D3DCreateBlob;
return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr;
}
namespace boo {
static logvisor::Module Log("boo::ApplicationUWP");
std::shared_ptr<IWindow> _WindowUWPNew(std::string_view title, Boo3DAppContextUWP& d3dCtx);
class ApplicationUWP final : public IApplication {
friend ref class AppView;
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
std::shared_ptr<IWindow> m_window;
bool m_singleInstance;
bool m_issuedWindow = false;
Boo3DAppContextUWP m_3dCtx;
void _deletedWindow(IWindow* window) override {}
public:
ApplicationUWP(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, const std::vector<std::string>& args, bool singleInstance)
: m_callback(callback)
, m_uniqueName(uniqueName)
, m_friendlyName(friendlyName)
, m_pname(pname)
, m_args(args)
, m_singleInstance(singleInstance) {
using CreateDXGIFactory1PROC = HRESULT (WINAPI *)(REFIID riid, _COM_Outptr_ void** ppFactory);
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1;
bool no12 = true;
for (const std::string& arg : args)
if (!arg.compare(L"--d3d12"))
no12 = false;
#if _WIN32_WINNT_WIN10
if (!no12) {
if (!FindBestD3DCompile())
Log.report(logvisor::Fatal, FMT_STRING("unable to find D3DCompile_[43-47].dll"));
D3D12SerializeRootSignaturePROC = D3D12SerializeRootSignature;
/* Create device */
PFN_D3D12_CREATE_DEVICE MyD3D12CreateDevice = D3D12CreateDevice;
/* Obtain DXGI Factory */
HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory2), &m_3dCtx.m_ctx12.m_dxFactory);
if (FAILED(hr))
Log.report(logvisor::Fatal, FMT_STRING("unable to create DXGI factory"));
/* Adapter */
ComPtr<IDXGIAdapter1> ppAdapter;
for (UINT adapterIndex = 0;; ++adapterIndex) {
ComPtr<IDXGIAdapter1> pAdapter;
if (DXGI_ERROR_NOT_FOUND == m_3dCtx.m_ctx12.m_dxFactory->EnumAdapters1(adapterIndex, &pAdapter))
break;
// Check to see if the adapter supports Direct3D 12, but don't create the
// actual device yet.
if (SUCCEEDED(MyD3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {
ppAdapter = std::move(pAdapter);
break;
}
}
/* Create device */
hr = ppAdapter ? MyD3D12CreateDevice(ppAdapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device),
&m_3dCtx.m_ctx12.m_dev)
: E_FAIL;
if (!FAILED(hr)) {
/* Establish loader objects */
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), &m_3dCtx.m_ctx12.m_loadqalloc)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create loader allocator"));
D3D12_COMMAND_QUEUE_DESC desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
D3D12_COMMAND_QUEUE_FLAG_NONE};
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue),
&m_3dCtx.m_ctx12.m_loadq)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create loader queue"));
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
&m_3dCtx.m_ctx12.m_loadfence)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create loader fence"));
m_3dCtx.m_ctx12.m_loadfencehandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandList(
0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_3dCtx.m_ctx12.m_loadqalloc.Get(), nullptr,
__uuidof(ID3D12GraphicsCommandList), &m_3dCtx.m_ctx12.m_loadlist)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create loader list"));
Log.report(logvisor::Info, FMT_STRING("initialized D3D12 renderer"));
return;
} else {
/* Some Win10 client HW doesn't support D3D12 (despite being supposedly HW-agnostic) */
m_3dCtx.m_ctx12.m_dev.Reset();
m_3dCtx.m_ctx12.m_dxFactory.Reset();
}
}
#endif
{
if (!FindBestD3DCompile())
Log.report(logvisor::Fatal, FMT_STRING("unable to find D3DCompile_[43-47].dll"));
/* Create device proc */
PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice = D3D11CreateDevice;
/* Create device */
D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;
ComPtr<ID3D11Device> tempDev;
ComPtr<ID3D11DeviceContext> tempCtx;
if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, 1,
D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create D3D11 device"));
ComPtr<IDXGIDevice2> device;
if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev ||
FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx ||
FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) {
exit(1);
}
/* Obtain DXGI Factory */
ComPtr<IDXGIAdapter> adapter;
device->GetParent(__uuidof(IDXGIAdapter), &adapter);
adapter->GetParent(__uuidof(IDXGIFactory2), &m_3dCtx.m_ctx11.m_dxFactory);
/* Build default sampler here */
CD3D11_SAMPLER_DESC sampDesc(D3D11_DEFAULT);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[0]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[1]);
Log.report(logvisor::Info, FMT_STRING("initialized D3D11 renderer"));
return;
}
Log.report(logvisor::Fatal, FMT_STRING("system doesn't support D3D11 or D3D12"));
}
EPlatformType getPlatformType() const override { return EPlatformType::UWP; }
std::thread m_clientThread;
int run() override {
/* Spawn client thread */
int clientReturn = 0;
m_clientThread = std::thread([&]() {
std::string thrName = std::string(getFriendlyName()) + " Client Thread";
logvisor::RegisterThreadName(thrName.c_str());
clientReturn = m_callback.appMain(this);
});
CoreWindow::GetForCurrentThread()->Activate();
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
return 0;
}
void quit() {
m_callback.appQuitting(this);
if (m_clientThread.joinable())
m_clientThread.join();
}
std::string_view getUniqueName() const override { return m_uniqueName; }
std::string_view getFriendlyName() const override { return m_friendlyName; }
std::string_view getProcessName() const override { return m_pname; }
const std::vector<std::string>& getArgs() const override { return m_args; }
std::shared_ptr<IWindow> newWindow(std::string_view title, uint32_t sampleCount) override {
if (!m_issuedWindow) {
m_issuedWindow = true;
return m_window;
}
return {};
}
void _setWindow(CoreWindow ^ window) { m_window = _WindowUWPNew(m_friendlyName, m_3dCtx); }
};
IApplication* APP = nullptr;
ref class AppView sealed : public IFrameworkView {
ApplicationUWP m_app;
internal : AppView(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, const std::vector<std::string>& args, bool singleInstance)
: m_app(callback, uniqueName, friendlyName, pname, args, singleInstance) {
APP = &m_app;
}
public:
virtual void Initialize(CoreApplicationView ^ applicationView) {
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView ^, IActivatedEventArgs ^>(this, &AppView::OnActivated);
}
virtual void SetWindow(CoreWindow ^ window) { m_app._setWindow(window); }
virtual void Load(String ^ entryPoint) {}
virtual void Run() { m_app.run(); }
virtual void Uninitialize() { m_app.quit(); }
void OnActivated(CoreApplicationView ^ applicationView, IActivatedEventArgs ^ args) {
CoreWindow::GetForCurrentThread()->Activate();
}
};
IFrameworkView ^ ViewProvider::CreateView() {
return ref new AppView(m_appCb, m_uniqueName, m_friendlyName, m_pname, m_args, m_singleInstance);
}
} // namespace boo

View File

@ -1,528 +0,0 @@
#include "lib/win/Win32Common.hpp"
#include <shellapi.h>
#include <initguid.h>
#include <Usbiodef.h>
#include <winver.h>
#include <Dbt.h>
#if _WIN32_WINNT_WINBLUE
PFN_GetScaleFactorForMonitor MyGetScaleFactorForMonitor = nullptr;
#endif
#if _DEBUG
#define D3D11_CREATE_DEVICE_FLAGS D3D11_CREATE_DEVICE_DEBUG
#else
#define D3D11_CREATE_DEVICE_FLAGS 0
#endif
#include <condition_variable>
#include <cstdlib>
#include <mutex>
#include "boo/IApplication.hpp"
#include "boo/System.hpp"
#include "boo/graphicsdev/D3D.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
#include <logvisor/logvisor.hpp>
#if BOO_HAS_VULKAN
#include "boo/graphicsdev/Vulkan.hpp"
#endif
DWORD g_mainThreadId = 0;
std::mutex g_nwmt;
std::condition_variable g_nwcv;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
pD3DCompile D3DCompilePROC = nullptr;
pD3DCreateBlob D3DCreateBlobPROC = nullptr;
pD3DPERF_BeginEvent D3DPERF_BeginEventPROC = nullptr;
pD3DPERF_EndEvent D3DPERF_EndEventPROC = nullptr;
static bool FindBestD3DCompile() {
HMODULE d3dCompilelib = LoadLibraryW(L"D3DCompiler_47.dll");
if (!d3dCompilelib) {
d3dCompilelib = LoadLibraryW(L"D3DCompiler_46.dll");
if (!d3dCompilelib) {
d3dCompilelib = LoadLibraryW(L"D3DCompiler_45.dll");
if (!d3dCompilelib) {
d3dCompilelib = LoadLibraryW(L"D3DCompiler_44.dll");
if (!d3dCompilelib) {
d3dCompilelib = LoadLibraryW(L"D3DCompiler_43.dll");
}
}
}
}
if (d3dCompilelib) {
D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile");
D3DCreateBlobPROC = (pD3DCreateBlob)GetProcAddress(d3dCompilelib, "D3DCreateBlob");
return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr;
}
return false;
}
static bool FindD3DPERF() {
HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
if (d3d9lib) {
D3DPERF_BeginEventPROC = (pD3DPERF_BeginEvent)GetProcAddress(d3d9lib, "D3DPERF_BeginEvent");
D3DPERF_EndEventPROC = (pD3DPERF_EndEvent)GetProcAddress(d3d9lib, "D3DPERF_EndEvent");
return D3DPERF_BeginEventPROC != nullptr && D3DPERF_EndEventPROC != nullptr;
}
return false;
}
namespace boo {
static logvisor::Module Log("boo::ApplicationWin32");
Win32Cursors WIN32_CURSORS;
std::shared_ptr<IWindow> _WindowWin32New(std::string_view title, Boo3DAppContextWin32& d3dCtx);
class ApplicationWin32 final : public IApplication {
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
std::unordered_map<HWND, std::weak_ptr<IWindow>> m_allWindows;
Boo3DAppContextWin32 m_3dCtx;
#if BOO_HAS_VULKAN
PFN_vkGetInstanceProcAddr m_getVkProc = nullptr;
#endif
void _deletedWindow(IWindow* window) override { m_allWindows.erase(HWND(window->getPlatformHandle())); }
public:
ApplicationWin32(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, const std::vector<std::string>& args, std::string_view gfxApi,
uint32_t samples, uint32_t anisotropy, bool deepColor, bool singleInstance)
: m_callback(callback), m_uniqueName(uniqueName), m_friendlyName(friendlyName), m_pname(pname), m_args(args) {
m_3dCtx.m_ctx11.m_sampleCount = samples;
m_3dCtx.m_ctx11.m_anisotropy = anisotropy;
m_3dCtx.m_ctx11.m_fbFormat = deepColor ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
#if BOO_HAS_GL
m_3dCtx.m_ctxOgl.m_glCtx.m_sampleCount = samples;
m_3dCtx.m_ctxOgl.m_glCtx.m_anisotropy = anisotropy;
m_3dCtx.m_ctxOgl.m_glCtx.m_deepColor = deepColor;
#endif
#if BOO_HAS_VULKAN
g_VulkanContext.m_sampleCountColor = samples;
g_VulkanContext.m_sampleCountDepth = samples;
g_VulkanContext.m_anisotropy = anisotropy;
g_VulkanContext.m_deepColor = deepColor;
#endif
HMODULE dxgilib = LoadLibraryW(L"dxgi.dll");
if (!dxgilib)
Log.report(logvisor::Fatal, FMT_STRING("unable to load dxgi.dll"));
using CreateDXGIFactory1PROC = HRESULT(WINAPI*)(REFIID riid, _COM_Outptr_ void** ppFactory);
auto MyCreateDXGIFactory1 = (CreateDXGIFactory1PROC)GetProcAddress(dxgilib, "CreateDXGIFactory1");
if (!MyCreateDXGIFactory1)
Log.report(logvisor::Fatal, FMT_STRING("unable to find CreateDXGIFactory1 in DXGI.dll\n"));
bool noD3d = false;
#if BOO_HAS_VULKAN
bool useVulkan = true;
#endif
if (!gfxApi.empty()) {
#if BOO_HAS_VULKAN
if (!gfxApi.compare("Vulkan")) {
noD3d = true;
useVulkan = true;
}
if (!gfxApi.compare("OpenGL")) {
noD3d = true;
useVulkan = false;
}
#else
if (!gfxApi.compare("OpenGL"))
noD3d = true;
#endif
}
for (const std::string& arg : args) {
#if BOO_HAS_VULKAN
if (!arg.compare("--d3d11")) {
useVulkan = false;
noD3d = false;
}
if (!arg.compare("--vulkan")) {
noD3d = true;
useVulkan = true;
}
if (!arg.compare("--gl")) {
noD3d = true;
useVulkan = false;
}
#else
if (!arg.compare(L"--d3d11"))
noD3d = false;
if (!arg.compare(L"--gl"))
noD3d = true;
#endif
}
#if BOO_HAS_VULKAN
if (useVulkan) {
HMODULE vulkanLib = LoadLibraryW(L"vulkan-1.dll");
if (vulkanLib) {
m_getVkProc = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkanLib, "vkGetInstanceProcAddr");
if (m_getVkProc) {
/* Check device support for vulkan */
if (g_VulkanContext.m_instance == VK_NULL_HANDLE) {
auto appName = getUniqueName();
if (g_VulkanContext.initVulkan(appName.data(), m_getVkProc)) {
if (g_VulkanContext.enumerateDevices()) {
/* Obtain DXGI Factory */
HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_vulkanDxFactory);
if (FAILED(hr))
Log.report(logvisor::Fatal, FMT_STRING("unable to create DXGI factory"));
Log.report(logvisor::Info, FMT_STRING("initialized Vulkan renderer"));
return;
}
}
}
}
}
}
#endif
HMODULE d3d11lib = nullptr;
if (!noD3d)
d3d11lib = LoadLibraryW(L"D3D11.dll");
if (d3d11lib) {
if (!FindBestD3DCompile())
Log.report(logvisor::Fatal, FMT_STRING("unable to find D3DCompile_[43-47].dll"));
if (!FindD3DPERF())
Log.report(logvisor::Fatal, FMT_STRING("unable to find d3d9.dll"));
/* Create device proc */
PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice =
(PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11lib, "D3D11CreateDevice");
if (!MyD3D11CreateDevice)
Log.report(logvisor::Fatal, FMT_STRING("unable to find D3D11CreateDevice in D3D11.dll"));
/* Create device */
D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;
ComPtr<ID3D11Device> tempDev;
ComPtr<ID3D11DeviceContext> tempCtx;
if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, 1,
D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create D3D11 device"));
ComPtr<IDXGIDevice2> device;
if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev ||
FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx ||
FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) {
MessageBoxW(nullptr,
L"Windows 7 users should install 'Platform Update for Windows 7':\n"
L"https://www.microsoft.com/en-us/download/details.aspx?id=36805",
L"IDXGIDevice2 interface error", MB_OK | MB_ICONERROR);
exit(1);
}
/* Obtain DXGI Factory */
ComPtr<IDXGIAdapter> adapter;
device->GetParent(__uuidof(IDXGIAdapter), &adapter);
adapter->GetParent(__uuidof(IDXGIFactory2), &m_3dCtx.m_ctx11.m_dxFactory);
m_3dCtx.m_ctx11.m_anisotropy = std::min(m_3dCtx.m_ctx11.m_anisotropy, uint32_t(16));
/* Build default sampler here */
CD3D11_SAMPLER_DESC sampDesc(D3D11_DEFAULT);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.Filter = D3D11_FILTER_ANISOTROPIC;
sampDesc.MaxAnisotropy = m_3dCtx.m_ctx11.m_anisotropy;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[0]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[1]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
std::fill(std::begin(sampDesc.BorderColor), std::end(sampDesc.BorderColor), 0.f);
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[2]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[3]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
m_3dCtx.m_ctx11.m_dev->CreateSamplerState(&sampDesc, &m_3dCtx.m_ctx11.m_ss[4]);
Log.report(logvisor::Info, FMT_STRING("initialized D3D11 renderer"));
return;
}
#if BOO_HAS_GL
/* Finally try OpenGL */
{
/* Obtain DXGI Factory */
HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_ctxOgl.m_dxFactory);
if (FAILED(hr))
Log.report(logvisor::Fatal, FMT_STRING("unable to create DXGI factory"));
Log.report(logvisor::Info, FMT_STRING("initialized OpenGL renderer"));
return;
}
#endif
Log.report(logvisor::Fatal, FMT_STRING("system doesn't support Vulkan, D3D11, or OpenGL"));
}
EPlatformType getPlatformType() const override { return EPlatformType::Win32; }
LRESULT winHwndHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
/* Lookup boo window instance */
auto search = m_allWindows.find(hwnd);
if (search == m_allWindows.end())
return DefWindowProc(hwnd, uMsg, wParam, lParam);
;
std::shared_ptr<IWindow> window = search->second.lock();
if (!window)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
switch (uMsg) {
case WM_CREATE:
return 0;
case WM_DEVICECHANGE:
return DeviceFinder::winDevChangedHandler(wParam, lParam);
case WM_CLOSE:
case WM_SIZE:
case WM_MOVING:
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_MOUSEMOVE:
case WM_MOUSELEAVE:
case WM_NCMOUSELEAVE:
case WM_MOUSEHOVER:
case WM_NCMOUSEHOVER:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_CHAR:
case WM_UNICHAR: {
HWNDEvent eventData(uMsg, wParam, lParam);
window->_incomingEvent(&eventData);
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
template <class W>
static void DoSetFullscreen(W& win, bool fs) {
std::lock_guard<std::mutex> lk(g_nwmt);
if (fs) {
win.m_fsStyle = GetWindowLong(win.m_hwnd, GWL_STYLE);
win.m_fsExStyle = GetWindowLong(win.m_hwnd, GWL_EXSTYLE);
GetWindowRect(win.m_hwnd, &win.m_fsRect);
SetWindowLongPtr(win.m_hwnd, GWL_STYLE, win.m_fsStyle & ~(WS_CAPTION | WS_THICKFRAME));
SetWindowLongPtr(win.m_hwnd, GWL_EXSTYLE,
win.m_fsExStyle &
~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
MONITORINFO monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
GetMonitorInfo(MonitorFromWindow(win.m_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info);
SetWindowPos(win.m_hwnd, nullptr, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
monitor_info.rcMonitor.right - monitor_info.rcMonitor.left,
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
win.m_fs = true;
} else {
SetWindowLongPtr(win.m_hwnd, GWL_STYLE, win.m_fsStyle);
SetWindowLongPtr(win.m_hwnd, GWL_EXSTYLE, win.m_fsExStyle);
SetWindowPos(win.m_hwnd, nullptr, win.m_fsRect.left, win.m_fsRect.top, win.m_fsRect.right - win.m_fsRect.left,
win.m_fsRect.bottom - win.m_fsRect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
win.m_fs = false;
}
g_nwcv.notify_one();
}
int run() override {
g_mainThreadId = GetCurrentThreadId();
/* Spawn client thread */
int clientReturn = 0;
std::thread clientThread([&]() {
std::string thrName = std::string(getFriendlyName()) + " Client Thread";
logvisor::RegisterThreadName(thrName.c_str());
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
clientReturn = m_callback.appMain(this);
PostThreadMessageW(g_mainThreadId, WM_USER + 1, 0, 0);
});
/* Pump messages */
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!msg.hwnd) {
/* PostThreadMessage events */
switch (msg.message) {
case WM_USER: {
/* New-window message (coalesced onto main thread) */
std::lock_guard<std::mutex> lk(g_nwmt);
std::string_view* title = reinterpret_cast<std::string_view*>(msg.wParam);
m_mwret = newWindow(*title);
g_nwcv.notify_one();
continue;
}
case WM_USER + 1:
/* Quit message from client thread */
PostQuitMessage(0);
continue;
case WM_USER + 2:
/* SetCursor call from client thread */
SetCursor(HCURSOR(msg.wParam));
continue;
case WM_USER + 3:
/* ImmSetOpenStatus call from client thread */
ImmSetOpenStatus(HIMC(msg.wParam), BOOL(msg.lParam));
continue;
case WM_USER + 4:
/* ImmSetCompositionWindow call from client thread */
ImmSetCompositionWindow(HIMC(msg.wParam), LPCOMPOSITIONFORM(msg.lParam));
continue;
case WM_USER + 5:
/* SetFullscreen call for OpenGL window */
DoSetFullscreen(*reinterpret_cast<OGLContext::Window*>(msg.wParam), msg.lParam);
continue;
#if BOO_HAS_VULKAN
case WM_USER + 6:
/* SetFullscreen call for Vulkan window */
DoSetFullscreen(*reinterpret_cast<boo::VulkanContext::Window*>(msg.wParam), msg.lParam);
continue;
#endif
default:
break;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
m_callback.appQuitting(this);
clientThread.join();
return clientReturn;
}
~ApplicationWin32() override {
for (auto& p : m_allWindows)
if (auto w = p.second.lock())
w->_cleanup();
}
std::string_view getUniqueName() const override { return m_uniqueName; }
std::string_view getFriendlyName() const override { return m_friendlyName; }
std::string_view getProcessName() const override { return m_pname; }
const std::vector<std::string>& getArgs() const override { return m_args; }
std::shared_ptr<IWindow> m_mwret;
std::shared_ptr<IWindow> newWindow(std::string_view title) override {
if (GetCurrentThreadId() != g_mainThreadId) {
std::unique_lock<std::mutex> lk(g_nwmt);
if (!PostThreadMessageW(g_mainThreadId, WM_USER, WPARAM(&title), 0))
Log.report(logvisor::Fatal, FMT_STRING("PostThreadMessage error"));
g_nwcv.wait(lk);
std::shared_ptr<IWindow> ret = std::move(m_mwret);
m_mwret.reset();
return ret;
}
std::shared_ptr<IWindow> window = _WindowWin32New(title, m_3dCtx);
HWND hwnd = HWND(window->getPlatformHandle());
m_allWindows[hwnd] = window;
return window;
}
};
IApplication* APP = nullptr;
int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, std::string_view uniqueName,
std::string_view friendlyName, std::string_view pname, const std::vector<std::string>& args,
std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor,
bool singleInstance) {
std::string thrName = std::string(friendlyName) + " Main Thread";
logvisor::RegisterThreadName(thrName.c_str());
if (APP)
return 1;
if (platform != IApplication::EPlatformType::Win32 && platform != IApplication::EPlatformType::Auto)
return 1;
#if _WIN32_WINNT_WINBLUE
/* HI-DPI support */
HMODULE shcoreLib = LoadLibraryW(L"Shcore.dll");
if (shcoreLib)
MyGetScaleFactorForMonitor = (PFN_GetScaleFactorForMonitor)GetProcAddress(shcoreLib, "GetScaleFactorForMonitor");
#endif
WIN32_CURSORS.m_arrow = LoadCursor(nullptr, IDC_ARROW);
WIN32_CURSORS.m_weResize = LoadCursor(nullptr, IDC_SIZEWE);
WIN32_CURSORS.m_nsResize = LoadCursor(nullptr, IDC_SIZENS);
WIN32_CURSORS.m_ibeam = LoadCursor(nullptr, IDC_IBEAM);
WIN32_CURSORS.m_crosshairs = LoadCursor(nullptr, IDC_CROSS);
WIN32_CURSORS.m_wait = LoadCursor(nullptr, IDC_WAIT);
WIN32_CURSORS.m_nwseResize = LoadCursor(nullptr, IDC_SIZENWSE);
WIN32_CURSORS.m_neswResize = LoadCursor(nullptr, IDC_SIZENESW);
WIN32_CURSORS.m_hand = LoadCursor(nullptr, IDC_HAND);
WIN32_CURSORS.m_notAllowed = LoadCursor(nullptr, IDC_NO);
/* One class for *all* boo windows */
WNDCLASS wndClass = {0, WindowProc, 0, 0, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"BooWindow"};
wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101));
wndClass.hCursor = WIN32_CURSORS.m_arrow;
RegisterClassW(&wndClass);
APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
int ret = APP->run();
delete APP;
APP = nullptr;
return ret;
}
} // namespace boo
static const DEV_BROADCAST_DEVICEINTERFACE HOTPLUG_CONF = {sizeof(DEV_BROADCAST_DEVICEINTERFACE),
DBT_DEVTYP_DEVICEINTERFACE};
static bool HOTPLUG_REGISTERED = false;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (!HOTPLUG_REGISTERED && uMsg == WM_CREATE) {
/* Register hotplug notification with windows */
RegisterDeviceNotification(hwnd, (LPVOID)&HOTPLUG_CONF,
DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
HOTPLUG_REGISTERED = true;
}
return static_cast<boo::ApplicationWin32*>(boo::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam);
}

View File

@ -1,74 +0,0 @@
#pragma once
#include "lib/win/WinCommon.hpp"
struct Boo3DAppContextUWP : Boo3DAppContext {
bool isFullscreen(const boo::IWindow* window) {
#if _WIN32_WINNT_WIN10
if (m_ctx12.m_dev) {
D3D12Context::Window& win = m_ctx12.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
return isFScr != 0;
}
#endif
if (m_ctx11.m_dev) {
D3D11Context::Window& win = m_ctx11.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
return isFScr != 0;
}
return false;
}
bool setFullscreen(boo::IWindow* window, bool fs) {
#if _WIN32_WINNT_WIN10
if (m_ctx12.m_dev) {
D3D12Context::Window& win = m_ctx12.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
if (fs && isFScr)
return false;
else if (!fs && !isFScr)
return false;
if (fs) {
ComPtr<IDXGIOutput> out;
win.m_swapChain->GetContainingOutput(&out);
DXGI_OUTPUT_DESC outDesc;
out->GetDesc(&outDesc);
win.m_swapChain->SetFullscreenState(true, nullptr);
DXGI_MODE_DESC mdesc = {UINT(outDesc.DesktopCoordinates.right - outDesc.DesktopCoordinates.left),
UINT(outDesc.DesktopCoordinates.bottom - outDesc.DesktopCoordinates.top)};
win.m_swapChain->ResizeTarget(&mdesc);
} else
win.m_swapChain->SetFullscreenState(false, nullptr);
return true;
}
#endif
if (m_ctx11.m_dev) {
D3D11Context::Window& win = m_ctx11.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
if (fs && isFScr)
return false;
else if (!fs && !isFScr)
return false;
if (fs) {
ComPtr<IDXGIOutput> out;
win.m_swapChain->GetContainingOutput(&out);
DXGI_OUTPUT_DESC outDesc;
out->GetDesc(&outDesc);
win.m_fsdesc.Width = outDesc.DesktopCoordinates.right;
win.m_fsdesc.Height = outDesc.DesktopCoordinates.bottom;
}
win.m_fs = fs;
win.m_needsFSTransition = true;
return true;
}
return false;
}
};

View File

@ -1,162 +0,0 @@
#pragma once
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include "WinCommon.hpp"
#include <windows.h>
#if BOO_HAS_VULKAN
#include "boo/graphicsdev/Vulkan.hpp"
#endif
#if BOO_HAS_GL
#include "boo/graphicsdev/GL.hpp"
#endif
#include <condition_variable>
#include <mutex>
extern DWORD g_mainThreadId;
extern std::mutex g_nwmt;
extern std::condition_variable g_nwcv;
#if _WIN32_WINNT_WINBLUE && !WINDOWS_STORE
#include <ShellScalingApi.h>
using PFN_GetScaleFactorForMonitor = HRESULT(WINAPI*)(_In_ HMONITOR, _Out_ DEVICE_SCALE_FACTOR*);
extern PFN_GetScaleFactorForMonitor MyGetScaleFactorForMonitor;
#endif
struct OGLContext {
ComPtr<IDXGIFactory1> m_dxFactory;
HGLRC m_lastContext = nullptr;
struct Window {
HWND m_hwnd;
HDC m_deviceContext;
HGLRC m_mainContext;
HGLRC m_renderContext;
bool m_needsResize = false;
size_t width, height;
bool m_fs = false;
LONG_PTR m_fsStyle;
LONG_PTR m_fsExStyle;
RECT m_fsRect;
int m_fsCountDown = 0;
};
std::unordered_map<const boo::IWindow*, Window> m_windows;
#if BOO_HAS_GL
boo::GLContext m_glCtx;
#endif
};
#if !WINDOWS_STORE
static inline void SetFullscreen(OGLContext::Window& win, bool fs) {
std::unique_lock<std::mutex> lk(g_nwmt);
PostThreadMessageW(g_mainThreadId, WM_USER + 5, WPARAM(&win), LPARAM(fs));
g_nwcv.wait(lk);
}
#if BOO_HAS_VULKAN
static inline void SetFullscreen(boo::VulkanContext::Window& win, bool fs) {
std::unique_lock<std::mutex> lk(g_nwmt);
PostThreadMessageW(g_mainThreadId, WM_USER + 6, WPARAM(&win), LPARAM(fs));
g_nwcv.wait(lk);
}
#endif
#endif
struct Boo3DAppContextWin32 : Boo3DAppContext {
OGLContext m_ctxOgl;
ComPtr<IDXGIFactory1> m_vulkanDxFactory;
bool isFullscreen(const boo::IWindow* window) {
#if BOO_HAS_VULKAN
if (m_vulkanDxFactory) {
boo::VulkanContext::Window& win = *boo::g_VulkanContext.m_windows[window];
return win.m_fs;
}
#endif
if (m_ctx11.m_dev) {
D3D11Context::Window& win = m_ctx11.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
return isFScr != 0;
}
OGLContext::Window& win = m_ctxOgl.m_windows[window];
return win.m_fs;
}
bool setFullscreen(boo::IWindow* window, bool fs) {
#if BOO_HAS_VULKAN
if (m_vulkanDxFactory) {
boo::VulkanContext::Window& win = *boo::g_VulkanContext.m_windows[window];
if (fs && win.m_fs)
return false;
else if (!fs && !win.m_fs)
return false;
SetFullscreen(win, fs);
return true;
}
#endif
if (m_ctx11.m_dev) {
D3D11Context::Window& win = m_ctx11.m_windows[window];
BOOL isFScr;
win.m_swapChain->GetFullscreenState(&isFScr, nullptr);
if (fs && isFScr)
return false;
else if (!fs && !isFScr)
return false;
if (fs) {
ComPtr<IDXGIOutput> out;
win.m_swapChain->GetContainingOutput(&out);
DXGI_OUTPUT_DESC outDesc;
out->GetDesc(&outDesc);
win.m_fsdesc.Width = outDesc.DesktopCoordinates.right;
win.m_fsdesc.Height = outDesc.DesktopCoordinates.bottom;
}
win.m_fs = fs;
win.m_needsFSTransition = true;
return true;
}
#if !WINDOWS_STORE
OGLContext::Window& win = m_ctxOgl.m_windows[window];
if (fs && win.m_fs)
return false;
else if (!fs && !win.m_fs)
return false;
SetFullscreen(win, fs);
#endif
return true;
}
};
struct HWNDEvent {
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
HWNDEvent(UINT m, WPARAM w, LPARAM l) : uMsg(m), wParam(w), lParam(l) {}
};
struct Win32Cursors {
HCURSOR m_arrow;
HCURSOR m_weResize;
HCURSOR m_nsResize;
HCURSOR m_ibeam;
HCURSOR m_crosshairs;
HCURSOR m_wait;
HCURSOR m_nwseResize;
HCURSOR m_neswResize;
HCURSOR m_hand;
HCURSOR m_notAllowed;
};
namespace boo {
extern Win32Cursors WIN32_CURSORS;
}

View File

@ -1,117 +0,0 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <unordered_map>
#include "boo/IWindow.hpp"
namespace boo {
class IWindow;
} // namespace boo
#if _WIN32_WINNT_WIN10
#include <dxgi1_4.h>
#include <d3d12.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <wingdi.h>
#elif _WIN32_WINNT_WIN7
#include <dxgi1_2.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <wingdi.h>
#else
#error Unsupported Windows target
#endif
#include <d3d9.h>
using pD3DPERF_BeginEvent = int (WINAPI*)(D3DCOLOR col, LPCWSTR wszName);
using pD3DPERF_EndEvent = int (WINAPI*)();
struct D3D12Context {
ComPtr<IDXGIFactory2> m_dxFactory;
ComPtr<ID3D12Device> m_dev;
ComPtr<ID3D12CommandAllocator> m_qalloc[2];
ComPtr<ID3D12CommandQueue> m_q;
ComPtr<ID3D12CommandAllocator> m_loadqalloc;
ComPtr<ID3D12CommandQueue> m_loadq;
ComPtr<ID3D12Fence> m_loadfence;
UINT64 m_loadfenceval = 0;
HANDLE m_loadfencehandle;
ComPtr<ID3D12GraphicsCommandList> m_loadlist;
ComPtr<ID3D12RootSignature> m_rs;
struct Window {
ComPtr<IDXGISwapChain3> m_swapChain;
std::unordered_map<ID3D12Resource*, ComPtr<ID3D12DescriptorHeap>> m_rtvHeaps;
UINT m_backBuf = 0;
bool m_needsResize = false;
size_t width, height;
};
std::unordered_map<const boo::IWindow*, Window> m_windows;
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
struct RGBATex2DFBViewDesc : D3D12_SHADER_RESOURCE_VIEW_DESC {
RGBATex2DFBViewDesc() {
Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
Texture2D = {UINT(0), UINT(1), UINT(0), 0.0f};
}
} RGBATex2DFBViewDesc;
};
struct D3D11Context {
ComPtr<IDXGIFactory2> m_dxFactory;
ComPtr<ID3D11Device1> m_dev;
ComPtr<ID3D11DeviceContext1> m_devCtx;
ComPtr<ID3D11SamplerState> m_ss[5];
struct Window {
ComPtr<IDXGISwapChain1> m_swapChain;
ComPtr<ID3D11Texture2D> m_swapChainTex;
ComPtr<ID3D11RenderTargetView> m_swapChainRTV;
bool m_needsResize = false;
size_t width, height;
bool m_needsFSTransition = false;
bool m_fs = false;
DXGI_MODE_DESC m_fsdesc = {};
void clearRTV() {
m_swapChainTex.Reset();
m_swapChainRTV.Reset();
}
void setupRTV(ComPtr<IDXGISwapChain1>& sc, ID3D11Device* dev) {
m_swapChain = sc;
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &m_swapChainTex);
D3D11_TEXTURE2D_DESC resDesc;
m_swapChainTex->GetDesc(&resDesc);
width = resDesc.Width;
height = resDesc.Height;
CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D, resDesc.Format);
dev->CreateRenderTargetView(m_swapChainTex.Get(), &rtvDesc, &m_swapChainRTV);
}
};
std::unordered_map<const boo::IWindow*, Window> m_windows;
uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1;
DXGI_FORMAT m_fbFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
};
struct Boo3DAppContext {
D3D11Context m_ctx11;
void resize(boo::IWindow* window, size_t width, size_t height) {
D3D11Context::Window& win = m_ctx11.m_windows[window];
win.width = width;
win.height = height;
win.m_needsResize = true;
}
};

View File

@ -1,500 +0,0 @@
#include "lib/win/UWPCommon.hpp"
#include "boo/IApplication.hpp"
#include "boo/IGraphicsContext.hpp"
#include "boo/IWindow.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp"
#include "boo/graphicsdev/D3D.hpp"
#include <logvisor/logvisor.hpp>
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::ViewManagement;
using namespace Windows::System;
using namespace Windows::Graphics::Display;
using namespace Windows::Foundation;
using namespace Platform;
#include <agile.h>
namespace boo {
static logvisor::Module Log("boo::WindowWin32");
#if _WIN32_WINNT_WIN10
IGraphicsCommandQueue* _NewD3D12CommandQueue(D3D12Context* ctx, D3D12Context::Window* windowCtx,
IGraphicsContext* parent, ID3D12CommandQueue** cmdQueueOut);
IGraphicsDataFactory* _NewD3D12DataFactory(D3D12Context* ctx, IGraphicsContext* parent, uint32_t sampleCount);
#endif
IGraphicsCommandQueue* _NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx,
IGraphicsContext* parent);
IGraphicsDataFactory* _NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent, uint32_t sampleCount);
struct GraphicsContextUWP : IGraphicsContext {
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
Boo3DAppContextUWP& m_3dCtx;
ComPtr<IDXGIOutput> m_output;
GraphicsContextUWP(EGraphicsAPI api, IWindow* parentWindow, Boo3DAppContextUWP& b3dCtx)
: m_api(api), m_pf(EPixelFormat::RGBA8), m_parentWindow(parentWindow), m_3dCtx(b3dCtx) {}
virtual void resized(const SWindowRect& rect) { m_3dCtx.resize(m_parentWindow, rect.size[0], rect.size[1]); }
};
struct GraphicsContextUWPD3D : GraphicsContextUWP {
ComPtr<IDXGISwapChain1> m_swapChain;
IGraphicsCommandQueue* m_commandQueue = nullptr;
IGraphicsDataFactory* m_dataFactory = nullptr;
public:
IWindowCallback* m_callback;
GraphicsContextUWPD3D(EGraphicsAPI api, IWindow* parentWindow, Agile<CoreWindow>& coreWindow,
Boo3DAppContextUWP& b3dCtx)
: GraphicsContextUWP(api, parentWindow, b3dCtx) {
/* Create Swap Chain */
DXGI_SWAP_CHAIN_DESC1 scDesc = {};
scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scDesc.SampleDesc.Count = 1;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.BufferCount = 2;
#if !WINDOWS_STORE
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
#else
scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
#endif
scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
IUnknown* cw = reinterpret_cast<IUnknown*>(coreWindow.Get());
#if _WIN32_WINNT_WIN10
if (b3dCtx.m_ctx12.m_dev) {
auto insIt = b3dCtx.m_ctx12.m_windows.emplace(std::make_pair(parentWindow, D3D12Context::Window()));
D3D12Context::Window& w = insIt.first->second;
ID3D12CommandQueue* cmdQueue;
m_dataFactory = _NewD3D12DataFactory(&b3dCtx.m_ctx12, this);
m_commandQueue = _NewD3D12CommandQueue(&b3dCtx.m_ctx12, &w, this, &cmdQueue);
scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
HRESULT hr =
b3dCtx.m_ctx12.m_dxFactory->CreateSwapChainForCoreWindow(cmdQueue, cw, &scDesc, nullptr, &m_swapChain);
if (FAILED(hr))
Log.report(logvisor::Fatal, FMT_STRING("unable to create swap chain"));
m_swapChain.As<IDXGISwapChain3>(&w.m_swapChain);
ComPtr<ID3D12Resource> fb;
m_swapChain->GetBuffer(0, __uuidof(ID3D12Resource), &fb);
w.m_backBuf = w.m_swapChain->GetCurrentBackBufferIndex();
D3D12_RESOURCE_DESC resDesc = fb->GetDesc();
w.width = resDesc.Width;
w.height = resDesc.Height;
if (FAILED(m_swapChain->GetContainingOutput(&m_output)))
Log.report(logvisor::Fatal, FMT_STRING("unable to get DXGI output"));
} else
#endif
{
if (FAILED(b3dCtx.m_ctx11.m_dxFactory->CreateSwapChainForCoreWindow(b3dCtx.m_ctx11.m_dev.Get(), cw, &scDesc,
nullptr, &m_swapChain)))
Log.report(logvisor::Fatal, FMT_STRING("unable to create swap chain"));
auto insIt = b3dCtx.m_ctx11.m_windows.emplace(std::make_pair(parentWindow, D3D11Context::Window()));
D3D11Context::Window& w = insIt.first->second;
m_swapChain.As<IDXGISwapChain1>(&w.m_swapChain);
ComPtr<ID3D11Texture2D> fbRes;
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &fbRes);
D3D11_TEXTURE2D_DESC resDesc;
fbRes->GetDesc(&resDesc);
w.width = resDesc.Width;
w.height = resDesc.Height;
m_dataFactory = _NewD3D11DataFactory(&b3dCtx.m_ctx11, this);
m_commandQueue = _NewD3D11CommandQueue(&b3dCtx.m_ctx11, &insIt.first->second, this);
if (FAILED(m_swapChain->GetContainingOutput(&m_output)))
Log.report(logvisor::Fatal, FMT_STRING("unable to get DXGI output"));
}
}
~GraphicsContextUWPD3D() override {
#if _WIN32_WINNT_WIN10
if (m_3dCtx.m_ctx12.m_dev)
m_3dCtx.m_ctx12.m_windows.erase(m_parentWindow);
else
#endif
m_3dCtx.m_ctx11.m_windows.erase(m_parentWindow);
}
void _setCallback(IWindowCallback* cb) override { m_callback = cb; }
EGraphicsAPI getAPI() const override { return m_api; }
EPixelFormat getPixelFormat() const override { return m_pf; }
void setPixelFormat(EPixelFormat pf) override {
if (pf > EPixelFormat::RGBAF32_Z24)
return;
m_pf = pf;
}
bool initializeContext(void*) override { return true; }
void makeCurrent() override {}
void postInit() override {}
void present() override {}
IGraphicsCommandQueue* getCommandQueue() override { return m_commandQueue; }
IGraphicsDataFactory* getDataFactory() override { return m_dataFactory; }
IGraphicsDataFactory* getMainContextDataFactory() override { return m_dataFactory; }
IGraphicsDataFactory* getLoadContextDataFactory() override { return m_dataFactory; }
};
static uint32_t translateKeysym(CoreWindow ^ window, VirtualKey sym, ESpecialKey& specialSym,
EModifierKey& modifierSym) {
specialSym = ESpecialKey::None;
modifierSym = EModifierKey::None;
if (sym >= VirtualKey::F1 && sym <= VirtualKey::F12)
specialSym = ESpecialKey(uint32_t(ESpecialKey::F1) + uint32_t(sym - VirtualKey::F1));
else if (sym == VirtualKey::Escape)
specialSym = ESpecialKey::Esc;
else if (sym == VirtualKey::Enter)
specialSym = ESpecialKey::Enter;
else if (sym == VirtualKey::Back)
specialSym = ESpecialKey::Backspace;
else if (sym == VirtualKey::Insert)
specialSym = ESpecialKey::Insert;
else if (sym == VirtualKey::Delete)
specialSym = ESpecialKey::Delete;
else if (sym == VirtualKey::Home)
specialSym = ESpecialKey::Home;
else if (sym == VirtualKey::End)
specialSym = ESpecialKey::End;
else if (sym == VirtualKey::PageUp)
specialSym = ESpecialKey::PgUp;
else if (sym == VirtualKey::PageDown)
specialSym = ESpecialKey::PgDown;
else if (sym == VirtualKey::Left)
specialSym = ESpecialKey::Left;
else if (sym == VirtualKey::Right)
specialSym = ESpecialKey::Right;
else if (sym == VirtualKey::Up)
specialSym = ESpecialKey::Up;
else if (sym == VirtualKey::Down)
specialSym = ESpecialKey::Down;
else if (sym == VirtualKey::Tab)
specialSym = ESpecialKey::Tab;
else if (sym == VirtualKey::Shift)
modifierSym = EModifierKey::Shift;
else if (sym == VirtualKey::Control)
modifierSym = EModifierKey::Ctrl;
else if (sym == VirtualKey::Menu)
modifierSym = EModifierKey::Alt;
else if (sym >= VirtualKey::A && sym <= VirtualKey::Z)
return uint32_t(sym - VirtualKey::A) + (window->GetKeyState(VirtualKey::Shift) != CoreVirtualKeyStates::None) ? 'A'
: 'a';
return 0;
}
static EModifierKey translateModifiers(CoreWindow ^ window) {
EModifierKey retval = EModifierKey::None;
if (window->GetKeyState(VirtualKey::Shift) != CoreVirtualKeyStates::None)
retval |= EModifierKey::Shift;
if (window->GetKeyState(VirtualKey::Control) != CoreVirtualKeyStates::None)
retval |= EModifierKey::Ctrl;
if (window->GetKeyState(VirtualKey::Menu) != CoreVirtualKeyStates::None)
retval |= EModifierKey::Alt;
return retval;
}
class WindowUWP : public IWindow {
friend struct GraphicsContextUWP;
ApplicationView ^ m_appView = ApplicationView::GetForCurrentView();
Platform::Agile<CoreWindow> m_coreWindow;
Rect m_bounds;
float m_dispInfoDpiFactor = 1.f;
std::unique_ptr<GraphicsContextUWP> m_gfxCtx;
IWindowCallback* m_callback = nullptr;
public:
ref struct EventReceiver sealed {
void OnKeyDown(CoreWindow ^ window, KeyEventArgs ^ keyEventArgs) { w.OnKeyDown(window, keyEventArgs); }
void OnKeyUp(CoreWindow ^ window, KeyEventArgs ^ keyEventArgs) { w.OnKeyUp(window, keyEventArgs); }
void OnPointerEntered(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerEntered(window, args); }
void OnPointerExited(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerExited(window, args); }
void OnPointerMoved(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerMoved(window, args); }
void OnPointerPressed(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerPressed(window, args); }
void OnPointerReleased(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerReleased(window, args); }
void OnPointerWheelChanged(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerWheelChanged(window, args); }
void OnClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ args) { w.OnClosed(sender, args); }
void SizeChanged(CoreWindow ^ window, WindowSizeChangedEventArgs ^) {
w.m_bounds = window->Bounds;
w._resized();
}
void DisplayInfoChanged(DisplayInformation ^ di, Object ^) {
w.m_dispInfoDpiFactor = di->LogicalDpi / 96.f;
w._resized();
}
internal : WindowUWP& w;
EventReceiver(WindowUWP& w) : w(w) {
w.m_coreWindow->KeyDown +=
ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &EventReceiver::OnKeyDown);
w.m_coreWindow->KeyUp += ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &EventReceiver::OnKeyUp);
w.m_coreWindow->PointerEntered +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerEntered);
w.m_coreWindow->PointerExited +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerExited);
w.m_coreWindow->PointerMoved +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerMoved);
w.m_coreWindow->PointerPressed +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerPressed);
w.m_coreWindow->PointerReleased +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerReleased);
w.m_coreWindow->PointerWheelChanged +=
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &EventReceiver::OnPointerWheelChanged);
w.m_coreWindow->Closed +=
ref new TypedEventHandler<CoreWindow ^, CoreWindowEventArgs ^>(this, &EventReceiver::OnClosed);
w.m_coreWindow->SizeChanged +=
ref new TypedEventHandler<CoreWindow ^, WindowSizeChangedEventArgs ^>(this, &EventReceiver::SizeChanged);
DisplayInformation::GetForCurrentView()->DpiChanged +=
ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &EventReceiver::DisplayInfoChanged);
}
};
EventReceiver ^ m_eventReceiver;
WindowUWP(std::string_view title, Boo3DAppContextUWP& b3dCtx)
: m_coreWindow(CoreWindow::GetForCurrentThread()), m_eventReceiver(ref new EventReceiver(*this)) {
IGraphicsContext::EGraphicsAPI api = IGraphicsContext::EGraphicsAPI::D3D11;
#if _WIN32_WINNT_WIN10
if (b3dCtx.m_ctx12.m_dev)
api = IGraphicsContext::EGraphicsAPI::D3D12;
#endif
m_gfxCtx.reset(new GraphicsContextUWPD3D(api, this, m_coreWindow, b3dCtx));
setTitle(title);
m_bounds = m_coreWindow->Bounds;
m_dispInfoDpiFactor = DisplayInformation::GetForCurrentView()->LogicalDpi / 96.f;
if (auto titleBar = ApplicationView::GetForCurrentView()->TitleBar) {
Color grey = {0xFF, 0x33, 0x33, 0x33};
Color transWhite = {0xFF, 0x88, 0x88, 0x88};
titleBar->ButtonBackgroundColor = grey;
titleBar->ButtonForegroundColor = Colors::White;
titleBar->BackgroundColor = grey;
titleBar->ForegroundColor = Colors::White;
titleBar->ButtonInactiveBackgroundColor = grey;
titleBar->ButtonInactiveForegroundColor = transWhite;
titleBar->InactiveBackgroundColor = grey;
titleBar->InactiveForegroundColor = transWhite;
}
}
~WindowUWP() override = default;
void setCallback(IWindowCallback* cb) override { m_callback = cb; }
void closeWindow() override { m_coreWindow->Close(); }
void showWindow() override {}
void hideWindow() override {}
std::string getTitle() override { return std::string(m_appView->Title->Data()); }
void setTitle(std::string_view title) override { m_appView->Title = ref new Platform::String(title.data()); }
void setCursor(EMouseCursor cursor) override {}
void setWaitCursor(bool wait) override {}
double getWindowRefreshRate() const {
/* TODO: Actually get refresh rate */
return 60.0;
}
void setWindowFrameDefault() override {}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const override {
xOut = m_bounds.X * m_dispInfoDpiFactor;
yOut = m_bounds.Y * m_dispInfoDpiFactor;
wOut = m_bounds.Width * m_dispInfoDpiFactor;
hOut = m_bounds.Height * m_dispInfoDpiFactor;
}
void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const override {
xOut = m_bounds.X * m_dispInfoDpiFactor;
yOut = m_bounds.Y * m_dispInfoDpiFactor;
wOut = m_bounds.Width * m_dispInfoDpiFactor;
hOut = m_bounds.Height * m_dispInfoDpiFactor;
}
void setWindowFrame(float x, float y, float w, float h) override {}
void setWindowFrame(int x, int y, int w, int h) override {}
float getVirtualPixelFactor() const override { return m_dispInfoDpiFactor; }
bool isFullscreen() const override { return ApplicationView::GetForCurrentView()->IsFullScreenMode; }
void setFullscreen(bool fs) override {
if (fs)
ApplicationView::GetForCurrentView()->TryEnterFullScreenMode();
else
ApplicationView::GetForCurrentView()->ExitFullScreenMode();
}
void claimKeyboardFocus(const int coord[2]) override {}
bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) override { return false; }
std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz) override {
return std::unique_ptr<uint8_t[]>();
}
int waitForRetrace(IAudioVoiceEngine* engine) override {
if (engine)
engine->pumpAndMixVoices();
m_gfxCtx->m_output->WaitForVBlank();
return 1;
}
uintptr_t getPlatformHandle() const override { return 0; }
bool _incomingEvent(void* ev) override { return false; }
void OnKeyDown(CoreWindow ^ window, KeyEventArgs ^ keyEventArgs) {
ESpecialKey specialKey;
EModifierKey modifierKey;
uint32_t charCode = translateKeysym(m_coreWindow.Get(), keyEventArgs->VirtualKey, specialKey, modifierKey);
EModifierKey modifierMask = translateModifiers(window);
bool repeat = keyEventArgs->KeyStatus.RepeatCount > 1;
if (charCode)
m_callback->charKeyDown(charCode, modifierMask, repeat);
else if (specialKey != ESpecialKey::None)
m_callback->specialKeyDown(specialKey, modifierMask, repeat);
else if (modifierKey != EModifierKey::None)
m_callback->modKeyDown(modifierKey, repeat);
}
void OnKeyUp(CoreWindow ^ window, KeyEventArgs ^ keyEventArgs) {
ESpecialKey specialKey;
EModifierKey modifierKey;
uint32_t charCode = translateKeysym(m_coreWindow.Get(), keyEventArgs->VirtualKey, specialKey, modifierKey);
EModifierKey modifierMask = translateModifiers(window);
if (charCode)
m_callback->charKeyUp(charCode, modifierMask);
else if (specialKey != ESpecialKey::None)
m_callback->specialKeyUp(specialKey, modifierMask);
else if (modifierKey != EModifierKey::None)
m_callback->modKeyUp(modifierKey);
}
SWindowCoord GetCursorCoords(const Point& point) {
SWindowCoord coord = {point.X * m_dispInfoDpiFactor,
(m_bounds.Height - point.Y) * m_dispInfoDpiFactor,
point.X,
m_bounds.Height - point.Y,
point.X / m_bounds.Width,
(m_bounds.Height - point.Y) / m_bounds.Height};
return coord;
}
void OnPointerEntered(CoreWindow ^ window, PointerEventArgs ^ args) {
m_callback->mouseEnter(GetCursorCoords(args->CurrentPoint->Position));
}
void OnPointerExited(CoreWindow ^ window, PointerEventArgs ^ args) {
m_callback->mouseLeave(GetCursorCoords(args->CurrentPoint->Position));
}
void OnPointerMoved(CoreWindow ^ window, PointerEventArgs ^ args) {
m_callback->mouseMove(GetCursorCoords(args->CurrentPoint->Position));
}
boo::EMouseButton m_pressedButton = boo::EMouseButton::None;
void OnPointerPressed(CoreWindow ^ window, PointerEventArgs ^ args) {
auto properties = args->CurrentPoint->Properties;
boo::EMouseButton button = boo::EMouseButton::None;
if (properties->IsLeftButtonPressed)
button = boo::EMouseButton::Primary;
else if (properties->IsMiddleButtonPressed)
button = boo::EMouseButton::Middle;
else if (properties->IsRightButtonPressed)
button = boo::EMouseButton::Secondary;
else if (properties->IsXButton1Pressed)
button = boo::EMouseButton::Aux1;
else if (properties->IsXButton2Pressed)
button = boo::EMouseButton::Aux2;
m_callback->mouseDown(GetCursorCoords(args->CurrentPoint->Position), button,
translateModifiers(m_coreWindow.Get()));
m_pressedButton = button;
}
void OnPointerReleased(CoreWindow ^ window, PointerEventArgs ^ args) {
auto properties = args->CurrentPoint->Properties;
m_callback->mouseUp(GetCursorCoords(args->CurrentPoint->Position), m_pressedButton,
translateModifiers(m_coreWindow.Get()));
}
void OnPointerWheelChanged(CoreWindow ^ window, PointerEventArgs ^ args) {
auto properties = args->CurrentPoint->Properties;
SScrollDelta scroll = {};
scroll.delta[1] = properties->MouseWheelDelta / double(WHEEL_DELTA);
m_callback->scroll(GetCursorCoords(args->CurrentPoint->Position), scroll);
}
void OnClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ args) {
if (m_callback)
m_callback->destroyed();
}
void _resized() {
boo::SWindowRect rect(m_bounds.X * m_dispInfoDpiFactor, m_bounds.Y * m_dispInfoDpiFactor,
m_bounds.Width * m_dispInfoDpiFactor, m_bounds.Height * m_dispInfoDpiFactor);
m_gfxCtx->resized(rect);
if (m_callback)
m_callback->resized(rect, false);
}
ETouchType getTouchType() const override { return ETouchType::None; }
void setStyle(EWindowStyle style) override {}
EWindowStyle getStyle() const override {
EWindowStyle retval = EWindowStyle::None;
return retval;
}
IGraphicsCommandQueue* getCommandQueue() override { return m_gfxCtx->getCommandQueue(); }
IGraphicsDataFactory* getDataFactory() override { return m_gfxCtx->getDataFactory(); }
/* Creates a new context on current thread!! Call from main client thread */
IGraphicsDataFactory* getMainContextDataFactory() override { return m_gfxCtx->getMainContextDataFactory(); }
/* Creates a new context on current thread!! Call from client loading thread */
IGraphicsDataFactory* getLoadContextDataFactory() override { return m_gfxCtx->getLoadContextDataFactory(); }
};
std::shared_ptr<IWindow> _WindowUWPNew(std::string_view title, Boo3DAppContextUWP& d3dCtx) {
return std::make_shared<WindowUWP>(title, d3dCtx);
}
} // namespace boo

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
/* Meta-implementation for dynamically-constructing user's preferred
* platform interface
*/
#define APPLICATION_UNIX_CPP
#include <cstdint>
#include <cstdlib>
#include "boo/IApplication.hpp"
#include <dbus/dbus.h>
#include <logvisor/logvisor.hpp>
#include <unistd.h>
namespace boo {
static logvisor::Module Log("boo::ApplicationUnix");
IApplication* APP = nullptr;
class ScreenSaverInhibitor {
DBusConnection* m_dbus;
uint64_t m_wid;
DBusPendingCall* m_pending = nullptr;
uint32_t m_cookie = UINT32_MAX;
static void Callback(DBusPendingCall* pending, ScreenSaverInhibitor* user_data) {
user_data->HandleReply();
}
void HandleReply() {
DBusMessage* msg = nullptr;
DBusError err = DBUS_ERROR_INIT;
if ((msg = dbus_pending_call_steal_reply(m_pending)) &&
dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &m_cookie, DBUS_TYPE_INVALID)) {
Log.report(logvisor::Info, FMT_STRING("Screen saver inhibited"));
} else {
/* Fallback to xdg-screensaver */
dbus_error_free(&err);
Log.report(logvisor::Info, FMT_STRING("Falling back to xdg-screensaver inhibit"));
if (!fork()) {
execlp("xdg-screensaver", "xdg-screensaver", "suspend", fmt::format(FMT_STRING("0x{:X}"), m_wid).c_str(), nullptr);
exit(1);
}
}
if (msg)
dbus_message_unref(msg);
dbus_pending_call_unref(m_pending);
m_pending = nullptr;
}
public:
ScreenSaverInhibitor(DBusConnection* dbus, uint64_t wid) : m_dbus(dbus), m_wid(wid) {
#ifndef BOO_MSAN
DBusMessage* msg =
dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver", "Inhibit");
const char* appName = APP->getUniqueName().data();
const char* reason = "Game Active";
dbus_message_append_args(msg, DBUS_TYPE_STRING, &appName, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
dbus_connection_send_with_reply(m_dbus, msg, &m_pending, -1);
dbus_pending_call_set_notify(m_pending, DBusPendingCallNotifyFunction(Callback), this, nullptr);
dbus_message_unref(msg);
dbus_connection_flush(m_dbus);
#endif
}
~ScreenSaverInhibitor() {
#ifndef BOO_MSAN
if (m_cookie != UINT32_MAX) {
DBusMessage* msg =
dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver", "UnInhibit");
dbus_message_append_args(msg, DBUS_TYPE_UINT32, &m_cookie, DBUS_TYPE_INVALID);
dbus_connection_send(m_dbus, msg, nullptr);
dbus_message_unref(msg);
dbus_connection_flush(m_dbus);
}
#endif
}
};
}
#include "ApplicationXlib.hpp"
#include "ApplicationWayland.hpp"
#include <memory>
#include <cstdio>
/* No icon by default */
extern "C" const uint8_t MAINICON_NETWM[] __attribute__((weak)) = {};
extern "C" const size_t MAINICON_NETWM_SZ __attribute__((weak)) = 0;
DBusConnection* RegisterDBus(const char* appName, bool& isFirst) {
isFirst = true;
DBusError err = {};
dbus_error_init(&err);
/* connect to the bus and check for errors */
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
fmt::print(stderr, FMT_STRING("DBus Connection Error ({})\n"), err.message);
dbus_error_free(&err);
}
if (conn == nullptr)
return nullptr;
/* request our name on the bus and check for errors */
int ret = dbus_bus_request_name(conn, fmt::format(FMT_STRING("boo.{}.unique"), appName).c_str(),
DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
if (dbus_error_is_set(&err)) {
fmt::print(stderr, FMT_STRING("DBus Name Error ({})\n"), err.message);
dbus_error_free(&err);
dbus_connection_close(conn);
return nullptr;
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
isFirst = false;
return conn;
}
namespace boo {
int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, std::string_view uniqueName,
std::string_view friendlyName, std::string_view pname, const std::vector<std::string>& args,
std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor,
bool singleInstance) {
std::string thrName = std::string(friendlyName) + " Main";
logvisor::RegisterThreadName(thrName.c_str());
if (APP)
return 1;
if (platform == IApplication::EPlatformType::Wayland)
APP = new ApplicationWayland(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
else if (platform == IApplication::EPlatformType::Xlib || platform == IApplication::EPlatformType::Auto)
APP = new ApplicationXlib(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
singleInstance);
else
return 1;
int ret = APP->run();
delete APP;
APP = nullptr;
return ret;
}
} // namespace boo

View File

@ -1,53 +0,0 @@
#ifndef APPLICATION_UNIX_CPP
#error This file may only be included from CApplicationUnix.cpp
#endif
#include "boo/IApplication.hpp"
#include <dbus/dbus.h>
DBusConnection* RegisterDBus(const char* appName, bool& isFirst);
namespace boo {
std::shared_ptr<IWindow> _WindowWaylandNew(std::string_view title);
class ApplicationWayland final : public IApplication {
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
bool m_singleInstance;
void _deletedWindow([[maybe_unused]] IWindow* window) override {}
public:
ApplicationWayland(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, const std::vector<std::string>& args, std::string_view gfxApi,
uint32_t samples, uint32_t anisotropy, bool deepColor, bool singleInstance)
: m_callback(callback)
, m_uniqueName(uniqueName)
, m_friendlyName(friendlyName)
, m_pname(pname)
, m_args(args)
, m_singleInstance(singleInstance) {
(void)m_callback;
(void)m_singleInstance;
}
EPlatformType getPlatformType() const override { return EPlatformType::Wayland; }
int run() override { return 0; }
std::string_view getUniqueName() const override { return m_uniqueName; }
std::string_view getFriendlyName() const override { return m_friendlyName; }
std::string_view getProcessName() const override { return m_pname; }
const std::vector<std::string>& getArgs() const override { return m_args; }
std::shared_ptr<IWindow> newWindow(std::string_view title) override { return _WindowWaylandNew(title); }
};
} // namespace boo

View File

@ -1,559 +0,0 @@
#ifndef APPLICATION_UNIX_CPP
#error This file may only be included from ApplicationUnix.cpp
#endif
#include "boo/IApplication.hpp"
#include "boo/graphicsdev/GL.hpp"
#include "lib/Common.hpp"
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h>
#include <GL/glx.h>
#include <GL/glxext.h>
#include <dbus/dbus.h>
DBusConnection* RegisterDBus(const char* appName, bool& isFirst);
#include <clocale>
#include <condition_variable>
#include <csignal>
#include <locale>
#include <mutex>
#include <sys/param.h>
#include <thread>
#include <optional>
#include "XlibCommon.hpp"
#include <X11/cursorfont.h>
#if BOO_HAS_VULKAN
#include <X11/Xlib-xcb.h>
#include <vulkan/vulkan.h>
#include <dlfcn.h>
#include "boo/graphicsdev/Vulkan.hpp"
#endif
namespace boo {
XlibCursors X_CURSORS;
int XINPUT_OPCODE = 0;
static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) {
switch (event->type) {
case SelectionRequest: {
windowEvent = true;
return event->xselectionrequest.owner;
}
case ClientMessage: {
windowEvent = true;
return event->xclient.window;
}
case Expose: {
windowEvent = true;
return event->xexpose.window;
}
case ConfigureNotify: {
windowEvent = true;
return event->xconfigure.window;
}
case KeyPress:
case KeyRelease: {
windowEvent = true;
return event->xkey.window;
}
case ButtonPress:
case ButtonRelease: {
windowEvent = true;
return event->xbutton.window;
}
case MotionNotify: {
windowEvent = true;
return event->xmotion.window;
}
case EnterNotify:
case LeaveNotify: {
windowEvent = true;
return event->xcrossing.window;
}
case FocusIn:
case FocusOut: {
windowEvent = true;
return event->xfocus.window;
}
case GenericEvent: {
if (event->xgeneric.extension == XINPUT_OPCODE) {
switch (event->xgeneric.evtype) {
case XI_Motion:
case XI_TouchBegin:
case XI_TouchUpdate:
case XI_TouchEnd: {
XIDeviceEvent* ev = (XIDeviceEvent*)event;
windowEvent = true;
return ev->event;
}
}
}
}
}
windowEvent = false;
return 0;
}
std::shared_ptr<IWindow> _WindowXlibNew(std::string_view title, Display* display, void* xcbConn, int defaultScreen,
XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, GLXContext lastCtx,
void* vulkanHandle, GLContext* glCtx);
static XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2) {
XIMStyle s, t;
XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
XIMStyle status = XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone;
if (style1 == 0)
return style2;
if (style2 == 0)
return style1;
if ((style1 & (preedit | status)) == (style2 & (preedit | status)))
return style1;
s = style1 & preedit;
t = style2 & preedit;
if (s != t) {
if (s | t | XIMPreeditCallbacks)
return (s == XIMPreeditCallbacks) ? style1 : style2;
else if (s | t | XIMPreeditPosition)
return (s == XIMPreeditPosition) ? style1 : style2;
else if (s | t | XIMPreeditArea)
return (s == XIMPreeditArea) ? style1 : style2;
else if (s | t | XIMPreeditNothing)
return (s == XIMPreeditNothing) ? style1 : style2;
} else { /* if preedit flags are the same, compare status flags */
s = style1 & status;
t = style2 & status;
if (s | t | XIMStatusCallbacks)
return (s == XIMStatusCallbacks) ? style1 : style2;
else if (s | t | XIMStatusArea)
return (s == XIMStatusArea) ? style1 : style2;
else if (s | t | XIMStatusNothing)
return (s == XIMStatusNothing) ? style1 : style2;
}
return 0;
}
class ApplicationXlib final : public IApplication {
friend class ScreenSaverInhibitor;
IApplicationCallback& m_callback;
const std::string m_uniqueName;
const std::string m_friendlyName;
const std::string m_pname;
const std::vector<std::string> m_args;
GLContext m_glContext;
/* DBus single-instance */
bool m_singleInstance;
#ifndef BOO_MSAN
DBusConnection* m_dbus = nullptr;
#endif
/* All windows */
std::unordered_map<Window, std::weak_ptr<IWindow>> m_windows;
Display* m_xDisp = nullptr;
XIM m_xIM = nullptr;
XFontSet m_fontset = nullptr;
XIMStyle m_bestStyle = 0;
int m_xDefaultScreen = 0;
int m_x11Fd, m_dbusFd, m_maxFd;
#if BOO_HAS_VULKAN
/* Vulkan enable */
xcb_connection_t* m_xcbConn;
void* m_vkHandle = nullptr;
PFN_vkGetInstanceProcAddr m_getVkProc = 0;
bool loadVk() {
const char filename[] = "libvulkan.so";
void *handle, *symbol;
#ifdef UNINSTALLED_LOADER
handle = dlopen(UNINSTALLED_LOADER, RTLD_LAZY);
if (!handle)
handle = dlopen(filename, RTLD_LAZY);
#else
handle = dlopen(filename, RTLD_LAZY);
#endif
if (handle)
symbol = dlsym(handle, "vkGetInstanceProcAddr");
if (!handle || !symbol) {
if (handle)
dlclose(handle);
return false;
}
m_vkHandle = handle;
m_getVkProc = reinterpret_cast<PFN_vkGetInstanceProcAddr>(symbol);
return true;
}
#endif
void _deletedWindow(IWindow* window) override { m_windows.erase((Window)window->getPlatformHandle()); }
public:
ApplicationXlib(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view pname, const std::vector<std::string>& args, std::string_view gfxApi,
uint32_t samples, uint32_t anisotropy, bool deepColor, bool singleInstance)
: m_callback(callback)
, m_uniqueName(uniqueName)
, m_friendlyName(friendlyName)
, m_pname(pname)
, m_args(args)
, m_singleInstance(singleInstance) {
m_glContext.m_sampleCount = samples;
m_glContext.m_anisotropy = anisotropy;
m_glContext.m_deepColor = deepColor;
#if BOO_HAS_VULKAN
g_VulkanContext.m_sampleCountColor = samples;
g_VulkanContext.m_sampleCountDepth = samples;
g_VulkanContext.m_anisotropy = anisotropy;
g_VulkanContext.m_deepColor = deepColor;
/* Check for Vulkan presence and preference */
bool tryVulkan = true;
if (gfxApi == "OpenGL")
tryVulkan = false;
for (const std::string& arg : args) {
if (arg == "--gl") {
tryVulkan = false;
break;
}
if (arg == "--vulkan") {
tryVulkan = true;
break;
}
}
if (tryVulkan)
loadVk();
if (m_getVkProc)
Log.report(logvisor::Info, FMT_STRING("using Vulkan renderer"));
else
#endif
Log.report(logvisor::Info, FMT_STRING("using OpenGL renderer"));
#ifndef BOO_MSAN
/* DBus single instance registration */
bool isFirst;
m_dbus = RegisterDBus(uniqueName.data(), isFirst);
if (m_singleInstance) {
if (!isFirst) {
/* This is a duplicate instance, send signal and return */
if (args.size()) {
/* create a signal & check for errors */
DBusMessage* msg = dbus_message_new_signal("/boo/signal/FileHandler", "boo.signal.FileHandling", "Open");
/* append arguments onto signal */
DBusMessageIter argsIter;
dbus_message_iter_init_append(msg, &argsIter);
for (const std::string& arg : args) {
const char* sigvalue = arg.c_str();
dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &sigvalue);
}
/* send the message and flush the connection */
dbus_uint32_t serial;
dbus_connection_send(m_dbus, msg, &serial);
dbus_connection_flush(m_dbus);
dbus_message_unref(msg);
}
return;
} else {
/* This is the first instance, register for signal */
// add a rule for which messages we want to see
DBusError err = {};
dbus_bus_add_match(m_dbus, "type='signal',interface='boo.signal.FileHandling'", &err);
dbus_connection_add_filter(m_dbus, DBusHandleMessageFunction(DBusCallback), this, nullptr);
dbus_connection_flush(m_dbus);
}
}
#endif
if (!XInitThreads()) {
Log.report(logvisor::Fatal, FMT_STRING("X doesn't support multithreading"));
return;
}
/* Program is portable to all locales */
setlocale(LC_ALL, "");
/* Open Xlib Display */
m_xDisp = XOpenDisplay(0);
if (!m_xDisp) {
Log.report(logvisor::Fatal, FMT_STRING("Can't open X display"));
return;
}
#if BOO_HAS_VULKAN
/* Cast Display to XCB connection for vulkan */
m_xcbConn = XGetXCBConnection(m_xDisp);
if (!m_xcbConn) {
Log.report(logvisor::Fatal, FMT_STRING("Can't cast Display to XCB connection for Vulkan"));
return;
}
#endif
/* Configure locale */
if (!XSupportsLocale()) {
Log.report(logvisor::Fatal, FMT_STRING("X does not support locale {}."), setlocale(LC_ALL, nullptr));
return;
}
if (XSetLocaleModifiers("") == nullptr)
Log.report(logvisor::Warning, FMT_STRING("Cannot set locale modifiers."));
if ((m_xIM = XOpenIM(m_xDisp, nullptr, nullptr, nullptr))) {
char** missing_charsets;
int num_missing_charsets = 0;
char* default_string;
m_fontset = XCreateFontSet(m_xDisp,
"-adobe-helvetica-*-r-*-*-*-120-*-*-*-*-*-*,\
-misc-fixed-*-r-*-*-*-130-*-*-*-*-*-*",
&missing_charsets, &num_missing_charsets, &default_string);
/* figure out which styles the IM can support */
XIMStyles* im_supported_styles;
XIMStyle app_supported_styles;
XGetIMValues(m_xIM, XNQueryInputStyle, &im_supported_styles, nullptr);
/* set flags for the styles our application can support */
app_supported_styles = XIMPreeditNone | XIMPreeditNothing | XIMPreeditPosition;
app_supported_styles |= XIMStatusNone | XIMStatusNothing;
/*
* now look at each of the IM supported styles, and
* chose the "best" one that we can support.
*/
for (int i = 0; i < im_supported_styles->count_styles; ++i) {
XIMStyle style = im_supported_styles->supported_styles[i];
if ((style & app_supported_styles) == style) /* if we can handle it */
m_bestStyle = ChooseBetterStyle(style, m_bestStyle);
}
/* if we couldn't support any of them, print an error and exit */
if (m_bestStyle == 0) {
Log.report(logvisor::Fatal, FMT_STRING("interaction style not supported."));
return;
}
XFree(im_supported_styles);
}
m_xDefaultScreen = DefaultScreen(m_xDisp);
X_CURSORS.m_pointer = XCreateFontCursor(m_xDisp, XC_left_ptr);
X_CURSORS.m_weArrow = XCreateFontCursor(m_xDisp, XC_sb_h_double_arrow);
X_CURSORS.m_nsArrow = XCreateFontCursor(m_xDisp, XC_sb_v_double_arrow);
X_CURSORS.m_ibeam = XCreateFontCursor(m_xDisp, XC_xterm);
X_CURSORS.m_crosshairs = XCreateFontCursor(m_xDisp, XC_cross);
X_CURSORS.m_wait = XCreateFontCursor(m_xDisp, XC_watch);
X_CURSORS.m_nwseResize = XCreateFontCursor(m_xDisp, XC_lr_angle);
X_CURSORS.m_neswResize = XCreateFontCursor(m_xDisp, XC_ll_angle);
X_CURSORS.m_hand = XCreateFontCursor(m_xDisp, XC_hand2);
X_CURSORS.m_notAllowed = XCreateFontCursor(m_xDisp, XC_pirate);
/* The xkb extension requests that the X server does not
* send repeated keydown events when a key is held */
XkbQueryExtension(m_xDisp, &XINPUT_OPCODE, nullptr, nullptr, nullptr, nullptr);
XkbSetDetectableAutoRepeat(m_xDisp, True, nullptr);
/* Get file descriptors of xcb and dbus interfaces */
m_x11Fd = ConnectionNumber(m_xDisp);
#ifndef BOO_MSAN
dbus_connection_get_unix_fd(m_dbus, &m_dbusFd);
#else
m_dbusFd = 0;
#endif
m_maxFd = MAX(m_x11Fd, m_dbusFd);
XFlush(m_xDisp);
}
~ApplicationXlib() override {
for (auto& p : m_windows)
if (auto w = p.second.lock())
w->_cleanup();
#if BOO_HAS_VULKAN
g_VulkanContext.destroyDevice();
#endif
if (m_fontset)
XFreeFontSet(m_xDisp, m_fontset);
if (m_xIM)
XCloseIM(m_xIM);
if (m_xDisp)
XCloseDisplay(m_xDisp);
}
EPlatformType getPlatformType() const override { return EPlatformType::Xlib; }
/* Empty handler for SIGINT */
static void _sigint(int) {}
static DBusHandlerResult DBusCallback(DBusConnection* connection,
DBusMessage* message,
ApplicationXlib* user_data) {
return user_data->HandleDBusMessage(message);
}
DBusHandlerResult HandleDBusMessage(DBusMessage* message) {
if (dbus_message_is_signal(message, "boo.signal.FileHandling", "Open")) {
/* read the parameters */
std::vector<std::string> paths;
DBusMessageIter iter;
dbus_message_iter_init(message, &iter);
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) {
const char* argVal;
dbus_message_iter_get_basic(&iter, &argVal);
paths.push_back(argVal);
dbus_message_iter_next(&iter);
}
m_callback.appFilesOpen(this, paths);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
int run() override {
if (!m_xDisp)
return 1;
/* SIGINT will be used to cancel main thread when client thread ends
* (also enables graceful quitting via ctrl-c) */
pthread_t mainThread = pthread_self();
struct sigaction s;
s.sa_handler = _sigint;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(SIGINT, &s, nullptr);
sigaction(SIGUSR2, &s, nullptr);
sigset_t waitmask, origmask;
sigemptyset(&waitmask);
sigaddset(&waitmask, SIGINT);
sigaddset(&waitmask, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &waitmask, &origmask);
/* Screen Saver inhibitor */
std::optional<ScreenSaverInhibitor> inhibitor;
/* Spawn client thread */
int clientReturn = INT_MIN;
std::mutex initmt;
std::condition_variable initcv;
std::unique_lock<std::mutex> outerLk(initmt);
std::thread clientThread([&]() {
std::unique_lock<std::mutex> innerLk(initmt);
innerLk.unlock();
initcv.notify_one();
std::string thrName = std::string(getFriendlyName()) + " Client";
logvisor::RegisterThreadName(thrName.c_str());
clientReturn = m_callback.appMain(this);
pthread_kill(mainThread, SIGUSR2);
});
initcv.wait(outerLk);
/* Begin application event loop */
while (clientReturn == INT_MIN) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_x11Fd, &fds);
FD_SET(m_dbusFd, &fds);
if (pselect(m_maxFd + 1, &fds, nullptr, nullptr, nullptr, &origmask) < 0) {
/* SIGINT/SIGUSR2 handled here */
if (errno == EINTR)
break;
}
if (FD_ISSET(m_x11Fd, &fds)) {
bool needsQuit = false;
XLockDisplay(m_xDisp);
while (XPending(m_xDisp)) {
XEvent event = {};
XNextEvent(m_xDisp, &event);
if (XFilterEvent(&event, None))
continue;
bool windowEvent;
Window evWindow = GetWindowOfEvent(&event, windowEvent);
if (windowEvent) {
if (event.type == ClientMessage && event.xclient.data.l[0] == 'NWID') {
#ifndef BOO_MSAN
if (!inhibitor) /* First window created, use to inhibit screensaver */
inhibitor.emplace(m_dbus, evWindow);
#endif
} else {
auto window = m_windows.find(evWindow);
if (window != m_windows.end())
if (std::shared_ptr<IWindow> w = window->second.lock())
if (w->_incomingEvent(&event) && m_windows.size() == 1) {
needsQuit = true;
break;
}
}
}
}
XUnlockDisplay(m_xDisp);
if (needsQuit)
break;
}
#ifndef BOO_MSAN
if (FD_ISSET(m_dbusFd, &fds)) {
dbus_connection_read_write(m_dbus, 0);
while (dbus_connection_dispatch(m_dbus) == DBUS_DISPATCH_DATA_REMAINS) {}
}
#endif
}
m_callback.appQuitting(this);
if (clientThread.joinable())
clientThread.join();
return clientReturn;
}
std::string_view getUniqueName() const override { return m_uniqueName; }
std::string_view getFriendlyName() const override { return m_friendlyName; }
std::string_view getProcessName() const override { return m_pname; }
const std::vector<std::string>& getArgs() const override { return m_args; }
std::shared_ptr<IWindow> newWindow(std::string_view title) override {
XLockDisplay(m_xDisp);
#if BOO_HAS_VULKAN
std::shared_ptr<IWindow> newWindow = _WindowXlibNew(title, m_xDisp, m_xcbConn, m_xDefaultScreen, m_xIM, m_bestStyle,
m_fontset, m_lastGlxCtx, (void*)m_getVkProc, &m_glContext);
#else
std::shared_ptr<IWindow> newWindow = _WindowXlibNew(title, m_xDisp, nullptr, m_xDefaultScreen, m_xIM, m_bestStyle,
m_fontset, m_lastGlxCtx, nullptr, &m_glContext);
#endif
Window wid = (Window)newWindow->getPlatformHandle();
m_windows[wid] = newWindow;
XEvent reply = {};
reply.xclient.type = ClientMessage;
reply.xclient.window = wid;
reply.xclient.message_type = XA_INTEGER;
reply.xclient.format = 32;
reply.xclient.data.l[0] = 'NWID';
XSendEvent(m_xDisp, wid, false, 0, &reply);
XUnlockDisplay(m_xDisp);
return newWindow;
}
/* Last GLX context */
GLXContext m_lastGlxCtx = nullptr;
};
void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx) { static_cast<ApplicationXlib*>(APP)->m_lastGlxCtx = lastGlxCtx; }
} // namespace boo

View File

@ -1,122 +0,0 @@
#include "boo/IWindow.hpp"
#include "boo/IGraphicsContext.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp"
#include <X11/Xlib.h>
#undef None
namespace boo {
struct GraphicsContextWayland : IGraphicsContext {
EGraphicsAPI m_api;
EPixelFormat m_pf;
IWindow* m_parentWindow;
public:
IWindowCallback* m_callback;
GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow)
: m_api(api), m_pf(EPixelFormat::RGBA8), m_parentWindow(parentWindow) {}
~GraphicsContextWayland() override = default;
void _setCallback(IWindowCallback* cb) override { m_callback = cb; }
EGraphicsAPI getAPI() const override { return m_api; }
EPixelFormat getPixelFormat() const override { return m_pf; }
void setPixelFormat(EPixelFormat pf) override {
if (pf > EPixelFormat::RGBAF32_Z24)
return;
m_pf = pf;
}
bool initializeContext(void*) override { return false; }
void makeCurrent() override {}
void postInit() override {}
IGraphicsCommandQueue* getCommandQueue() override { return nullptr; }
IGraphicsDataFactory* getDataFactory() override { return nullptr; }
IGraphicsDataFactory* getMainContextDataFactory() override { return nullptr; }
IGraphicsDataFactory* getLoadContextDataFactory() override { return nullptr; }
void present() override {}
};
struct WindowWayland : IWindow {
GraphicsContextWayland m_gfxCtx;
WindowWayland(std::string_view title) : m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this) {}
~WindowWayland() override = default;
void setCallback(IWindowCallback* cb) override {}
void closeWindow() override {}
void showWindow() override {}
void hideWindow() override {}
std::string getTitle() override { return ""; }
void setTitle(std::string_view title) override {}
void setCursor(EMouseCursor cursor) override {}
void setWaitCursor(bool wait) override {}
double getWindowRefreshRate() const override { return 60.0; }
void setWindowFrameDefault() override {}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const override {}
void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const override {}
void setWindowFrame(float x, float y, float w, float h) override {}
void setWindowFrame(int x, int y, int w, int h) override {}
float getVirtualPixelFactor() const override { return 0; }
void setStyle(EWindowStyle /*style*/) override {}
EWindowStyle getStyle() const override { return EWindowStyle::None; }
bool isFullscreen() const override { return false; }
void setFullscreen(bool fs) override {}
void claimKeyboardFocus(const int coord[2]) override {}
bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) override { return false; }
std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz) override { return std::unique_ptr<uint8_t[]>(); }
int waitForRetrace() override { return 1; }
uintptr_t getPlatformHandle() const override { return 0; }
ETouchType getTouchType() const override { return ETouchType::None; }
IGraphicsCommandQueue* getCommandQueue() override { return m_gfxCtx.getCommandQueue(); }
IGraphicsDataFactory* getDataFactory() override { return m_gfxCtx.getDataFactory(); }
IGraphicsDataFactory* getMainContextDataFactory() override { return m_gfxCtx.getMainContextDataFactory(); }
IGraphicsDataFactory* getLoadContextDataFactory() override { return m_gfxCtx.getLoadContextDataFactory(); }
};
std::shared_ptr<IWindow> _WindowWaylandNew(std::string_view title) { return std::make_shared<WindowWayland>(title); }
} // namespace boo

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
#pragma once
#include <X11/Xlib.h>
namespace boo {
struct XlibCursors {
Cursor m_pointer;
Cursor m_weArrow;
Cursor m_nsArrow;
Cursor m_ibeam;
Cursor m_crosshairs;
Cursor m_wait;
Cursor m_nwseResize;
Cursor m_neswResize;
Cursor m_hand;
Cursor m_notAllowed;
};
extern XlibCursors X_CURSORS;
} // namespace boo

@ -1 +0,0 @@
Subproject commit 9420e3007e66d6d9219868d93da997f42b7719a8

1
optick

@ -1 +0,0 @@
Subproject commit 1db8585d2bf80c4e1497280d31fedc6fab4e1bba

View File

@ -1,11 +0,0 @@
add_executable(booTest WIN32 main.cpp)
target_link_libraries(booTest boo)
if (COMMAND add_nro_target)
set_target_properties(booTest PROPERTIES SUFFIX ".elf")
add_nro_target(booTest booTest "Antidote/Jackoalan" "1.0.0")
endif()
if(COMMAND add_sanitizers)
add_sanitizers(booTest)
endif()

View File

@ -1,505 +0,0 @@
#include <boo/boo.hpp>
#include <boo/graphicsdev/D3D.hpp>
#include <boo/graphicsdev/GL.hpp>
#include <boo/graphicsdev/GLSLMacros.hpp>
#include <boo/graphicsdev/Metal.hpp>
#include <boo/graphicsdev/Vulkan.hpp>
#include <condition_variable>
#include <cstdio>
#include <thread>
#include <logvisor/logvisor.hpp>
namespace boo {
class DolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback {
void controllerConnected(unsigned idx, EDolphinControllerType) override {
// printf("CONTROLLER %u CONNECTED\n", idx);
}
void controllerDisconnected(unsigned idx) override {
// printf("CONTROLLER %u DISCONNECTED\n", idx);
}
void controllerUpdate(unsigned idx, EDolphinControllerType, const DolphinControllerState& state) override {
// printf("CONTROLLER %u UPDATE %d %d\n", idx, state.m_leftStick[0], state.m_leftStick[1]);
// printf(" %d %d\n", state.m_rightStick[0], state.m_rightStick[1]);
// printf(" %d %d\n", state.m_analogTriggers[0], state.m_analogTriggers[1]);
}
};
class DualshockPadCallback : public IDualshockPadCallback {
void controllerDisconnected() override { printf("CONTROLLER DISCONNECTED\n"); }
void controllerUpdate(DualshockPad& pad, const DualshockPadState& state) override {
static time_t timeTotal;
static time_t lastTime = 0;
timeTotal = time(NULL);
time_t timeDif = timeTotal - lastTime;
/*
if (timeDif >= .15)
{
uint8_t led = ctrl->getLED();
led *= 2;
if (led > 0x10)
led = 2;
ctrl->setRawLED(led);
lastTime = timeTotal;
}
*/
if (state.m_psButtonState) {
if (timeDif >= 1) // wait 30 seconds before issuing another rumble event
{
pad.startRumble(EDualshockMotor::Left);
pad.startRumble(EDualshockMotor::Right, 100);
lastTime = timeTotal;
}
}
/*
else
ctrl->stopRumble(DS3_MOTOR_RIGHT | DS3_MOTOR_LEFT);*/
printf("CONTROLLER UPDATE %d %d\n", state.m_leftStick[0], state.m_leftStick[1]);
printf(" %d %d\n", state.m_rightStick[0], state.m_rightStick[1]);
printf(" %f %f %f\n", state.accPitch, state.accYaw, state.gyroZ);
}
};
class GenericPadCallback : public IGenericPadCallback {
void controllerConnected() override { printf("CONTROLLER CONNECTED\n"); }
void controllerDisconnected() override { printf("CONTROLLER DISCONNECTED\n"); }
void valueUpdate(const HIDMainItem& item, int32_t value) override {
const char* pageName = item.GetUsagePageName();
const char* usageName = item.GetUsageName();
if (pageName) {
if (usageName)
printf("%s %s %d\n", pageName, usageName, int(value));
else
printf("%s %d %d\n", pageName, int(item.m_usage), int(value));
} else {
if (usageName)
printf("page%d %s %d\n", int(item.m_usagePage), usageName, int(value));
else
printf("page%d %d %d\n", int(item.m_usagePage), int(item.m_usage), int(value));
}
}
};
class NintendoPowerACallback : public INintendoPowerACallback {
void controllerDisconnected() override { fprintf(stderr, "CONTROLLER DISCONNECTED\n"); }
void controllerUpdate(const NintendoPowerAState& state) override {
fprintf(stderr,
"%i %i\n"
"%i %i\n",
state.leftX, state.leftY, state.rightX, state.rightY);
}
};
class TestDeviceFinder : public DeviceFinder {
std::shared_ptr<DolphinSmashAdapter> m_smashAdapter;
std::shared_ptr<NintendoPowerA> m_nintendoPowerA;
std::shared_ptr<DualshockPad> m_ds3;
std::shared_ptr<GenericPad> m_generic;
DolphinSmashAdapterCallback m_cb;
NintendoPowerACallback m_nintendoPowerACb;
DualshockPadCallback m_ds3CB;
GenericPadCallback m_genericCb;
public:
TestDeviceFinder()
: DeviceFinder({dev_typeid(DolphinSmashAdapter), dev_typeid(NintendoPowerA), dev_typeid(GenericPad)}) {}
void deviceConnected(DeviceToken& tok) override {
auto dev = tok.openAndGetDevice();
if (!dev)
return;
if (dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) {
m_smashAdapter = std::static_pointer_cast<DolphinSmashAdapter>(dev);
m_smashAdapter->setCallback(&m_cb);
} else if (dev->getTypeHash() == dev_typeid(NintendoPowerA)) {
m_nintendoPowerA = std::static_pointer_cast<NintendoPowerA>(dev);
m_nintendoPowerA->setCallback(&m_nintendoPowerACb);
} else if (dev->getTypeHash() == dev_typeid(DualshockPad)) {
m_ds3 = std::static_pointer_cast<DualshockPad>(dev);
m_ds3->setCallback(&m_ds3CB);
m_ds3->setLED(EDualshockLED::LED_1);
} else if (dev->getTypeHash() == dev_typeid(GenericPad)) {
m_generic = std::static_pointer_cast<GenericPad>(dev);
m_generic->setCallback(&m_genericCb);
}
}
void deviceDisconnected(DeviceToken&, DeviceBase* device) override {
if (m_smashAdapter.get() == device)
m_smashAdapter.reset();
if (m_ds3.get() == device)
m_ds3.reset();
if (m_generic.get() == device)
m_generic.reset();
if (m_nintendoPowerA.get() == device)
m_nintendoPowerA.reset();
}
};
struct CTestWindowCallback : IWindowCallback {
bool m_fullscreenToggleRequested = false;
SWindowRect m_lastRect;
bool m_rectDirty = false;
bool m_windowInvalid = false;
void resized(const SWindowRect& rect, bool sync) override {
m_lastRect = rect;
m_rectDirty = true;
fprintf(stderr, "Resized %d, %d (%d, %d)\n", rect.size[0], rect.size[1], rect.location[0], rect.location[1]);
}
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) override {
fprintf(stderr, "Mouse Down %d (%f,%f)\n", int(button), coord.norm[0], coord.norm[1]);
}
void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) override {
fprintf(stderr, "Mouse Up %d (%f,%f)\n", int(button), coord.norm[0], coord.norm[1]);
}
void mouseMove(const SWindowCoord& coord) override {
// fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]);
}
void mouseEnter(const SWindowCoord& coord) override {
fprintf(stderr, "Mouse entered (%f,%f)\n", coord.norm[0], coord.norm[1]);
}
void mouseLeave(const SWindowCoord& coord) override { fprintf(stderr, "Mouse left (%f,%f)\n", coord.norm[0], coord.norm[1]); }
void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) override {
// fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0],
// scroll.delta[1]);
}
void touchDown(const STouchCoord& coord, uintptr_t tid) override {
// fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void touchUp(const STouchCoord& coord, uintptr_t tid) override {
// fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void touchMove(const STouchCoord& coord, uintptr_t tid) override {
// fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]);
}
void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) override {}
void charKeyUp(unsigned long charCode, EModifierKey mods) override {}
void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) override {
if (key == ESpecialKey::Enter && True(mods & EModifierKey::Alt))
m_fullscreenToggleRequested = true;
}
void specialKeyUp(ESpecialKey key, EModifierKey mods) override {}
void modKeyDown(EModifierKey mod, bool isRepeat) override {}
void modKeyUp(EModifierKey mod) override {}
void windowMoved(const SWindowRect& rect) override {
// fprintf(stderr, "Moved %d, %d (%d, %d)\n", rect.size[0], rect.size[1], rect.location[0], rect.location[1]);
}
void destroyed() override { m_windowInvalid = true; }
};
struct TestApplicationCallback : IApplicationCallback {
std::shared_ptr<IWindow> mainWindow;
boo::TestDeviceFinder devFinder;
CTestWindowCallback windowCallback;
bool running = true;
boo::ObjToken<IShaderDataBinding> m_binding;
boo::ObjToken<ITextureR> m_renderTarget;
static void LoaderProc(TestApplicationCallback* self) {
IGraphicsDataFactory* factory = self->mainWindow->getLoadContextDataFactory();
factory->commitTransaction([&](IGraphicsDataFactory::Context& ctx) {
/* Create render target */
int x, y, w, h;
self->mainWindow->getWindowFrame(x, y, w, h);
self->m_renderTarget = ctx.newRenderTexture(w, h, boo::TextureClampMode::ClampToEdge, 1, 0);
/* Make Tri-strip VBO */
struct Vert {
float pos[3];
float uv[2];
};
/*
static const Vert quad[4] =
{
{{0.5,0.5},{1.0,1.0}},
{{-0.5,0.5},{0.0,1.0}},
{{0.5,-0.5},{1.0,0.0}},
{{-0.5,-0.5},{0.0,0.0}}
};
*/
static const Vert quad[4] = {
{{1.0, 1.0}, {1.0, 1.0}}, {{-1.0, 1.0}, {0.0, 1.0}}, {{1.0, -1.0}, {1.0, 0.0}}, {{-1.0, -1.0}, {0.0, 0.0}}};
auto vbo = ctx.newStaticBuffer(BufferUse::Vertex, quad, sizeof(Vert), 4);
/* Make vertex format */
VertexElementDescriptor descs[2] = {{VertexSemantic::Position3}, {VertexSemantic::UV2}};
/* Make ramp texture */
using Pixel = uint8_t[4];
static Pixel tex[256][256];
for (int i = 0; i < 256; ++i)
for (int j = 0; j < 256; ++j) {
tex[i][j][0] = i;
tex[i][j][1] = j;
tex[i][j][2] = 0;
tex[i][j][3] = 0xff;
}
boo::ObjToken<ITexture> texture = ctx.newStaticTexture(256, 256, 1, TextureFormat::RGBA8,
boo::TextureClampMode::ClampToEdge, tex, 256 * 256 * 4)
.get();
/* Make shader pipeline */
boo::ObjToken<IShaderPipeline> pipeline;
auto plat = ctx.platform();
AdditionalPipelineInfo info = {
BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips, boo::ZTest::LEqual, true, true, false,
CullMode::None};
#if BOO_HAS_GL
if (plat == IGraphicsDataFactory::Platform::OpenGL) {
static const char* VS = "#version 330\n" BOO_GLSL_BINDING_HEAD
"layout(location=0) in vec3 in_pos;\n"
"layout(location=1) in vec2 in_uv;\n"
"SBINDING(0) out vec2 out_uv;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(in_pos, 1.0);\n"
" out_uv = in_uv;\n"
"}\n";
static const char* FS = "#version 330\n" BOO_GLSL_BINDING_HEAD
"precision highp float;\n"
"TBINDING0 uniform sampler2D tex;\n"
"layout(location=0) out vec4 out_frag;\n"
"SBINDING(0) in vec2 out_uv;\n"
"void main()\n"
"{\n"
" //out_frag = texture(tex, out_uv);\n"
" out_frag = vec4(out_uv.xy, 0.0, 1.0);\n"
"}\n";
auto vertex = ctx.newShaderStage((uint8_t*)VS, 0, PipelineStage::Vertex);
auto fragment = ctx.newShaderStage((uint8_t*)FS, 0, PipelineStage::Fragment);
pipeline = ctx.newShaderPipeline(vertex, fragment,
{{VertexSemantic::Position3},
{ VertexSemantic::UV2 }},
info);
} else
#endif
#if BOO_HAS_VULKAN
if (plat == IGraphicsDataFactory::Platform::Vulkan) {
static const char* VS = "#version 330\n" BOO_GLSL_BINDING_HEAD
"layout(location=0) in vec3 in_pos;\n"
"layout(location=1) in vec2 in_uv;\n"
"SBINDING(0) out vec2 out_uv;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(in_pos, 1.0);\n"
" out_uv = in_uv;\n"
"}\n";
static const char* FS = "#version 330\n" BOO_GLSL_BINDING_HEAD
"precision highp float;\n"
"TBINDING0 uniform sampler2D texs[1];\n"
"layout(location=0) out vec4 out_frag;\n"
"SBINDING(0) in vec2 out_uv;\n"
"void main()\n"
"{\n"
" out_frag = texture(texs[0], out_uv);\n"
"}\n";
auto vertexSiprv = VulkanDataFactory::CompileGLSL(VS, PipelineStage::Vertex);
auto vertexShader = ctx.newShaderStage(vertexSiprv, PipelineStage::Vertex);
auto fragmentSiprv = VulkanDataFactory::CompileGLSL(FS, PipelineStage::Fragment);
auto fragmentShader = ctx.newShaderStage(fragmentSiprv, PipelineStage::Fragment);
pipeline = ctx.newShaderPipeline(vertexShader, fragmentShader, descs, info);
} else
#endif
#if _WIN32
if (plat == IGraphicsDataFactory::Platform::D3D11) {
static const char* VS =
"struct VertData {float3 in_pos : POSITION; float2 in_uv : UV;};\n"
"struct VertToFrag {float4 out_pos : SV_Position; float2 out_uv : UV;};\n"
"VertToFrag main(in VertData v)\n"
"{\n"
" VertToFrag retval;\n"
" retval.out_pos = float4(v.in_pos, 1.0);\n"
" retval.out_uv = v.in_uv;\n"
" return retval;\n"
"}\n";
static const char* PS =
"SamplerState samp : register(s0);\n"
"Texture2D tex : register(t0);\n"
"struct VertToFrag {float4 out_pos : SV_Position; float2 out_uv : UV;};\n"
"float4 main(in VertToFrag d) : SV_Target0\n"
"{\n"
" //return tex.Sample(samp, d.out_uv);\n"
" return float4(d.out_uv.xy, 0.0, 1.0);\n"
"}\n";
auto vertexSiprv = D3D11DataFactory::CompileHLSL(VS, PipelineStage::Vertex);
auto vertexShader = ctx.newShaderStage(vertexSiprv, PipelineStage::Vertex);
auto fragmentSiprv = D3D11DataFactory::CompileHLSL(PS, PipelineStage::Fragment);
auto fragmentShader = ctx.newShaderStage(fragmentSiprv, PipelineStage::Fragment);
pipeline = ctx.newShaderPipeline(vertexShader, fragmentShader, descs, info);
} else
#elif BOO_HAS_METAL
if (plat == IGraphicsDataFactory::Platform::Metal) {
static const char* VS =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"struct VertData {float3 in_pos [[ attribute(0) ]]; float2 in_uv [[ attribute(1) ]];};\n"
"struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n"
"vertex VertToFrag vmain(VertData v [[ stage_in ]])\n"
"{\n"
" VertToFrag retval;\n"
" retval.out_pos = float4(v.in_pos, 1.0);\n"
" retval.out_uv = v.in_uv;\n"
" return retval;\n"
"}\n";
static const char* FS =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n"
"fragment float4 fmain(VertToFrag d [[ stage_in ]],\n"
" sampler samp [[ sampler(3) ]],\n"
" texture2d<float> tex [[ texture(0) ]])\n"
"{\n"
" return tex.sample(samp, d.out_uv);\n"
"}\n";
auto vertexMetal = MetalDataFactory::CompileMetal(VS, PipelineStage::Vertex);
auto vertexShader = ctx.newShaderStage(vertexMetal, PipelineStage::Vertex);
auto fragmentMetal = MetalDataFactory::CompileMetal(FS, PipelineStage::Fragment);
auto fragmentShader = ctx.newShaderStage(fragmentMetal, PipelineStage::Fragment);
pipeline = ctx.newShaderPipeline(vertexShader, fragmentShader, descs, info);
} else
#endif
{
}
/* Make shader data binding */
self->m_binding = ctx.newShaderDataBinding(pipeline, vbo.get(), nullptr, nullptr, 0, nullptr, nullptr, 1,
&texture, nullptr, nullptr);
return true;
} BooTrace);
}
int appMain(IApplication* app) override {
mainWindow = app->newWindow("YAY!");
mainWindow->setCallback(&windowCallback);
mainWindow->showWindow();
windowCallback.m_lastRect = mainWindow->getWindowFrame();
// mainWindow->setFullscreen(true);
devFinder.startScanning();
IGraphicsCommandQueue* gfxQ = mainWindow->getCommandQueue();
LoaderProc(this);
size_t frameIdx = 0;
size_t lastCheck = 0;
while (running) {
if (windowCallback.m_windowInvalid) {
running = false;
break;
}
mainWindow->waitForRetrace();
if (windowCallback.m_rectDirty) {
gfxQ->resizeRenderTexture(m_renderTarget, windowCallback.m_lastRect.size[0], windowCallback.m_lastRect.size[1]);
windowCallback.m_rectDirty = false;
}
if (windowCallback.m_fullscreenToggleRequested) {
mainWindow->setFullscreen(!mainWindow->isFullscreen());
windowCallback.m_fullscreenToggleRequested = false;
}
gfxQ->setRenderTarget(m_renderTarget);
SWindowRect r = windowCallback.m_lastRect;
r.location[0] = 0;
r.location[1] = 0;
gfxQ->setViewport(r);
gfxQ->setScissor(r);
// float rgba[] = {std::max(0.f, sinf(frameIdx / 60.0)), std::max(0.f, cosf(frameIdx / 60.0)), 0.0, 1.0};
float gammaT = sinf(frameIdx / 60.0) + 1.f;
if (gammaT < 1.f)
gammaT = gammaT * 0.5f + 0.5f;
// printf("%f\n", gammaT);
mainWindow->getDataFactory()->setDisplayGamma(gammaT);
// gfxQ->setClearColor(rgba);
gfxQ->clearTarget();
gfxQ->setShaderDataBinding(m_binding);
gfxQ->draw(0, 4);
gfxQ->resolveDisplay(m_renderTarget);
gfxQ->execute();
// fprintf(stderr, "%zu\n", frameIdx);
++frameIdx;
if ((frameIdx - lastCheck) > 100) {
lastCheck = frameIdx;
// mainWindow->setFullscreen(!mainWindow->isFullscreen());
}
}
gfxQ->stopRenderer();
m_renderTarget.reset();
m_binding.reset();
return 0;
}
void appQuitting(IApplication*) override { running = false; }
void appFilesOpen(IApplication*, const std::vector<std::string>& paths) override {
fprintf(stderr, "OPENING: ");
for (const std::string& path : paths) {
fprintf(stderr, "%s ", path.c_str());
}
fprintf(stderr, "\n");
}
};
} // namespace boo
#if !WINDOWS_STORE
int main(int argc, char** argv) {
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
boo::TestApplicationCallback appCb;
int ret = ApplicationRun(boo::IApplication::EPlatformType::Auto, appCb, "boo", "boo", argc, argv,
{}, 1, 1, true);
return ret;
}
#else
using namespace Windows::ApplicationModel::Core;
[Platform::MTAThread] int WINAPIV main(Platform::Array<Platform::String ^> ^ params) {
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
boo::TestApplicationCallback appCb;
boo::ViewProvider ^ viewProvider =
ref new boo::ViewProvider(appCb, "boo", "boo", "boo", params, false);
CoreApplication::Run(viewProvider);
return 0;
}
#endif
#if _WIN32 && !WINDOWS_STORE
#include <nowide/args.hpp>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int) {
int argc = 0;
char** argv = nullptr;
nowide::args _(argc, argv);
logvisor::CreateWin32Console();
return main(argc, argv);
}
#endif