mirror of https://github.com/AxioDL/boo.git
Gut the rest of graphicsdev and inputdev
This commit is contained in:
parent
94d11cb328
commit
33cfcd8b63
|
@ -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
|
257
CMakeLists.txt
257
CMakeLists.txt
|
@ -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()
|
||||
|
|
74
GLEW-LICENSE
74
GLEW-LICENSE
|
@ -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.
|
||||
|
|
@ -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
glslang
1
glslang
|
@ -1 +0,0 @@
|
|||
Subproject commit 02c70ad10e1f9dc88ae4ee509f26fe5f9fb31843
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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__
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
|
@ -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"
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace boo {}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace boo {}
|
|
@ -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
|
|
@ -1,6 +1,5 @@
|
|||
#include "lib/audiodev/AudioVoiceEngine.hpp"
|
||||
|
||||
#include "boo/IApplication.hpp"
|
||||
#include "lib/CFPointer.hpp"
|
||||
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#include "lib/audiodev/AudioVoiceEngine.hpp"
|
||||
|
||||
#include "boo/boo.hpp"
|
||||
#include "lib/audiodev/LinuxMidi.hpp"
|
||||
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -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
|
@ -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
|
23822
lib/graphicsdev/glew.c
23822
lib/graphicsdev/glew.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1 +0,0 @@
|
|||
#include "boo/inputdev/CafeProPad.hpp"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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, ®_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
|
|
@ -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
|
|
@ -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
|
|
@ -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); }
|
||||
};
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
#include "boo/inputdev/RevolutionPad.hpp"
|
|
@ -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
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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
logvisor
1
logvisor
|
@ -1 +0,0 @@
|
|||
Subproject commit 9420e3007e66d6d9219868d93da997f42b7719a8
|
1
optick
1
optick
|
@ -1 +0,0 @@
|
|||
Subproject commit 1db8585d2bf80c4e1497280d31fedc6fab4e1bba
|
|
@ -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()
|
505
test/main.cpp
505
test/main.cpp
|
@ -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
|
Loading…
Reference in New Issue