diff --git a/InputDeviceClasses.cpp b/InputDeviceClasses.cpp index 6f72a7b..bb6ac6a 100644 --- a/InputDeviceClasses.cpp +++ b/InputDeviceClasses.cpp @@ -5,17 +5,13 @@ #include "boo/inputdev/XInputPad.hpp" #include "boo/inputdev/NintendoPowerA.hpp" -namespace boo -{ +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() -}; +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()}; } diff --git a/include/boo/BooObject.hpp b/include/boo/BooObject.hpp index 60f0b87..c1134e4 100644 --- a/include/boo/BooObject.hpp +++ b/include/boo/BooObject.hpp @@ -4,50 +4,80 @@ #include #include "nxstl/mutex" -namespace boo -{ +namespace boo { + +class IObj { + std::atomic_int m_refCount = {0}; -class IObj -{ - std::atomic_int m_refCount = {0}; protected: - virtual ~IObj() = default; + virtual ~IObj() = default; + public: - virtual std::unique_lock destructorLock()=0; - void increment() { m_refCount++; } - void decrement() - { - if (m_refCount.fetch_sub(1) == 1) - { - auto lk = destructorLock(); - delete this; - } + virtual std::unique_lock destructorLock() = 0; + void increment() { m_refCount++; } + void decrement() { + if (m_refCount.fetch_sub(1) == 1) { + auto lk = destructorLock(); + delete this; } + } }; -template -class ObjToken -{ - SubCls* m_obj = nullptr; +template +class ObjToken { + SubCls* m_obj = nullptr; + public: - ObjToken() = default; - ObjToken(SubCls* obj) : m_obj(obj) { if (m_obj) m_obj->increment(); } - ObjToken(const ObjToken& other) : m_obj(other.m_obj) { if (m_obj) m_obj->increment(); } - ObjToken(ObjToken&& other) : m_obj(other.m_obj) { other.m_obj = nullptr; } - ObjToken& operator=(SubCls* obj) - { if (m_obj) m_obj->decrement(); m_obj = obj; if (m_obj) m_obj->increment(); return *this; } - ObjToken& operator=(const ObjToken& other) - { if (m_obj) m_obj->decrement(); m_obj = other.m_obj; if (m_obj) m_obj->increment(); return *this; } - ObjToken& operator=(ObjToken&& other) - { if (m_obj) m_obj->decrement(); m_obj = other.m_obj; other.m_obj = nullptr; return *this; } - ~ObjToken() { if (m_obj) m_obj->decrement(); } - SubCls* get() const { return m_obj; } - SubCls* operator->() const { return m_obj; } - SubCls& operator*() const { return *m_obj; } - template T* cast() const { return static_cast(m_obj); } - operator bool() const { return m_obj != nullptr; } - void reset() { if (m_obj) m_obj->decrement(); m_obj = nullptr; } + ObjToken() = default; + ObjToken(SubCls* obj) : m_obj(obj) { + if (m_obj) + m_obj->increment(); + } + ObjToken(const ObjToken& other) : m_obj(other.m_obj) { + if (m_obj) + m_obj->increment(); + } + ObjToken(ObjToken&& other) : m_obj(other.m_obj) { other.m_obj = nullptr; } + ObjToken& operator=(SubCls* obj) { + if (m_obj) + m_obj->decrement(); + m_obj = obj; + if (m_obj) + m_obj->increment(); + return *this; + } + ObjToken& operator=(const ObjToken& other) { + if (m_obj) + m_obj->decrement(); + m_obj = other.m_obj; + if (m_obj) + m_obj->increment(); + return *this; + } + ObjToken& operator=(ObjToken&& other) { + if (m_obj) + m_obj->decrement(); + m_obj = other.m_obj; + other.m_obj = nullptr; + return *this; + } + ~ObjToken() { + if (m_obj) + m_obj->decrement(); + } + SubCls* get() const { return m_obj; } + SubCls* operator->() const { return m_obj; } + SubCls& operator*() const { return *m_obj; } + template + T* cast() const { + return static_cast(m_obj); + } + operator bool() const { return m_obj != nullptr; } + void reset() { + if (m_obj) + m_obj->decrement(); + m_obj = nullptr; + } }; -} - +} // namespace boo diff --git a/include/boo/DeferredWindowEvents.hpp b/include/boo/DeferredWindowEvents.hpp index 4fe545f..9646b4a 100644 --- a/include/boo/DeferredWindowEvents.hpp +++ b/include/boo/DeferredWindowEvents.hpp @@ -5,269 +5,242 @@ #include #include "nxstl/condition_variable" -namespace boo -{ +namespace boo { template -struct DeferredWindowEvents : public IWindowCallback -{ - Receiver& m_rec; - std::mutex m_mt; - std::condition_variable m_resizeCv; - DeferredWindowEvents(Receiver& rec) : m_rec(rec) {} +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() - { - m_destroyed = true; + bool m_destroyed = false; + void destroyed() { m_destroyed = true; } + + bool m_hasResize = false; + SWindowRect m_latestResize; + void resized(const SWindowRect& rect, bool sync) { + std::unique_lock 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; + } } - bool m_hasResize = false; - SWindowRect m_latestResize; - void resized(const SWindowRect& rect, bool sync) - { - std::unique_lock lk(m_mt); - m_latestResize = rect; - m_hasResize = true; - if (sync) - m_resizeCv.wait_for(lk, std::chrono::milliseconds(500)); + Command(Type tp) : m_type(tp) {} + }; + std::vector m_cmds; + + void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseMove); + m_cmds.back().m_coord = coord; + } + + void mouseEnter(const SWindowCoord& coord) { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseEnter); + m_cmds.back().m_coord = coord; + } + + void mouseLeave(const SWindowCoord& coord) { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseLeave); + m_cmds.back().m_coord = coord; + } + + void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock 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) { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::ModKeyUp); + m_cmds.back().m_mods = mod; + } + + ITextInputCallback* getTextInputCallback() { return m_rec.getTextInputCallback(); } + + void dispatchEvents() { + std::unique_lock lk(m_mt); + bool destroyed = m_destroyed; + bool hasResize = m_hasResize; + if (hasResize) + m_hasResize = false; + SWindowRect latestResize = m_latestResize; + std::vector cmds; + m_cmds.swap(cmds); + lk.unlock(); + + if (destroyed) { + m_rec.destroyed(); + return; } - struct Command - { - enum class Type - { - MouseDown, - MouseUp, - MouseMove, - MouseEnter, - MouseLeave, - Scroll, - TouchDown, - TouchUp, - TouchMove, - CharKeyDown, - CharKeyUp, - SpecialKeyDown, - SpecialKeyUp, - ModKeyDown, - ModKeyUp - } m_type; + if (hasResize) + m_rec.resized(latestResize, false); - 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 m_cmds; - - void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock lk(m_mt); - m_cmds.emplace_back(Command::Type::MouseMove); - m_cmds.back().m_coord = coord; - } - - void mouseEnter(const SWindowCoord& coord) - { - std::unique_lock lk(m_mt); - m_cmds.emplace_back(Command::Type::MouseEnter); - m_cmds.back().m_coord = coord; - } - - void mouseLeave(const SWindowCoord& coord) - { - std::unique_lock lk(m_mt); - m_cmds.emplace_back(Command::Type::MouseLeave); - m_cmds.back().m_coord = coord; - } - - void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock 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) - { - std::unique_lock lk(m_mt); - m_cmds.emplace_back(Command::Type::ModKeyUp); - m_cmds.back().m_mods = mod; - } - - ITextInputCallback* getTextInputCallback() { return m_rec.getTextInputCallback(); } - - void dispatchEvents() - { - std::unique_lock lk(m_mt); - bool destroyed = m_destroyed; - bool hasResize = m_hasResize; - if (hasResize) - m_hasResize = false; - SWindowRect latestResize = m_latestResize; - std::vector 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); - } + for (const Command& cmd : cmds) + cmd.dispatch(m_rec); + } }; -} - +} // namespace boo diff --git a/include/boo/IApplication.hpp b/include/boo/IApplication.hpp index 7218b15..b254c54 100644 --- a/include/boo/IApplication.hpp +++ b/include/boo/IApplication.hpp @@ -7,88 +7,68 @@ #include "IWindow.hpp" #include "inputdev/DeviceFinder.hpp" -namespace boo -{ +namespace boo { class IApplication; -struct IApplicationCallback -{ - virtual int appMain(IApplication*)=0; - virtual void appQuitting(IApplication*)=0; - virtual void appFilesOpen(IApplication*, const std::vector&) {} +struct IApplicationCallback { + virtual int appMain(IApplication*) = 0; + virtual void appQuitting(IApplication*) = 0; + virtual void appFilesOpen(IApplication*, const std::vector&) {} }; -class IApplication -{ - friend class WindowCocoa; - friend class WindowWayland; - friend class WindowXlib; - friend class WindowWin32; - virtual void _deletedWindow(IWindow* window)=0; +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 SystemStringView getUniqueName() const=0; - virtual SystemStringView getFriendlyName() const=0; - virtual SystemStringView getProcessName() const=0; - virtual const std::vector& getArgs() const=0; - - /* Constructors/initializers for sub-objects */ - virtual std::shared_ptr newWindow(SystemStringView title)=0; + 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 SystemStringView getUniqueName() const = 0; + virtual SystemStringView getFriendlyName() const = 0; + virtual SystemStringView getProcessName() const = 0; + virtual const std::vector& getArgs() const = 0; + + /* Constructors/initializers for sub-objects */ + virtual std::shared_ptr newWindow(SystemStringView title) = 0; }; -int -ApplicationRun(IApplication::EPlatformType platform, - IApplicationCallback& cb, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& args, - std::string_view gfxApi = {}, - uint32_t samples = 1, - uint32_t anisotropy = 1, - bool deepColor = false, - bool singleInstance=true); +int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName, + SystemStringView friendlyName, SystemStringView pname, const std::vector& 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, - SystemStringView uniqueName, - SystemStringView friendlyName, - int argc, const SystemChar** 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 args; - for (int i=1 ; i 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 diff --git a/include/boo/IGraphicsContext.hpp b/include/boo/IGraphicsContext.hpp index 2478d2d..cf01c0b 100644 --- a/include/boo/IGraphicsContext.hpp +++ b/include/boo/IGraphicsContext.hpp @@ -3,61 +3,55 @@ #include #include -namespace boo -{ +namespace boo { struct IGraphicsCommandQueue; struct IGraphicsDataFactory; -class IGraphicsContext -{ - friend class WindowCocoa; - friend class WindowXCB; - virtual void _setCallback(class IWindowCallback* cb) {(void)cb;} +class IGraphicsContext { + friend class WindowCocoa; + friend class WindowXCB; + virtual void _setCallback(class IWindowCallback* cb) { (void)cb; } public: - - enum class EGraphicsAPI - { - None = 0, - OpenGL3_3 = 1, - OpenGL4_2 = 2, - Vulkan = 3, - D3D11 = 4, - Metal = 6, - GX = 7, - GX2 = 8, - NX = 9 - }; - - enum class EPixelFormat - { - None = 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; + enum class EGraphicsAPI { + None = 0, + OpenGL3_3 = 1, + OpenGL4_2 = 2, + Vulkan = 3, + D3D11 = 4, + Metal = 6, + GX = 7, + GX2 = 8, + NX = 9 + }; - virtual IGraphicsCommandQueue* getCommandQueue()=0; - virtual IGraphicsDataFactory* getDataFactory()=0; + enum class EPixelFormat { + None = 0, + RGBA8 = 1, /* Default */ + RGBA16 = 2, + RGBA8_Z24 = 3, + RGBAF32 = 4, + RGBAF32_Z24 = 5 + }; - /* Creates a new context on current thread!! Call from main client thread */ - virtual IGraphicsDataFactory* getMainContextDataFactory()=0; + virtual ~IGraphicsContext() = default; - /* Creates a new context on current thread!! Call from client loading thread */ - virtual IGraphicsDataFactory* getLoadContextDataFactory()=0; + 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 diff --git a/include/boo/IWindow.hpp b/include/boo/IWindow.hpp index 9324d95..3a00b4a 100644 --- a/include/boo/IWindow.hpp +++ b/include/boo/IWindow.hpp @@ -8,315 +8,286 @@ #undef min #undef max -namespace boo -{ +namespace boo { struct IGraphicsCommandQueue; struct IGraphicsDataFactory; struct IAudioVoiceEngine; -enum class EMouseButton -{ - None = 0, - Primary = 1, - Secondary = 2, - Middle = 3, - Aux1 = 4, - Aux2 = 5 +enum class EMouseButton { None = 0, Primary = 1, Secondary = 2, Middle = 3, Aux1 = 4, Aux2 = 5 }; + +struct SWindowCoord { + int pixel[2]; + int virtualPixel[2]; + float norm[2]; }; -struct SWindowCoord -{ - int pixel[2]; - int virtualPixel[2]; - float norm[2]; +struct SWindowRect { + int location[2]; + int size[2]; + + SWindowRect() { std::memset(this, 0, sizeof(SWindowRect)); } + + SWindowRect(int x, int y, int w, int h) { + location[0] = x; + location[1] = y; + size[0] = w; + size[1] = h; + } + + bool operator!=(const SWindowRect& other) const { + return location[0] != other.location[0] || location[1] != other.location[1] || size[0] != other.size[0] || + size[1] != other.size[1]; + } + bool operator==(const SWindowRect& other) const { return !(*this != other); } + + bool coordInRect(const SWindowCoord& coord) const { + 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]; + } + + SWindowRect intersect(const SWindowRect& other) const { + 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 SWindowRect -{ - int location[2]; - int size[2]; - - SWindowRect() {std::memset(this, 0, sizeof(SWindowRect));} - - SWindowRect(int x, int y, int w, int h) - { - location[0] = x; - location[1] = y; - size[0] = w; - size[1] = h; - } - - bool operator!=(const SWindowRect& other) const - { - return location[0] != other.location[0] || - location[1] != other.location[1] || - size[0] != other.size[0] || - size[1] != other.size[1]; - } - bool operator==(const SWindowRect& other) const {return !(*this != other);} - - bool coordInRect(const SWindowCoord& coord) const - { - 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]; - } - - SWindowRect intersect(const SWindowRect& other) const - { - 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 { + double coord[2]; }; -struct STouchCoord -{ - double coord[2]; +struct SScrollDelta { + double delta[2]; + bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */ + bool isAccelerated = false; /* System performs acceleration computation */ + + SScrollDelta operator+(const SScrollDelta& other) { + 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; + } + SScrollDelta& operator+=(const SScrollDelta& other) { + delta[0] += other.delta[0]; + delta[1] += other.delta[1]; + isFine |= other.isFine; + isAccelerated |= other.isAccelerated; + return *this; + } + void zeroOut() { + delta[0] = 0.0; + delta[1] = 0.0; + } }; -struct SScrollDelta -{ - double delta[2]; - bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */ - bool isAccelerated = false; /* System performs acceleration computation */ - - SScrollDelta operator+(const SScrollDelta& other) - { - 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; - } - SScrollDelta& operator+=(const SScrollDelta& other) - { - delta[0] += other.delta[0]; - delta[1] += other.delta[1]; - isFine |= other.isFine; - isAccelerated |= other.isAccelerated; - return *this; - } - void zeroOut() {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 }; -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 -}; - -enum class EModifierKey -{ - None = 0, - Ctrl = 1<<0, - Alt = 1<<2, - Shift = 1<<3, - Command = 1<<4, - CtrlCommand = EModifierKey::Ctrl | EModifierKey::Command +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 markedRange() const=0; - virtual std::pair selectedRange() const=0; - virtual void setMarkedText(std::string_view str, - const std::pair& selectedRange, - const std::pair& replacementRange)=0; - virtual void unmarkText()=0; - - virtual std::string substringForRange(const std::pair& range, - std::pair& actualRange) const=0; - virtual void insertText(std::string_view str, const std::pair& range={-1,0})=0; - virtual int characterIndexAtPoint(const SWindowCoord& point) const=0; - virtual SWindowRect rectForCharacterRange(const std::pair& range, - std::pair& actualRange) const=0; + +struct ITextInputCallback { + virtual bool hasMarkedText() const = 0; + virtual std::pair markedRange() const = 0; + virtual std::pair selectedRange() const = 0; + virtual void setMarkedText(std::string_view str, const std::pair& selectedRange, + const std::pair& replacementRange) = 0; + virtual void unmarkText() = 0; + + virtual std::string substringForRange(const std::pair& range, std::pair& actualRange) const = 0; + virtual void insertText(std::string_view str, const std::pair& range = {-1, 0}) = 0; + virtual int characterIndexAtPoint(const SWindowCoord& point) const = 0; + virtual SWindowRect rectForCharacterRange(const std::pair& range, + std::pair& actualRange) const = 0; }; -class IWindowCallback -{ +class IWindowCallback { public: - virtual void resized(const SWindowRect& rect, bool sync) - {(void)rect;} - virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) - {(void)coord;(void)button;(void)mods;} - virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) - {(void)coord;(void)button;(void)mods;} - virtual void mouseMove(const SWindowCoord& coord) - {(void)coord;} - virtual void mouseEnter(const SWindowCoord& coord) - {(void)coord;} - virtual void mouseLeave(const SWindowCoord& coord) - {(void)coord;} - virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) - {(void)coord;(void)scroll;} + virtual void resized(const SWindowRect& rect, bool sync) { (void)rect; } + virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { + (void)coord; + (void)button; + (void)mods; + } + virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { + (void)coord; + (void)button; + (void)mods; + } + virtual void mouseMove(const SWindowCoord& coord) { (void)coord; } + virtual void mouseEnter(const SWindowCoord& coord) { (void)coord; } + virtual void mouseLeave(const SWindowCoord& coord) { (void)coord; } + virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { + (void)coord; + (void)scroll; + } - virtual void touchDown(const STouchCoord& coord, uintptr_t tid) - {(void)coord;(void)tid;} - virtual void touchUp(const STouchCoord& coord, uintptr_t tid) - {(void)coord;(void)tid;} - virtual void touchMove(const STouchCoord& coord, uintptr_t tid) - {(void)coord;(void)tid;} + virtual void touchDown(const STouchCoord& coord, uintptr_t tid) { + (void)coord; + (void)tid; + } + virtual void touchUp(const STouchCoord& coord, uintptr_t tid) { + (void)coord; + (void)tid; + } + virtual void touchMove(const STouchCoord& coord, uintptr_t tid) { + (void)coord; + (void)tid; + } - virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) - {(void)charCode;(void)mods;(void)isRepeat;} - virtual void charKeyUp(unsigned long charCode, EModifierKey mods) - {(void)charCode;(void)mods;} - virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) - {(void)key;(void)mods;(void)isRepeat;} - virtual void specialKeyUp(ESpecialKey key, EModifierKey mods) - {(void)key;(void)mods;} - virtual void modKeyDown(EModifierKey mod, bool isRepeat) - {(void)mod;(void)isRepeat;} - virtual void modKeyUp(EModifierKey mod) {(void)mod;} - - virtual ITextInputCallback* getTextInputCallback() {return nullptr;} - - virtual void focusLost() {} - virtual void focusGained() {} - virtual void windowMoved(const SWindowRect& rect) - { (void)rect; } + virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) { + (void)charCode; + (void)mods; + (void)isRepeat; + } + virtual void charKeyUp(unsigned long charCode, EModifierKey mods) { + (void)charCode; + (void)mods; + } + virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) { + (void)key; + (void)mods; + (void)isRepeat; + } + virtual void specialKeyUp(ESpecialKey key, EModifierKey mods) { + (void)key; + (void)mods; + } + virtual void modKeyDown(EModifierKey mod, bool isRepeat) { + (void)mod; + (void)isRepeat; + } + virtual void modKeyUp(EModifierKey mod) { (void)mod; } - virtual void destroyed() - {} + virtual ITextInputCallback* getTextInputCallback() { return nullptr; } + + virtual void focusLost() {} + virtual void focusGained() {} + virtual void windowMoved(const SWindowRect& rect) { (void)rect; } + + virtual void destroyed() {} }; -enum class ETouchType -{ - None = 0, - Display = 1, - Trackpad = 2 -}; +enum class ETouchType { None = 0, Display = 1, Trackpad = 2 }; -enum class EWindowStyle -{ - None = 0, - Titlebar = 1<<0, - Resize = 1<<1, - Close = 1<<2, +enum class EWindowStyle { + None = 0, + Titlebar = 1 << 0, + Resize = 1 << 1, + Close = 1 << 2, - Default = Titlebar | Resize | Close + Default = Titlebar | Resize | Close }; ENABLE_BITWISE_ENUM(EWindowStyle) -enum class EMouseCursor -{ - None = 0, - Pointer = 1, - HorizontalArrow = 2, - VerticalArrow = 3, - IBeam = 4, - Crosshairs = 5 -}; +enum class EMouseCursor { None = 0, Pointer = 1, HorizontalArrow = 2, VerticalArrow = 3, IBeam = 4, Crosshairs = 5 }; -enum class EClipboardType -{ - None = 0, - String = 1, - UTF8String = 2, - PNGImage = 3 -}; +enum class EClipboardType { None = 0, String = 1, UTF8String = 2, PNGImage = 3 }; -class IWindow : public std::enable_shared_from_this -{ +class IWindow : public std::enable_shared_from_this { public: - - virtual ~IWindow() = default; - - virtual void setCallback(IWindowCallback* cb)=0; + virtual ~IWindow() = default; - virtual void closeWindow()=0; - virtual void showWindow()=0; - virtual void hideWindow()=0; - - virtual SystemString getTitle()=0; - virtual void setTitle(SystemStringView title)=0; + virtual void setCallback(IWindowCallback* cb) = 0; - virtual void setCursor(EMouseCursor cursor)=0; - virtual void setWaitCursor(bool wait)=0; + virtual void closeWindow() = 0; + virtual void showWindow() = 0; + virtual void hideWindow() = 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 SystemString getTitle() = 0; + virtual void setTitle(SystemStringView title) = 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 clipboardPaste(EClipboardType type, size_t& sz)=0; + virtual void setCursor(EMouseCursor cursor) = 0; + virtual void setWaitCursor(bool wait) = 0; - virtual void waitForRetrace()=0; - - virtual uintptr_t getPlatformHandle() const=0; - virtual bool _incomingEvent(void* event) {(void)event; return false;} - virtual void _cleanup() {} + 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 ETouchType getTouchType() const=0; + virtual bool isFullscreen() const = 0; + virtual void setFullscreen(bool fs) = 0; - virtual void setStyle(EWindowStyle style)=0; - virtual EWindowStyle getStyle() const=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 clipboardPaste(EClipboardType type, size_t& sz) = 0; - virtual void setTouchBarProvider(void*) {} + virtual void waitForRetrace() = 0; - virtual IGraphicsCommandQueue* getCommandQueue()=0; - virtual IGraphicsDataFactory* getDataFactory()=0; + virtual uintptr_t getPlatformHandle() const = 0; + virtual bool _incomingEvent(void* event) { + (void)event; + return false; + } + virtual void _cleanup() {} - /* Creates a new context on current thread!! Call from main client thread */ - virtual IGraphicsDataFactory* getMainContextDataFactory()=0; + virtual ETouchType getTouchType() const = 0; - /* Creates a new context on current thread!! Call from client loading thread */ - virtual IGraphicsDataFactory* getLoadContextDataFactory()=0; + virtual void setStyle(EWindowStyle style) = 0; + virtual EWindowStyle getStyle() const = 0; + + virtual void setTouchBarProvider(void*) {} + + 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 diff --git a/include/boo/System.hpp b/include/boo/System.hpp index c87828f..9f99306 100644 --- a/include/boo/System.hpp +++ b/include/boo/System.hpp @@ -14,68 +14,65 @@ template using ComPtr = Microsoft::WRL::ComPtr; template -static inline ComPtr* ReferenceComPtr(ComPtr& ptr) -{ return reinterpret_cast*>(ptr.GetAddressOf()); } +static inline ComPtr* ReferenceComPtr(ComPtr& ptr) { + return reinterpret_cast*>(ptr.GetAddressOf()); +} #endif #include #include #ifndef ENABLE_BITWISE_ENUM -#define ENABLE_BITWISE_ENUM(type)\ -constexpr type operator|(type a, type b)\ -{\ - using T = std::underlying_type_t;\ - return type(static_cast(a) | static_cast(b));\ -}\ -constexpr type operator&(type a, type b)\ -{\ - using T = std::underlying_type_t;\ - return type(static_cast(a) & static_cast(b));\ -}\ -inline type& operator|=(type& a, const type& b)\ -{\ - using T = std::underlying_type_t;\ - a = type(static_cast(a) | static_cast(b));\ - return a;\ -}\ -inline type& operator&=(type& a, const type& b)\ -{\ - using T = std::underlying_type_t;\ - a = type(static_cast(a) & static_cast(b));\ - return a;\ -}\ -inline type operator~(const type& key)\ -{\ - using T = std::underlying_type_t;\ - return type(~static_cast(key));\ -} +#define ENABLE_BITWISE_ENUM(type) \ + constexpr type operator|(type a, type b) { \ + using T = std::underlying_type_t; \ + return type(static_cast(a) | static_cast(b)); \ + } \ + constexpr type operator&(type a, type b) { \ + using T = std::underlying_type_t; \ + return type(static_cast(a) & static_cast(b)); \ + } \ + inline type& operator|=(type& a, const type& b) { \ + using T = std::underlying_type_t; \ + a = type(static_cast(a) | static_cast(b)); \ + return a; \ + } \ + inline type& operator&=(type& a, const type& b) { \ + using T = std::underlying_type_t; \ + a = type(static_cast(a) & static_cast(b)); \ + return a; \ + } \ + inline type operator~(const type& key) { \ + using T = std::underlying_type_t; \ + return type(~static_cast(key)); \ + } #endif -namespace boo -{ +namespace boo { #ifdef _WIN32 - using SystemString = std::wstring; - using SystemStringView = std::wstring_view; - using SystemChar = wchar_t; -# ifndef _SYS_STR -# define _SYS_STR(val) L ## val -# endif +using SystemString = std::wstring; +using SystemStringView = std::wstring_view; +using SystemChar = wchar_t; +#ifndef _SYS_STR +#define _SYS_STR(val) L##val +#endif #else - using SystemString = std::string; - using SystemStringView = std::string_view; - using SystemChar = char; -# ifndef _SYS_STR -# define _SYS_STR(val) val -# endif +using SystemString = std::string; +using SystemStringView = std::string_view; +using SystemChar = char; +#ifndef _SYS_STR +#define _SYS_STR(val) val +#endif #endif #ifndef NDEBUG -#define __BooTraceArgs , const char* file, int line +#define __BooTraceArgs , const char *file, int line #define __BooTraceArgsUse , file, line #define __BooTraceInitializer , m_file(file), m_line(line) -#define __BooTraceFields const char* m_file; int m_line; +#define __BooTraceFields \ + const char* m_file; \ + int m_line; #define BooTrace , __FILE__, __LINE__ #else #define __BooTraceArgs @@ -85,5 +82,4 @@ namespace boo #define BooTrace #endif -} - +} // namespace boo diff --git a/include/boo/ThreadLocalPtr.hpp b/include/boo/ThreadLocalPtr.hpp index 8473683..05652a5 100644 --- a/include/boo/ThreadLocalPtr.hpp +++ b/include/boo/ThreadLocalPtr.hpp @@ -9,25 +9,25 @@ /** Multiplatform TLS-pointer wrapper (for compilers without proper thread_local support) */ template -class ThreadLocalPtr -{ +class ThreadLocalPtr { #if _WIN32 - DWORD m_key; + DWORD m_key; + public: - ThreadLocalPtr() {m_key = TlsAlloc();} - ~ThreadLocalPtr() {TlsFree(m_key);} - T* get() const {return static_cast(TlsGetValue(m_key));} - void reset(T* v=nullptr) {TlsSetValue(m_key, LPVOID(v));} + ThreadLocalPtr() { m_key = TlsAlloc(); } + ~ThreadLocalPtr() { TlsFree(m_key); } + T* get() const { return static_cast(TlsGetValue(m_key)); } + void reset(T* v = nullptr) { TlsSetValue(m_key, LPVOID(v)); } #else - pthread_key_t m_key; + 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(pthread_getspecific(m_key));} - void reset(T* v=nullptr) {pthread_setspecific(m_key, v);} + ThreadLocalPtr() { pthread_key_create(&m_key, nullptr); } + ~ThreadLocalPtr() { pthread_key_delete(m_key); } + T* get() const { return static_cast(pthread_getspecific(m_key)); } + void reset(T* v = nullptr) { pthread_setspecific(m_key, v); } #endif - T* operator->() {return get();} + T* operator->() { return get(); } }; #endif - diff --git a/include/boo/UWPViewProvider.hpp b/include/boo/UWPViewProvider.hpp index dcc54b6..e01aedb 100644 --- a/include/boo/UWPViewProvider.hpp +++ b/include/boo/UWPViewProvider.hpp @@ -2,43 +2,37 @@ #include "IApplication.hpp" -namespace boo -{ +namespace boo { #if WINDOWS_STORE using namespace Windows::ApplicationModel::Core; -ref struct ViewProvider sealed : IFrameworkViewSource -{ -internal: - ViewProvider(boo::IApplicationCallback& appCb, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - Platform::Array^ params, - bool singleInstance) - : m_appCb(appCb), m_uniqueName(uniqueName), m_friendlyName(friendlyName), - m_pname(pname), m_singleInstance(singleInstance) - { - SystemChar 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(); +ref struct ViewProvider sealed : IFrameworkViewSource { + internal : ViewProvider(boo::IApplicationCallback& appCb, SystemStringView uniqueName, SystemStringView friendlyName, + SystemStringView pname, Platform::Array ^ params, bool singleInstance) + : m_appCb(appCb) + , m_uniqueName(uniqueName) + , m_friendlyName(friendlyName) + , m_pname(pname) + , m_singleInstance(singleInstance) { + SystemChar 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()); + } -internal: - boo::IApplicationCallback& m_appCb; - SystemString m_uniqueName; - SystemString m_friendlyName; - SystemString m_pname; - std::vector m_args; - bool m_singleInstance; +public: + virtual IFrameworkView ^ CreateView(); + + internal : boo::IApplicationCallback& m_appCb; + SystemString m_uniqueName; + SystemString m_friendlyName; + SystemString m_pname; + std::vector m_args; + bool m_singleInstance; }; #endif - -} +} // namespace boo diff --git a/include/boo/audiodev/IAudioSubmix.hpp b/include/boo/audiodev/IAudioSubmix.hpp index 42b67a8..f3c6694 100644 --- a/include/boo/audiodev/IAudioSubmix.hpp +++ b/include/boo/audiodev/IAudioSubmix.hpp @@ -5,51 +5,39 @@ #include #include "boo/BooObject.hpp" -namespace boo -{ +namespace boo { struct IAudioVoice; struct IAudioVoiceCallback; struct ChannelMap; struct IAudioSubmixCallback; -enum class SubmixFormat -{ - Int16, - Int32, - Float +enum class SubmixFormat { Int16, Int32, Float }; + +struct IAudioSubmix : IObj { + /** Reset channel-levels to silence; unbind all submixes */ + virtual void resetSendLevels() = 0; + + /** Set channel-levels for target submix (AudioChannel enum for array index) */ + virtual void setSendLevel(IAudioSubmix* submix, float level, bool slew) = 0; + + /** Gets fixed sample rate of submix this way */ + virtual double getSampleRate() const = 0; + + /** Gets fixed sample format of submix this way */ + virtual SubmixFormat getSampleFormat() const = 0; }; -struct IAudioSubmix : IObj -{ - /** Reset channel-levels to silence; unbind all submixes */ - virtual void resetSendLevels()=0; +struct IAudioSubmixCallback { + /** Client-provided claim to implement / is ready to call applyEffect() */ + virtual bool canApplyEffect() const = 0; - /** Set channel-levels for target submix (AudioChannel enum for array index) */ - virtual void setSendLevel(IAudioSubmix* submix, float level, bool slew)=0; + /** Client-provided effect solution for interleaved, master sample-rate audio */ + virtual void applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0; + virtual void applyEffect(int32_t* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0; + virtual void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0; - /** Gets fixed sample rate of submix this way */ - virtual double getSampleRate() const=0; - - /** Gets fixed sample format of submix this way */ - virtual SubmixFormat getSampleFormat() const=0; + /** Notify of output sample rate changes (for instance, changing the default audio device on Windows) */ + virtual void resetOutputSampleRate(double sampleRate) = 0; }; -struct IAudioSubmixCallback -{ - /** Client-provided claim to implement / is ready to call applyEffect() */ - virtual bool canApplyEffect() const=0; - - /** Client-provided effect solution for interleaved, master sample-rate audio */ - virtual void applyEffect(int16_t* audio, size_t frameCount, - const ChannelMap& chanMap, double sampleRate) const=0; - virtual void applyEffect(int32_t* audio, size_t frameCount, - const ChannelMap& chanMap, double sampleRate) const=0; - virtual void applyEffect(float* audio, size_t frameCount, - const ChannelMap& chanMap, double sampleRate) const=0; - - /** Notify of output sample rate changes (for instance, changing the default audio device on Windows) */ - virtual void resetOutputSampleRate(double sampleRate)=0; -}; - -} - +} // namespace boo diff --git a/include/boo/audiodev/IAudioVoice.hpp b/include/boo/audiodev/IAudioVoice.hpp index e5b6c7a..1c0db37 100644 --- a/include/boo/audiodev/IAudioVoice.hpp +++ b/include/boo/audiodev/IAudioVoice.hpp @@ -5,106 +5,89 @@ #include #include "boo/BooObject.hpp" -namespace boo -{ +namespace boo { struct IAudioSubmix; -enum class AudioChannelSet -{ - Stereo, - Quad, - Surround51, - Surround71, - Unknown = 0xff +enum class AudioChannelSet { Stereo, Quad, Surround51, Surround71, Unknown = 0xff }; + +enum class AudioChannel { + FrontLeft, + FrontRight, + RearLeft, + RearRight, + FrontCenter, + LFE, + SideLeft, + SideRight, + Unknown = 0xff }; -enum class AudioChannel -{ - FrontLeft, - FrontRight, - RearLeft, - RearRight, - FrontCenter, - LFE, - SideLeft, - SideRight, - Unknown = 0xff +struct ChannelMap { + unsigned m_channelCount = 0; + AudioChannel m_channels[8] = {}; }; -struct ChannelMap -{ - unsigned m_channelCount = 0; - AudioChannel m_channels[8] = {}; -}; - -static inline unsigned ChannelCount(AudioChannelSet layout) -{ - switch (layout) - { - case AudioChannelSet::Stereo: - return 2; - case AudioChannelSet::Quad: - return 4; - case AudioChannelSet::Surround51: - return 6; - case AudioChannelSet::Surround71: - return 8; - default: break; - } - return 0; +static inline unsigned ChannelCount(AudioChannelSet layout) { + switch (layout) { + case AudioChannelSet::Stereo: + return 2; + case AudioChannelSet::Quad: + return 4; + case AudioChannelSet::Surround51: + return 6; + case AudioChannelSet::Surround71: + return 8; + default: + break; + } + return 0; } -struct IAudioVoice : IObj -{ - /** Set sample rate into voice (may result in audio discontinuities) */ - virtual void resetSampleRate(double sampleRate)=0; +struct IAudioVoice : IObj { + /** Set sample rate into voice (may result in audio discontinuities) */ + virtual void resetSampleRate(double sampleRate) = 0; - /** Reset channel-levels to silence; unbind all submixes */ - virtual void resetChannelLevels()=0; + /** Reset channel-levels to silence; unbind all submixes */ + virtual void resetChannelLevels() = 0; - /** Set channel-levels for mono audio source (AudioChannel enum for array index) */ - virtual void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew)=0; + /** Set channel-levels for mono audio source (AudioChannel enum for array index) */ + virtual void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) = 0; - /** Set channel-levels for stereo audio source (AudioChannel enum for array index) */ - virtual void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew)=0; + /** Set channel-levels for stereo audio source (AudioChannel enum for array index) */ + virtual void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) = 0; - /** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */ - virtual void setPitchRatio(double ratio, bool slew)=0; + /** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */ + virtual void setPitchRatio(double ratio, bool slew) = 0; - /** Instructs platform to begin consuming sample data; invoking callback as needed */ - virtual void start()=0; + /** Instructs platform to begin consuming sample data; invoking callback as needed */ + virtual void start() = 0; - /** Instructs platform to stop consuming sample data */ - virtual void stop()=0; + /** Instructs platform to stop consuming sample data */ + virtual void stop() = 0; }; -struct IAudioVoiceCallback -{ - /** boo calls this on behalf of the audio platform to proactively invoke potential - * pitch or panning changes before processing samples */ - virtual void preSupplyAudio(boo::IAudioVoice& voice, double dt)=0; +struct IAudioVoiceCallback { + /** boo calls this on behalf of the audio platform to proactively invoke potential + * pitch or panning changes before processing samples */ + virtual void preSupplyAudio(boo::IAudioVoice& voice, double dt) = 0; - /** boo calls this on behalf of the audio platform to request more audio - * frames from the client */ - virtual size_t supplyAudio(IAudioVoice& voice, size_t frames, int16_t* data)=0; + /** boo calls this on behalf of the audio platform to request more audio + * frames from the client */ + virtual size_t supplyAudio(IAudioVoice& voice, size_t frames, int16_t* data) = 0; - /** after resampling, boo calls this for each submix that this voice targets; - * client performs volume processing and bus-routing this way */ - virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out) - { - memmove(out, in, frames * channels * 2); - } + /** after resampling, boo calls this for each submix that this voice targets; + * client performs volume processing and bus-routing this way */ + virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out) { + memmove(out, in, frames * channels * 2); + } - virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out) - { - memmove(out, in, frames * channels * 4); - } + virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out) { + memmove(out, in, frames * channels * 4); + } - virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out) - { - memmove(out, in, frames * channels * 4); - } + virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out) { + memmove(out, in, frames * channels * 4); + } }; -} - +} // namespace boo diff --git a/include/boo/audiodev/IAudioVoiceEngine.hpp b/include/boo/audiodev/IAudioVoiceEngine.hpp index f63572c..f05e0de 100644 --- a/include/boo/audiodev/IAudioVoiceEngine.hpp +++ b/include/boo/audiodev/IAudioVoiceEngine.hpp @@ -7,100 +7,95 @@ #include #include -namespace boo -{ +namespace boo { struct IAudioVoiceEngine; /** Time-sensitive event callback for synchronizing the client with rendered audio waveform */ -struct IAudioVoiceEngineCallback -{ - /** All mixing occurs in virtual 5ms intervals; - * this is called at the start of each interval for all mixable entities */ - virtual void on5MsInterval(IAudioVoiceEngine& engine, double dt) {} +struct IAudioVoiceEngineCallback { + /** All mixing occurs in virtual 5ms intervals; + * this is called at the start of each interval for all mixable entities */ + virtual void on5MsInterval(IAudioVoiceEngine& engine, double dt) {} - /** When a pumping cycle is complete this is called to allow the client to - * perform periodic cleanup tasks */ - virtual void onPumpCycleComplete(IAudioVoiceEngine& engine) {} + /** When a pumping cycle is complete this is called to allow the client to + * perform periodic cleanup tasks */ + virtual void onPumpCycleComplete(IAudioVoiceEngine& engine) {} }; /** Mixing and sample-rate-conversion system. Allocates voices and mixes them * before sending the final samples to an OS-supplied audio-queue */ -struct IAudioVoiceEngine -{ - virtual ~IAudioVoiceEngine() = default; +struct IAudioVoiceEngine { + virtual ~IAudioVoiceEngine() = default; - /** Client calls this to request allocation of new mixer-voice. - * Returns empty unique_ptr if necessary resources aren't available. - * ChannelLayout automatically reduces to maximum-supported layout by HW. - * - * Client must be prepared to supply audio frames via the callback when this is called; - * the backing audio-buffers are primed with initial data for low-latency playback start - */ - virtual ObjToken allocateNewMonoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch=false)=0; + /** Client calls this to request allocation of new mixer-voice. + * Returns empty unique_ptr if necessary resources aren't available. + * ChannelLayout automatically reduces to maximum-supported layout by HW. + * + * Client must be prepared to supply audio frames via the callback when this is called; + * the backing audio-buffers are primed with initial data for low-latency playback start + */ + virtual ObjToken allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb, + bool dynamicPitch = false) = 0; - /** Same as allocateNewMonoVoice, but source audio is stereo-interleaved */ - virtual ObjToken allocateNewStereoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch=false)=0; + /** Same as allocateNewMonoVoice, but source audio is stereo-interleaved */ + virtual ObjToken allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb, + bool dynamicPitch = false) = 0; - /** Client calls this to allocate a Submix for gathering audio together for effects processing */ - virtual ObjToken allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId)=0; + /** Client calls this to allocate a Submix for gathering audio together for effects processing */ + virtual ObjToken allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId) = 0; - /** Client can register for key callback events from the mixing engine this way */ - virtual void setCallbackInterface(IAudioVoiceEngineCallback* cb)=0; + /** Client can register for key callback events from the mixing engine this way */ + virtual void setCallbackInterface(IAudioVoiceEngineCallback* cb) = 0; - /** Client may use this to determine current speaker-setup */ - virtual AudioChannelSet getAvailableSet()=0; + /** Client may use this to determine current speaker-setup */ + virtual AudioChannelSet getAvailableSet() = 0; - /** Ensure backing platform buffer is filled as much as possible with mixed samples */ - virtual void pumpAndMixVoices()=0; + /** Ensure backing platform buffer is filled as much as possible with mixed samples */ + virtual void pumpAndMixVoices() = 0; - /** Set total volume of engine */ - virtual void setVolume(float vol)=0; + /** Set total volume of engine */ + virtual void setVolume(float vol) = 0; - /** Enable or disable Lt/Rt surround encoding. If successful, getAvailableSet() will return Surround51 */ - virtual bool enableLtRt(bool enable)=0; + /** Enable or disable Lt/Rt surround encoding. If successful, getAvailableSet() will return Surround51 */ + virtual bool enableLtRt(bool enable) = 0; - /** Get current Audio output in use */ - virtual std::string getCurrentAudioOutput() const=0; + /** Get current Audio output in use */ + virtual std::string getCurrentAudioOutput() const = 0; - /** Set current Audio output to use */ - virtual bool setCurrentAudioOutput(const char* name)=0; + /** Set current Audio output to use */ + virtual bool setCurrentAudioOutput(const char* name) = 0; - /** Get list of Audio output devices found on system */ - virtual std::vector> enumerateAudioOutputs() const=0; + /** Get list of Audio output devices found on system */ + virtual std::vector> enumerateAudioOutputs() const = 0; - /** Get list of MIDI input devices found on system */ - virtual std::vector> enumerateMIDIInputs() const=0; + /** Get list of MIDI input devices found on system */ + virtual std::vector> enumerateMIDIInputs() const = 0; - /** Query if system supports creating a virtual MIDI input */ - virtual bool supportsVirtualMIDIIn() const=0; + /** Query if system supports creating a virtual MIDI input */ + virtual bool supportsVirtualMIDIIn() const = 0; - /** Create ad-hoc MIDI in port and register with system */ - virtual std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver)=0; + /** Create ad-hoc MIDI in port and register with system */ + virtual std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) = 0; - /** Create ad-hoc MIDI out port and register with system */ - virtual std::unique_ptr newVirtualMIDIOut()=0; + /** Create ad-hoc MIDI out port and register with system */ + virtual std::unique_ptr newVirtualMIDIOut() = 0; - /** Create ad-hoc MIDI in/out port and register with system */ - virtual std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver)=0; + /** Create ad-hoc MIDI in/out port and register with system */ + virtual std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) = 0; - /** Open named MIDI in port, name format depends on OS */ - virtual std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)=0; + /** Open named MIDI in port, name format depends on OS */ + virtual std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) = 0; - /** Open named MIDI out port, name format depends on OS */ - virtual std::unique_ptr newRealMIDIOut(const char* name)=0; + /** Open named MIDI out port, name format depends on OS */ + virtual std::unique_ptr newRealMIDIOut(const char* name) = 0; - /** Open named MIDI in/out port, name format depends on OS */ - virtual std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)=0; + /** Open named MIDI in/out port, name format depends on OS */ + virtual std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) = 0; - /** If this returns true, MIDI callbacks are assumed to be *not* thread-safe; need protection via mutex */ - virtual bool useMIDILock() const=0; + /** If this returns true, MIDI callbacks are assumed to be *not* thread-safe; need protection via mutex */ + virtual bool useMIDILock() const = 0; - /** Get canonical count of frames for each 5ms output block */ - virtual size_t get5MsFrames() const=0; + /** Get canonical count of frames for each 5ms output block */ + virtual size_t get5MsFrames() const = 0; }; /** Construct host platform's voice engine */ @@ -112,5 +107,4 @@ std::unique_ptr NewWAVAudioVoiceEngine(const char* path, doub std::unique_ptr NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans); #endif -} - +} // namespace boo diff --git a/include/boo/audiodev/IMIDIPort.hpp b/include/boo/audiodev/IMIDIPort.hpp index 4af9988..8fba831 100644 --- a/include/boo/audiodev/IMIDIPort.hpp +++ b/include/boo/audiodev/IMIDIPort.hpp @@ -5,58 +5,56 @@ #include #include -namespace boo -{ +namespace boo { struct IAudioVoiceEngine; using ReceiveFunctor = std::function&&, double time)>; -class IMIDIPort -{ - bool m_virtual; +class IMIDIPort { + bool m_virtual; + protected: - IAudioVoiceEngine* m_parent; - IMIDIPort(IAudioVoiceEngine* parent, bool virt) : m_virtual(virt), m_parent(parent) {} + IAudioVoiceEngine* m_parent; + IMIDIPort(IAudioVoiceEngine* parent, bool virt) : m_virtual(virt), m_parent(parent) {} + public: - virtual ~IMIDIPort(); - bool isVirtual() const {return m_virtual;} - virtual std::string description() const=0; - void _disown() { m_parent = nullptr; } + virtual ~IMIDIPort(); + bool isVirtual() const { return m_virtual; } + virtual std::string description() const = 0; + void _disown() { m_parent = nullptr; } }; -class IMIDIReceiver -{ +class IMIDIReceiver { public: - ReceiveFunctor m_receiver; - IMIDIReceiver(ReceiveFunctor&& receiver) : m_receiver(std::move(receiver)) {} + ReceiveFunctor m_receiver; + IMIDIReceiver(ReceiveFunctor&& receiver) : m_receiver(std::move(receiver)) {} }; -class IMIDIIn : public IMIDIPort, public IMIDIReceiver -{ +class IMIDIIn : public IMIDIPort, public IMIDIReceiver { protected: - IMIDIIn(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) - : IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {} + IMIDIIn(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) + : IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {} + public: - virtual ~IMIDIIn(); + virtual ~IMIDIIn(); }; -class IMIDIOut : public IMIDIPort -{ +class IMIDIOut : public IMIDIPort { protected: - IMIDIOut(IAudioVoiceEngine* parent, bool virt) : IMIDIPort(parent, virt) {} + IMIDIOut(IAudioVoiceEngine* parent, bool virt) : IMIDIPort(parent, virt) {} + public: - virtual ~IMIDIOut(); - virtual size_t send(const void* buf, size_t len) const=0; + virtual ~IMIDIOut(); + virtual size_t send(const void* buf, size_t len) const = 0; }; -class IMIDIInOut : public IMIDIPort, public IMIDIReceiver -{ +class IMIDIInOut : public IMIDIPort, public IMIDIReceiver { protected: - IMIDIInOut(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) - : IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {} + IMIDIInOut(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) + : IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {} + public: - virtual ~IMIDIInOut(); - virtual size_t send(const void* buf, size_t len) const=0; + virtual ~IMIDIInOut(); + virtual size_t send(const void* buf, size_t len) const = 0; }; -} - +} // namespace boo diff --git a/include/boo/audiodev/IMIDIReader.hpp b/include/boo/audiodev/IMIDIReader.hpp index b604a3c..61e1d93 100644 --- a/include/boo/audiodev/IMIDIReader.hpp +++ b/include/boo/audiodev/IMIDIReader.hpp @@ -3,39 +3,36 @@ #include #include -namespace boo -{ +namespace boo { -class IMIDIReader -{ +class IMIDIReader { public: - virtual void noteOff(uint8_t chan, uint8_t key, uint8_t velocity)=0; - virtual void noteOn(uint8_t chan, uint8_t key, uint8_t velocity)=0; - virtual void notePressure(uint8_t chan, uint8_t key, uint8_t pressure)=0; - virtual void controlChange(uint8_t chan, uint8_t control, uint8_t value)=0; - virtual void programChange(uint8_t chan, uint8_t program)=0; - virtual void channelPressure(uint8_t chan, uint8_t pressure)=0; - virtual void pitchBend(uint8_t chan, int16_t pitch)=0; + virtual void noteOff(uint8_t chan, uint8_t key, uint8_t velocity) = 0; + virtual void noteOn(uint8_t chan, uint8_t key, uint8_t velocity) = 0; + virtual void notePressure(uint8_t chan, uint8_t key, uint8_t pressure) = 0; + virtual void controlChange(uint8_t chan, uint8_t control, uint8_t value) = 0; + virtual void programChange(uint8_t chan, uint8_t program) = 0; + virtual void channelPressure(uint8_t chan, uint8_t pressure) = 0; + virtual void pitchBend(uint8_t chan, int16_t pitch) = 0; - virtual void allSoundOff(uint8_t chan)=0; - virtual void resetAllControllers(uint8_t chan)=0; - virtual void localControl(uint8_t chan, bool on)=0; - virtual void allNotesOff(uint8_t chan)=0; - virtual void omniMode(uint8_t chan, bool on)=0; - virtual void polyMode(uint8_t chan, bool on)=0; + virtual void allSoundOff(uint8_t chan) = 0; + virtual void resetAllControllers(uint8_t chan) = 0; + virtual void localControl(uint8_t chan, bool on) = 0; + virtual void allNotesOff(uint8_t chan) = 0; + virtual void omniMode(uint8_t chan, bool on) = 0; + virtual void polyMode(uint8_t chan, bool on) = 0; - virtual void sysex(const void* data, size_t len)=0; - virtual void timeCodeQuarterFrame(uint8_t message, uint8_t value)=0; - virtual void songPositionPointer(uint16_t pointer)=0; - virtual void songSelect(uint8_t song)=0; - virtual void tuneRequest()=0; + virtual void sysex(const void* data, size_t len) = 0; + virtual void timeCodeQuarterFrame(uint8_t message, uint8_t value) = 0; + virtual void songPositionPointer(uint16_t pointer) = 0; + virtual void songSelect(uint8_t song) = 0; + virtual void tuneRequest() = 0; - virtual void startSeq()=0; - virtual void continueSeq()=0; - virtual void stopSeq()=0; + virtual void startSeq() = 0; + virtual void continueSeq() = 0; + virtual void stopSeq() = 0; - virtual void reset()=0; + virtual void reset() = 0; }; -} - +} // namespace boo diff --git a/include/boo/audiodev/MIDIDecoder.hpp b/include/boo/audiodev/MIDIDecoder.hpp index 9ad3572..1263f0f 100644 --- a/include/boo/audiodev/MIDIDecoder.hpp +++ b/include/boo/audiodev/MIDIDecoder.hpp @@ -5,22 +5,18 @@ #include #include -namespace boo -{ +namespace boo { + +class MIDIDecoder { + IMIDIReader& m_out; + uint8_t m_status = 0; + bool _readContinuedValue(std::vector::const_iterator& it, std::vector::const_iterator end, + uint32_t& valOut); -class MIDIDecoder -{ - IMIDIReader& m_out; - uint8_t m_status = 0; - bool _readContinuedValue(std::vector::const_iterator& it, - std::vector::const_iterator end, - uint32_t& valOut); public: - MIDIDecoder(IMIDIReader& out) : m_out(out) {} - std::vector::const_iterator - receiveBytes(std::vector::const_iterator begin, - std::vector::const_iterator end); + MIDIDecoder(IMIDIReader& out) : m_out(out) {} + std::vector::const_iterator receiveBytes(std::vector::const_iterator begin, + std::vector::const_iterator end); }; -} - +} // namespace boo diff --git a/include/boo/audiodev/MIDIEncoder.hpp b/include/boo/audiodev/MIDIEncoder.hpp index 690f639..9a23eb6 100644 --- a/include/boo/audiodev/MIDIEncoder.hpp +++ b/include/boo/audiodev/MIDIEncoder.hpp @@ -3,46 +3,44 @@ #include "boo/audiodev/IMIDIReader.hpp" #include "boo/audiodev/IMIDIPort.hpp" -namespace boo -{ +namespace boo { template -class MIDIEncoder : public IMIDIReader -{ - Sender& m_sender; - uint8_t m_status = 0; - void _sendMessage(const uint8_t* data, size_t len); - void _sendContinuedValue(uint32_t val); +class MIDIEncoder : public IMIDIReader { + Sender& m_sender; + uint8_t m_status = 0; + void _sendMessage(const uint8_t* data, size_t len); + void _sendContinuedValue(uint32_t val); + public: - MIDIEncoder(Sender& sender) : m_sender(sender) {} + MIDIEncoder(Sender& sender) : m_sender(sender) {} - void noteOff(uint8_t chan, uint8_t key, uint8_t velocity); - void noteOn(uint8_t chan, uint8_t key, uint8_t velocity); - void notePressure(uint8_t chan, uint8_t key, uint8_t pressure); - void controlChange(uint8_t chan, uint8_t control, uint8_t value); - void programChange(uint8_t chan, uint8_t program); - void channelPressure(uint8_t chan, uint8_t pressure); - void pitchBend(uint8_t chan, int16_t pitch); + void noteOff(uint8_t chan, uint8_t key, uint8_t velocity); + void noteOn(uint8_t chan, uint8_t key, uint8_t velocity); + void notePressure(uint8_t chan, uint8_t key, uint8_t pressure); + void controlChange(uint8_t chan, uint8_t control, uint8_t value); + void programChange(uint8_t chan, uint8_t program); + void channelPressure(uint8_t chan, uint8_t pressure); + void pitchBend(uint8_t chan, int16_t pitch); - void allSoundOff(uint8_t chan); - void resetAllControllers(uint8_t chan); - void localControl(uint8_t chan, bool on); - void allNotesOff(uint8_t chan); - void omniMode(uint8_t chan, bool on); - void polyMode(uint8_t chan, bool on); + void allSoundOff(uint8_t chan); + void resetAllControllers(uint8_t chan); + void localControl(uint8_t chan, bool on); + void allNotesOff(uint8_t chan); + void omniMode(uint8_t chan, bool on); + void polyMode(uint8_t chan, bool on); - void sysex(const void* data, size_t len); - void timeCodeQuarterFrame(uint8_t message, uint8_t value); - void songPositionPointer(uint16_t pointer); - void songSelect(uint8_t song); - void tuneRequest(); + void sysex(const void* data, size_t len); + void timeCodeQuarterFrame(uint8_t message, uint8_t value); + void songPositionPointer(uint16_t pointer); + void songSelect(uint8_t song); + void tuneRequest(); - void startSeq(); - void continueSeq(); - void stopSeq(); + void startSeq(); + void continueSeq(); + void stopSeq(); - void reset(); + void reset(); }; -} - +} // namespace boo diff --git a/include/boo/boo.hpp b/include/boo/boo.hpp index d25c6ee..606bd65 100644 --- a/include/boo/boo.hpp +++ b/include/boo/boo.hpp @@ -10,4 +10,3 @@ #include "graphicsdev/IGraphicsCommandQueue.hpp" #include "graphicsdev/IGraphicsDataFactory.hpp" #include "DeferredWindowEvents.hpp" - diff --git a/include/boo/graphicsdev/D3D.hpp b/include/boo/graphicsdev/D3D.hpp index 9864a83..b6a6415 100644 --- a/include/boo/graphicsdev/D3D.hpp +++ b/include/boo/graphicsdev/D3D.hpp @@ -9,70 +9,61 @@ #include #include -typedef HRESULT (WINAPI *pD3DCreateBlob) - (SIZE_T Size, - ID3DBlob** ppBlob); +typedef HRESULT(WINAPI* pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob); extern pD3DCreateBlob D3DCreateBlobPROC; -namespace boo -{ +namespace boo { struct BaseGraphicsData; -class D3D11DataFactory : public IGraphicsDataFactory -{ +class D3D11DataFactory : public IGraphicsDataFactory { public: - virtual ~D3D11DataFactory() = default; + virtual ~D3D11DataFactory() = default; - Platform platform() const {return Platform::D3D11;} - const SystemChar* platformName() const {return _SYS_STR("D3D11");} + Platform platform() const { return Platform::D3D11; } + const SystemChar* platformName() const { return _SYS_STR("D3D11"); } - class Context final : public IGraphicsDataFactory::Context - { - friend class D3D11DataFactoryImpl; - D3D11DataFactory& m_parent; - boo::ObjToken m_data; - Context(D3D11DataFactory& parent __BooTraceArgs); - ~Context(); - public: - Platform platform() const {return Platform::D3D11;} - const SystemChar* platformName() const {return _SYS_STR("D3D11");} + class Context final : public IGraphicsDataFactory::Context { + friend class D3D11DataFactoryImpl; + D3D11DataFactory& m_parent; + boo::ObjToken m_data; + Context(D3D11DataFactory& parent __BooTraceArgs); + ~Context(); - boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); - boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); + public: + Platform platform() const { return Platform::D3D11; } + const SystemChar* platformName() const { return _SYS_STR("D3D11"); } - boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz); - boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); - boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); + boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); + boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); - ObjToken - newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); + boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz); + boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode); + boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindCount, size_t depthBindCount); - ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - boo::ObjToken - newShaderDataBinding(const boo::ObjToken& pipeline, - const boo::ObjToken& vbo, - const boo::ObjToken& instVbo, - const boo::ObjToken& ibo, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* bindDepth, - size_t baseVert = 0, size_t baseInst = 0); - }; + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); - static std::vector CompileHLSL(const char* source, PipelineStage stage); + boo::ObjToken newShaderDataBinding( + const boo::ObjToken& pipeline, const boo::ObjToken& vbo, + const boo::ObjToken& instVbo, const boo::ObjToken& ibo, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* bindIdxs, + const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0); + }; + + static std::vector CompileHLSL(const char* source, PipelineStage stage); }; -} +} // namespace boo #endif // _WIN32 diff --git a/include/boo/graphicsdev/GL.hpp b/include/boo/graphicsdev/GL.hpp index 822060a..72e4106 100644 --- a/include/boo/graphicsdev/GL.hpp +++ b/include/boo/graphicsdev/GL.hpp @@ -6,64 +6,56 @@ #include "boo/IGraphicsContext.hpp" #include "GLSLMacros.hpp" -namespace boo -{ +namespace boo { struct BaseGraphicsData; -struct GLContext -{ - uint32_t m_sampleCount = 1; - uint32_t m_anisotropy = 1; - bool m_deepColor = false; +struct GLContext { + uint32_t m_sampleCount = 1; + uint32_t m_anisotropy = 1; + bool m_deepColor = false; }; -class GLDataFactory : public IGraphicsDataFactory -{ +class GLDataFactory : public IGraphicsDataFactory { public: - class Context final : public IGraphicsDataFactory::Context - { - friend class GLDataFactoryImpl; - GLDataFactory& m_parent; - ObjToken m_data; - Context(GLDataFactory& parent __BooTraceArgs); - ~Context(); - public: - Platform platform() const { return Platform::OpenGL; } - const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } + class Context final : public IGraphicsDataFactory::Context { + friend class GLDataFactoryImpl; + GLDataFactory& m_parent; + ObjToken m_data; + Context(GLDataFactory& parent __BooTraceArgs); + ~Context(); - ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); - ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); + public: + Platform platform() const { return Platform::OpenGL; } + const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } - ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz); - ObjToken newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz); - ObjToken newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); - ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindingCount, size_t depthBindingCount); + ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); + ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); - ObjToken - newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); + ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz); + ObjToken newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, const void* data, + size_t sz); + ObjToken newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); + ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindingCount, size_t depthBindingCount); - ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - ObjToken - newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const ObjToken* texs, - const int* texBindIdx, const bool* depthBind, - size_t baseVert = 0, size_t baseInst = 0); - }; + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); + + ObjToken newShaderDataBinding( + const ObjToken& pipeline, const ObjToken& vbo, + const ObjToken& instVbo, const ObjToken& ibo, size_t ubufCount, + const ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const ObjToken* texs, const int* texBindIdx, + const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0); + }; }; -} +} // namespace boo #endif diff --git a/include/boo/graphicsdev/GLSLMacros.hpp b/include/boo/graphicsdev/GLSLMacros.hpp index 1f87528..d8ae8f6 100644 --- a/include/boo/graphicsdev/GLSLMacros.hpp +++ b/include/boo/graphicsdev/GLSLMacros.hpp @@ -3,48 +3,47 @@ #define BOO_GLSL_MAX_UNIFORM_COUNT 8 #define BOO_GLSL_MAX_TEXTURE_COUNT 8 -#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" \ -"#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" \ -"#endif\n" - +#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" \ + "#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" \ + "#endif\n" diff --git a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp index 79a70e0..b9b6d48 100644 --- a/include/boo/graphicsdev/IGraphicsCommandQueue.hpp +++ b/include/boo/graphicsdev/IGraphicsCommandQueue.hpp @@ -4,41 +4,38 @@ #include "boo/IWindow.hpp" #include -namespace boo -{ +namespace boo { -struct IGraphicsCommandQueue -{ - virtual ~IGraphicsCommandQueue() = default; +struct IGraphicsCommandQueue { + virtual ~IGraphicsCommandQueue() = default; - using Platform = IGraphicsDataFactory::Platform; - virtual Platform platform() const=0; - virtual const SystemChar* platformName() const=0; + using Platform = IGraphicsDataFactory::Platform; + virtual Platform platform() const = 0; + virtual const SystemChar* platformName() const = 0; - virtual void setShaderDataBinding(const ObjToken& binding)=0; - virtual void setRenderTarget(const ObjToken& target)=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 setShaderDataBinding(const ObjToken& binding) = 0; + virtual void setRenderTarget(const ObjToken& target) = 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& tex, size_t width, size_t height)=0; - virtual void schedulePostFrameHandler(std::function&& func)=0; + virtual void resizeRenderTexture(const ObjToken& tex, size_t width, size_t height) = 0; + virtual void schedulePostFrameHandler(std::function&& func) = 0; - virtual void setClearColor(const float rgba[4])=0; - virtual void clearTarget(bool render=true, bool depth=true)=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)=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 draw(size_t start, size_t count) = 0; + virtual void drawIndexed(size_t start, size_t count) = 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& texture, const SWindowRect& rect, - bool tlOrigin, int bindIdx, bool color, bool depth, bool clearDepth=false)=0; - virtual void resolveDisplay(const ObjToken& source)=0; - virtual void execute()=0; + virtual void resolveBindTexture(const ObjToken& texture, const SWindowRect& rect, bool tlOrigin, + int bindIdx, bool color, bool depth, bool clearDepth = false) = 0; + virtual void resolveDisplay(const ObjToken& source) = 0; + virtual void execute() = 0; - virtual void startRenderer()=0; - virtual void stopRenderer()=0; + virtual void startRenderer() = 0; + virtual void stopRenderer() = 0; }; -} - +} // namespace boo diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index 68b5112..e651da5 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -12,165 +12,126 @@ #include #endif -namespace boo -{ +namespace boo { struct IGraphicsCommandQueue; /** Supported buffer uses */ -enum class BufferUse -{ - Null, - Vertex, - Index, - Uniform -}; +enum class BufferUse { Null, Vertex, Index, Uniform }; /** Typeless graphics buffer */ -struct IGraphicsBuffer : IObj -{ - bool dynamic() const { return m_dynamic; } +struct IGraphicsBuffer : IObj { + bool dynamic() const { return m_dynamic; } + protected: - bool m_dynamic; - explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {} + bool m_dynamic; + explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {} }; /** Static resource buffer for verts, indices, uniform constants */ -struct IGraphicsBufferS : IGraphicsBuffer -{ +struct IGraphicsBufferS : IGraphicsBuffer { protected: - IGraphicsBufferS() : IGraphicsBuffer(false) {} + 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; +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) {} + IGraphicsBufferD() : IGraphicsBuffer(true) {} }; /** Texture access types */ -enum class TextureType -{ - Static, - StaticArray, - Dynamic, - Render -}; +enum class TextureType { Static, StaticArray, Dynamic, Render }; /** Supported texture formats */ -enum class TextureFormat -{ - RGBA8, - I8, - I16, - DXT1, - PVRTC4 -}; +enum class TextureFormat { RGBA8, I8, I16, DXT1, PVRTC4 }; /** Supported texture clamp modes */ -enum class TextureClampMode -{ - Invalid = -1, - Repeat, - ClampToWhite, - ClampToBlack, - ClampToEdge, - ClampToEdgeNearest -}; +enum class TextureClampMode { Invalid = -1, Repeat, ClampToWhite, ClampToBlack, ClampToEdge, ClampToEdgeNearest }; /** Typeless texture */ -struct ITexture : IObj -{ - TextureType type() const { return m_type; } +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) {} + /* 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) {} + TextureType m_type; + explicit ITexture(TextureType type) : m_type(type) {} }; /** Static resource buffer for textures */ -struct ITextureS : ITexture -{ +struct ITextureS : ITexture { protected: - ITextureS() : ITexture(TextureType::Static) {} + ITextureS() : ITexture(TextureType::Static) {} }; /** Static-array resource buffer for array textures */ -struct ITextureSA : ITexture -{ +struct ITextureSA : ITexture { protected: - ITextureSA() : ITexture(TextureType::StaticArray) {} + 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; +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) {} + ITextureD() : ITexture(TextureType::Dynamic) {} }; /** Resource buffer for render-target textures */ -struct ITextureR : ITexture -{ +struct ITextureR : ITexture { protected: - ITextureR() : ITexture(TextureType::Render) {} + ITextureR() : ITexture(TextureType::Render) {} }; /** Types of vertex attributes */ -enum class VertexSemantic -{ - None = 0, - Position3, - Position4, - Normal3, - Normal4, - Color, - ColorUNorm, - UV2, - UV4, - Weight, - ModelView, - SemanticMask = 0xf, - Instanced = 0x10 +enum class VertexSemantic { + None = 0, + Position3, + Position4, + Normal3, + Normal4, + Color, + ColorUNorm, + UV2, + UV4, + Weight, + ModelView, + 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) {} +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; +struct VertexFormatInfo { + size_t elementCount = 0; + const VertexElementDescriptor* elements = nullptr; - VertexFormatInfo() = default; + VertexFormatInfo() = default; - VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem) - : elementCount(sz), elements(elem) {} + VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem) : elementCount(sz), elements(elem) {} - template - VertexFormatInfo(const T& tp) - : elementCount(std::extent_v), elements(tp) {} + template + VertexFormatInfo(const T& tp) : elementCount(std::extent_v), elements(tp) {} - VertexFormatInfo(const std::initializer_list& l) - : elementCount(l.size()), elements(l.begin()) {} + VertexFormatInfo(const std::initializer_list& l) + : elementCount(l.size()), elements(l.begin()) {} }; /** Opaque token for referencing a shader stage usable in a graphics pipeline */ @@ -186,176 +147,128 @@ struct IShaderPipeline : IObj {}; struct IShaderDataBinding : IObj {}; /** Used wherever distinction of pipeline stages is needed */ -enum class PipelineStage -{ - Null, - Vertex, - Fragment, - Geometry, - Control, - Evaluation +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 Primitive -{ - Triangles, - TriStrips, - Patches -}; +enum class BlendFactor { + Zero, + One, + SrcColor, + InvSrcColor, + DstColor, + InvDstColor, + SrcAlpha, + InvSrcAlpha, + DstAlpha, + InvDstAlpha, + SrcColor1, + InvSrcColor1, -/** 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 + /* 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 = true; - bool depthAttachment = true; +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 = true; + bool depthAttachment = true; }; /** Factory object for creating batches of resources as an IGraphicsData token */ -struct IGraphicsDataFactory -{ - virtual ~IGraphicsDataFactory() = default; +struct IGraphicsDataFactory { + virtual ~IGraphicsDataFactory() = default; - enum class Platform - { - Null, - OpenGL, - D3D11, - Metal, - Vulkan, - GX, - NX - }; - virtual Platform platform() const=0; - virtual const SystemChar* platformName() const=0; + enum class Platform { Null, OpenGL, D3D11, Metal, Vulkan, GX, NX }; + virtual Platform platform() const = 0; + virtual const SystemChar* platformName() const = 0; - struct Context - { - virtual Platform platform() const=0; - virtual const SystemChar* platformName() const=0; + struct Context { + virtual Platform platform() const = 0; + virtual const SystemChar* platformName() const = 0; - virtual ObjToken - newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)=0; - virtual ObjToken - newDynamicBuffer(BufferUse use, size_t stride, size_t count)=0; + virtual ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, + size_t count) = 0; + virtual ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count) = 0; - virtual ObjToken - newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz)=0; - virtual ObjToken - 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 - newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode)=0; - virtual ObjToken - newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindingCount, size_t depthBindingCount)=0; + virtual ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz) = 0; + virtual ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) = 0; + virtual ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindingCount, size_t depthBindingCount) = 0; - virtual ObjToken - newShaderStage(const uint8_t* data, size_t size, PipelineStage stage)=0; + virtual ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) = 0; - ObjToken - newShaderStage(const std::vector& data, PipelineStage stage) - { - return newShaderStage(data.data(), data.size(), stage); - } + ObjToken newShaderStage(const std::vector& data, PipelineStage stage) { + return newShaderStage(data.data(), data.size(), stage); + } - virtual ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo)=0; + virtual ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, + const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) = 0; - ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - const VertexFormatInfo& vtxFmt, const AdditionalPipelineInfo& additionalInfo) - { - return newShaderPipeline(vertex, fragment, {}, {}, {}, vtxFmt, additionalInfo); - } + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) { + return newShaderPipeline(vertex, fragment, {}, {}, {}, vtxFmt, additionalInfo); + } - virtual ObjToken - newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const ObjToken* texs, - const int* texBindIdx, const bool* depthBind, - size_t baseVert = 0, size_t baseInst = 0)=0; + virtual ObjToken newShaderDataBinding( + const ObjToken& pipeline, const ObjToken& vbo, + const ObjToken& instVbo, const ObjToken& ibo, size_t ubufCount, + const ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const ObjToken* texs, const int* texBindIdx, + const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0) = 0; - ObjToken - newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, const PipelineStage* ubufStages, - size_t texCount, const ObjToken* 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); - } - }; + ObjToken newShaderDataBinding(const ObjToken& pipeline, + const ObjToken& vbo, + const ObjToken& instVbo, + const ObjToken& ibo, size_t ubufCount, + const ObjToken* ubufs, + const PipelineStage* ubufStages, size_t texCount, + const ObjToken* 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& __BooTraceArgs)=0; - virtual ObjToken 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 commitTransaction(const std::function& __BooTraceArgs) = 0; + virtual ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) = 0; + virtual void setDisplayGamma(float gamma) = 0; + virtual bool isTessellationSupported(uint32_t& maxPatchSizeOut) = 0; }; using GraphicsDataFactoryContext = IGraphicsDataFactory::Context; using FactoryCommitFunc = std::function; -} - +} // namespace boo diff --git a/include/boo/graphicsdev/Metal.hpp b/include/boo/graphicsdev/Metal.hpp index c7e5cdf..e8205ba 100644 --- a/include/boo/graphicsdev/Metal.hpp +++ b/include/boo/graphicsdev/Metal.hpp @@ -6,60 +6,53 @@ #include "IGraphicsCommandQueue.hpp" #include "boo/IGraphicsContext.hpp" -namespace boo -{ +namespace boo { struct BaseGraphicsData; -class MetalDataFactory : public IGraphicsDataFactory -{ +class MetalDataFactory : public IGraphicsDataFactory { public: - class Context final : public IGraphicsDataFactory::Context - { - friend class MetalDataFactoryImpl; - MetalDataFactory& m_parent; - ObjToken m_data; - Context(MetalDataFactory& parent __BooTraceArgs); - ~Context(); - public: - Platform platform() const { return Platform::Metal; } - const SystemChar* platformName() const { return _SYS_STR("Metal"); } + class Context final : public IGraphicsDataFactory::Context { + friend class MetalDataFactoryImpl; + MetalDataFactory& m_parent; + ObjToken m_data; + Context(MetalDataFactory& parent __BooTraceArgs); + ~Context(); - ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); - ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); + public: + Platform platform() const { return Platform::Metal; } + const SystemChar* platformName() const { return _SYS_STR("Metal"); } - ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz); - ObjToken newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, const void* data, - size_t sz); - ObjToken newDynamicTexture(size_t width, size_t height, TextureFormat fmt, - TextureClampMode clampMode); - ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); + ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); + ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); - ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); + ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz); + ObjToken newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, const void* data, + size_t sz); + ObjToken newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); + ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t colorBindCount, + size_t depthBindCount); - ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - ObjToken - newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const ObjToken* texs, - const int* texBindIdxs, const bool* depthBind, - size_t baseVert = 0, size_t baseInst = 0); - }; + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); - static std::vector CompileMetal(const char* source, PipelineStage stage); + ObjToken newShaderDataBinding( + const ObjToken& pipeline, const ObjToken& vbo, + const ObjToken& instVbo, const ObjToken& ibo, size_t ubufCount, + const ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const ObjToken* texs, const int* texBindIdxs, + const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0); + }; + + static std::vector CompileMetal(const char* source, PipelineStage stage); }; -} +} // namespace boo #endif #endif // __APPLE__ diff --git a/include/boo/graphicsdev/NX.hpp b/include/boo/graphicsdev/NX.hpp index 11d8562..745544c 100644 --- a/include/boo/graphicsdev/NX.hpp +++ b/include/boo/graphicsdev/NX.hpp @@ -12,82 +12,74 @@ struct pipe_context; struct st_context; struct pipe_surface; -namespace boo -{ +namespace boo { struct BaseGraphicsData; -struct NXContext -{ - struct pipe_surface* m_windowSurfaces[2]; - NvFence m_fences[2]; - bool m_fence_swap; +struct NXContext { + struct pipe_surface* m_windowSurfaces[2]; + NvFence m_fences[2]; + bool m_fence_swap; - bool initialize(); - bool terminate(); - bool _resizeWindowSurfaces(); + bool initialize(); + bool terminate(); + bool _resizeWindowSurfaces(); - unsigned m_sampleCount = 1; + 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; + 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 m_samplers; - std::unordered_map m_blendStates; - std::unordered_map m_rasStates; - std::unordered_map m_dsStates; - std::unordered_map m_vtxElemStates; + std::unordered_map m_samplers; + std::unordered_map m_blendStates; + std::unordered_map m_rasStates; + std::unordered_map m_dsStates; + std::unordered_map m_vtxElemStates; }; -class NXDataFactory : public IGraphicsDataFactory -{ +class NXDataFactory : public IGraphicsDataFactory { public: - class Context final : public IGraphicsDataFactory::Context - { - friend class NXDataFactoryImpl; - NXDataFactory& m_parent; - boo::ObjToken m_data; - Context(NXDataFactory& parent __BooTraceArgs); - ~Context(); - public: - Platform platform() const {return Platform::NX;} - const SystemChar* platformName() const {return _SYS_STR("NX");} + class Context final : public IGraphicsDataFactory::Context { + friend class NXDataFactoryImpl; + NXDataFactory& m_parent; + boo::ObjToken m_data; + Context(NXDataFactory& parent __BooTraceArgs); + ~Context(); - boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); - boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); + public: + Platform platform() const { return Platform::NX; } + const SystemChar* platformName() const { return _SYS_STR("NX"); } - boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz); - boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); - boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); + boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); + boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); - ObjToken - newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); + boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz); + boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode); + boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindCount, size_t depthBindCount); - ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - boo::ObjToken - newShaderDataBinding(const boo::ObjToken& pipeline, - const boo::ObjToken& vbo, - const boo::ObjToken& instVbo, - const boo::ObjToken& ibo, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* bindDepth, - size_t baseVert = 0, size_t baseInst = 0); - }; + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); + + boo::ObjToken newShaderDataBinding( + const boo::ObjToken& pipeline, const boo::ObjToken& vbo, + const boo::ObjToken& instVbo, const boo::ObjToken& ibo, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* bindIdxs, + const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0); + }; }; -} +} // namespace boo #endif diff --git a/include/boo/graphicsdev/Vulkan.hpp b/include/boo/graphicsdev/Vulkan.hpp index d3828b9..40f2c64 100644 --- a/include/boo/graphicsdev/Vulkan.hpp +++ b/include/boo/graphicsdev/Vulkan.hpp @@ -15,171 +15,153 @@ /* Forward-declare handle type for Vulkan Memory Allocator */ struct VmaAllocator_T; -namespace boo -{ +namespace boo { struct BaseGraphicsData; -struct VulkanContext -{ - struct LayerProperties - { - VkLayerProperties properties; - std::vector extensions; - }; +struct VulkanContext { + struct LayerProperties { + VkLayerProperties properties; + std::vector extensions; + }; - std::vector m_instanceLayerProperties; - std::vector m_layerNames; - std::vector m_instanceExtensionNames; - VkInstance m_instance = VK_NULL_HANDLE; - std::vector m_deviceExtensionNames; - std::vector 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 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_passColorOnly = VK_NULL_HANDLE; - VkCommandPool m_loadPool = VK_NULL_HANDLE; - VkCommandBuffer m_loadCmdBuf = VK_NULL_HANDLE; - VkFormat m_displayFormat; - VkFormat m_internalFormat; + std::vector m_instanceLayerProperties; + std::vector m_layerNames; + std::vector m_instanceExtensionNames; + VkInstance m_instance = VK_NULL_HANDLE; + std::vector m_deviceExtensionNames; + std::vector 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 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_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 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; + 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 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 m_fsStyle; - LONG m_fsExStyle; - RECT m_fsRect; - int m_fsCountDown = 0; + HWND m_hwnd = 0; + bool m_fs = false; + LONG m_fsStyle; + LONG m_fsExStyle; + RECT m_fsRect; + int m_fsCountDown = 0; #endif - }; - std::unordered_map> m_windows; + }; + std::unordered_map> 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; + 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 m_samplers; + std::unordered_map 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); + 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 m_deferredResizes; - std::mutex m_resizeLock; - void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, - VkFormat format, VkColorSpaceKHR colorspace, - const SWindowRect& rect); - bool _resizeSwapChains(); + 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 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 -{ +class VulkanDataFactory : public IGraphicsDataFactory { public: - class Context final : public IGraphicsDataFactory::Context - { - friend class VulkanDataFactoryImpl; - VulkanDataFactory& m_parent; - boo::ObjToken m_data; - Context(VulkanDataFactory& parent __BooTraceArgs); - ~Context(); - public: - Platform platform() const {return Platform::Vulkan;} - const SystemChar* platformName() const {return _SYS_STR("Vulkan");} + class Context final : public IGraphicsDataFactory::Context { + friend class VulkanDataFactoryImpl; + VulkanDataFactory& m_parent; + boo::ObjToken m_data; + Context(VulkanDataFactory& parent __BooTraceArgs); + ~Context(); - boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); - boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); + public: + Platform platform() const { return Platform::Vulkan; } + const SystemChar* platformName() const { return _SYS_STR("Vulkan"); } - boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz); - boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); - boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); + boo::ObjToken newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); + boo::ObjToken newDynamicBuffer(BufferUse use, size_t stride, size_t count); - ObjToken - newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); + boo::ObjToken newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, size_t sz); + boo::ObjToken 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 newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode); + boo::ObjToken newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindCount, size_t depthBindCount); - ObjToken - newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo); + ObjToken newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); - boo::ObjToken - newShaderDataBinding(const boo::ObjToken& pipeline, - const boo::ObjToken& vbo, - const boo::ObjToken& instVbo, - const boo::ObjToken& ibo, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* bindDepth, - size_t baseVert = 0, size_t baseInst = 0); - }; + ObjToken newShaderPipeline(ObjToken vertex, ObjToken fragment, + ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo); - static std::vector CompileGLSL(const char* source, PipelineStage stage); + boo::ObjToken newShaderDataBinding( + const boo::ObjToken& pipeline, const boo::ObjToken& vbo, + const boo::ObjToken& instVbo, const boo::ObjToken& ibo, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* bindIdxs, + const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0); + }; + + static std::vector CompileGLSL(const char* source, PipelineStage stage); }; -} +} // namespace boo #endif diff --git a/include/boo/graphicsdev/VulkanDispatchTable.hpp b/include/boo/graphicsdev/VulkanDispatchTable.hpp index 7efa1e7..c3d15e1 100644 --- a/include/boo/graphicsdev/VulkanDispatchTable.hpp +++ b/include/boo/graphicsdev/VulkanDispatchTable.hpp @@ -214,4 +214,3 @@ void init_dispatch_table_middle(VkInstance instance, bool include_bottom); void init_dispatch_table_bottom(VkInstance instance, VkDevice dev); } // namespace vk - diff --git a/include/boo/graphicsdev/nx_compiler.hpp b/include/boo/graphicsdev/nx_compiler.hpp index 64a0aa2..23b6256 100644 --- a/include/boo/graphicsdev/nx_compiler.hpp +++ b/include/boo/graphicsdev/nx_compiler.hpp @@ -3,79 +3,76 @@ #include /* 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, +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; +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) {} +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; + 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) {} +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; } + 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); +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, size_t> - offline_link(unsigned num_stages, const nx_shader_stage_object **stages, std::string* infoLog = nullptr); + 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, size_t> offline_link(unsigned num_stages, const nx_shader_stage_object** stages, + std::string* infoLog = nullptr); }; diff --git a/include/boo/inputdev/CafeProPad.hpp b/include/boo/inputdev/CafeProPad.hpp index c308531..3a810c4 100644 --- a/include/boo/inputdev/CafeProPad.hpp +++ b/include/boo/inputdev/CafeProPad.hpp @@ -1,7 +1,3 @@ #pragma once -namespace boo -{ - -} - +namespace boo {} diff --git a/include/boo/inputdev/DeviceBase.hpp b/include/boo/inputdev/DeviceBase.hpp index d012b4a..b207998 100644 --- a/include/boo/inputdev/DeviceBase.hpp +++ b/include/boo/inputdev/DeviceBase.hpp @@ -13,80 +13,73 @@ #include #endif -namespace boo -{ +namespace boo { class DeviceToken; class IHIDDevice; -enum class HIDReportType -{ - Input, - Output, - Feature -}; +enum class HIDReportType { Input, Output, Feature }; -class DeviceBase : public std::enable_shared_from_this -{ - friend class DeviceToken; - friend struct DeviceSignature; - friend class HIDDeviceIOKit; +class DeviceBase : public std::enable_shared_from_this { + friend class DeviceToken; + friend struct DeviceSignature; + friend class HIDDeviceIOKit; - uint64_t m_typeHash; - class DeviceToken* m_token; - std::shared_ptr m_hidDev; - void _deviceDisconnected(); + uint64_t m_typeHash; + class DeviceToken* m_token; + std::shared_ptr m_hidDev; + void _deviceDisconnected(); public: - DeviceBase(uint64_t typeHash, DeviceToken* token); - virtual ~DeviceBase() = default; + DeviceBase(uint64_t typeHash, DeviceToken* token); + virtual ~DeviceBase() = default; - uint64_t getTypeHash() const { return m_typeHash; } + uint64_t getTypeHash() const { return m_typeHash; } - void closeDevice(); - - /* Callbacks */ - virtual void deviceDisconnected()=0; - virtual void deviceError(const char* error, ...); - virtual void initialCycle() {} - virtual void transferCycle() {} - virtual void finalCycle() {} + void closeDevice(); - /* Low-Level API */ - bool sendUSBInterruptTransfer(const uint8_t* data, size_t length); - size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length); + /* Callbacks */ + virtual void deviceDisconnected() = 0; + virtual void deviceError(const char* error, ...); + virtual void initialCycle() {} + virtual void transferCycle() {} + virtual void finalCycle() {} - inline unsigned getVendorId(); - inline unsigned getProductId(); - inline std::string_view getVendorName(); - inline std::string_view getProductName(); + /* Low-Level API */ + bool sendUSBInterruptTransfer(const uint8_t* data, size_t length); + size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length); - /* High-Level API */ + inline unsigned getVendorId(); + inline unsigned getProductId(); + inline std::string_view getVendorName(); + inline std::string_view getProductName(); + + /* High-Level API */ #if _WIN32 #if !WINDOWS_STORE - const PHIDP_PREPARSED_DATA getReportDescriptor(); + const PHIDP_PREPARSED_DATA getReportDescriptor(); #endif #else - std::vector getReportDescriptor(); + std::vector getReportDescriptor(); #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*/) {} + 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 TDeviceBase : public DeviceBase -{ +class TDeviceBase : public DeviceBase { protected: - std::mutex m_callbackLock; - CB* m_callback = nullptr; + 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 lk(m_callbackLock); - m_callback = cb; - } + TDeviceBase(uint64_t typeHash, DeviceToken* token) : DeviceBase(typeHash, token) {} + void setCallback(CB* cb) { + std::lock_guard lk(m_callbackLock); + m_callback = cb; + } }; -} - +} // namespace boo diff --git a/include/boo/inputdev/DeviceFinder.hpp b/include/boo/inputdev/DeviceFinder.hpp index 990ff6a..fa1eaf1 100644 --- a/include/boo/inputdev/DeviceFinder.hpp +++ b/include/boo/inputdev/DeviceFinder.hpp @@ -16,151 +16,131 @@ #include #endif -namespace boo -{ +namespace boo { -class DeviceFinder -{ +class DeviceFinder { public: - friend class HIDListenerIOKit; - friend class HIDListenerUdev; - friend class HIDListenerWinUSB; - static inline DeviceFinder* instance() {return skDevFinder;} + friend class HIDListenerIOKit; + friend class HIDListenerUdev; + friend class HIDListenerWinUSB; + static inline DeviceFinder* instance() { return skDevFinder; } private: - static class DeviceFinder* skDevFinder; + static class DeviceFinder* skDevFinder; - /* Types this finder is interested in (immutable) */ - DeviceSignature::TDeviceSignatureSet m_types; + /* 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 m_listener; + /* Platform-specific USB event registration + * (for auto-scanning, NULL if not registered) */ + std::unique_ptr m_listener; - /* Set of presently-connected device tokens */ - TDeviceTokens m_tokens; - std::mutex m_tokensLock; + /* 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 */ - inline bool _hasToken(const std::string& path) - { - auto preCheck = m_tokens.find(path); - if (preCheck != m_tokens.end()) - return true; - return false; + /* Friend methods for platform-listener to find/insert/remove + * tokens with type-filtering */ + inline bool _hasToken(const std::string& path) { + auto preCheck = m_tokens.find(path); + if (preCheck != m_tokens.end()) + return true; + return false; + } + inline bool _insertToken(std::unique_ptr&& token) { + if (DeviceSignature::DeviceMatchToken(*token, m_types)) { + m_tokensLock.lock(); + TInsertedDeviceToken inseredTok = m_tokens.insert(std::make_pair(token->getDevicePath(), std::move(token))); + m_tokensLock.unlock(); + deviceConnected(*inseredTok.first->second); + return true; } - inline bool _insertToken(std::unique_ptr&& token) - { - if (DeviceSignature::DeviceMatchToken(*token, m_types)) - { - m_tokensLock.lock(); - TInsertedDeviceToken inseredTok = - m_tokens.insert(std::make_pair(token->getDevicePath(), std::move(token))); - m_tokensLock.unlock(); - deviceConnected(*inseredTok.first->second); - return true; - } - return false; - } - inline void _removeToken(const std::string& path) - { - auto preCheck = m_tokens.find(path); - if (preCheck != m_tokens.end()) - { - DeviceToken& tok = *preCheck->second; - std::shared_ptr dev = tok.m_connectedDev; - tok._deviceClose(); - deviceDisconnected(tok, dev.get()); - m_tokensLock.lock(); - m_tokens.erase(preCheck); - m_tokensLock.unlock(); - } + return false; + } + inline void _removeToken(const std::string& path) { + auto preCheck = m_tokens.find(path); + if (preCheck != m_tokens.end()) { + DeviceToken& tok = *preCheck->second; + std::shared_ptr dev = tok.m_connectedDev; + tok._deviceClose(); + deviceDisconnected(tok, dev.get()); + m_tokensLock.lock(); + m_tokens.erase(preCheck); + m_tokensLock.unlock(); } + } public: + class CDeviceTokensHandle { + DeviceFinder& m_finder; - class CDeviceTokensHandle - { - DeviceFinder& m_finder; - public: - inline CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) - {m_finder.m_tokensLock.lock();} - inline ~CDeviceTokensHandle() {m_finder.m_tokensLock.unlock();} - inline TDeviceTokens::iterator begin() {return m_finder.m_tokens.begin();} - inline TDeviceTokens::iterator end() {return m_finder.m_tokens.end();} - }; + public: + inline CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) { m_finder.m_tokensLock.lock(); } + inline ~CDeviceTokensHandle() { m_finder.m_tokensLock.unlock(); } + inline TDeviceTokens::iterator begin() { return m_finder.m_tokens.begin(); } + inline TDeviceTokens::iterator end() { return m_finder.m_tokens.end(); } + }; - /* Application must specify its interested device-types */ - DeviceFinder(std::unordered_set types) - { - if (skDevFinder) - { - fprintf(stderr, "only one instance of CDeviceFinder may be constructed"); - 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; - } - } + /* Application must specify its interested device-types */ + DeviceFinder(std::unordered_set types) { + if (skDevFinder) { + fprintf(stderr, "only one instance of CDeviceFinder may be constructed"); + abort(); } - virtual ~DeviceFinder() - { - if (m_listener) - m_listener->stopScanning(); - skDevFinder = NULL; + 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; + } } + } + virtual ~DeviceFinder() { + if (m_listener) + m_listener->stopScanning(); + skDevFinder = NULL; + } - /* Get interested device-type mask */ - inline const DeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;} + /* Get interested device-type mask */ + inline const DeviceSignature::TDeviceSignatureSet& getTypes() const { return m_types; } - /* Iterable set of tokens */ - inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);} + /* Iterable set of tokens */ + inline CDeviceTokensHandle getTokens() { return CDeviceTokensHandle(*this); } - /* Automatic device scanning */ - inline bool startScanning() - { - if (!m_listener) - m_listener = IHIDListenerNew(*this); - if (m_listener) - return m_listener->startScanning(); - return false; - } - inline bool stopScanning() - { - if (!m_listener) - m_listener = IHIDListenerNew(*this); - if (m_listener) - return m_listener->stopScanning(); - return false; - } + /* Automatic device scanning */ + inline bool startScanning() { + if (!m_listener) + m_listener = IHIDListenerNew(*this); + if (m_listener) + return m_listener->startScanning(); + return false; + } + inline bool stopScanning() { + if (!m_listener) + m_listener = IHIDListenerNew(*this); + if (m_listener) + return m_listener->stopScanning(); + return false; + } - /* Manual device scanning */ - inline bool scanNow() - { - if (!m_listener) - m_listener = IHIDListenerNew(*this); - if (m_listener) - return m_listener->scanNow(); - return false; - } + /* Manual device scanning */ + inline bool scanNow() { + if (!m_listener) + m_listener = IHIDListenerNew(*this); + if (m_listener) + return m_listener->scanNow(); + return false; + } - virtual void deviceConnected(DeviceToken&) {} - virtual void deviceDisconnected(DeviceToken&, DeviceBase*) {} + virtual void deviceConnected(DeviceToken&) {} + virtual void deviceDisconnected(DeviceToken&, DeviceBase*) {} #if _WIN32 - /* Windows-specific WM_DEVICECHANGED handler */ - static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam); + /* Windows-specific WM_DEVICECHANGED handler */ + static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam); #endif - }; -} - +} // namespace boo diff --git a/include/boo/inputdev/DeviceSignature.hpp b/include/boo/inputdev/DeviceSignature.hpp index 9945fd1..b92669d 100644 --- a/include/boo/inputdev/DeviceSignature.hpp +++ b/include/boo/inputdev/DeviceSignature.hpp @@ -6,48 +6,36 @@ #include #include -namespace boo -{ +namespace boo { -enum class DeviceType -{ - None = 0, - USB = 1, - Bluetooth = 2, - HID = 3, - XInput = 4 -}; +enum class DeviceType { None = 0, USB = 1, Bluetooth = 2, HID = 3, XInput = 4 }; class DeviceToken; class DeviceBase; #define dev_typeid(type) std::hash()(#type) -struct DeviceSignature -{ - typedef std::vector TDeviceSignatureSet; - typedef std::function(DeviceToken*)> TFactoryLambda; - const char* m_name; - uint64_t m_typeHash; - unsigned m_vid, m_pid; - TFactoryLambda m_factory; - DeviceType m_type; - DeviceSignature() : m_name(NULL), 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 DeviceNew(DeviceToken& token); +struct DeviceSignature { + typedef std::vector TDeviceSignatureSet; + typedef std::function(DeviceToken*)> TFactoryLambda; + const char* m_name; + uint64_t m_typeHash; + unsigned m_vid, m_pid; + TFactoryLambda m_factory; + DeviceType m_type; + DeviceSignature() : m_name(NULL), 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 DeviceNew(DeviceToken& token); }; -#define DEVICE_SIG(name, vid, pid, type) \ - DeviceSignature(#name, dev_typeid(name), vid, pid,\ - [](DeviceToken* tok) -> std::shared_ptr {return std::make_shared(tok);}, type) +#define DEVICE_SIG(name, vid, pid, type) \ + DeviceSignature(#name, dev_typeid(name), vid, pid, \ + [](DeviceToken* tok) -> std::shared_ptr { return std::make_shared(tok); }, type) #define DEVICE_SIG_SENTINEL() DeviceSignature() extern const DeviceSignature BOO_DEVICE_SIGS[]; -} - - +} // namespace boo diff --git a/include/boo/inputdev/DeviceToken.hpp b/include/boo/inputdev/DeviceToken.hpp index dacb019..fc3036c 100644 --- a/include/boo/inputdev/DeviceToken.hpp +++ b/include/boo/inputdev/DeviceToken.hpp @@ -4,75 +4,62 @@ #include "DeviceBase.hpp" #include "DeviceSignature.hpp" -namespace boo -{ +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 m_connectedDev; - - friend class DeviceFinder; - inline void _deviceClose() - { - if (m_connectedDev) - m_connectedDev->_deviceDisconnected(); - m_connectedDev = NULL; - } +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 m_connectedDev; + + friend class DeviceFinder; + inline void _deviceClose() { + if (m_connectedDev) + m_connectedDev->_deviceDisconnected(); + m_connectedDev = NULL; + } public: + DeviceToken(const DeviceToken&) = delete; + DeviceToken(const DeviceToken&& other) + : m_devType(other.m_devType) + , m_vendorId(other.m_vendorId) + , m_productId(other.m_productId) + , m_vendorName(other.m_vendorName) + , m_productName(other.m_productName) + , m_devPath(other.m_devPath) + , m_connectedDev(other.m_connectedDev) {} + inline 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(const DeviceToken&) = delete; - DeviceToken(const DeviceToken&& other) - : m_devType(other.m_devType), - m_vendorId(other.m_vendorId), - m_productId(other.m_productId), - m_vendorName(other.m_vendorName), - m_productName(other.m_productName), - m_devPath(other.m_devPath), - m_connectedDev(other.m_connectedDev) - {} - inline 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; - } - - inline DeviceType getDeviceType() const {return m_devType;} - inline unsigned getVendorId() const {return m_vendorId;} - inline unsigned getProductId() const {return m_productId;} - inline std::string_view getVendorName() const {return m_vendorName;} - inline std::string_view getProductName() const {return m_productName;} - inline std::string_view getDevicePath() const {return m_devPath;} - inline bool isDeviceOpen() const {return (m_connectedDev != NULL);} - inline std::shared_ptr openAndGetDevice() - { - if (!m_connectedDev) - m_connectedDev = DeviceSignature::DeviceNew(*this); - return m_connectedDev; - } - - inline bool operator ==(const DeviceToken& rhs) const - {return m_devPath == rhs.m_devPath;} - inline bool operator <(const DeviceToken& rhs) const - {return m_devPath < rhs.m_devPath;} + inline DeviceType getDeviceType() const { return m_devType; } + inline unsigned getVendorId() const { return m_vendorId; } + inline unsigned getProductId() const { return m_productId; } + inline std::string_view getVendorName() const { return m_vendorName; } + inline std::string_view getProductName() const { return m_productName; } + inline std::string_view getDevicePath() const { return m_devPath; } + inline bool isDeviceOpen() const { return (m_connectedDev != NULL); } + inline std::shared_ptr openAndGetDevice() { + if (!m_connectedDev) + m_connectedDev = DeviceSignature::DeviceNew(*this); + return m_connectedDev; + } + + inline bool operator==(const DeviceToken& rhs) const { return m_devPath == rhs.m_devPath; } + inline bool operator<(const DeviceToken& rhs) const { return m_devPath < rhs.m_devPath; } }; -} - +} // namespace boo diff --git a/include/boo/inputdev/DolphinSmashAdapter.hpp b/include/boo/inputdev/DolphinSmashAdapter.hpp index 1b96645..f3e6724 100644 --- a/include/boo/inputdev/DolphinSmashAdapter.hpp +++ b/include/boo/inputdev/DolphinSmashAdapter.hpp @@ -4,88 +4,93 @@ #include "DeviceBase.hpp" #include "../System.hpp" -namespace boo -{ +namespace boo { -enum class EDolphinControllerType -{ - None = 0, - Normal = 0x10, - Wavebird = 0x20, +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 +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 -{ - int16_t m_leftStick[2] = {0}; - int16_t m_rightStick[2] = {0}; - int16_t m_analogTriggers[2] = {0}; - uint16_t m_btns = 0; - void reset() - { - m_leftStick[0] = 0; - m_leftStick[1] = 0; - m_rightStick[0] = 0; - m_rightStick[1] = 0; - m_analogTriggers[0] = 0; - m_analogTriggers[1] = 0; - m_btns = 0; - } - void clamp(); +struct DolphinControllerState { + int16_t m_leftStick[2] = {0}; + int16_t m_rightStick[2] = {0}; + int16_t m_analogTriggers[2] = {0}; + uint16_t m_btns = 0; + void reset() { + m_leftStick[0] = 0; + m_leftStick[1] = 0; + m_rightStick[0] = 0; + m_rightStick[1] = 0; + m_analogTriggers[0] = 0; + m_analogTriggers[1] = 0; + m_btns = 0; + } + void clamp(); }; -struct IDolphinSmashAdapterCallback -{ - virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;} - virtual void controllerDisconnected(unsigned idx) {(void)idx;} - virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, - const DolphinControllerState& state) {(void)idx;(void)type;(void)state;} +struct IDolphinSmashAdapterCallback { + virtual void controllerConnected(unsigned idx, EDolphinControllerType type) { + (void)idx; + (void)type; + } + virtual void controllerDisconnected(unsigned idx) { (void)idx; } + virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, const DolphinControllerState& state) { + (void)idx; + (void)type; + (void)state; + } }; -class DolphinSmashAdapter final : public TDeviceBase -{ - int16_t m_leftStickCal[2] = {0x7f}; - int16_t m_rightStickCal[2] = {0x7f}; - int16_t m_triggersCal[2] = {0x0}; - uint8_t m_knownControllers = 0; - uint8_t m_rumbleRequest = 0; - bool m_hardStop[4] = {false}; - uint8_t m_rumbleState = 0xf; /* Force initial send of stop-rumble command */ - void deviceDisconnected(); - void initialCycle(); - void transferCycle(); - void finalCycle(); +class DolphinSmashAdapter final : public TDeviceBase { + int16_t m_leftStickCal[2] = {0x7f}; + int16_t m_rightStickCal[2] = {0x7f}; + int16_t m_triggersCal[2] = {0x0}; + uint8_t m_knownControllers = 0; + uint8_t m_rumbleRequest = 0; + bool m_hardStop[4] = {false}; + uint8_t m_rumbleState = 0xf; /* Force initial send of stop-rumble command */ + void deviceDisconnected(); + void initialCycle(); + void transferCycle(); + void finalCycle(); + public: - DolphinSmashAdapter(DeviceToken* token); - ~DolphinSmashAdapter(); - - void setCallback(IDolphinSmashAdapterCallback* cb) - { - TDeviceBase::setCallback(cb); - m_knownControllers = 0; - } - void startRumble(unsigned idx) - {if (idx >= 4) return; m_rumbleRequest |= 1<= 4) return; m_rumbleRequest &= ~(1<::setCallback(cb); + m_knownControllers = 0; + } + void startRumble(unsigned idx) { + if (idx >= 4) + return; + m_rumbleRequest |= 1 << idx; + } + void stopRumble(unsigned idx, bool hard = false) { + if (idx >= 4) + return; + m_rumbleRequest &= ~(1 << idx); + m_hardStop[idx] = hard; + } }; -} - +} // namespace boo diff --git a/include/boo/inputdev/DualshockPad.hpp b/include/boo/inputdev/DualshockPad.hpp index fdbb690..bff84ec 100644 --- a/include/boo/inputdev/DualshockPad.hpp +++ b/include/boo/inputdev/DualshockPad.hpp @@ -4,181 +4,153 @@ #include "DeviceBase.hpp" #include "boo/System.hpp" -namespace boo -{ +namespace boo { -struct DualshockLED -{ - uint8_t timeEnabled; - uint8_t dutyLength; - uint8_t enabled; - uint8_t dutyOff; - uint8_t dutyOn; +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; +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]; +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 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, +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 -}; +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; +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&) {} +struct IDualshockPadCallback { + virtual void controllerDisconnected() {} + virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {} }; -class DualshockPad final : public TDeviceBase -{ - EDualshockMotor m_rumbleRequest; - EDualshockMotor m_rumbleState; - uint8_t m_rumbleDuration[2]; - uint8_t m_rumbleIntensity[2]; - EDualshockLED m_led; - DualshockOutReport m_report; - void deviceDisconnected(); - void initialCycle(); - void transferCycle(); - void finalCycle(); - void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); +class DualshockPad final : public TDeviceBase { + EDualshockMotor m_rumbleRequest; + EDualshockMotor m_rumbleState; + uint8_t m_rumbleDuration[2]; + uint8_t m_rumbleIntensity[2]; + EDualshockLED m_led; + DualshockOutReport m_report; + void deviceDisconnected(); + void initialCycle(); + void transferCycle(); + void finalCycle(); + void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); + public: - DualshockPad(DeviceToken* token); - ~DualshockPad(); + DualshockPad(DeviceToken* token); + ~DualshockPad(); - void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255) - { - m_rumbleRequest |= motor; - if ((EDualshockMotor(motor) & EDualshockMotor::Left) != EDualshockMotor::None) - { - m_rumbleDuration[0] = duration; - m_rumbleIntensity[0] = intensity; - } - if ((EDualshockMotor(motor) & EDualshockMotor::Right) != EDualshockMotor::None) - { - m_rumbleDuration[1] = duration; - m_rumbleIntensity[1] = intensity; - } + void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity = 255) { + m_rumbleRequest |= motor; + if ((EDualshockMotor(motor) & EDualshockMotor::Left) != EDualshockMotor::None) { + m_rumbleDuration[0] = duration; + m_rumbleIntensity[0] = intensity; } - - void stopRumble(int motor) - { - m_rumbleRequest &= ~EDualshockMotor(motor); + if ((EDualshockMotor(motor) & EDualshockMotor::Right) != EDualshockMotor::None) { + m_rumbleDuration[1] = duration; + m_rumbleIntensity[1] = intensity; } + } - EDualshockLED getLED() - { - return m_led; - } + void stopRumble(int motor) { m_rumbleRequest &= ~EDualshockMotor(motor); } - void setLED(EDualshockLED led, bool on = true) - { - if (on) - m_led |= led; - else - m_led &= ~led; + EDualshockLED getLED() { return m_led; } - setRawLED(int(led)); - } + void setLED(EDualshockLED led, bool on = true) { + if (on) + m_led |= led; + else + m_led &= ~led; - void setRawLED(int led) - { - m_report.leds = led; - sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01); - } + setRawLED(int(led)); + } + + void setRawLED(int led) { + m_report.leds = led; + sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01); + } }; -} - +} // namespace boo diff --git a/include/boo/inputdev/GenericPad.hpp b/include/boo/inputdev/GenericPad.hpp index f89cda7..e7624f2 100644 --- a/include/boo/inputdev/GenericPad.hpp +++ b/include/boo/inputdev/GenericPad.hpp @@ -5,29 +5,26 @@ #include #include -namespace boo -{ +namespace boo { -struct IGenericPadCallback -{ - virtual void controllerConnected() {} - virtual void controllerDisconnected() {} - virtual void valueUpdate(const HIDMainItem& item, int32_t value) {} +struct IGenericPadCallback { + virtual void controllerConnected() {} + virtual void controllerDisconnected() {} + virtual void valueUpdate(const HIDMainItem& item, int32_t value) {} }; -class GenericPad final : public TDeviceBase -{ - HIDParser m_parser; +class GenericPad final : public TDeviceBase { + HIDParser m_parser; + public: - GenericPad(DeviceToken* token); - ~GenericPad(); + GenericPad(DeviceToken* token); + ~GenericPad(); - void deviceDisconnected(); - void initialCycle(); - void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); + void deviceDisconnected(); + void initialCycle(); + void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); - void enumerateValues(const std::function& valueCB) const; + void enumerateValues(const std::function& valueCB) const; }; -} - +} // namespace boo diff --git a/include/boo/inputdev/HIDParser.hpp b/include/boo/inputdev/HIDParser.hpp index 7a5cf8d..00a4cca 100644 --- a/include/boo/inputdev/HIDParser.hpp +++ b/include/boo/inputdev/HIDParser.hpp @@ -10,211 +10,197 @@ #include #endif -namespace boo -{ +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 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, +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, + /* 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, + /* 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; /* [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; } +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; + 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 -{ +class HIDParser { public: - enum class ParserStatus - { - OK, - Done, - Error - }; + enum class ParserStatus { OK, Done, Error }; + private: - - ParserStatus m_status = ParserStatus::OK; + ParserStatus m_status = ParserStatus::OK; #if _WIN32 #if !WINDOWS_STORE - std::vector m_itemPool; - mutable std::vector m_dataList; - PHIDP_PREPARSED_DATA m_descriptorData = nullptr; + std::vector m_itemPool; + mutable std::vector m_dataList; + PHIDP_PREPARSED_DATA m_descriptorData = nullptr; #endif #else - std::unique_ptr m_itemPool; - using Report = std::pair>; - std::unique_ptr m_reportPool; - std::pair m_inputReports = {}; - std::pair m_outputReports = {}; - std::pair m_featureReports = {}; - bool m_multipleReports = false; - static ParserStatus ParseItem(HIDReports& reportsOut, - std::stack& stateStack, - std::stack& collectionStack, - const uint8_t*& it, const uint8_t* end, - bool& multipleReports); + std::unique_ptr m_itemPool; + using Report = std::pair>; + std::unique_ptr m_reportPool; + std::pair m_inputReports = {}; + std::pair m_outputReports = {}; + std::pair m_featureReports = {}; + bool m_multipleReports = false; + static ParserStatus ParseItem(HIDReports& reportsOut, std::stack& stateStack, + std::stack& 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); + 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 GetApplicationUsage(const uint8_t* descriptorData, size_t len); + ParserStatus Parse(const uint8_t* descriptorData, size_t len); + static size_t CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len); + static std::pair GetApplicationUsage(const uint8_t* descriptorData, size_t len); #endif - operator bool() const { return m_status == ParserStatus::Done; } - void EnumerateValues(const std::function& valueCB) const; - void ScanValues(const std::function& valueCB, - const uint8_t* data, size_t len) const; + operator bool() const { return m_status == ParserStatus::Done; } + void EnumerateValues(const std::function& valueCB) const; + void ScanValues(const std::function& valueCB, const uint8_t* data, + size_t len) const; }; -} - +} // namespace boo diff --git a/include/boo/inputdev/IHIDListener.hpp b/include/boo/inputdev/IHIDListener.hpp index 89f04fb..d68e2bf 100644 --- a/include/boo/inputdev/IHIDListener.hpp +++ b/include/boo/inputdev/IHIDListener.hpp @@ -4,35 +4,31 @@ #include #include "DeviceToken.hpp" -namespace boo -{ +namespace boo { typedef std::unordered_map> TDeviceTokens; typedef std::pair TInsertedDeviceToken; class DeviceFinder; -class IHIDListener -{ +class IHIDListener { public: - virtual ~IHIDListener() = default; - - /* Automatic device scanning */ - virtual bool startScanning()=0; - virtual bool stopScanning()=0; - - /* Manual device scanning */ - virtual bool scanNow()=0; + 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; + /* 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 IHIDListenerNew(DeviceFinder& finder); -} - +} // namespace boo diff --git a/include/boo/inputdev/NintendoPowerA.hpp b/include/boo/inputdev/NintendoPowerA.hpp index b4fc23c..f1bb2ea 100644 --- a/include/boo/inputdev/NintendoPowerA.hpp +++ b/include/boo/inputdev/NintendoPowerA.hpp @@ -2,51 +2,47 @@ #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); - bool operator!=(const NintendoPowerAState& other); +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); + bool operator!=(const NintendoPowerAState& other); }; class NintendoPowerA; -struct INintendoPowerACallback -{ - virtual void controllerDisconnected() {} - virtual void controllerUpdate(const NintendoPowerAState& state) {} +struct INintendoPowerACallback { + virtual void controllerDisconnected() {} + virtual void controllerUpdate(const NintendoPowerAState& state) {} }; -class NintendoPowerA final : public TDeviceBase -{ - NintendoPowerAState m_last; - void deviceDisconnected(); - void initialCycle(); - void transferCycle(); - void finalCycle(); - void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); +class NintendoPowerA final : public TDeviceBase { + NintendoPowerAState m_last; + void deviceDisconnected(); + void initialCycle(); + void transferCycle(); + void finalCycle(); + void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); + public: - NintendoPowerA(DeviceToken*); - ~NintendoPowerA(); + NintendoPowerA(DeviceToken*); + ~NintendoPowerA(); }; -} - +} // namespace boo diff --git a/include/boo/inputdev/RevolutionPad.hpp b/include/boo/inputdev/RevolutionPad.hpp index c308531..3a810c4 100644 --- a/include/boo/inputdev/RevolutionPad.hpp +++ b/include/boo/inputdev/RevolutionPad.hpp @@ -1,7 +1,3 @@ #pragma once -namespace boo -{ - -} - +namespace boo {} diff --git a/include/boo/inputdev/XInputPad.hpp b/include/boo/inputdev/XInputPad.hpp index c9a70c4..ecf4e92 100644 --- a/include/boo/inputdev/XInputPad.hpp +++ b/include/boo/inputdev/XInputPad.hpp @@ -4,63 +4,55 @@ #include "DeviceSignature.hpp" #include "boo/System.hpp" -namespace boo -{ +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; +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, +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&) {} +struct IXInputPadCallback { + virtual void controllerDisconnected() {} + virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {} }; -class XInputPad final : public TDeviceBase -{ - friend class HIDListenerWinUSB; - uint16_t m_rumbleRequest[2] = {}; - uint16_t m_rumbleState[2] = {}; +class XInputPad final : public TDeviceBase { + friend class HIDListenerWinUSB; + uint16_t m_rumbleRequest[2] = {}; + uint16_t m_rumbleState[2] = {}; + public: - XInputPad(DeviceToken* token) : TDeviceBase(dev_typeid(XInputPad), token) {} - void deviceDisconnected() - { - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerDisconnected(); - } - void startRumble(EXInputMotor motors, uint16_t intensity) - { - if ((motors & EXInputMotor::Left) != EXInputMotor::None) - m_rumbleRequest[0] = intensity; - if ((motors & EXInputMotor::Right) != EXInputMotor::None) - m_rumbleRequest[1] = intensity; - } - void stopRumble(EXInputMotor motors) - { - if ((motors & EXInputMotor::Left) != EXInputMotor::None) - m_rumbleRequest[0] = 0; - if ((motors & EXInputMotor::Right) != EXInputMotor::None) - m_rumbleRequest[1] = 0; - } + XInputPad(DeviceToken* token) : TDeviceBase(dev_typeid(XInputPad), token) {} + void deviceDisconnected() { + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(); + } + void startRumble(EXInputMotor motors, uint16_t intensity) { + if ((motors & EXInputMotor::Left) != EXInputMotor::None) + m_rumbleRequest[0] = intensity; + if ((motors & EXInputMotor::Right) != EXInputMotor::None) + m_rumbleRequest[1] = intensity; + } + void stopRumble(EXInputMotor motors) { + if ((motors & EXInputMotor::Left) != EXInputMotor::None) + m_rumbleRequest[0] = 0; + if ((motors & EXInputMotor::Right) != EXInputMotor::None) + m_rumbleRequest[1] = 0; + } }; -} - +} // namespace boo diff --git a/lib/CFPointer.hpp b/lib/CFPointer.hpp index 4e429f6..5b1538b 100644 --- a/lib/CFPointer.hpp +++ b/lib/CFPointer.hpp @@ -5,151 +5,127 @@ #include /// A smart pointer that can manage the lifecycle of Core Foundation objects. -template +template class CFPointer { public: - CFPointer() : storage(nullptr) { } + CFPointer() : storage(nullptr) {} - CFPointer(T pointer) : storage(toStorageType(pointer)) { - if (storage) { - CFRetain(storage); - } + CFPointer(T pointer) : storage(toStorageType(pointer)) { + if (storage) { + CFRetain(storage); } + } - CFPointer(const CFPointer & other) : storage(other.storage) { - if (CFTypeRef ptr = storage) { - CFRetain(ptr); - } + CFPointer(const CFPointer& other) : storage(other.storage) { + if (CFTypeRef ptr = storage) { + CFRetain(ptr); } + } - CFPointer(CFPointer && other) : storage(std::exchange(other.storage, nullptr)) { } + CFPointer(CFPointer&& other) : storage(std::exchange(other.storage, nullptr)) {} - ~CFPointer() { - if (CFTypeRef pointer = storage) { - CFRelease(pointer); - } + ~CFPointer() { + if (CFTypeRef pointer = storage) { + CFRelease(pointer); } + } - static inline CFPointer adopt(T CF_RELEASES_ARGUMENT ptr) { - return CFPointer(ptr, CFPointer::Adopt); - } + static inline CFPointer adopt(T CF_RELEASES_ARGUMENT ptr) { return CFPointer(ptr, CFPointer::Adopt); } - T get() const { - return fromStorageType(storage); - } + T get() const { return fromStorageType(storage); } - CFPointer &operator=(CFPointer other) { - swap(other); - return *this; - } + CFPointer& operator=(CFPointer other) { + swap(other); + return *this; + } - T* operator&() - { - if (CFTypeRef pointer = storage) { - CFRelease(pointer); - } - return (T*)&storage; + T* operator&() { + if (CFTypeRef pointer = storage) { + CFRelease(pointer); } - operator bool() const { return storage != nullptr; } + return (T*)&storage; + } + operator bool() const { return storage != nullptr; } - void reset() - { - if (storage) - { - CFRelease(storage); - storage = nullptr; - } + void reset() { + if (storage) { + CFRelease(storage); + storage = nullptr; } + } private: - CFTypeRef storage; + CFTypeRef storage; - enum AdoptTag { Adopt }; - CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) { } + enum AdoptTag { Adopt }; + CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {} - inline CFTypeRef toStorageType(CFTypeRef ptr) const { - return (CFTypeRef)ptr; - } + inline CFTypeRef toStorageType(CFTypeRef ptr) const { return (CFTypeRef)ptr; } - inline T fromStorageType(CFTypeRef pointer) const { - return (T)pointer; - } + inline T fromStorageType(CFTypeRef pointer) const { return (T)pointer; } - void swap(CFPointer &other) { - std::swap(storage, other.storage); - } + void swap(CFPointer& other) { std::swap(storage, other.storage); } }; /// A smart pointer that can manage the lifecycle of CoreFoundation IUnknown objects. -template +template class IUnknownPointer { public: - IUnknownPointer() : _storage(nullptr) { } + IUnknownPointer() : _storage(nullptr) {} - IUnknownPointer(T** pointer) : _storage(toStorageType(pointer)) { - if (_storage) { - (*pointer)->AddRef(pointer); - } + IUnknownPointer(T** pointer) : _storage(toStorageType(pointer)) { + if (_storage) { + (*pointer)->AddRef(pointer); } + } - IUnknownPointer(const IUnknownPointer & other) : _storage(other._storage) { - if (IUnknownVTbl** ptr = _storage) { - (*ptr)->AddRef(ptr); - } + IUnknownPointer(const IUnknownPointer& other) : _storage(other._storage) { + if (IUnknownVTbl** ptr = _storage) { + (*ptr)->AddRef(ptr); } - IUnknownPointer& operator=(const IUnknownPointer & other) { - if (IUnknownVTbl** pointer = _storage) { - (*pointer)->Release(pointer); - } - _storage = other._storage; - if (IUnknownVTbl** ptr = _storage) { - (*ptr)->AddRef(ptr); - } - return *this; + } + IUnknownPointer& operator=(const IUnknownPointer& other) { + if (IUnknownVTbl** pointer = _storage) { + (*pointer)->Release(pointer); } + _storage = other._storage; + if (IUnknownVTbl** ptr = _storage) { + (*ptr)->AddRef(ptr); + } + return *this; + } - IUnknownPointer(IUnknownPointer && other) : _storage(std::exchange(other._storage, nullptr)) { } + IUnknownPointer(IUnknownPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {} - ~IUnknownPointer() { - if (IUnknownVTbl** pointer = _storage) { - (*pointer)->Release(pointer); - } + ~IUnknownPointer() { + if (IUnknownVTbl** pointer = _storage) { + (*pointer)->Release(pointer); } + } - static inline IUnknownPointer adopt(T** ptr) { - return IUnknownPointer(ptr, IUnknownPointer::Adopt); - } + static inline IUnknownPointer adopt(T** ptr) { return IUnknownPointer(ptr, IUnknownPointer::Adopt); } - T* get() const { - return fromStorageType(_storage); - } + T* get() const { return fromStorageType(_storage); } - T* operator->() const { return get(); } - T** storage() const { return (T**)_storage; } - LPVOID* operator&() { - if (IUnknownVTbl** pointer = _storage) { - printf("%p RELEASE %d\n", pointer, (*pointer)->Release(pointer)); - } - return (LPVOID*)&_storage; + T* operator->() const { return get(); } + T** storage() const { return (T**)_storage; } + LPVOID* operator&() { + if (IUnknownVTbl** pointer = _storage) { + printf("%p RELEASE %d\n", pointer, (*pointer)->Release(pointer)); } - operator bool() const { return _storage != nullptr; } + return (LPVOID*)&_storage; + } + operator bool() const { return _storage != nullptr; } private: - IUnknownVTbl** _storage; + IUnknownVTbl** _storage; - enum AdoptTag { Adopt }; - IUnknownPointer(T** ptr, AdoptTag) : _storage(toStorageType(ptr)) { } + enum AdoptTag { Adopt }; + IUnknownPointer(T** ptr, AdoptTag) : _storage(toStorageType(ptr)) {} - inline IUnknownVTbl** toStorageType(T** ptr) const { - return (IUnknownVTbl**)ptr; - } + inline IUnknownVTbl** toStorageType(T** ptr) const { return (IUnknownVTbl**)ptr; } - inline T* fromStorageType(IUnknownVTbl** pointer) const { - return *(T**)pointer; - } + inline T* fromStorageType(IUnknownVTbl** pointer) const { return *(T**)pointer; } - void swap(IUnknownPointer &other) { - std::swap(_storage, other._storage); - } + void swap(IUnknownPointer& other) { std::swap(_storage, other._storage); } }; - diff --git a/lib/Common.hpp b/lib/Common.hpp index 5cc3e2c..f305521 100644 --- a/lib/Common.hpp +++ b/lib/Common.hpp @@ -3,26 +3,31 @@ #include "boo/BooObject.hpp" #include -namespace boo -{ +namespace boo { /** Linked-list iterator shareable by ListNode types. */ template -class ListIterator -{ - T* m_node; -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = T; - using difference_type = std::ptrdiff_t; - using pointer = T*; - using reference = T&; +class ListIterator { + T* m_node; - explicit ListIterator(T* node) : m_node(node) {} - T& operator*() const { return *m_node; } - bool operator!=(const ListIterator& other) const { return m_node != other.m_node; } - ListIterator& operator++() { m_node = m_node->m_next; return *this; } - ListIterator& operator--() { m_node = m_node->m_prev; return *this; } +public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + explicit ListIterator(T* node) : m_node(node) {} + T& operator*() const { return *m_node; } + bool operator!=(const ListIterator& other) const { return m_node != other.m_node; } + ListIterator& operator++() { + m_node = m_node->m_next; + return *this; + } + ListIterator& operator--() { + m_node = m_node->m_prev; + return *this; + } }; /** Linked-list IObj node made part of objects participating in list. @@ -30,50 +35,43 @@ public: * to support the common list-management functionality. */ template -struct ListNode : P -{ - using iterator = ListIterator; - iterator begin() { return iterator(static_cast(this)); } - iterator end() { return iterator(nullptr); } +struct ListNode : P { + using iterator = ListIterator; + iterator begin() { return iterator(static_cast(this)); } + iterator end() { return iterator(nullptr); } + + H m_head; + N* m_next; + N* m_prev = nullptr; + ListNode(H head) : m_head(head) { + auto lk = N::_getHeadLock(head); + m_next = N::_getHeadPtr(head); + if (m_next) + m_next->m_prev = static_cast(this); + N::_getHeadPtr(head) = static_cast(this); + } - H m_head; - N* m_next; - N* m_prev = nullptr; - ListNode(H head) : m_head(head) - { - auto lk = N::_getHeadLock(head); - m_next = N::_getHeadPtr(head); - if (m_next) - m_next->m_prev = static_cast(this); - N::_getHeadPtr(head) = static_cast(this); - } protected: - ~ListNode() - { - if (m_prev) - { - if (m_next) - m_next->m_prev = m_prev; - m_prev->m_next = m_next; - } - else - { - if (m_next) - m_next->m_prev = nullptr; - N::_getHeadPtr(m_head) = m_next; - } + ~ListNode() { + if (m_prev) { + if (m_next) + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + } else { + if (m_next) + m_next->m_prev = nullptr; + N::_getHeadPtr(m_head) = m_next; } + } }; -static inline uint32_t flp2(uint32_t x) -{ - x = x | (x >> 1); - x = x | (x >> 2); - x = x | (x >> 4); - x = x | (x >> 8); - x = x | (x >> 16); - return x - (x >> 1); -} - +static inline uint32_t flp2(uint32_t x) { + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); + return x - (x >> 1); } +} // namespace boo diff --git a/lib/audiodev/AQS.cpp b/lib/audiodev/AQS.cpp index c508320..1379f96 100644 --- a/lib/audiodev/AQS.cpp +++ b/lib/audiodev/AQS.cpp @@ -10,947 +10,865 @@ #include #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::AQS"); #define AQS_NUM_BUFFERS 24 -static AudioChannel AQSChannelToBooChannel(AudioChannelLabel ch) -{ - switch (ch) - { - case kAudioChannelLabel_Left: - return AudioChannel::FrontLeft; - case kAudioChannelLabel_Right: - return AudioChannel::FrontRight; - case kAudioChannelLabel_LeftSurround: - return AudioChannel::RearLeft; - case kAudioChannelLabel_RightSurround: - return AudioChannel::RearRight; - case kAudioChannelLabel_Center: - return AudioChannel::FrontCenter; - case kAudioChannelLabel_LFEScreen: - return AudioChannel::LFE; - case kAudioChannelLabel_LeftSurroundDirect: - return AudioChannel::RearLeft; - case kAudioChannelLabel_RightSurroundDirect: - return AudioChannel::SideRight; - } - return AudioChannel::Unknown; +static AudioChannel AQSChannelToBooChannel(AudioChannelLabel ch) { + switch (ch) { + case kAudioChannelLabel_Left: + return AudioChannel::FrontLeft; + case kAudioChannelLabel_Right: + return AudioChannel::FrontRight; + case kAudioChannelLabel_LeftSurround: + return AudioChannel::RearLeft; + case kAudioChannelLabel_RightSurround: + return AudioChannel::RearRight; + case kAudioChannelLabel_Center: + return AudioChannel::FrontCenter; + case kAudioChannelLabel_LFEScreen: + return AudioChannel::LFE; + case kAudioChannelLabel_LeftSurroundDirect: + return AudioChannel::RearLeft; + case kAudioChannelLabel_RightSurroundDirect: + return AudioChannel::SideRight; + } + return AudioChannel::Unknown; } -struct AQSAudioVoiceEngine : BaseAudioVoiceEngine -{ - CFPointer m_runLoopMode; - CFPointer m_devName; +struct AQSAudioVoiceEngine : BaseAudioVoiceEngine { + CFPointer m_runLoopMode; + CFPointer m_devName; - AudioQueueRef m_queue = nullptr; - AudioQueueBufferRef m_buffers[AQS_NUM_BUFFERS]; - size_t m_frameBytes; + AudioQueueRef m_queue = nullptr; + AudioQueueBufferRef m_buffers[AQS_NUM_BUFFERS]; + size_t m_frameBytes; - MIDIClientRef m_midiClient = 0; + MIDIClientRef m_midiClient = 0; - bool m_cbRunning = true; - bool m_needsRebuild = false; + bool m_cbRunning = true; + bool m_needsRebuild = false; - static void Callback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) - { - if (!engine->m_cbRunning) - return; - engine->_pumpAndMixVoices(engine->m_mixInfo.m_periodFrames, - reinterpret_cast(inBuffer->mAudioData)); - inBuffer->mAudioDataByteSize = engine->m_frameBytes; - AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nullptr); + static void Callback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { + if (!engine->m_cbRunning) + return; + engine->_pumpAndMixVoices(engine->m_mixInfo.m_periodFrames, reinterpret_cast(inBuffer->mAudioData)); + inBuffer->mAudioDataByteSize = engine->m_frameBytes; + AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nullptr); + } + + static void DummyCallback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {} + + std::pair _getAvailableSetAndRate() { + AudioObjectPropertyAddress propertyAddress; + UInt32 argSize; + int numStreams; + std::vector streamIDs; + + CFStringRef devName = m_devName.get(); + AudioObjectID devId; + propertyAddress.mSelector = kAudioHardwarePropertyTranslateUIDToDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + argSize = sizeof(devId); + if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, sizeof(devName), &devName, &argSize, + &devId) != noErr) { + Log.report(logvisor::Error, "unable to resolve audio device UID %s, using default", + CFStringGetCStringPtr(devName, kCFStringEncodingUTF8)); + argSize = sizeof(devId); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &devId) == noErr) { + argSize = sizeof(CFStringRef); + AudioObjectPropertyAddress deviceAddress; + deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; + AudioObjectGetPropertyData(devId, &deviceAddress, 0, NULL, &argSize, &m_devName); + } else { + Log.report(logvisor::Fatal, "unable determine default audio device"); + return {AudioChannelSet::Unknown, 48000.0}; + } } - static void DummyCallback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {} + propertyAddress.mSelector = kAudioDevicePropertyStreams; + if (AudioObjectGetPropertyDataSize(devId, &propertyAddress, 0, NULL, &argSize) == noErr) { + numStreams = argSize / sizeof(AudioStreamID); + streamIDs.resize(numStreams); - std::pair _getAvailableSetAndRate() - { - AudioObjectPropertyAddress propertyAddress; - UInt32 argSize; - int numStreams; - std::vector streamIDs; - - CFStringRef devName = m_devName.get(); - AudioObjectID devId; - propertyAddress.mSelector = kAudioHardwarePropertyTranslateUIDToDevice; - propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; - propertyAddress.mElement = kAudioObjectPropertyElementMaster; - argSize = sizeof(devId); - if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, sizeof(devName), &devName, &argSize, &devId) != noErr) { - Log.report(logvisor::Error, "unable to resolve audio device UID %s, using default", - CFStringGetCStringPtr(devName, kCFStringEncodingUTF8)); - argSize = sizeof(devId); - propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &devId) == noErr) { - argSize = sizeof(CFStringRef); - AudioObjectPropertyAddress deviceAddress; - deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; - AudioObjectGetPropertyData(devId, &deviceAddress, 0, NULL, &argSize, &m_devName); - } else { - Log.report(logvisor::Fatal, "unable determine default audio device"); - return {AudioChannelSet::Unknown, 48000.0}; + if (AudioObjectGetPropertyData(devId, &propertyAddress, 0, NULL, &argSize, &streamIDs[0]) == noErr) { + propertyAddress.mSelector = kAudioStreamPropertyDirection; + for (int stm = 0; stm < numStreams; stm++) { + UInt32 streamDir; + argSize = sizeof(streamDir); + if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &streamDir) == noErr) { + if (streamDir == 0) { + propertyAddress.mSelector = kAudioStreamPropertyPhysicalFormat; + AudioStreamBasicDescription asbd; + argSize = sizeof(asbd); + if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &asbd) == noErr) { + switch (asbd.mChannelsPerFrame) { + case 2: + return {AudioChannelSet::Stereo, asbd.mSampleRate}; + case 4: + return {AudioChannelSet::Quad, asbd.mSampleRate}; + case 6: + return {AudioChannelSet::Surround51, asbd.mSampleRate}; + case 8: + return {AudioChannelSet::Surround71, asbd.mSampleRate}; + default: + break; + } + if (asbd.mChannelsPerFrame > 8) + return {AudioChannelSet::Surround71, asbd.mSampleRate}; + } + break; } + } } + } + } - propertyAddress.mSelector = kAudioDevicePropertyStreams; - if (AudioObjectGetPropertyDataSize(devId, &propertyAddress, 0, NULL, &argSize) == noErr) { - numStreams = argSize / sizeof(AudioStreamID); + return {AudioChannelSet::Unknown, 48000.0}; + } + + std::string getCurrentAudioOutput() const { return CFStringGetCStringPtr(m_devName.get(), kCFStringEncodingUTF8); } + + bool setCurrentAudioOutput(const char* name) { + m_devName = CFPointer::adopt(CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8)); + _rebuildAudioQueue(); + return true; + } + + /* + * https://stackoverflow.com/questions/1983984/how-to-get-audio-device-uid-to-pass-into-nssounds-setplaybackdeviceidentifier + */ + std::vector> enumerateAudioOutputs() const { + std::vector> ret; + + AudioObjectPropertyAddress propertyAddress; + std::vector deviceIDs; + UInt32 propertySize; + int numDevices; + + std::vector streamIDs; + int numStreams; + + propertyAddress.mSelector = kAudioHardwarePropertyDevices; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) == noErr) { + numDevices = propertySize / sizeof(AudioDeviceID); + ret.reserve(numDevices); + deviceIDs.resize(numDevices); + + if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, + &deviceIDs[0]) == noErr) { + char deviceName[64]; + + for (int idx = 0; idx < numDevices; idx++) { + propertyAddress.mSelector = kAudioDevicePropertyStreams; + if (AudioObjectGetPropertyDataSize(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize) == noErr) { + numStreams = propertySize / sizeof(AudioStreamID); streamIDs.resize(numStreams); - if (AudioObjectGetPropertyData(devId, &propertyAddress, 0, NULL, &argSize, &streamIDs[0]) == noErr) { - propertyAddress.mSelector = kAudioStreamPropertyDirection; - for (int stm = 0; stm < numStreams; stm++) { - UInt32 streamDir; - argSize = sizeof(streamDir); - if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &streamDir) == noErr) { - if (streamDir == 0) { - propertyAddress.mSelector = kAudioStreamPropertyPhysicalFormat; - AudioStreamBasicDescription asbd; - argSize = sizeof(asbd); - if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &asbd) == noErr) { - switch (asbd.mChannelsPerFrame) - { - case 2: - return {AudioChannelSet::Stereo, asbd.mSampleRate}; - case 4: - return {AudioChannelSet::Quad, asbd.mSampleRate}; - case 6: - return {AudioChannelSet::Surround51, asbd.mSampleRate}; - case 8: - return {AudioChannelSet::Surround71, asbd.mSampleRate}; - default: break; - } - if (asbd.mChannelsPerFrame > 8) - return {AudioChannelSet::Surround71, asbd.mSampleRate}; - } - break; - } - } + if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &streamIDs[0]) == + noErr) { + propertyAddress.mSelector = kAudioStreamPropertyDirection; + bool foundOutput = false; + for (int stm = 0; stm < numStreams; stm++) { + UInt32 streamDir; + propertySize = sizeof(streamDir); + if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &propertySize, &streamDir) == + noErr) { + if (streamDir == 0) { + foundOutput = true; + break; + } } + } + if (!foundOutput) + continue; } - } + } - return {AudioChannelSet::Unknown, 48000.0}; - } + propertySize = sizeof(deviceName); + propertyAddress.mSelector = kAudioDevicePropertyDeviceName; + if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, deviceName) == + noErr) { + CFPointer uidString; - std::string getCurrentAudioOutput() const - { - return CFStringGetCStringPtr(m_devName.get(), kCFStringEncodingUTF8); - } - - bool setCurrentAudioOutput(const char* name) - { - m_devName = CFPointer::adopt(CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8)); - _rebuildAudioQueue(); - return true; - } - - /* - * https://stackoverflow.com/questions/1983984/how-to-get-audio-device-uid-to-pass-into-nssounds-setplaybackdeviceidentifier - */ - std::vector> enumerateAudioOutputs() const - { - std::vector> ret; - - AudioObjectPropertyAddress propertyAddress; - std::vector deviceIDs; - UInt32 propertySize; - int numDevices; - - std::vector streamIDs; - int numStreams; - - propertyAddress.mSelector = kAudioHardwarePropertyDevices; - propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; - propertyAddress.mElement = kAudioObjectPropertyElementMaster; - if (AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize) == noErr) { - numDevices = propertySize / sizeof(AudioDeviceID); - ret.reserve(numDevices); - deviceIDs.resize(numDevices); - - if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &deviceIDs[0]) == noErr) { - char deviceName[64]; - - for (int idx = 0; idx < numDevices; idx++) { - propertyAddress.mSelector = kAudioDevicePropertyStreams; - if (AudioObjectGetPropertyDataSize(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize) == noErr) { - numStreams = propertySize / sizeof(AudioStreamID); - streamIDs.resize(numStreams); - - if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &streamIDs[0]) == noErr) { - propertyAddress.mSelector = kAudioStreamPropertyDirection; - bool foundOutput = false; - for (int stm = 0; stm < numStreams; stm++) { - UInt32 streamDir; - propertySize = sizeof(streamDir); - if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &propertySize, &streamDir) == noErr) { - if (streamDir == 0) { - foundOutput = true; - break; - } - } - } - if (!foundOutput) - continue; - } - } - - propertySize = sizeof(deviceName); - propertyAddress.mSelector = kAudioDevicePropertyDeviceName; - if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, deviceName) == noErr) { - CFPointer uidString; - - propertySize = sizeof(CFStringRef); - propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; - if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &uidString) == noErr) { - ret.emplace_back(CFStringGetCStringPtr(uidString.get(), kCFStringEncodingUTF8), deviceName); - } - } - } + propertySize = sizeof(CFStringRef); + propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; + if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &uidString) == + noErr) { + ret.emplace_back(CFStringGetCStringPtr(uidString.get(), kCFStringEncodingUTF8), deviceName); } + } } - - return ret; + } } - std::vector> enumerateMIDIInputs() const - { - if (!m_midiClient) - return {}; + return ret; + } - std::vector> ret; + std::vector> enumerateMIDIInputs() const { + if (!m_midiClient) + return {}; - ItemCount numDevices = MIDIGetNumberOfDevices(); - ret.reserve(numDevices); - for (int i=int(numDevices)-1 ; i>=0 ; --i) - { - MIDIDeviceRef dev = MIDIGetDevice(i); - if (!dev) - continue; + std::vector> ret; - bool isInput = false; - ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); - for (ItemCount j=0 ; j= 0; --i) { + MIDIDeviceRef dev = MIDIGetDevice(i); + if (!dev) + continue; - SInt32 idNum; - if (MIDIObjectGetIntegerProperty(dev, kMIDIPropertyUniqueID, &idNum)) - continue; - - CFPointer namestr; - const char* nameCstr; - if (MIDIObjectGetStringProperty(dev, kMIDIPropertyName, &namestr)) - continue; - - if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) - continue; - - char idStr[9]; - snprintf(idStr, 9, "%08X\n", idNum); - ret.push_back(std::make_pair(std::string(idStr), - std::string(nameCstr))); + bool isInput = false; + ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); + for (ItemCount j = 0; j < numEnt; ++j) { + MIDIEntityRef ent = MIDIDeviceGetEntity(dev, j); + if (ent) { + ItemCount numSrc = MIDIEntityGetNumberOfSources(ent); + if (numSrc) { + isInput = true; + break; + } } + } + if (!isInput) + continue; - return ret; + SInt32 idNum; + if (MIDIObjectGetIntegerProperty(dev, kMIDIPropertyUniqueID, &idNum)) + continue; + + CFPointer namestr; + const char* nameCstr; + if (MIDIObjectGetStringProperty(dev, kMIDIPropertyName, &namestr)) + continue; + + if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) + continue; + + char idStr[9]; + snprintf(idStr, 9, "%08X\n", idNum); + ret.push_back(std::make_pair(std::string(idStr), std::string(nameCstr))); } - bool supportsVirtualMIDIIn() const - { - return true; + return ret; + } + + bool supportsVirtualMIDIIn() const { return true; } + + static MIDIDeviceRef LookupMIDIDevice(const char* name) { + ItemCount numDevices = MIDIGetNumberOfDevices(); + for (ItemCount i = 0; i < numDevices; ++i) { + MIDIDeviceRef dev = MIDIGetDevice(i); + if (!dev) + continue; + + SInt32 idNum; + if (MIDIObjectGetIntegerProperty(dev, kMIDIPropertyUniqueID, &idNum)) + continue; + + char idStr[9]; + snprintf(idStr, 9, "%08X\n", idNum); + if (strcmp(idStr, name)) + continue; + + return dev; } - static MIDIDeviceRef LookupMIDIDevice(const char* name) - { - ItemCount numDevices = MIDIGetNumberOfDevices(); - for (ItemCount i=0 ; ipacket[0]; + for (int i = 0; i < pktlist->numPackets; ++i) { + std::vector bytes(std::cbegin(packet->data), std::cbegin(packet->data) + packet->length); + readProcRefCon->m_receiver(std::move(bytes), AudioConvertHostTimeToNanos(packet->timeStamp) / 1.0e9); + packet = MIDIPacketNext(packet); + } + } + + struct MIDIIn : public IMIDIIn { + MIDIEndpointRef m_midi = 0; + MIDIPortRef m_midiPort = 0; + + MIDIIn(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) + : IMIDIIn(parent, virt, std::move(receiver)) {} + + ~MIDIIn() { + if (m_midi) + MIDIEndpointDispose(m_midi); + if (m_midiPort) + MIDIPortDispose(m_midiPort); + } + + std::string description() const { + CFPointer namestr; + const char* nameCstr; + if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) return {}; - } - - static MIDIEndpointRef LookupMIDISource(const char* name) - { - MIDIDeviceRef dev = LookupMIDIDevice(name); - if (!dev) - return {}; - - ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); - for (ItemCount i=0 ; i namestr; + const char* nameCstr; + if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) return {}; + + if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) + return {}; + + return nameCstr; } - static void MIDIReceiveProc(const MIDIPacketList* pktlist, - IMIDIReceiver* readProcRefCon, - void*) - { - const MIDIPacket* packet = &pktlist->packet[0]; - for (int i=0 ; inumPackets ; ++i) - { - std::vector bytes(std::cbegin(packet->data), std::cbegin(packet->data) + packet->length); - readProcRefCon->m_receiver(std::move(bytes), AudioConvertHostTimeToNanos(packet->timeStamp) / 1.0e9); - packet = MIDIPacketNext(packet); - } + size_t send(const void* buf, size_t len) const { + union { + MIDIPacketList head; + Byte storage[512]; + } list; + MIDIPacket* curPacket = MIDIPacketListInit(&list.head); + if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), len, + reinterpret_cast(buf))) { + if (m_midiPort) + MIDISend(m_midiPort, m_midi, &list.head); + else + MIDIReceived(m_midi, &list.head); + return len; + } + return 0; + } + }; + + struct MIDIInOut : public IMIDIInOut { + MIDIEndpointRef m_midiIn = 0; + MIDIPortRef m_midiPortIn = 0; + MIDIEndpointRef m_midiOut = 0; + MIDIPortRef m_midiPortOut = 0; + + MIDIInOut(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) + : IMIDIInOut(parent, virt, std::move(receiver)) {} + + ~MIDIInOut() { + if (m_midiIn) + MIDIEndpointDispose(m_midiIn); + if (m_midiPortIn) + MIDIPortDispose(m_midiPortIn); + if (m_midiOut) + MIDIEndpointDispose(m_midiOut); + if (m_midiPortOut) + MIDIPortDispose(m_midiPortOut); } - struct MIDIIn : public IMIDIIn - { - MIDIEndpointRef m_midi = 0; - MIDIPortRef m_midiPort = 0; + std::string description() const { + CFPointer namestr; + const char* nameCstr; + if (MIDIObjectGetStringProperty(m_midiIn, kMIDIPropertyName, &namestr)) + return {}; - MIDIIn(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) - : IMIDIIn(parent, virt, std::move(receiver)) {} + if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) + return {}; - ~MIDIIn() - { - if (m_midi) - MIDIEndpointDispose(m_midi); - if (m_midiPort) - MIDIPortDispose(m_midiPort); - } - - std::string description() const - { - CFPointer namestr; - const char* nameCstr; - if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) - return {}; - - if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) - return {}; - - return nameCstr; - } - }; - - struct MIDIOut : public IMIDIOut - { - MIDIEndpointRef m_midi = 0; - MIDIPortRef m_midiPort = 0; - - MIDIOut(AQSAudioVoiceEngine* parent, bool virt) - : IMIDIOut(parent, virt) {} - - ~MIDIOut() - { - if (m_midi) - MIDIEndpointDispose(m_midi); - if (m_midiPort) - MIDIPortDispose(m_midiPort); - } - - std::string description() const - { - CFPointer namestr; - const char* nameCstr; - if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) - return {}; - - if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) - return {}; - - return nameCstr; - } - - size_t send(const void* buf, size_t len) const - { - union - { - MIDIPacketList head; - Byte storage[512]; - } list; - MIDIPacket* curPacket = MIDIPacketListInit(&list.head); - if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), - len, reinterpret_cast(buf))) - { - if (m_midiPort) - MIDISend(m_midiPort, m_midi, &list.head); - else - MIDIReceived(m_midi, &list.head); - return len; - } - return 0; - } - }; - - struct MIDIInOut : public IMIDIInOut - { - MIDIEndpointRef m_midiIn = 0; - MIDIPortRef m_midiPortIn = 0; - MIDIEndpointRef m_midiOut = 0; - MIDIPortRef m_midiPortOut = 0; - - MIDIInOut(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) - : IMIDIInOut(parent, virt, std::move(receiver)) {} - - ~MIDIInOut() - { - if (m_midiIn) - MIDIEndpointDispose(m_midiIn); - if (m_midiPortIn) - MIDIPortDispose(m_midiPortIn); - if (m_midiOut) - MIDIEndpointDispose(m_midiOut); - if (m_midiPortOut) - MIDIPortDispose(m_midiPortOut); - } - - std::string description() const - { - CFPointer namestr; - const char* nameCstr; - if (MIDIObjectGetStringProperty(m_midiIn, kMIDIPropertyName, &namestr)) - return {}; - - if (!(nameCstr = CFStringGetCStringPtr(namestr.get(), kCFStringEncodingUTF8))) - return {}; - - return nameCstr; - } - - size_t send(const void* buf, size_t len) const - { - union - { - MIDIPacketList head; - Byte storage[512]; - } list; - MIDIPacket* curPacket = MIDIPacketListInit(&list.head); - if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), - len, reinterpret_cast(buf))) - { - if (m_midiPortOut) - MIDISend(m_midiPortOut, m_midiOut, &list.head); - else - MIDIReceived(m_midiOut, &list.head); - return len; - } - return 0; - } - }; - - unsigned m_midiInCounter = 0; - unsigned m_midiOutCounter = 0; - - std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) - { - if (!m_midiClient) - return {}; - - std::unique_ptr ret = std::make_unique(this, true, std::move(receiver)); - if (!ret) - return {}; - - char name[256]; - auto appName = APP->getFriendlyName(); - if (!m_midiInCounter) - snprintf(name, 256, "%s MIDI-In", appName.data()); - else - snprintf(name, 256, "%s MIDI-In %u", appName.data(), m_midiInCounter); - m_midiInCounter++; - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); - OSStatus stat; - if ((stat = MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), - static_cast(ret.get()), - &static_cast(*ret).m_midi))) - ret.reset(); - - return ret; + return nameCstr; } - std::unique_ptr newVirtualMIDIOut() - { - if (!m_midiClient) - return {}; - - std::unique_ptr ret = std::make_unique(this, true); - if (!ret) - return {}; - - char name[256]; - auto appName = APP->getFriendlyName(); - if (!m_midiOutCounter) - snprintf(name, 256, "%s MIDI-Out", appName.data()); + size_t send(const void* buf, size_t len) const { + union { + MIDIPacketList head; + Byte storage[512]; + } list; + MIDIPacket* curPacket = MIDIPacketListInit(&list.head); + if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), len, + reinterpret_cast(buf))) { + if (m_midiPortOut) + MIDISend(m_midiPortOut, m_midiOut, &list.head); else - snprintf(name, 256, "%s MIDI-Out %u", appName.data(), m_midiOutCounter); - m_midiOutCounter++; - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDISourceCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midi)) - ret.reset(); + MIDIReceived(m_midiOut, &list.head); + return len; + } + return 0; + } + }; - return ret; + unsigned m_midiInCounter = 0; + unsigned m_midiOutCounter = 0; + + std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) { + if (!m_midiClient) + return {}; + + std::unique_ptr ret = std::make_unique(this, true, std::move(receiver)); + if (!ret) + return {}; + + char name[256]; + auto appName = APP->getFriendlyName(); + if (!m_midiInCounter) + snprintf(name, 256, "%s MIDI-In", appName.data()); + else + snprintf(name, 256, "%s MIDI-In %u", appName.data(), m_midiInCounter); + m_midiInCounter++; + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); + OSStatus stat; + if ((stat = MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), + static_cast(ret.get()), &static_cast(*ret).m_midi))) + ret.reset(); + + return ret; + } + + std::unique_ptr newVirtualMIDIOut() { + if (!m_midiClient) + return {}; + + std::unique_ptr ret = std::make_unique(this, true); + if (!ret) + return {}; + + char name[256]; + auto appName = APP->getFriendlyName(); + if (!m_midiOutCounter) + snprintf(name, 256, "%s MIDI-Out", appName.data()); + else + snprintf(name, 256, "%s MIDI-Out %u", appName.data(), m_midiOutCounter); + m_midiOutCounter++; + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDISourceCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midi)) + ret.reset(); + + return ret; + } + + std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) { + if (!m_midiClient) + return {}; + + std::unique_ptr ret = std::make_unique(this, true, std::move(receiver)); + if (!ret) + return {}; + + char name[256]; + auto appName = APP->getFriendlyName(); + if (!m_midiInCounter) + snprintf(name, 256, "%s MIDI-In", appName.data()); + else + snprintf(name, 256, "%s MIDI-In %u", appName.data(), m_midiInCounter); + m_midiInCounter++; + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), + static_cast(ret.get()), &static_cast(*ret).m_midiIn)) + ret.reset(); + + if (!ret) + return {}; + + if (!m_midiOutCounter) + snprintf(name, 256, "%s MIDI-Out", appName.data()); + else + snprintf(name, 256, "%s MIDI-Out %u", appName.data(), m_midiOutCounter); + m_midiOutCounter++; + midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDISourceCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiOut)) + ret.reset(); + + return ret; + } + + std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { + if (!m_midiClient) + return {}; + + MIDIEndpointRef src = LookupMIDISource(name); + if (!src) + return {}; + + std::unique_ptr ret = std::make_unique(this, false, std::move(receiver)); + if (!ret) + return {}; + + char mname[256]; + snprintf(mname, 256, "Boo MIDI Real In %u", m_midiInCounter++); + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), + static_cast(ret.get()), &static_cast(*ret).m_midiPort)) + ret.reset(); + else + MIDIPortConnectSource(static_cast(*ret).m_midiPort, src, nullptr); + + return ret; + } + + std::unique_ptr newRealMIDIOut(const char* name) { + if (!m_midiClient) + return {}; + + MIDIEndpointRef dst = LookupMIDIDest(name); + if (!dst) + return {}; + + std::unique_ptr ret = std::make_unique(this, false); + if (!ret) + return {}; + + char mname[256]; + snprintf(mname, 256, "Boo MIDI Real Out %u", m_midiOutCounter++); + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDIOutputPortCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiPort)) + ret.reset(); + else + static_cast(*ret).m_midi = dst; + + return ret; + } + + std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { + if (!m_midiClient) + return {}; + + MIDIEndpointRef src = LookupMIDISource(name); + if (!src) + return {}; + + MIDIEndpointRef dst = LookupMIDIDest(name); + if (!dst) + return {}; + + std::unique_ptr ret = std::make_unique(this, false, std::move(receiver)); + if (!ret) + return {}; + + char mname[256]; + snprintf(mname, 256, "Boo MIDI Real In %u", m_midiInCounter++); + CFPointer midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), + static_cast(ret.get()), &static_cast(*ret).m_midiPortIn)) + ret.reset(); + else + MIDIPortConnectSource(static_cast(*ret).m_midiPortIn, src, nullptr); + + if (!ret) + return {}; + + snprintf(mname, 256, "Boo MIDI Real Out %u", m_midiOutCounter++); + midiName = CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); + if (MIDIOutputPortCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiPortOut)) + ret.reset(); + else + static_cast(*ret).m_midiOut = dst; + + return ret; + } + + bool useMIDILock() const { return true; } + + static void SampleRateChanged(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueuePropertyID inID) { + engine->m_needsRebuild = true; + } + + void _rebuildAudioQueue() { + if (m_queue) { + m_cbRunning = false; + AudioQueueDispose(m_queue, true); + m_cbRunning = true; + m_queue = nullptr; } - std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) - { - if (!m_midiClient) - return {}; + auto setAndRate = _getAvailableSetAndRate(); + m_mixInfo.m_channels = setAndRate.first; + unsigned chCount = ChannelCount(m_mixInfo.m_channels); - std::unique_ptr ret = std::make_unique(this, true, std::move(receiver)); - if (!ret) - return {}; + AudioStreamBasicDescription desc = {}; + desc.mSampleRate = setAndRate.second; + desc.mFormatID = kAudioFormatLinearPCM; + desc.mFormatFlags = kLinearPCMFormatFlagIsFloat; + desc.mBytesPerPacket = chCount * 4; + desc.mFramesPerPacket = 1; + desc.mBytesPerFrame = chCount * 4; + desc.mChannelsPerFrame = chCount; + desc.mBitsPerChannel = 32; - char name[256]; - auto appName = APP->getFriendlyName(); - if (!m_midiInCounter) - snprintf(name, 256, "%s MIDI-In", appName.data()); - else - snprintf(name, 256, "%s MIDI-In %u", appName.data(), m_midiInCounter); - m_midiInCounter++; - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), - static_cast(ret.get()), - &static_cast(*ret).m_midiIn)) - ret.reset(); - - if (!ret) - return {}; - - if (!m_midiOutCounter) - snprintf(name, 256, "%s MIDI-Out", appName.data()); - else - snprintf(name, 256, "%s MIDI-Out %u", appName.data(), m_midiOutCounter); - m_midiOutCounter++; - midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDISourceCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiOut)) - ret.reset(); - - return ret; + OSStatus err; + if ((err = AudioQueueNewOutput(&desc, AudioQueueOutputCallback(Callback), this, CFRunLoopGetCurrent(), + m_runLoopMode.get(), 0, &m_queue))) { + Log.report(logvisor::Fatal, "unable to create output audio queue"); + return; } - std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) - { - if (!m_midiClient) - return {}; - - MIDIEndpointRef src = LookupMIDISource(name); - if (!src) - return {}; - - std::unique_ptr ret = std::make_unique(this, false, std::move(receiver)); - if (!ret) - return {}; - - char mname[256]; - snprintf(mname, 256, "Boo MIDI Real In %u", m_midiInCounter++); - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), - static_cast(ret.get()), - &static_cast(*ret).m_midiPort)) - ret.reset(); - else - MIDIPortConnectSource(static_cast(*ret).m_midiPort, src, nullptr); - - return ret; + CFStringRef devName = m_devName.get(); + if ((err = AudioQueueSetProperty(m_queue, kAudioQueueProperty_CurrentDevice, &devName, sizeof(devName)))) { + Log.report(logvisor::Fatal, "unable to set current device into audio queue"); + return; } - std::unique_ptr newRealMIDIOut(const char* name) - { - if (!m_midiClient) - return {}; + AudioQueueAddPropertyListener(m_queue, kAudioQueueDeviceProperty_SampleRate, + AudioQueuePropertyListenerProc(SampleRateChanged), this); - MIDIEndpointRef dst = LookupMIDIDest(name); - if (!dst) - return {}; + m_mixInfo.m_sampleRate = desc.mSampleRate; + m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; + m_mixInfo.m_bitsPerSample = 32; + m_5msFrames = desc.mSampleRate * 5 / 1000; - std::unique_ptr ret = std::make_unique(this, false); - if (!ret) - return {}; - - char mname[256]; - snprintf(mname, 256, "Boo MIDI Real Out %u", m_midiOutCounter++); - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDIOutputPortCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiPort)) - ret.reset(); - else - static_cast(*ret).m_midi = dst; - - return ret; - } - - std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) - { - if (!m_midiClient) - return {}; - - MIDIEndpointRef src = LookupMIDISource(name); - if (!src) - return {}; - - MIDIEndpointRef dst = LookupMIDIDest(name); - if (!dst) - return {}; - - std::unique_ptr ret = std::make_unique(this, false, std::move(receiver)); - if (!ret) - return {}; - - char mname[256]; - snprintf(mname, 256, "Boo MIDI Real In %u", m_midiInCounter++); - CFPointer midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), - static_cast(ret.get()), - &static_cast(*ret).m_midiPortIn)) - ret.reset(); - else - MIDIPortConnectSource(static_cast(*ret).m_midiPortIn, src, nullptr); - - if (!ret) - return {}; - - snprintf(mname, 256, "Boo MIDI Real Out %u", m_midiOutCounter++); - midiName = CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); - if (MIDIOutputPortCreate(m_midiClient, midiName.get(), &static_cast(*ret).m_midiPortOut)) - ret.reset(); - else - static_cast(*ret).m_midiOut = dst; - - return ret; - } - - bool useMIDILock() const {return true;} - - static void SampleRateChanged(AQSAudioVoiceEngine* engine, - AudioQueueRef inAQ, - AudioQueuePropertyID inID) - { - engine->m_needsRebuild = true; - } - - void _rebuildAudioQueue() - { - if (m_queue) - { - m_cbRunning = false; - AudioQueueDispose(m_queue, true); - m_cbRunning = true; - m_queue = nullptr; + ChannelMap& chMapOut = m_mixInfo.m_channelMap; + chMapOut.m_channelCount = 0; + if (chCount > 2) { + AudioChannelLayout layout; + UInt32 layoutSz = sizeof(layout); + if (AudioQueueGetProperty(m_queue, kAudioQueueProperty_ChannelLayout, &layout, &layoutSz)) { + Log.report(logvisor::Warning, "unable to get channel layout from audio queue; using count's default"); + switch (m_mixInfo.m_channels) { + case AudioChannelSet::Stereo: + default: + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; + break; + case AudioChannelSet::Quad: + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; + break; + case AudioChannelSet::Surround51: + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; + break; + case AudioChannelSet::Surround71: + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideRight; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; + break; } - - auto setAndRate = _getAvailableSetAndRate(); - m_mixInfo.m_channels = setAndRate.first; - unsigned chCount = ChannelCount(m_mixInfo.m_channels); - - AudioStreamBasicDescription desc = {}; - desc.mSampleRate = setAndRate.second; - desc.mFormatID = kAudioFormatLinearPCM; - desc.mFormatFlags = kLinearPCMFormatFlagIsFloat; - desc.mBytesPerPacket = chCount * 4; - desc.mFramesPerPacket = 1; - desc.mBytesPerFrame = chCount * 4; - desc.mChannelsPerFrame = chCount; - desc.mBitsPerChannel = 32; - - OSStatus err; - if ((err = AudioQueueNewOutput(&desc, AudioQueueOutputCallback(Callback), - this, CFRunLoopGetCurrent(), m_runLoopMode.get(), 0, &m_queue))) - { - Log.report(logvisor::Fatal, "unable to create output audio queue"); - return; - } - - CFStringRef devName = m_devName.get(); - if ((err = AudioQueueSetProperty(m_queue, kAudioQueueProperty_CurrentDevice, &devName, sizeof(devName)))) - { - Log.report(logvisor::Fatal, "unable to set current device into audio queue"); - return; - } - - AudioQueueAddPropertyListener(m_queue, kAudioQueueDeviceProperty_SampleRate, - AudioQueuePropertyListenerProc(SampleRateChanged), this); - - m_mixInfo.m_sampleRate = desc.mSampleRate; - m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; - m_mixInfo.m_bitsPerSample = 32; - m_5msFrames = desc.mSampleRate * 5 / 1000; - - ChannelMap& chMapOut = m_mixInfo.m_channelMap; - chMapOut.m_channelCount = 0; - if (chCount > 2) - { - AudioChannelLayout layout; - UInt32 layoutSz = sizeof(layout); - if (AudioQueueGetProperty(m_queue, kAudioQueueProperty_ChannelLayout, &layout, &layoutSz)) - { - Log.report(logvisor::Warning, "unable to get channel layout from audio queue; using count's default"); - switch (m_mixInfo.m_channels) - { - case AudioChannelSet::Stereo: - default: - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; - break; - case AudioChannelSet::Quad: - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; - break; - case AudioChannelSet::Surround51: - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; - break; - case AudioChannelSet::Surround71: - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideRight; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; - break; - } - } - else - { - switch (layout.mChannelLayoutTag) - { - case kAudioChannelLayoutTag_UseChannelDescriptions: - chMapOut.m_channelCount = layout.mNumberChannelDescriptions; - for (int i = 0; i < layout.mNumberChannelDescriptions; ++i) - { - AudioChannel ch = AQSChannelToBooChannel(layout.mChannelDescriptions[i].mChannelLabel); - chMapOut.m_channels[i] = ch; - } - break; - case kAudioChannelLayoutTag_UseChannelBitmap: - if ((layout.mChannelBitmap & kAudioChannelBit_Left) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; - if ((layout.mChannelBitmap & kAudioChannelBit_Right) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; - if ((layout.mChannelBitmap & kAudioChannelBit_Center) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; - if ((layout.mChannelBitmap & kAudioChannelBit_LFEScreen) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; - if ((layout.mChannelBitmap & kAudioChannelBit_LeftSurround) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; - if ((layout.mChannelBitmap & kAudioChannelBit_RightSurround) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; - if ((layout.mChannelBitmap & kAudioChannelBit_LeftSurroundDirect) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideLeft; - if ((layout.mChannelBitmap & kAudioChannelBit_RightSurroundDirect) != 0) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideRight; - break; - case kAudioChannelLayoutTag_Stereo: - case kAudioChannelLayoutTag_StereoHeadphones: - chMapOut.m_channelCount = 2; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - break; - case kAudioChannelLayoutTag_Quadraphonic: - chMapOut.m_channelCount = 4; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::RearLeft; - chMapOut.m_channels[3] = AudioChannel::RearRight; - break; - case kAudioChannelLayoutTag_Pentagonal: - chMapOut.m_channelCount = 5; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::RearLeft; - chMapOut.m_channels[3] = AudioChannel::RearRight; - chMapOut.m_channels[4] = AudioChannel::FrontCenter; - break; - default: - Log.report(logvisor::Warning, - "unknown channel layout %u; using stereo", - layout.mChannelLayoutTag); - chMapOut.m_channelCount = 2; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - break; - } - } - } - else - { + } else { + switch (layout.mChannelLayoutTag) { + case kAudioChannelLayoutTag_UseChannelDescriptions: + chMapOut.m_channelCount = layout.mNumberChannelDescriptions; + for (int i = 0; i < layout.mNumberChannelDescriptions; ++i) { + AudioChannel ch = AQSChannelToBooChannel(layout.mChannelDescriptions[i].mChannelLabel); + chMapOut.m_channels[i] = ch; + } + break; + case kAudioChannelLayoutTag_UseChannelBitmap: + if ((layout.mChannelBitmap & kAudioChannelBit_Left) != 0) chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + if ((layout.mChannelBitmap & kAudioChannelBit_Right) != 0) chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; + if ((layout.mChannelBitmap & kAudioChannelBit_Center) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontCenter; + if ((layout.mChannelBitmap & kAudioChannelBit_LFEScreen) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::LFE; + if ((layout.mChannelBitmap & kAudioChannelBit_LeftSurround) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearLeft; + if ((layout.mChannelBitmap & kAudioChannelBit_RightSurround) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; + if ((layout.mChannelBitmap & kAudioChannelBit_LeftSurroundDirect) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideLeft; + if ((layout.mChannelBitmap & kAudioChannelBit_RightSurroundDirect) != 0) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::SideRight; + break; + case kAudioChannelLayoutTag_Stereo: + case kAudioChannelLayoutTag_StereoHeadphones: + chMapOut.m_channelCount = 2; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + break; + case kAudioChannelLayoutTag_Quadraphonic: + chMapOut.m_channelCount = 4; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::RearLeft; + chMapOut.m_channels[3] = AudioChannel::RearRight; + break; + case kAudioChannelLayoutTag_Pentagonal: + chMapOut.m_channelCount = 5; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::RearLeft; + chMapOut.m_channels[3] = AudioChannel::RearRight; + chMapOut.m_channels[4] = AudioChannel::FrontCenter; + break; + default: + Log.report(logvisor::Warning, "unknown channel layout %u; using stereo", layout.mChannelLayoutTag); + chMapOut.m_channelCount = 2; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + break; } - - while (chMapOut.m_channelCount < chCount) - chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::Unknown; - - m_mixInfo.m_periodFrames = m_5msFrames; - for (int i=0 ; imAudioData, 0, m_frameBytes); - m_buffers[i]->mAudioDataByteSize = m_frameBytes; - AudioQueueEnqueueBuffer(m_queue, m_buffers[i], 0, nullptr); - } - AudioQueuePrime(m_queue, 0, nullptr); - AudioQueueStart(m_queue, nullptr); + } + } else { + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; } - static OSStatus AudioDeviceChanged(AudioObjectID inObjectID, - UInt32 inNumberAddresses, - const AudioObjectPropertyAddress* inAddresses, - AQSAudioVoiceEngine* engine) - { - AudioObjectID defaultDeviceId; - UInt32 argSize = sizeof(defaultDeviceId); - if (AudioObjectGetPropertyData(inObjectID, inAddresses, 0, NULL, &argSize, &defaultDeviceId) == noErr) { - argSize = sizeof(CFStringRef); - AudioObjectPropertyAddress deviceAddress; - deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; - AudioObjectGetPropertyData(defaultDeviceId, &deviceAddress, 0, NULL, &argSize, &engine->m_devName); - } - engine->m_needsRebuild = true; - return noErr; + while (chMapOut.m_channelCount < chCount) + chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::Unknown; + + m_mixInfo.m_periodFrames = m_5msFrames; + for (int i = 0; i < AQS_NUM_BUFFERS; ++i) + if (AudioQueueAllocateBuffer(m_queue, m_mixInfo.m_periodFrames * chCount * 4, &m_buffers[i])) { + Log.report(logvisor::Fatal, "unable to create audio queue buffer"); + AudioQueueDispose(m_queue, false); + m_queue = nullptr; + return; + } + + m_frameBytes = m_mixInfo.m_periodFrames * m_mixInfo.m_channelMap.m_channelCount * 4; + + _resetSampleRate(); + + for (unsigned i = 0; i < AQS_NUM_BUFFERS; ++i) { + memset(m_buffers[i]->mAudioData, 0, m_frameBytes); + m_buffers[i]->mAudioDataByteSize = m_frameBytes; + AudioQueueEnqueueBuffer(m_queue, m_buffers[i], 0, nullptr); + } + AudioQueuePrime(m_queue, 0, nullptr); + AudioQueueStart(m_queue, nullptr); + } + + static OSStatus AudioDeviceChanged(AudioObjectID inObjectID, UInt32 inNumberAddresses, + const AudioObjectPropertyAddress* inAddresses, AQSAudioVoiceEngine* engine) { + AudioObjectID defaultDeviceId; + UInt32 argSize = sizeof(defaultDeviceId); + if (AudioObjectGetPropertyData(inObjectID, inAddresses, 0, NULL, &argSize, &defaultDeviceId) == noErr) { + argSize = sizeof(CFStringRef); + AudioObjectPropertyAddress deviceAddress; + deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; + AudioObjectGetPropertyData(defaultDeviceId, &deviceAddress, 0, NULL, &argSize, &engine->m_devName); + } + engine->m_needsRebuild = true; + return noErr; + } + + AQSAudioVoiceEngine() + : m_runLoopMode(CFPointer::adopt( + CFStringCreateWithCStringNoCopy(nullptr, "BooAQSMode", kCFStringEncodingUTF8, kCFAllocatorNull))) { + AudioObjectPropertyAddress propertyAddress; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + AudioObjectID defaultDeviceId; + UInt32 argSize = sizeof(defaultDeviceId); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &defaultDeviceId) == + noErr) { + argSize = sizeof(CFStringRef); + AudioObjectPropertyAddress deviceAddress; + deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; + AudioObjectGetPropertyData(defaultDeviceId, &deviceAddress, 0, NULL, &argSize, &m_devName); + } else { + Log.report(logvisor::Fatal, "unable determine default audio device"); + return; } - AQSAudioVoiceEngine() - : m_runLoopMode(CFPointer::adopt( - CFStringCreateWithCStringNoCopy(nullptr, "BooAQSMode", kCFStringEncodingUTF8, kCFAllocatorNull))) - { - AudioObjectPropertyAddress propertyAddress; - propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; - propertyAddress.mElement = kAudioObjectPropertyElementMaster; + propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, + AudioObjectPropertyListenerProc(AudioDeviceChanged), this); - AudioObjectID defaultDeviceId; - UInt32 argSize = sizeof(defaultDeviceId); - propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &defaultDeviceId) == noErr) { - argSize = sizeof(CFStringRef); - AudioObjectPropertyAddress deviceAddress; - deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; - AudioObjectGetPropertyData(defaultDeviceId, &deviceAddress, 0, NULL, &argSize, &m_devName); - } else { - Log.report(logvisor::Fatal, "unable determine default audio device"); - return; - } + _rebuildAudioQueue(); - propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propertyAddress, - AudioObjectPropertyListenerProc(AudioDeviceChanged), this); + /* Also create shared MIDI client */ + MIDIClientCreate(CFSTR("Boo MIDI"), nullptr, nullptr, &m_midiClient); + } - _rebuildAudioQueue(); + ~AQSAudioVoiceEngine() { + m_cbRunning = false; + AudioQueueDispose(m_queue, true); + if (m_midiClient) + MIDIClientDispose(m_midiClient); + } - /* Also create shared MIDI client */ - MIDIClientCreate(CFSTR("Boo MIDI"), nullptr, nullptr, &m_midiClient); - } - - ~AQSAudioVoiceEngine() - { - m_cbRunning = false; - AudioQueueDispose(m_queue, true); - if (m_midiClient) - MIDIClientDispose(m_midiClient); - } - - void pumpAndMixVoices() - { - while (CFRunLoopRunInMode(m_runLoopMode.get(), 0, true) == kCFRunLoopRunHandledSource) {} - if (m_needsRebuild) - { - _rebuildAudioQueue(); - m_needsRebuild = false; - } + void pumpAndMixVoices() { + while (CFRunLoopRunInMode(m_runLoopMode.get(), 0, true) == kCFRunLoopRunHandledSource) {} + if (m_needsRebuild) { + _rebuildAudioQueue(); + m_needsRebuild = false; } + } }; -std::unique_ptr NewAudioVoiceEngine() -{ - std::unique_ptr ret = std::make_unique(); - if (!static_cast(*ret).m_queue) - return {}; - return ret; +std::unique_ptr NewAudioVoiceEngine() { + std::unique_ptr ret = std::make_unique(); + if (!static_cast(*ret).m_queue) + return {}; + return ret; } -} +} // namespace boo diff --git a/lib/audiodev/AudioMatrix.cpp b/lib/audiodev/AudioMatrix.cpp index 306b9b0..f64f3d6 100644 --- a/lib/audiodev/AudioMatrix.cpp +++ b/lib/audiodev/AudioMatrix.cpp @@ -2,295 +2,228 @@ #include "AudioVoiceEngine.hpp" #include -namespace boo -{ +namespace boo { -void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) -{ - m_curSlewFrame = 0; - m_slewFrames = 0; - memset(&m_coefs, 0, sizeof(m_coefs)); - switch (acSet) - { - case AudioChannelSet::Stereo: - case AudioChannelSet::Quad: - m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; - m_coefs.v[int(AudioChannel::FrontRight)] = 1.0; - break; - case AudioChannelSet::Surround51: - case AudioChannelSet::Surround71: - m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; - break; - default: break; +void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) { + m_curSlewFrame = 0; + m_slewFrames = 0; + memset(&m_coefs, 0, sizeof(m_coefs)); + switch (acSet) { + case AudioChannelSet::Stereo: + case AudioChannelSet::Quad: + m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; + m_coefs.v[int(AudioChannel::FrontRight)] = 1.0; + break; + case AudioChannelSet::Surround51: + case AudioChannelSet::Surround71: + m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; + break; + default: + break; + } +} + +int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, + int16_t* dataOut, size_t samples) { + const ChannelMap& chmap = info.m_channelMap; + for (size_t s = 0; s < samples; ++s, ++dataIn) { + if (m_slewFrames && m_curSlewFrame < m_slewFrames) { + double t = m_curSlewFrame / double(m_slewFrames); + double omt = 1.0 - t; + + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); + ++dataOut; + } + } + + ++m_curSlewFrame; + } else { + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]); + ++dataOut; + } + } } + } + return dataOut; } -int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const int16_t* dataIn, int16_t* dataOut, size_t samples) -{ - const ChannelMap& chmap = info.m_channelMap; - for (size_t s=0 ; s #endif -namespace boo -{ +namespace boo { struct AudioVoiceEngineMixInfo; -static inline int16_t Clamp16(float in) -{ - if (in < SHRT_MIN) - return SHRT_MIN; - else if (in > SHRT_MAX) - return SHRT_MAX; - return in; +static inline int16_t Clamp16(float in) { + if (in < SHRT_MIN) + return SHRT_MIN; + else if (in > SHRT_MAX) + return SHRT_MAX; + return in; } -static inline int32_t Clamp32(float in) -{ - if (in < INT_MIN) - return INT_MIN; - else if (in > INT_MAX) - return INT_MAX; - return in; +static inline int32_t Clamp32(float in) { + if (in < INT_MIN) + return INT_MIN; + else if (in > INT_MAX) + return INT_MAX; + return in; } -class AudioMatrixMono -{ - union Coefs - { - float v[8]; +class AudioMatrixMono { + union Coefs { + float v[8]; #if __SSE__ - __m128 q[2]; - __m64 d[4]; + __m128 q[2]; + __m64 d[4]; #endif - }; - Coefs m_coefs = {}; - Coefs m_oldCoefs = {}; - size_t m_slewFrames = 0; - size_t m_curSlewFrame = ~size_t(0); + }; + Coefs m_coefs = {}; + Coefs m_oldCoefs = {}; + size_t m_slewFrames = 0; + size_t m_curSlewFrame = ~size_t(0); + public: - AudioMatrixMono() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);} + AudioMatrixMono() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); } - void setDefaultMatrixCoefficients(AudioChannelSet acSet); - void setMatrixCoefficients(const float coefs[8], size_t slewFrames=0) - { - m_slewFrames = slewFrames; + void setDefaultMatrixCoefficients(AudioChannelSet acSet); + void setMatrixCoefficients(const float coefs[8], size_t slewFrames = 0) { + m_slewFrames = slewFrames; #if __SSE__ - if (m_curSlewFrame != 0) - { - m_oldCoefs.q[0] = m_coefs.q[0]; - m_oldCoefs.q[1] = m_coefs.q[1]; - } - m_coefs.q[0] = _mm_loadu_ps(coefs); - m_coefs.q[1] = _mm_loadu_ps(&coefs[4]); + if (m_curSlewFrame != 0) { + m_oldCoefs.q[0] = m_coefs.q[0]; + m_oldCoefs.q[1] = m_coefs.q[1]; + } + m_coefs.q[0] = _mm_loadu_ps(coefs); + m_coefs.q[1] = _mm_loadu_ps(&coefs[4]); #else - for (int i=0 ; i<8 ; ++i) - { - if (m_curSlewFrame != 0) - m_oldCoefs.v[i] = m_coefs.v[i]; - m_coefs.v[i] = coefs[i]; - } + for (int i = 0; i < 8; ++i) { + if (m_curSlewFrame != 0) + m_oldCoefs.v[i] = m_coefs.v[i]; + m_coefs.v[i] = coefs[i]; + } #endif - m_curSlewFrame = 0; - } + m_curSlewFrame = 0; + } - int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const int16_t* dataIn, int16_t* dataOut, size_t samples); - int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const int32_t* dataIn, int32_t* dataOut, size_t samples); - float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const float* dataIn, float* dataOut, size_t samples); + int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, int16_t* dataOut, + size_t samples); + int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn, int32_t* dataOut, + size_t samples); + float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut, size_t samples); - bool isSilent() const - { - if (m_curSlewFrame < m_slewFrames) - for (int i=0 ; i<8 ; ++i) - if (m_oldCoefs.v[i] > FLT_EPSILON) - return false; - for (int i=0 ; i<8 ; ++i) - if (m_coefs.v[i] > FLT_EPSILON) - return false; - return true; - } + bool isSilent() const { + if (m_curSlewFrame < m_slewFrames) + for (int i = 0; i < 8; ++i) + if (m_oldCoefs.v[i] > FLT_EPSILON) + return false; + for (int i = 0; i < 8; ++i) + if (m_coefs.v[i] > FLT_EPSILON) + return false; + return true; + } }; -class AudioMatrixStereo -{ - union Coefs - { - float v[8][2]; +class AudioMatrixStereo { + union Coefs { + float v[8][2]; #if __SSE__ - __m128 q[4]; - __m64 d[8]; + __m128 q[4]; + __m64 d[8]; #endif - }; - Coefs m_coefs = {}; - Coefs m_oldCoefs = {}; - size_t m_slewFrames = 0; - size_t m_curSlewFrame = ~size_t(0); + }; + Coefs m_coefs = {}; + Coefs m_oldCoefs = {}; + size_t m_slewFrames = 0; + size_t m_curSlewFrame = ~size_t(0); + public: - AudioMatrixStereo() {setDefaultMatrixCoefficients(AudioChannelSet::Stereo);} + AudioMatrixStereo() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); } - void setDefaultMatrixCoefficients(AudioChannelSet acSet); - void setMatrixCoefficients(const float coefs[8][2], size_t slewFrames=0) - { - m_slewFrames = slewFrames; + void setDefaultMatrixCoefficients(AudioChannelSet acSet); + void setMatrixCoefficients(const float coefs[8][2], size_t slewFrames = 0) { + m_slewFrames = slewFrames; #if __SSE__ - if (m_curSlewFrame != 0) - { - m_oldCoefs.q[0] = m_coefs.q[0]; - m_oldCoefs.q[1] = m_coefs.q[1]; - m_oldCoefs.q[2] = m_coefs.q[2]; - m_oldCoefs.q[3] = m_coefs.q[3]; - } - m_coefs.q[0] = _mm_loadu_ps(coefs[0]); - m_coefs.q[1] = _mm_loadu_ps(coefs[2]); - m_coefs.q[2] = _mm_loadu_ps(coefs[4]); - m_coefs.q[3] = _mm_loadu_ps(coefs[6]); + if (m_curSlewFrame != 0) { + m_oldCoefs.q[0] = m_coefs.q[0]; + m_oldCoefs.q[1] = m_coefs.q[1]; + m_oldCoefs.q[2] = m_coefs.q[2]; + m_oldCoefs.q[3] = m_coefs.q[3]; + } + m_coefs.q[0] = _mm_loadu_ps(coefs[0]); + m_coefs.q[1] = _mm_loadu_ps(coefs[2]); + m_coefs.q[2] = _mm_loadu_ps(coefs[4]); + m_coefs.q[3] = _mm_loadu_ps(coefs[6]); #else - for (int i=0 ; i<8 ; ++i) - { - if (m_curSlewFrame != 0) - { - m_oldCoefs.v[i][0] = m_coefs.v[i][0]; - m_oldCoefs.v[i][1] = m_coefs.v[i][1]; - } - m_coefs.v[i][0] = coefs[i][0]; - m_coefs.v[i][1] = coefs[i][1]; - } + for (int i = 0; i < 8; ++i) { + if (m_curSlewFrame != 0) { + m_oldCoefs.v[i][0] = m_coefs.v[i][0]; + m_oldCoefs.v[i][1] = m_coefs.v[i][1]; + } + m_coefs.v[i][0] = coefs[i][0]; + m_coefs.v[i][1] = coefs[i][1]; + } #endif - m_curSlewFrame = 0; - } + m_curSlewFrame = 0; + } - int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, - const int16_t* dataIn, int16_t* dataOut, size_t frames); - int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, - const int32_t* dataIn, int32_t* dataOut, size_t frames); - float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, - const float* dataIn, float* dataOut, size_t frames); + int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, int16_t* dataOut, + size_t frames); + int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn, int32_t* dataOut, + size_t frames); + float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut, size_t frames); - bool isSilent() const - { - if (m_curSlewFrame < m_slewFrames) - for (int i=0 ; i<8 ; ++i) - if (m_oldCoefs.v[i][0] > FLT_EPSILON || m_oldCoefs.v[i][1] > FLT_EPSILON) - return false; - for (int i=0 ; i<8 ; ++i) - if (m_coefs.v[i][0] > FLT_EPSILON || m_coefs.v[i][1] > FLT_EPSILON) - return false; - return true; - } + bool isSilent() const { + if (m_curSlewFrame < m_slewFrames) + for (int i = 0; i < 8; ++i) + if (m_oldCoefs.v[i][0] > FLT_EPSILON || m_oldCoefs.v[i][1] > FLT_EPSILON) + return false; + for (int i = 0; i < 8; ++i) + if (m_coefs.v[i][0] > FLT_EPSILON || m_coefs.v[i][1] > FLT_EPSILON) + return false; + return true; + } }; -} - +} // namespace boo diff --git a/lib/audiodev/AudioMatrixSSE.cpp b/lib/audiodev/AudioMatrixSSE.cpp index c8b1b46..23826d6 100644 --- a/lib/audiodev/AudioMatrixSSE.cpp +++ b/lib/audiodev/AudioMatrixSSE.cpp @@ -4,531 +4,440 @@ #include -namespace boo -{ +namespace boo { -typedef union -{ - float v[4]; +typedef union { + float v[4]; #if __SSE__ - __m128 q; - __m64 d[2]; + __m128 q; + __m64 d[2]; #endif } TVectorUnion; static constexpr TVectorUnion Min32Vec = {{INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN}}; static constexpr TVectorUnion Max32Vec = {{INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX}}; -void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) -{ - m_curSlewFrame = 0; - m_slewFrames = 0; - m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]); - m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]); - switch (acSet) - { - case AudioChannelSet::Stereo: - case AudioChannelSet::Quad: - m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; - m_coefs.v[int(AudioChannel::FrontRight)] = 1.0; +void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) { + m_curSlewFrame = 0; + m_slewFrames = 0; + m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]); + m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]); + switch (acSet) { + case AudioChannelSet::Stereo: + case AudioChannelSet::Quad: + m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; + m_coefs.v[int(AudioChannel::FrontRight)] = 1.0; + break; + case AudioChannelSet::Surround51: + case AudioChannelSet::Surround71: + m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; + break; + default: + break; + } +} + +int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, + int16_t* dataOut, size_t samples) { + const ChannelMap& chmap = info.m_channelMap; + for (size_t s = 0; s < samples; ++s, ++dataIn) { + if (m_slewFrames && m_curSlewFrame < m_slewFrames) { + double t = m_curSlewFrame / double(m_slewFrames); + double omt = 1.0 - t; + + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); + ++dataOut; + } + } + + ++m_curSlewFrame; + } else { + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]); + ++dataOut; + } + } + } + } + return dataOut; +} + +int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn, + int32_t* dataOut, size_t samples) { + const ChannelMap& chmap = info.m_channelMap; + for (size_t s = 0; s < samples; ++s, ++dataIn) { + if (m_slewFrames && m_curSlewFrame < m_slewFrames) { + float t = m_curSlewFrame / float(m_slewFrames); + float omt = 1.f - t; + + switch (chmap.m_channelCount) { + case 2: { + ++m_curSlewFrame; + float t2 = m_curSlewFrame / float(m_slewFrames); + float omt2 = 1.f - t2; + + TVectorUnion coefs, samps; + coefs.q = _mm_add_ps( + _mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), _mm_set_ps(t, t, t2, t2)), + _mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), + _mm_set_ps(omt, omt, omt2, omt2))); + samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0])); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + ++s; + ++dataIn; break; - case AudioChannelSet::Surround51: - case AudioChannelSet::Surround71: - m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; + } + case 4: { + TVectorUnion coefs, samps; + coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt))); + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; break; - default: break; - } -} + } + case 6: { + TVectorUnion coefs, samps; + coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt))); + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); -int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const int16_t* dataIn, int16_t* dataOut, size_t samples) -{ - const ChannelMap& chmap = info.m_channelMap; - for (size_t s=0 ; s(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - for (unsigned c=0 ; c(dataIn))); -int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, - const int32_t* dataIn, int32_t* dataOut, size_t samples) -{ - const ChannelMap& chmap = info.m_channelMap; - for (size_t s=0 ; s(dataOut); + __m128i loadOut = _mm_loadu_si128(out); + pre = _mm_add_ps(_mm_cvtepi32_ps(loadOut), _mm_mul_ps(coefs.q, samps.q)); + _mm_storel_epi64(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - switch (chmap.m_channelCount) - { - case 2: - { - ++m_curSlewFrame; - float t2 = m_curSlewFrame / float(m_slewFrames); - float omt2 = 1.f - t2; - - TVectorUnion coefs, samps; - coefs.q = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), - _mm_set_ps(t, t, t2, t2)), - _mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), - _mm_set_ps(omt, omt, omt2, omt2))); - samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0])); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - ++s; - ++dataIn; - break; - } - case 4: - { - TVectorUnion coefs, samps; - coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), - _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt))); - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - break; - } - case 6: - { - TVectorUnion coefs, samps; - coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), - _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt))); - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - - coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), - _mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt))); - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - out = reinterpret_cast<__m128i*>(dataOut); - __m128i loadOut = _mm_loadu_si128(out); - pre = _mm_add_ps(_mm_cvtepi32_ps(loadOut), _mm_mul_ps(coefs.q, samps.q)); - _mm_storel_epi64(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 2; - break; - } - case 8: - { - TVectorUnion coefs, samps; - coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), - _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt))); - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - - coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), - _mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt))); - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - out = reinterpret_cast<__m128i*>(dataOut); - pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - break; - } - default: - { - for (unsigned c=0 ; c(dataOut); - __m128i huh2 = _mm_loadu_si128(reinterpret_cast(out)); - __m128 huh3 = _mm_cvtepi32_ps(huh2); - __m128 pre = _mm_add_ps(huh3, _mm_mul_ps(coefs.q, samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - ++s; - ++dataIn; - break; - } - case 4: - { - TVectorUnion samps; - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - break; - } - case 6: - { - TVectorUnion samps; - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - out = reinterpret_cast<__m128i*>(dataOut); - __m128i loadOut = _mm_loadu_si128(out); - pre = _mm_add_ps(_mm_cvtepi32_ps(loadOut), _mm_mul_ps(m_coefs.q[1], samps.q)); - _mm_storel_epi64(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 2; - break; - } - case 8: - { - TVectorUnion samps; - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - __m128i* out = reinterpret_cast<__m128i*>(dataOut); - __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - - samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); - - out = reinterpret_cast<__m128i*>(dataOut); - pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[1], samps.q)); - _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); - - dataOut += 4; - break; - } - default: - { - for (unsigned c=0 ; c(dataIn))); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + + coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt))); + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + out = reinterpret_cast<__m128i*>(dataOut); + pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; break; - default: break; + } + default: { + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); + ++dataOut; + } + } + break; + } + } + + ++m_curSlewFrame; + } else { + switch (chmap.m_channelCount) { + case 2: { + TVectorUnion coefs, samps; + coefs.q = _mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)); + samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0])); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128i huh2 = _mm_loadu_si128(reinterpret_cast(out)); + __m128 huh3 = _mm_cvtepi32_ps(huh2); + __m128 pre = _mm_add_ps(huh3, _mm_mul_ps(coefs.q, samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + ++s; + ++dataIn; + break; + } + case 4: { + TVectorUnion samps; + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + break; + } + case 6: { + TVectorUnion samps; + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + out = reinterpret_cast<__m128i*>(dataOut); + __m128i loadOut = _mm_loadu_si128(out); + pre = _mm_add_ps(_mm_cvtepi32_ps(loadOut), _mm_mul_ps(m_coefs.q[1], samps.q)); + _mm_storel_epi64(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 2; + break; + } + case 8: { + TVectorUnion samps; + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + __m128i* out = reinterpret_cast<__m128i*>(dataOut); + __m128 pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[0], samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + + samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast(dataIn))); + + out = reinterpret_cast<__m128i*>(dataOut); + pre = _mm_add_ps(_mm_cvtepi32_ps(_mm_loadu_si128(out)), _mm_mul_ps(m_coefs.q[1], samps.q)); + _mm_storeu_si128(out, _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(pre, Min32Vec.q), Max32Vec.q))); + + dataOut += 4; + break; + } + default: { + for (unsigned c = 0; c < chmap.m_channelCount; ++c) { + AudioChannel ch = chmap.m_channels[c]; + if (ch != AudioChannel::Unknown) { + *dataOut = Clamp32(*dataOut + *dataIn * m_coefs.v[int(ch)]); + ++dataOut; + } + } + break; + } + } } + } + return dataOut; } -int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, - const int16_t* dataIn, int16_t* dataOut, size_t frames) -{ - const ChannelMap& chmap = info.m_channelMap; - for (size_t f=0 ; f(&root), m_busId(busId), m_mainOut(mainOut), m_cb(cb) -{ - if (mainOut) - setSendLevel(m_head->m_mainSubmix.get(), 1.f, false); +: ListNode(&root), m_busId(busId), m_mainOut(mainOut), m_cb(cb) { + if (mainOut) + setSendLevel(m_head->m_mainSubmix.get(), 1.f, false); } -AudioSubmix::~AudioSubmix() -{ - m_head->m_submixesDirty = true; -} +AudioSubmix::~AudioSubmix() { m_head->m_submixesDirty = true; } AudioSubmix*& AudioSubmix::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_submixHead; } -std::unique_lock AudioSubmix::_getHeadLock(BaseAudioVoiceEngine* head) -{ return std::unique_lock{head->m_dataMutex}; } -std::unique_lock AudioSubmix::destructorLock() -{ return std::unique_lock{m_head->m_dataMutex}; } - -bool AudioSubmix::_isDirectDependencyOf(AudioSubmix* send) -{ - return m_sendGains.find(send) != m_sendGains.cend(); +std::unique_lock AudioSubmix::_getHeadLock(BaseAudioVoiceEngine* head) { + return std::unique_lock{head->m_dataMutex}; +} +std::unique_lock AudioSubmix::destructorLock() { + return std::unique_lock{m_head->m_dataMutex}; } -bool AudioSubmix::_mergeC3(std::list& output, - std::vector>& lists) -{ - for (auto outerIt = lists.begin() ; outerIt != lists.cend() ; ++outerIt) - { - if (outerIt->empty()) - continue; - AudioSubmix* smx = outerIt->front(); - bool found = false; - for (auto innerIt = lists.begin() ; innerIt != lists.cend() ; ++innerIt) - { - if (innerIt->empty() || outerIt == innerIt) - continue; - if (smx == innerIt->front()) - { - innerIt->pop_front(); - found = true; - } - } - if (found) - { - outerIt->pop_front(); - output.push_back(smx); - return true; - } +bool AudioSubmix::_isDirectDependencyOf(AudioSubmix* send) { return m_sendGains.find(send) != m_sendGains.cend(); } + +bool AudioSubmix::_mergeC3(std::list& output, std::vector>& lists) { + for (auto outerIt = lists.begin(); outerIt != lists.cend(); ++outerIt) { + if (outerIt->empty()) + continue; + AudioSubmix* smx = outerIt->front(); + bool found = false; + for (auto innerIt = lists.begin(); innerIt != lists.cend(); ++innerIt) { + if (innerIt->empty() || outerIt == innerIt) + continue; + if (smx == innerIt->front()) { + innerIt->pop_front(); + found = true; + } } - return false; + if (found) { + outerIt->pop_front(); + output.push_back(smx); + return true; + } + } + return false; } -std::list AudioSubmix::_linearizeC3() -{ - std::vector> lists = {{}}; - if (m_head->m_submixHead) - for (AudioSubmix& smx : *m_head->m_submixHead) - { - if (&smx == this) - continue; - if (smx._isDirectDependencyOf(this)) - lists[0].push_back(&smx); - } - lists.reserve(lists[0].size() + 1); - for (AudioSubmix* smx : lists[0]) - lists.push_back(smx->_linearizeC3()); +std::list AudioSubmix::_linearizeC3() { + std::vector> lists = {{}}; + if (m_head->m_submixHead) + for (AudioSubmix& smx : *m_head->m_submixHead) { + if (&smx == this) + continue; + if (smx._isDirectDependencyOf(this)) + lists[0].push_back(&smx); + } + lists.reserve(lists[0].size() + 1); + for (AudioSubmix* smx : lists[0]) + lists.push_back(smx->_linearizeC3()); - std::list ret = {this}; - while (_mergeC3(ret, lists)) {} - return ret; + std::list ret = {this}; + while (_mergeC3(ret, lists)) {} + return ret; } template -void AudioSubmix::_zeroFill() -{ - if (_getScratch().size()) - std::fill(_getScratch().begin(), _getScratch().end(), 0); +void AudioSubmix::_zeroFill() { + if (_getScratch().size()) + std::fill(_getScratch().begin(), _getScratch().end(), 0); } template void AudioSubmix::_zeroFill(); @@ -94,16 +79,15 @@ template void AudioSubmix::_zeroFill(); template void AudioSubmix::_zeroFill(); template -T* AudioSubmix::_getMergeBuf(size_t frames) -{ - if (_getRedirect()) - return _getRedirect(); +T* AudioSubmix::_getMergeBuf(size_t frames) { + if (_getRedirect()) + return _getRedirect(); - size_t sampleCount = frames * m_head->clientMixInfo().m_channelMap.m_channelCount; - if (_getScratch().size() < sampleCount) - _getScratch().resize(sampleCount); + size_t sampleCount = frames * m_head->clientMixInfo().m_channelMap.m_channelCount; + if (_getScratch().size() < sampleCount) + _getScratch().resize(sampleCount); - return _getScratch().data(); + return _getScratch().data(); } template int16_t* AudioSubmix::_getMergeBuf(size_t frames); @@ -111,143 +95,116 @@ template int32_t* AudioSubmix::_getMergeBuf(size_t frames); template float* AudioSubmix::_getMergeBuf(size_t frames); template -static inline T ClampInt(float in) -{ - if (std::is_floating_point()) - { - return in; // Allow subsequent mixing stages to work with over-saturated values - } - else - { - constexpr T MAX = std::numeric_limits::max(); - constexpr T MIN = std::numeric_limits::min(); +static inline T ClampInt(float in) { + if (std::is_floating_point()) { + return in; // Allow subsequent mixing stages to work with over-saturated values + } else { + constexpr T MAX = std::numeric_limits::max(); + constexpr T MIN = std::numeric_limits::min(); - if (in < MIN) - return MIN; - else if (in > MAX) - return MAX; - else - return in; - } + if (in < MIN) + return MIN; + else if (in > MAX) + return MAX; + else + return in; + } } template -size_t AudioSubmix::_pumpAndMix(size_t frames) -{ - const ChannelMap& chMap = m_head->clientMixInfo().m_channelMap; - size_t chanCount = chMap.m_channelCount; +size_t AudioSubmix::_pumpAndMix(size_t frames) { + const ChannelMap& chMap = m_head->clientMixInfo().m_channelMap; + size_t chanCount = chMap.m_channelCount; - if (_getRedirect()) - { - if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(_getRedirect(), frames, chMap, m_head->mixInfo().m_sampleRate); - _getRedirect() += chanCount * frames; - } - else - { - size_t sampleCount = frames * chanCount; - if (_getScratch().size() < sampleCount) - _getScratch().resize(sampleCount); - if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(_getScratch().data(), frames, chMap, m_head->mixInfo().m_sampleRate); + if (_getRedirect()) { + if (m_cb && m_cb->canApplyEffect()) + m_cb->applyEffect(_getRedirect(), frames, chMap, m_head->mixInfo().m_sampleRate); + _getRedirect() += chanCount * frames; + } else { + size_t sampleCount = frames * chanCount; + if (_getScratch().size() < sampleCount) + _getScratch().resize(sampleCount); + if (m_cb && m_cb->canApplyEffect()) + m_cb->applyEffect(_getScratch().data(), frames, chMap, m_head->mixInfo().m_sampleRate); - size_t curSlewFrame = m_slewFrames; - for (auto& smx : m_sendGains) - { - curSlewFrame = m_curSlewFrame; - AudioSubmix& sm = *reinterpret_cast(smx.first); - auto it = _getScratch().begin(); - T* dataOut = sm._getMergeBuf(frames); + size_t curSlewFrame = m_slewFrames; + for (auto& smx : m_sendGains) { + curSlewFrame = m_curSlewFrame; + AudioSubmix& sm = *reinterpret_cast(smx.first); + auto it = _getScratch().begin(); + T* dataOut = sm._getMergeBuf(frames); - for (size_t f=0 ; f(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt)); - ++it; - ++dataOut; - } + for (unsigned c = 0; c < chanCount; ++c) { + *dataOut = ClampInt(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt)); + ++it; + ++dataOut; + } - ++curSlewFrame; - } - else - { - for (unsigned c=0 ; c(*dataOut + *it * smx.second[1]); - ++it; - ++dataOut; - } - } - } + ++curSlewFrame; + } else { + for (unsigned c = 0; c < chanCount; ++c) { + *dataOut = ClampInt(*dataOut + *it * smx.second[1]); + ++it; + ++dataOut; + } } - m_curSlewFrame += curSlewFrame; + } } + m_curSlewFrame += curSlewFrame; + } - return frames; + return frames; } template size_t AudioSubmix::_pumpAndMix(size_t frames); template size_t AudioSubmix::_pumpAndMix(size_t frames); template size_t AudioSubmix::_pumpAndMix(size_t frames); -void AudioSubmix::_resetOutputSampleRate() -{ - if (m_cb) - m_cb->resetOutputSampleRate(m_head->mixInfo().m_sampleRate); +void AudioSubmix::_resetOutputSampleRate() { + if (m_cb) + m_cb->resetOutputSampleRate(m_head->mixInfo().m_sampleRate); } -void AudioSubmix::resetSendLevels() -{ - if (m_sendGains.empty()) - return; - m_sendGains.clear(); +void AudioSubmix::resetSendLevels() { + if (m_sendGains.empty()) + return; + m_sendGains.clear(); + m_head->m_submixesDirty = true; +} + +void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew) { + auto search = m_sendGains.find(submix); + if (search == m_sendGains.cend()) { + search = m_sendGains.emplace(submix, std::array{1.f, 1.f}).first; m_head->m_submixesDirty = true; + } + + m_slewFrames = slew ? m_head->m_5msFrames : 0; + m_curSlewFrame = 0; + + search->second[0] = search->second[1]; + search->second[1] = level; } -void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew) -{ - auto search = m_sendGains.find(submix); - if (search == m_sendGains.cend()) - { - search = m_sendGains.emplace(submix, std::array{1.f, 1.f}).first; - m_head->m_submixesDirty = true; - } +const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const { return m_head->mixInfo(); } - m_slewFrames = slew ? m_head->m_5msFrames : 0; - m_curSlewFrame = 0; +double AudioSubmix::getSampleRate() const { return mixInfo().m_sampleRate; } - search->second[0] = search->second[1]; - search->second[1] = level; +SubmixFormat AudioSubmix::getSampleFormat() const { + switch (mixInfo().m_sampleFormat) { + case SOXR_INT16_I: + default: + return SubmixFormat::Int16; + case SOXR_INT32_I: + return SubmixFormat::Int32; + case SOXR_FLOAT32_I: + return SubmixFormat::Float; + } } -const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const -{ - return m_head->mixInfo(); -} - -double AudioSubmix::getSampleRate() const -{ - return mixInfo().m_sampleRate; -} - -SubmixFormat AudioSubmix::getSampleFormat() const -{ - switch (mixInfo().m_sampleFormat) - { - case SOXR_INT16_I: - default: - return SubmixFormat::Int16; - case SOXR_INT32_I: - return SubmixFormat::Int32; - case SOXR_FLOAT32_I: - return SubmixFormat::Float; - } -} - -} +} // namespace boo diff --git a/lib/audiodev/AudioSubmix.hpp b/lib/audiodev/AudioSubmix.hpp index a479524..2250117 100644 --- a/lib/audiodev/AudioSubmix.hpp +++ b/lib/audiodev/AudioSubmix.hpp @@ -3,7 +3,7 @@ #include "boo/audiodev/IAudioSubmix.hpp" #include #include -#include +#include #include #include "Common.hpp" @@ -15,88 +15,107 @@ struct AudioUnitVoiceEngine; struct VSTVoiceEngine; struct WAVOutVoiceEngine; -namespace boo -{ +namespace boo { class BaseAudioVoiceEngine; class AudioVoice; struct AudioVoiceEngineMixInfo; /* Output gains for each mix-send/channel */ -class AudioSubmix : public ListNode -{ - friend class BaseAudioVoiceEngine; - friend class AudioVoiceMono; - friend class AudioVoiceStereo; - friend struct WASAPIAudioVoiceEngine; - friend struct ::AudioUnitVoiceEngine; - friend struct ::VSTVoiceEngine; - friend struct ::WAVOutVoiceEngine; +class AudioSubmix : public ListNode { + friend class BaseAudioVoiceEngine; + friend class AudioVoiceMono; + friend class AudioVoiceStereo; + friend struct WASAPIAudioVoiceEngine; + friend struct ::AudioUnitVoiceEngine; + friend struct ::VSTVoiceEngine; + friend struct ::WAVOutVoiceEngine; - /* Mixer-engine relationships */ - int m_busId; - bool m_mainOut; + /* Mixer-engine relationships */ + int m_busId; + bool m_mainOut; - /* Callback (effect source, optional) */ - IAudioSubmixCallback* m_cb; + /* Callback (effect source, optional) */ + IAudioSubmixCallback* m_cb; - /* Slew state for output gains */ - size_t m_slewFrames = 0; - size_t m_curSlewFrame = 0; + /* Slew state for output gains */ + size_t m_slewFrames = 0; + size_t m_curSlewFrame = 0; - /* Output gains for each mix-send/channel */ - std::unordered_map> m_sendGains; + /* Output gains for each mix-send/channel */ + std::unordered_map> m_sendGains; - /* Temporary scratch buffers for accumulating submix audio */ - std::vector m_scratch16; - std::vector m_scratch32; - std::vector m_scratchFlt; - template std::vector& _getScratch(); + /* Temporary scratch buffers for accumulating submix audio */ + std::vector m_scratch16; + std::vector m_scratch32; + std::vector m_scratchFlt; + template + std::vector& _getScratch(); - /* Override scratch buffers with alternate destination */ - int16_t* m_redirect16 = nullptr; - int32_t* m_redirect32 = nullptr; - float* m_redirectFlt = nullptr; - template T*& _getRedirect(); + /* Override scratch buffers with alternate destination */ + int16_t* m_redirect16 = nullptr; + int32_t* m_redirect32 = nullptr; + float* m_redirectFlt = nullptr; + template + T*& _getRedirect(); - /* C3-linearization support (to mitigate a potential diamond problem on 'clever' submix routes) */ - bool _isDirectDependencyOf(AudioSubmix* send); - std::list _linearizeC3(); - static bool _mergeC3(std::list& output, - std::vector>& lists); + /* C3-linearization support (to mitigate a potential diamond problem on 'clever' submix routes) */ + bool _isDirectDependencyOf(AudioSubmix* send); + std::list _linearizeC3(); + static bool _mergeC3(std::list& output, std::vector>& lists); - /* Fill scratch buffers with silence for new mix cycle */ - template void _zeroFill(); + /* Fill scratch buffers with silence for new mix cycle */ + template + void _zeroFill(); - /* Receive audio from a single voice / submix */ - template T* _getMergeBuf(size_t frames); + /* Receive audio from a single voice / submix */ + template + T* _getMergeBuf(size_t frames); - /* Mix scratch buffers into sends */ - template size_t _pumpAndMix(size_t frames); + /* Mix scratch buffers into sends */ + template + size_t _pumpAndMix(size_t frames); - void _resetOutputSampleRate(); + void _resetOutputSampleRate(); public: - static AudioSubmix*& _getHeadPtr(BaseAudioVoiceEngine* head); - static std::unique_lock _getHeadLock(BaseAudioVoiceEngine* head); - std::unique_lock destructorLock(); + static AudioSubmix*& _getHeadPtr(BaseAudioVoiceEngine* head); + static std::unique_lock _getHeadLock(BaseAudioVoiceEngine* head); + std::unique_lock destructorLock(); - AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut); - ~AudioSubmix(); + AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut); + ~AudioSubmix(); - void resetSendLevels(); - void setSendLevel(IAudioSubmix* submix, float level, bool slew); - const AudioVoiceEngineMixInfo& mixInfo() const; - double getSampleRate() const; - SubmixFormat getSampleFormat() const; + void resetSendLevels(); + void setSendLevel(IAudioSubmix* submix, float level, bool slew); + const AudioVoiceEngineMixInfo& mixInfo() const; + double getSampleRate() const; + SubmixFormat getSampleFormat() const; }; -template <> inline std::vector& AudioSubmix::_getScratch() { return m_scratch16; } -template <> inline std::vector& AudioSubmix::_getScratch() { return m_scratch32; } -template <> inline std::vector& AudioSubmix::_getScratch() { return m_scratchFlt; } - -template <> inline int16_t*& AudioSubmix::_getRedirect() { return m_redirect16; } -template <> inline int32_t*& AudioSubmix::_getRedirect() { return m_redirect32; } -template <> inline float*& AudioSubmix::_getRedirect() { return m_redirectFlt; } - +template <> +inline std::vector& AudioSubmix::_getScratch() { + return m_scratch16; +} +template <> +inline std::vector& AudioSubmix::_getScratch() { + return m_scratch32; +} +template <> +inline std::vector& AudioSubmix::_getScratch() { + return m_scratchFlt; } +template <> +inline int16_t*& AudioSubmix::_getRedirect() { + return m_redirect16; +} +template <> +inline int32_t*& AudioSubmix::_getRedirect() { + return m_redirect32; +} +template <> +inline float*& AudioSubmix::_getRedirect() { + return m_redirectFlt; +} + +} // namespace boo diff --git a/lib/audiodev/AudioVoice.cpp b/lib/audiodev/AudioVoice.cpp index 78f04bc..d9c00ff 100644 --- a/lib/audiodev/AudioVoice.cpp +++ b/lib/audiodev/AudioVoice.cpp @@ -3,383 +3,303 @@ #include "logvisor/logvisor.hpp" #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::AudioVoice"); static AudioMatrixMono DefaultMonoMtx; static AudioMatrixStereo DefaultStereoMtx; -AudioVoice::AudioVoice(BaseAudioVoiceEngine& root, - IAudioVoiceCallback* cb, bool dynamicRate) -: ListNode(&root), m_cb(cb), m_dynamicRate(dynamicRate) -{} +AudioVoice::AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate) +: ListNode(&root), m_cb(cb), m_dynamicRate(dynamicRate) {} -AudioVoice::~AudioVoice() -{ - soxr_delete(m_src); -} +AudioVoice::~AudioVoice() { soxr_delete(m_src); } AudioVoice*& AudioVoice::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_voiceHead; } -std::unique_lock AudioVoice::_getHeadLock(BaseAudioVoiceEngine* head) -{ return std::unique_lock{head->m_dataMutex}; } -std::unique_lock AudioVoice::destructorLock() -{ return std::unique_lock{m_head->m_dataMutex}; } +std::unique_lock AudioVoice::_getHeadLock(BaseAudioVoiceEngine* head) { + return std::unique_lock{head->m_dataMutex}; +} +std::unique_lock AudioVoice::destructorLock() { + return std::unique_lock{m_head->m_dataMutex}; +} -void AudioVoice::_setPitchRatio(double ratio, bool slew) -{ - if (m_dynamicRate) - { - m_sampleRatio = ratio * m_sampleRateIn / m_sampleRateOut; - soxr_error_t err = soxr_set_io_ratio(m_src, m_sampleRatio, slew ? m_head->m_5msFrames : 0); - if (err) - { - Log.report(logvisor::Fatal, "unable to set resampler rate: %s", soxr_strerror(err)); - m_setPitchRatio = false; - return; - } +void AudioVoice::_setPitchRatio(double ratio, bool slew) { + if (m_dynamicRate) { + m_sampleRatio = ratio * m_sampleRateIn / m_sampleRateOut; + soxr_error_t err = soxr_set_io_ratio(m_src, m_sampleRatio, slew ? m_head->m_5msFrames : 0); + if (err) { + Log.report(logvisor::Fatal, "unable to set resampler rate: %s", soxr_strerror(err)); + m_setPitchRatio = false; + return; } - m_setPitchRatio = false; + } + m_setPitchRatio = false; } -void AudioVoice::_midUpdate() -{ - if (m_resetSampleRate) - _resetSampleRate(m_deferredSampleRate); - if (m_setPitchRatio) - _setPitchRatio(m_pitchRatio, m_slew); +void AudioVoice::_midUpdate() { + if (m_resetSampleRate) + _resetSampleRate(m_deferredSampleRate); + if (m_setPitchRatio) + _setPitchRatio(m_pitchRatio, m_slew); } -void AudioVoice::setPitchRatio(double ratio, bool slew) -{ - m_setPitchRatio = true; - m_pitchRatio = ratio; - m_slew = slew; +void AudioVoice::setPitchRatio(double ratio, bool slew) { + m_setPitchRatio = true; + m_pitchRatio = ratio; + m_slew = slew; } -void AudioVoice::resetSampleRate(double sampleRate) -{ - m_resetSampleRate = true; - m_deferredSampleRate = sampleRate; +void AudioVoice::resetSampleRate(double sampleRate) { + m_resetSampleRate = true; + m_deferredSampleRate = sampleRate; } -void AudioVoice::start() -{ - m_running = true; +void AudioVoice::start() { m_running = true; } + +void AudioVoice::stop() { m_running = false; } + +AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate) +: AudioVoice(root, cb, dynamicRate) { + _resetSampleRate(sampleRate); } -void AudioVoice::stop() -{ - m_running = false; -} +void AudioVoiceMono::_resetSampleRate(double sampleRate) { + soxr_delete(m_src); -AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, - double sampleRate, bool dynamicRate) -: AudioVoice(root, cb, dynamicRate) -{ - _resetSampleRate(sampleRate); -} + double rateOut = m_head->mixInfo().m_sampleRate; + soxr_datatype_t formatOut = m_head->mixInfo().m_sampleFormat; + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, formatOut); + soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); -void AudioVoiceMono::_resetSampleRate(double sampleRate) -{ - soxr_delete(m_src); + soxr_error_t err; + m_src = soxr_create(sampleRate, rateOut, 1, &err, &ioSpec, &qSpec, nullptr); - double rateOut = m_head->mixInfo().m_sampleRate; - soxr_datatype_t formatOut = m_head->mixInfo().m_sampleFormat; - soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, formatOut); - soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); - - soxr_error_t err; - m_src = soxr_create(sampleRate, rateOut, 1, - &err, &ioSpec, &qSpec, nullptr); - - if (err) - { - Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); - m_resetSampleRate = false; - return; - } - - m_sampleRateIn = sampleRate; - m_sampleRateOut = rateOut; - m_sampleRatio = m_sampleRateIn / m_sampleRateOut; - soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); - _setPitchRatio(m_pitchRatio, false); + if (err) { + Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); m_resetSampleRate = false; + return; + } + + m_sampleRateIn = sampleRate; + m_sampleRateOut = rateOut; + m_sampleRatio = m_sampleRateIn / m_sampleRateOut; + soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); + _setPitchRatio(m_pitchRatio, false); + m_resetSampleRate = false; } -size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) -{ - std::vector& scratchIn = ctx->m_head->m_scratchIn; - if (scratchIn.size() < frames) - scratchIn.resize(frames); - *data = scratchIn.data(); - if (ctx->m_silentOut) - { - memset(scratchIn.data(), 0, frames * 2); - return frames; - } - else - return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); +size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) { + std::vector& scratchIn = ctx->m_head->m_scratchIn; + if (scratchIn.size() < frames) + scratchIn.resize(frames); + *data = scratchIn.data(); + if (ctx->m_silentOut) { + memset(scratchIn.data(), 0, frames * 2); + return frames; + } else + return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); } -bool AudioVoiceMono::isSilent() const -{ - if (m_sendMatrices.size()) - { - for (auto& mtx : m_sendMatrices) - if (!mtx.second.isSilent()) - return false; - return true; - } - else - { - return DefaultMonoMtx.isSilent(); - } +bool AudioVoiceMono::isSilent() const { + if (m_sendMatrices.size()) { + for (auto& mtx : m_sendMatrices) + if (!mtx.second.isSilent()) + return false; + return true; + } else { + return DefaultMonoMtx.isSilent(); + } } template -size_t AudioVoiceMono::_pumpAndMix(size_t frames) -{ - auto& scratchPre = m_head->_getScratchPre(); - if (scratchPre.size() < frames) - scratchPre.resize(frames + 2); +size_t AudioVoiceMono::_pumpAndMix(size_t frames) { + auto& scratchPre = m_head->_getScratchPre(); + if (scratchPre.size() < frames) + scratchPre.resize(frames + 2); - auto& scratchPost = m_head->_getScratchPost(); - if (scratchPost.size() < frames) - scratchPost.resize(frames + 2); + auto& scratchPost = m_head->_getScratchPost(); + if (scratchPost.size() < frames) + scratchPost.resize(frames + 2); - double dt = frames / m_sampleRateOut; - m_cb->preSupplyAudio(*this, dt); - _midUpdate(); + double dt = frames / m_sampleRateOut; + m_cb->preSupplyAudio(*this, dt); + _midUpdate(); - if (isSilent()) - { - int16_t* dummy; - SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); - return 0; + if (isSilent()) { + int16_t* dummy; + SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); + return 0; + } + + size_t oDone = soxr_output(m_src, scratchPre.data(), frames); + + if (oDone) { + if (m_sendMatrices.size()) { + for (auto& mtx : m_sendMatrices) { + AudioSubmix& smx = *reinterpret_cast(mtx.first); + m_cb->routeAudio(oDone, 1, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); + mtx.second.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf(oDone), oDone); + } + } else { + AudioSubmix& smx = *m_head->m_mainSubmix; + m_cb->routeAudio(oDone, 1, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); + DefaultMonoMtx.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf(oDone), oDone); } + } - size_t oDone = soxr_output(m_src, scratchPre.data(), frames); - - if (oDone) - { - if (m_sendMatrices.size()) - { - for (auto& mtx : m_sendMatrices) - { - AudioSubmix& smx = *reinterpret_cast(mtx.first); - m_cb->routeAudio(oDone, 1, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); - mtx.second.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), - smx._getMergeBuf(oDone), oDone); - } - } - else - { - AudioSubmix& smx = *m_head->m_mainSubmix; - m_cb->routeAudio(oDone, 1, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); - DefaultMonoMtx.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), - smx._getMergeBuf(oDone), oDone); - } - } - - return oDone; + return oDone; } -void AudioVoiceMono::resetChannelLevels() -{ - m_head->m_submixesDirty = true; - m_sendMatrices.clear(); +void AudioVoiceMono::resetChannelLevels() { + m_head->m_submixesDirty = true; + m_sendMatrices.clear(); } -void AudioVoiceMono::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) -{ - if (!submix) - submix = m_head->m_mainSubmix.get(); +void AudioVoiceMono::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) { + if (!submix) + submix = m_head->m_mainSubmix.get(); - auto search = m_sendMatrices.find(submix); - if (search == m_sendMatrices.cend()) - search = m_sendMatrices.emplace(submix, AudioMatrixMono{}).first; - search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); + auto search = m_sendMatrices.find(submix); + if (search == m_sendMatrices.cend()) + search = m_sendMatrices.emplace(submix, AudioMatrixMono{}).first; + search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); } -void AudioVoiceMono::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) -{ - float newCoefs[8] = - { - coefs[0][0], - coefs[1][0], - coefs[2][0], - coefs[3][0], - coefs[4][0], - coefs[5][0], - coefs[6][0], - coefs[7][0] - }; +void AudioVoiceMono::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) { + float newCoefs[8] = {coefs[0][0], coefs[1][0], coefs[2][0], coefs[3][0], + coefs[4][0], coefs[5][0], coefs[6][0], coefs[7][0]}; - if (!submix) - submix = m_head->m_mainSubmix.get(); + if (!submix) + submix = m_head->m_mainSubmix.get(); - auto search = m_sendMatrices.find(submix); - if (search == m_sendMatrices.cend()) - search = m_sendMatrices.emplace(submix, AudioMatrixMono{}).first; - search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); + auto search = m_sendMatrices.find(submix); + if (search == m_sendMatrices.cend()) + search = m_sendMatrices.emplace(submix, AudioMatrixMono{}).first; + search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); } -AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, - double sampleRate, bool dynamicRate) -: AudioVoice(root, cb, dynamicRate) -{ - _resetSampleRate(sampleRate); +AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, + bool dynamicRate) +: AudioVoice(root, cb, dynamicRate) { + _resetSampleRate(sampleRate); } -void AudioVoiceStereo::_resetSampleRate(double sampleRate) -{ - soxr_delete(m_src); +void AudioVoiceStereo::_resetSampleRate(double sampleRate) { + soxr_delete(m_src); - double rateOut = m_head->mixInfo().m_sampleRate; - soxr_datatype_t formatOut = m_head->mixInfo().m_sampleFormat; - soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, formatOut); - soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); + double rateOut = m_head->mixInfo().m_sampleRate; + soxr_datatype_t formatOut = m_head->mixInfo().m_sampleFormat; + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, formatOut); + soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); - soxr_error_t err; - m_src = soxr_create(sampleRate, rateOut, 2, - &err, &ioSpec, &qSpec, nullptr); + soxr_error_t err; + m_src = soxr_create(sampleRate, rateOut, 2, &err, &ioSpec, &qSpec, nullptr); - if (!m_src) - { - Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); - m_resetSampleRate = false; - return; - } - - m_sampleRateIn = sampleRate; - m_sampleRateOut = rateOut; - m_sampleRatio = m_sampleRateIn / m_sampleRateOut; - soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); - _setPitchRatio(m_pitchRatio, false); + if (!m_src) { + Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); m_resetSampleRate = false; + return; + } + + m_sampleRateIn = sampleRate; + m_sampleRateOut = rateOut; + m_sampleRatio = m_sampleRateIn / m_sampleRateOut; + soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); + _setPitchRatio(m_pitchRatio, false); + m_resetSampleRate = false; } -size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) -{ - std::vector& scratchIn = ctx->m_head->m_scratchIn; - size_t samples = frames * 2; - if (scratchIn.size() < samples) - scratchIn.resize(samples); - *data = scratchIn.data(); - if (ctx->m_silentOut) - { - memset(scratchIn.data(), 0, samples * 2); - return frames; - } - else - return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); +size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) { + std::vector& scratchIn = ctx->m_head->m_scratchIn; + size_t samples = frames * 2; + if (scratchIn.size() < samples) + scratchIn.resize(samples); + *data = scratchIn.data(); + if (ctx->m_silentOut) { + memset(scratchIn.data(), 0, samples * 2); + return frames; + } else + return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); } -bool AudioVoiceStereo::isSilent() const -{ - if (m_sendMatrices.size()) - { - for (auto& mtx : m_sendMatrices) - if (!mtx.second.isSilent()) - return false; - return true; - } - else - { - return DefaultStereoMtx.isSilent(); - } +bool AudioVoiceStereo::isSilent() const { + if (m_sendMatrices.size()) { + for (auto& mtx : m_sendMatrices) + if (!mtx.second.isSilent()) + return false; + return true; + } else { + return DefaultStereoMtx.isSilent(); + } } template -size_t AudioVoiceStereo::_pumpAndMix(size_t frames) -{ - size_t samples = frames * 2; +size_t AudioVoiceStereo::_pumpAndMix(size_t frames) { + size_t samples = frames * 2; - auto& scratchPre = m_head->_getScratchPre(); - if (scratchPre.size() < samples) - scratchPre.resize(samples + 4); + auto& scratchPre = m_head->_getScratchPre(); + if (scratchPre.size() < samples) + scratchPre.resize(samples + 4); - auto& scratchPost = m_head->_getScratchPost(); - if (scratchPost.size() < samples) - scratchPost.resize(samples + 4); + auto& scratchPost = m_head->_getScratchPost(); + if (scratchPost.size() < samples) + scratchPost.resize(samples + 4); - double dt = frames / m_sampleRateOut; - m_cb->preSupplyAudio(*this, dt); - _midUpdate(); - - if (isSilent()) - { - int16_t* dummy; - SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); - return 0; + double dt = frames / m_sampleRateOut; + m_cb->preSupplyAudio(*this, dt); + _midUpdate(); + + if (isSilent()) { + int16_t* dummy; + SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); + return 0; + } + + size_t oDone = soxr_output(m_src, scratchPre.data(), frames); + + if (oDone) { + if (m_sendMatrices.size()) { + for (auto& mtx : m_sendMatrices) { + AudioSubmix& smx = *reinterpret_cast(mtx.first); + m_cb->routeAudio(oDone, 2, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); + mtx.second.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf(oDone), oDone); + } + } else { + AudioSubmix& smx = *m_head->m_mainSubmix; + m_cb->routeAudio(oDone, 2, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); + DefaultStereoMtx.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf(oDone), + oDone); } - - size_t oDone = soxr_output(m_src, scratchPre.data(), frames); + } - if (oDone) - { - if (m_sendMatrices.size()) - { - for (auto& mtx : m_sendMatrices) - { - AudioSubmix& smx = *reinterpret_cast(mtx.first); - m_cb->routeAudio(oDone, 2, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); - mtx.second.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), - smx._getMergeBuf(oDone), oDone); - } - } - else - { - AudioSubmix& smx = *m_head->m_mainSubmix; - m_cb->routeAudio(oDone, 2, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); - DefaultStereoMtx.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), - smx._getMergeBuf(oDone), oDone); - } - } - - return oDone; + return oDone; } -void AudioVoiceStereo::resetChannelLevels() -{ - m_head->m_submixesDirty = true; - m_sendMatrices.clear(); +void AudioVoiceStereo::resetChannelLevels() { + m_head->m_submixesDirty = true; + m_sendMatrices.clear(); } -void AudioVoiceStereo::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) -{ - float newCoefs[8][2] = - { - {coefs[0], coefs[0]}, - {coefs[1], coefs[1]}, - {coefs[2], coefs[2]}, - {coefs[3], coefs[3]}, - {coefs[4], coefs[4]}, - {coefs[5], coefs[5]}, - {coefs[6], coefs[6]}, - {coefs[7], coefs[7]} - }; +void AudioVoiceStereo::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) { + float newCoefs[8][2] = {{coefs[0], coefs[0]}, {coefs[1], coefs[1]}, {coefs[2], coefs[2]}, {coefs[3], coefs[3]}, + {coefs[4], coefs[4]}, {coefs[5], coefs[5]}, {coefs[6], coefs[6]}, {coefs[7], coefs[7]}}; - if (!submix) - submix = m_head->m_mainSubmix.get(); + if (!submix) + submix = m_head->m_mainSubmix.get(); - auto search = m_sendMatrices.find(submix); - if (search == m_sendMatrices.cend()) - search = m_sendMatrices.emplace(submix, AudioMatrixStereo{}).first; - search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); + auto search = m_sendMatrices.find(submix); + if (search == m_sendMatrices.cend()) + search = m_sendMatrices.emplace(submix, AudioMatrixStereo{}).first; + search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); } -void AudioVoiceStereo::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) -{ - if (!submix) - submix = m_head->m_mainSubmix.get(); +void AudioVoiceStereo::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) { + if (!submix) + submix = m_head->m_mainSubmix.get(); - auto search = m_sendMatrices.find(submix); - if (search == m_sendMatrices.cend()) - search = m_sendMatrices.emplace(submix, AudioMatrixStereo{}).first; - search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); + auto search = m_sendMatrices.find(submix); + if (search == m_sendMatrices.cend()) + search = m_sendMatrices.emplace(submix, AudioMatrixStereo{}).first; + search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); } -} +} // namespace boo diff --git a/lib/audiodev/AudioVoice.hpp b/lib/audiodev/AudioVoice.hpp index 187b405..db44128 100644 --- a/lib/audiodev/AudioVoice.hpp +++ b/lib/audiodev/AudioVoice.hpp @@ -12,121 +12,124 @@ struct AudioUnitVoiceEngine; struct VSTVoiceEngine; struct WAVOutVoiceEngine; -namespace boo -{ +namespace boo { class BaseAudioVoiceEngine; struct AudioVoiceEngineMixInfo; struct IAudioSubmix; -class AudioVoice : public ListNode -{ - friend class BaseAudioVoiceEngine; - friend class AudioSubmix; - friend struct WASAPIAudioVoiceEngine; - friend struct ::AudioUnitVoiceEngine; - friend struct ::VSTVoiceEngine; - friend struct ::WAVOutVoiceEngine; +class AudioVoice : public ListNode { + friend class BaseAudioVoiceEngine; + friend class AudioSubmix; + friend struct WASAPIAudioVoiceEngine; + friend struct ::AudioUnitVoiceEngine; + friend struct ::VSTVoiceEngine; + friend struct ::WAVOutVoiceEngine; protected: - /* Callback (audio source) */ - IAudioVoiceCallback* m_cb; + /* Callback (audio source) */ + IAudioVoiceCallback* m_cb; - /* Sample-rate converter */ - soxr_t m_src = nullptr; - double m_sampleRateIn; - double m_sampleRateOut; - bool m_dynamicRate; + /* Sample-rate converter */ + soxr_t m_src = nullptr; + double m_sampleRateIn; + double m_sampleRateOut; + bool m_dynamicRate; - /* Running bool */ - bool m_running = false; + /* Running bool */ + bool m_running = false; - /* Deferred sample-rate reset */ - bool m_resetSampleRate = false; - double m_deferredSampleRate; - virtual void _resetSampleRate(double sampleRate)=0; + /* Deferred sample-rate reset */ + bool m_resetSampleRate = false; + double m_deferredSampleRate; + virtual void _resetSampleRate(double sampleRate) = 0; - /* Deferred pitch ratio set */ - bool m_setPitchRatio = false; - double m_pitchRatio = 1.0; - double m_sampleRatio = 1.0; - bool m_slew = false; - void _setPitchRatio(double ratio, bool slew); + /* Deferred pitch ratio set */ + bool m_setPitchRatio = false; + double m_pitchRatio = 1.0; + double m_sampleRatio = 1.0; + bool m_slew = false; + void _setPitchRatio(double ratio, bool slew); - /* Mid-pump update */ - void _midUpdate(); + /* Mid-pump update */ + void _midUpdate(); - virtual size_t pumpAndMix16(size_t frames)=0; - virtual size_t pumpAndMix32(size_t frames)=0; - virtual size_t pumpAndMixFlt(size_t frames)=0; - template size_t pumpAndMix(size_t frames); + virtual size_t pumpAndMix16(size_t frames) = 0; + virtual size_t pumpAndMix32(size_t frames) = 0; + virtual size_t pumpAndMixFlt(size_t frames) = 0; + template + size_t pumpAndMix(size_t frames); - AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate); + AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate); public: - static AudioVoice*& _getHeadPtr(BaseAudioVoiceEngine* head); - static std::unique_lock _getHeadLock(BaseAudioVoiceEngine* head); - std::unique_lock destructorLock(); + static AudioVoice*& _getHeadPtr(BaseAudioVoiceEngine* head); + static std::unique_lock _getHeadLock(BaseAudioVoiceEngine* head); + std::unique_lock destructorLock(); - ~AudioVoice(); - void resetSampleRate(double sampleRate); - void setPitchRatio(double ratio, bool slew); - void start(); - void stop(); - double getSampleRateIn() const {return m_sampleRateIn;} - double getSampleRateOut() const {return m_sampleRateOut;} -}; - -template <> inline size_t AudioVoice::pumpAndMix(size_t frames) { return pumpAndMix16(frames); } -template <> inline size_t AudioVoice::pumpAndMix(size_t frames) { return pumpAndMix32(frames); } -template <> inline size_t AudioVoice::pumpAndMix(size_t frames) { return pumpAndMixFlt(frames); } - -class AudioVoiceMono : public AudioVoice -{ - std::unordered_map m_sendMatrices; - bool m_silentOut = false; - void _resetSampleRate(double sampleRate); - - static size_t SRCCallback(AudioVoiceMono* ctx, - int16_t** data, size_t requestedLen); - - bool isSilent() const; - - template size_t _pumpAndMix(size_t frames); - size_t pumpAndMix16(size_t frames) { return _pumpAndMix(frames); } - size_t pumpAndMix32(size_t frames) { return _pumpAndMix(frames); } - size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix(frames); } - -public: - AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, - double sampleRate, bool dynamicRate); - void resetChannelLevels(); - void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); - void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); -}; - -class AudioVoiceStereo : public AudioVoice -{ - std::unordered_map m_sendMatrices; - bool m_silentOut = false; - void _resetSampleRate(double sampleRate); - - static size_t SRCCallback(AudioVoiceStereo* ctx, - int16_t** data, size_t requestedLen); - - bool isSilent() const; - - template size_t _pumpAndMix(size_t frames); - size_t pumpAndMix16(size_t frames) { return _pumpAndMix(frames); } - size_t pumpAndMix32(size_t frames) { return _pumpAndMix(frames); } - size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix(frames); } - -public: - AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, - double sampleRate, bool dynamicRate); - void resetChannelLevels(); - void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); - void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); + ~AudioVoice(); + void resetSampleRate(double sampleRate); + void setPitchRatio(double ratio, bool slew); + void start(); + void stop(); + double getSampleRateIn() const { return m_sampleRateIn; } + double getSampleRateOut() const { return m_sampleRateOut; } }; +template <> +inline size_t AudioVoice::pumpAndMix(size_t frames) { + return pumpAndMix16(frames); +} +template <> +inline size_t AudioVoice::pumpAndMix(size_t frames) { + return pumpAndMix32(frames); +} +template <> +inline size_t AudioVoice::pumpAndMix(size_t frames) { + return pumpAndMixFlt(frames); } +class AudioVoiceMono : public AudioVoice { + std::unordered_map m_sendMatrices; + bool m_silentOut = false; + void _resetSampleRate(double sampleRate); + + static size_t SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t requestedLen); + + bool isSilent() const; + + template + size_t _pumpAndMix(size_t frames); + size_t pumpAndMix16(size_t frames) { return _pumpAndMix(frames); } + size_t pumpAndMix32(size_t frames) { return _pumpAndMix(frames); } + size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix(frames); } + +public: + AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate); + void resetChannelLevels(); + void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); + void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); +}; + +class AudioVoiceStereo : public AudioVoice { + std::unordered_map m_sendMatrices; + bool m_silentOut = false; + void _resetSampleRate(double sampleRate); + + static size_t SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t requestedLen); + + bool isSilent() const; + + template + size_t _pumpAndMix(size_t frames); + size_t pumpAndMix16(size_t frames) { return _pumpAndMix(frames); } + size_t pumpAndMix32(size_t frames) { return _pumpAndMix(frames); } + size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix(frames); } + +public: + AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate); + void resetChannelLevels(); + void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); + void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); +}; + +} // namespace boo diff --git a/lib/audiodev/AudioVoiceEngine.cpp b/lib/audiodev/AudioVoiceEngine.cpp index 0733a5d..e2e3fc9 100644 --- a/lib/audiodev/AudioVoiceEngine.cpp +++ b/lib/audiodev/AudioVoiceEngine.cpp @@ -1,156 +1,123 @@ #include "AudioVoiceEngine.hpp" #include -namespace boo -{ +namespace boo { -BaseAudioVoiceEngine::~BaseAudioVoiceEngine() -{ - m_mainSubmix.reset(); - assert(m_voiceHead == nullptr && "Dangling voices detected"); - assert(m_submixHead == nullptr && "Dangling submixes detected"); +BaseAudioVoiceEngine::~BaseAudioVoiceEngine() { + m_mainSubmix.reset(); + assert(m_voiceHead == nullptr && "Dangling voices detected"); + assert(m_submixHead == nullptr && "Dangling submixes detected"); } template -void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut) -{ - if (dataOut) - memset(dataOut, 0, sizeof(T) * frames * m_mixInfo.m_channelMap.m_channelCount); +void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut) { + if (dataOut) + memset(dataOut, 0, sizeof(T) * frames * m_mixInfo.m_channelMap.m_channelCount); + + if (m_ltRtProcessing) { + size_t sampleCount = m_5msFrames * 5; + if (_getLtRtIn().size() < sampleCount) + _getLtRtIn().resize(sampleCount); + m_mainSubmix->_getRedirect() = _getLtRtIn().data(); + } else { + m_mainSubmix->_getRedirect() = dataOut; + } + + if (m_submixesDirty) { + m_linearizedSubmixes = m_mainSubmix->_linearizeC3(); + m_submixesDirty = false; + } + + size_t remFrames = frames; + while (remFrames) { + size_t thisFrames; + if (remFrames < m_5msFrames) { + thisFrames = remFrames; + if (m_engineCallback) + m_engineCallback->on5MsInterval(*this, thisFrames / double(m_5msFrames) * 5.0 / 1000.0); + } else { + thisFrames = m_5msFrames; + if (m_engineCallback) + m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); + } if (m_ltRtProcessing) - { - size_t sampleCount = m_5msFrames * 5; - if (_getLtRtIn().size() < sampleCount) - _getLtRtIn().resize(sampleCount); - m_mainSubmix->_getRedirect() = _getLtRtIn().data(); - } - else - { - m_mainSubmix->_getRedirect() = dataOut; + std::fill(_getLtRtIn().begin(), _getLtRtIn().end(), 0.f); + + for (auto it = m_linearizedSubmixes.rbegin(); it != m_linearizedSubmixes.rend(); ++it) + (*it)->_zeroFill(); + + if (m_voiceHead) + for (AudioVoice& vox : *m_voiceHead) + if (vox.m_running) + vox.pumpAndMix(thisFrames); + + for (auto it = m_linearizedSubmixes.rbegin(); it != m_linearizedSubmixes.rend(); ++it) + (*it)->_pumpAndMix(thisFrames); + + remFrames -= thisFrames; + if (!dataOut) + continue; + + if (m_ltRtProcessing) { + m_ltRtProcessing->Process(_getLtRtIn().data(), dataOut, int(thisFrames)); + m_mainSubmix->_getRedirect() = _getLtRtIn().data(); } - if (m_submixesDirty) - { - m_linearizedSubmixes = m_mainSubmix->_linearizeC3(); - m_submixesDirty = false; - } + size_t sampleCount = thisFrames * m_mixInfo.m_channelMap.m_channelCount; + for (size_t i = 0; i < sampleCount; ++i) + dataOut[i] *= m_totalVol; - size_t remFrames = frames; - while (remFrames) - { - size_t thisFrames; - if (remFrames < m_5msFrames) - { - thisFrames = remFrames; - if (m_engineCallback) - m_engineCallback->on5MsInterval(*this, thisFrames / double(m_5msFrames) * 5.0 / 1000.0); - } - else - { - thisFrames = m_5msFrames; - if (m_engineCallback) - m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); - } + dataOut += sampleCount; + } - if (m_ltRtProcessing) - std::fill(_getLtRtIn().begin(), _getLtRtIn().end(), 0.f); - - for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it) - (*it)->_zeroFill(); - - if (m_voiceHead) - for (AudioVoice& vox : *m_voiceHead) - if (vox.m_running) - vox.pumpAndMix(thisFrames); - - for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it) - (*it)->_pumpAndMix(thisFrames); - - remFrames -= thisFrames; - if (!dataOut) - continue; - - if (m_ltRtProcessing) - { - m_ltRtProcessing->Process(_getLtRtIn().data(), dataOut, int(thisFrames)); - m_mainSubmix->_getRedirect() = _getLtRtIn().data(); - } - - size_t sampleCount = thisFrames * m_mixInfo.m_channelMap.m_channelCount; - for (size_t i=0 ; ionPumpCycleComplete(*this); + if (m_engineCallback) + m_engineCallback->onPumpCycleComplete(*this); } template void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int16_t* dataOut); template void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int32_t* dataOut); template void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut); -void BaseAudioVoiceEngine::_resetSampleRate() -{ - if (m_voiceHead) - for (boo::AudioVoice& vox : *m_voiceHead) - vox._resetSampleRate(vox.m_sampleRateIn); - if (m_submixHead) - for (boo::AudioSubmix& smx : *m_submixHead) - smx._resetOutputSampleRate(); +void BaseAudioVoiceEngine::_resetSampleRate() { + if (m_voiceHead) + for (boo::AudioVoice& vox : *m_voiceHead) + vox._resetSampleRate(vox.m_sampleRateIn); + if (m_submixHead) + for (boo::AudioSubmix& smx : *m_submixHead) + smx._resetOutputSampleRate(); } -ObjToken -BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch) -{ - return {new AudioVoiceMono(*this, cb, sampleRate, dynamicPitch)}; +ObjToken BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb, + bool dynamicPitch) { + return {new AudioVoiceMono(*this, cb, sampleRate, dynamicPitch)}; } -ObjToken -BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch) -{ - return {new AudioVoiceStereo(*this, cb, sampleRate, dynamicPitch)}; +ObjToken BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb, + bool dynamicPitch) { + return {new AudioVoiceStereo(*this, cb, sampleRate, dynamicPitch)}; } -ObjToken -BaseAudioVoiceEngine::allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId) -{ - return {new AudioSubmix(*this, cb, busId, mainOut)}; +ObjToken BaseAudioVoiceEngine::allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId) { + return {new AudioSubmix(*this, cb, busId, mainOut)}; } -void BaseAudioVoiceEngine::setCallbackInterface(IAudioVoiceEngineCallback* cb) -{ - m_engineCallback = cb; +void BaseAudioVoiceEngine::setCallbackInterface(IAudioVoiceEngineCallback* cb) { m_engineCallback = cb; } + +void BaseAudioVoiceEngine::setVolume(float vol) { m_totalVol = vol; } + +bool BaseAudioVoiceEngine::enableLtRt(bool enable) { + if (enable && m_mixInfo.m_channelMap.m_channelCount == 2 && m_mixInfo.m_channels == AudioChannelSet::Stereo) + m_ltRtProcessing = std::make_unique(m_5msFrames, m_mixInfo); + else + m_ltRtProcessing.reset(); + return m_ltRtProcessing.operator bool(); } -void BaseAudioVoiceEngine::setVolume(float vol) -{ - m_totalVol = vol; +const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::mixInfo() const { return m_mixInfo; } + +const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::clientMixInfo() const { + return m_ltRtProcessing ? m_ltRtProcessing->inMixInfo() : m_mixInfo; } -bool BaseAudioVoiceEngine::enableLtRt(bool enable) -{ - if (enable && m_mixInfo.m_channelMap.m_channelCount == 2 && - m_mixInfo.m_channels == AudioChannelSet::Stereo) - m_ltRtProcessing = std::make_unique(m_5msFrames, m_mixInfo); - else - m_ltRtProcessing.reset(); - return m_ltRtProcessing.operator bool(); -} - -const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::mixInfo() const -{ - return m_mixInfo; -} - -const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::clientMixInfo() const -{ - return m_ltRtProcessing ? m_ltRtProcessing->inMixInfo() : m_mixInfo; -} - -} +} // namespace boo diff --git a/lib/audiodev/AudioVoiceEngine.hpp b/lib/audiodev/AudioVoiceEngine.hpp index bb43761..fcd5723 100644 --- a/lib/audiodev/AudioVoiceEngine.hpp +++ b/lib/audiodev/AudioVoiceEngine.hpp @@ -8,87 +8,110 @@ #include #include -namespace boo -{ +namespace boo { /** Base class for managing mixing and sample-rate-conversion amongst active voices */ -class BaseAudioVoiceEngine : public IAudioVoiceEngine -{ +class BaseAudioVoiceEngine : public IAudioVoiceEngine { protected: - friend class AudioVoice; - friend class AudioSubmix; - friend class AudioVoiceMono; - friend class AudioVoiceStereo; - float m_totalVol = 1.f; - AudioVoiceEngineMixInfo m_mixInfo; - std::recursive_mutex m_dataMutex; - AudioVoice* m_voiceHead = nullptr; - AudioSubmix* m_submixHead = nullptr; - size_t m_5msFrames = 0; - IAudioVoiceEngineCallback* m_engineCallback = nullptr; + friend class AudioVoice; + friend class AudioSubmix; + friend class AudioVoiceMono; + friend class AudioVoiceStereo; + float m_totalVol = 1.f; + AudioVoiceEngineMixInfo m_mixInfo; + std::recursive_mutex m_dataMutex; + AudioVoice* m_voiceHead = nullptr; + AudioSubmix* m_submixHead = nullptr; + size_t m_5msFrames = 0; + IAudioVoiceEngineCallback* m_engineCallback = nullptr; - /* Shared scratch buffers for accumulating audio data for resampling */ - std::vector m_scratchIn; - std::vector m_scratch16Pre; - std::vector m_scratch32Pre; - std::vector m_scratchFltPre; - template std::vector& _getScratchPre(); - std::vector m_scratch16Post; - std::vector m_scratch32Post; - std::vector m_scratchFltPost; - template std::vector& _getScratchPost(); + /* Shared scratch buffers for accumulating audio data for resampling */ + std::vector m_scratchIn; + std::vector m_scratch16Pre; + std::vector m_scratch32Pre; + std::vector m_scratchFltPre; + template + std::vector& _getScratchPre(); + std::vector m_scratch16Post; + std::vector m_scratch32Post; + std::vector m_scratchFltPost; + template + std::vector& _getScratchPost(); - /* LtRt processing if enabled */ - std::unique_ptr m_ltRtProcessing; - std::vector m_ltRtIn16; - std::vector m_ltRtIn32; - std::vector m_ltRtInFlt; - template std::vector& _getLtRtIn(); + /* LtRt processing if enabled */ + std::unique_ptr m_ltRtProcessing; + std::vector m_ltRtIn16; + std::vector m_ltRtIn32; + std::vector m_ltRtInFlt; + template + std::vector& _getLtRtIn(); - std::unique_ptr m_mainSubmix; - std::list m_linearizedSubmixes; - bool m_submixesDirty = true; + std::unique_ptr m_mainSubmix; + std::list m_linearizedSubmixes; + bool m_submixesDirty = true; - template - void _pumpAndMixVoices(size_t frames, T* dataOut); + template + void _pumpAndMixVoices(size_t frames, T* dataOut); - void _resetSampleRate(); + void _resetSampleRate(); public: - BaseAudioVoiceEngine() : m_mainSubmix(std::make_unique(*this, nullptr, -1, false)) {} - ~BaseAudioVoiceEngine(); - ObjToken allocateNewMonoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch=false); + BaseAudioVoiceEngine() : m_mainSubmix(std::make_unique(*this, nullptr, -1, false)) {} + ~BaseAudioVoiceEngine(); + ObjToken allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb, bool dynamicPitch = false); - ObjToken allocateNewStereoVoice(double sampleRate, - IAudioVoiceCallback* cb, - bool dynamicPitch=false); + ObjToken allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb, bool dynamicPitch = false); - ObjToken allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId); + ObjToken allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId); - void setCallbackInterface(IAudioVoiceEngineCallback* cb); + void setCallbackInterface(IAudioVoiceEngineCallback* cb); - void setVolume(float vol); - bool enableLtRt(bool enable); - const AudioVoiceEngineMixInfo& mixInfo() const; - const AudioVoiceEngineMixInfo& clientMixInfo() const; - AudioChannelSet getAvailableSet() {return clientMixInfo().m_channels;} - void pumpAndMixVoices() {} - size_t get5MsFrames() const {return m_5msFrames;} + void setVolume(float vol); + bool enableLtRt(bool enable); + const AudioVoiceEngineMixInfo& mixInfo() const; + const AudioVoiceEngineMixInfo& clientMixInfo() const; + AudioChannelSet getAvailableSet() { return clientMixInfo().m_channels; } + void pumpAndMixVoices() {} + size_t get5MsFrames() const { return m_5msFrames; } }; -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { return m_scratch16Pre; } -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { return m_scratch32Pre; } -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { return m_scratchFltPre; } - -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { return m_scratch16Post; } -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { return m_scratch32Post; } -template <> inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { return m_scratchFltPost; } - -template <> inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { return m_ltRtIn16; } -template <> inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { return m_ltRtIn32; } -template <> inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { return m_ltRtInFlt; } - +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { + return m_scratch16Pre; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { + return m_scratch32Pre; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPre() { + return m_scratchFltPre; } +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { + return m_scratch16Post; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { + return m_scratch32Post; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getScratchPost() { + return m_scratchFltPost; +} + +template <> +inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { + return m_ltRtIn16; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { + return m_ltRtIn32; +} +template <> +inline std::vector& BaseAudioVoiceEngine::_getLtRtIn() { + return m_ltRtInFlt; +} + +} // namespace boo diff --git a/lib/audiodev/Common.hpp b/lib/audiodev/Common.hpp index 8024945..c0bd49c 100644 --- a/lib/audiodev/Common.hpp +++ b/lib/audiodev/Common.hpp @@ -4,19 +4,16 @@ #include "../Common.hpp" #include "boo/audiodev/IAudioVoice.hpp" -namespace boo -{ +namespace boo { /** Pertinent information from audio backend about optimal mixed-audio representation */ -struct AudioVoiceEngineMixInfo -{ - double m_sampleRate = 32000.0; - soxr_datatype_t m_sampleFormat = SOXR_FLOAT32_I; - unsigned m_bitsPerSample = 32; - AudioChannelSet m_channels = AudioChannelSet::Stereo; - ChannelMap m_channelMap = {2, {AudioChannel::FrontLeft, AudioChannel::FrontRight}}; - size_t m_periodFrames = 160; +struct AudioVoiceEngineMixInfo { + double m_sampleRate = 32000.0; + soxr_datatype_t m_sampleFormat = SOXR_FLOAT32_I; + unsigned m_bitsPerSample = 32; + AudioChannelSet m_channels = AudioChannelSet::Stereo; + ChannelMap m_channelMap = {2, {AudioChannel::FrontLeft, AudioChannel::FrontRight}}; + size_t m_periodFrames = 160; }; -} - +} // namespace boo diff --git a/lib/audiodev/LinuxMidi.hpp b/lib/audiodev/LinuxMidi.hpp index 02aae3b..7805ab4 100644 --- a/lib/audiodev/LinuxMidi.hpp +++ b/lib/audiodev/LinuxMidi.hpp @@ -7,304 +7,259 @@ #include #include -namespace boo -{ +namespace boo { extern logvisor::Module ALSALog; -static inline double TimespecToDouble(struct timespec& ts) -{ - return ts.tv_sec + ts.tv_nsec / 1.0e9; -} +static inline double TimespecToDouble(struct timespec& ts) { return ts.tv_sec + ts.tv_nsec / 1.0e9; } -struct LinuxMidi : BaseAudioVoiceEngine -{ - std::unordered_map m_openHandles; - void _addOpenHandle(const char* name, IMIDIPort* port) - { - m_openHandles[name] = port; +struct LinuxMidi : BaseAudioVoiceEngine { + std::unordered_map m_openHandles; + void _addOpenHandle(const char* name, IMIDIPort* port) { m_openHandles[name] = port; } + void _removeOpenHandle(IMIDIPort* port) { + for (auto it = m_openHandles.begin(); it != m_openHandles.end();) { + if (it->second == port) { + it = m_openHandles.erase(it); + continue; + } + ++it; } - void _removeOpenHandle(IMIDIPort* port) - { - for (auto it = m_openHandles.begin(); it != m_openHandles.end();) - { - if (it->second == port) - { - it = m_openHandles.erase(it); - continue; - } - ++it; + } + + ~LinuxMidi() { + for (auto& p : m_openHandles) + p.second->_disown(); + } + + std::vector> enumerateMIDIInputs() const { + std::vector> ret; + int status; + int card = -1; /* use -1 to prime the pump of iterating through card list */ + + if ((status = snd_card_next(&card)) < 0) + return {}; + if (card < 0) + return {}; + + snd_rawmidi_info_t* info; + snd_rawmidi_info_malloc(&info); + + while (card >= 0) { + snd_ctl_t* ctl; + char name[32]; + int device = -1; + int status; + sprintf(name, "hw:%d", card); + if ((status = snd_ctl_open(&ctl, name, 0)) < 0) + continue; + + do { + status = snd_ctl_rawmidi_next_device(ctl, &device); + if (status < 0) + break; + if (device >= 0) { + sprintf(name + strlen(name), ",%d", device); + auto search = m_openHandles.find(name); + if (search != m_openHandles.cend()) { + ret.push_back(std::make_pair(name, search->second->description())); + continue; + } + + snd_rawmidi_t* midi; + if (!snd_rawmidi_open(&midi, nullptr, name, SND_RAWMIDI_NONBLOCK)) { + snd_rawmidi_info(midi, info); + ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info))); + snd_rawmidi_close(midi); + } } + } while (device >= 0); + + snd_ctl_close(ctl); + + if ((status = snd_card_next(&card)) < 0) + break; } - ~LinuxMidi() - { - for (auto& p : m_openHandles) - p.second->_disown(); - } + snd_rawmidi_info_free(info); - std::vector> enumerateMIDIInputs() const - { - std::vector> ret; - int status; - int card = -1; /* use -1 to prime the pump of iterating through card list */ + return ret; + } - if ((status = snd_card_next(&card)) < 0) - return {}; - if (card < 0) - return {}; + bool supportsVirtualMIDIIn() const { return true; } - snd_rawmidi_info_t* info; - snd_rawmidi_info_malloc(&info); + static void MIDIFreeProc(void* midiStatus) { snd_rawmidi_status_free((snd_rawmidi_status_t*)midiStatus); } - while (card >= 0) - { - snd_ctl_t *ctl; - char name[32]; - int device = -1; - int status; - sprintf(name, "hw:%d", card); - if ((status = snd_ctl_open(&ctl, name, 0)) < 0) - continue; + static void MIDIReceiveProc(snd_rawmidi_t* midi, const ReceiveFunctor& receiver) { + logvisor::RegisterThreadName("Boo MIDI"); + snd_rawmidi_status_t* midiStatus; + snd_rawmidi_status_malloc(&midiStatus); + pthread_cleanup_push(MIDIFreeProc, midiStatus); - do { - status = snd_ctl_rawmidi_next_device(ctl, &device); - if (status < 0) - break; - if (device >= 0) - { - sprintf(name + strlen(name), ",%d", device); - auto search = m_openHandles.find(name); - if (search != m_openHandles.cend()) - { - ret.push_back(std::make_pair(name, search->second->description())); - continue; - } - - snd_rawmidi_t* midi; - if (!snd_rawmidi_open(&midi, nullptr, name, SND_RAWMIDI_NONBLOCK)) - { - snd_rawmidi_info(midi, info); - ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info))); - snd_rawmidi_close(midi); - } - } - } while (device >= 0); - - snd_ctl_close(ctl); - - if ((status = snd_card_next(&card)) < 0) - break; + uint8_t buf[512]; + while (true) { + snd_htimestamp_t ts; + snd_rawmidi_status(midi, midiStatus); + snd_rawmidi_status_get_tstamp(midiStatus, &ts); + int rdBytes = snd_rawmidi_read(midi, buf, 512); + if (rdBytes < 0) { + if (rdBytes != -EINTR) { + ALSALog.report(logvisor::Error, "MIDI connection lost"); + break; } + continue; + } - snd_rawmidi_info_free(info); - - return ret; + int oldtype; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype); + receiver(std::vector(std::cbegin(buf), std::cbegin(buf) + rdBytes), TimespecToDouble(ts)); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldtype); + pthread_testcancel(); } - bool supportsVirtualMIDIIn() const - { - return true; + pthread_cleanup_pop(1); + } + + struct MIDIIn : public IMIDIIn { + snd_rawmidi_t* m_midi; + std::thread m_midiThread; + + MIDIIn(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver) + : IMIDIIn(parent, virt, std::move(receiver)) + , m_midi(midi) + , m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {} + + ~MIDIIn() { + if (m_parent) + static_cast(m_parent)->_removeOpenHandle(this); + pthread_cancel(m_midiThread.native_handle()); + if (m_midiThread.joinable()) + m_midiThread.join(); + snd_rawmidi_close(m_midi); } - static void MIDIFreeProc(void* midiStatus) - { - snd_rawmidi_status_free((snd_rawmidi_status_t*)midiStatus); + std::string description() const { + snd_rawmidi_info_t* info; + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info(m_midi, info); + std::string ret = snd_rawmidi_info_get_name(info); + return ret; + } + }; + + struct MIDIOut : public IMIDIOut { + snd_rawmidi_t* m_midi; + MIDIOut(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt) : IMIDIOut(parent, virt), m_midi(midi) {} + + ~MIDIOut() { + if (m_parent) + static_cast(m_parent)->_removeOpenHandle(this); + snd_rawmidi_close(m_midi); } - static void MIDIReceiveProc(snd_rawmidi_t* midi, const ReceiveFunctor& receiver) - { - logvisor::RegisterThreadName("Boo MIDI"); - snd_rawmidi_status_t* midiStatus; - snd_rawmidi_status_malloc(&midiStatus); - pthread_cleanup_push(MIDIFreeProc, midiStatus); - - uint8_t buf[512]; - while (true) - { - snd_htimestamp_t ts; - snd_rawmidi_status(midi, midiStatus); - snd_rawmidi_status_get_tstamp(midiStatus, &ts); - int rdBytes = snd_rawmidi_read(midi, buf, 512); - if (rdBytes < 0) - { - if (rdBytes != -EINTR) - { - ALSALog.report(logvisor::Error, "MIDI connection lost"); - break; - } - continue; - } - - int oldtype; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype); - receiver(std::vector(std::cbegin(buf), std::cbegin(buf) + rdBytes), TimespecToDouble(ts)); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldtype); - pthread_testcancel(); - } - - pthread_cleanup_pop(1); + std::string description() const { + snd_rawmidi_info_t* info; + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info(m_midi, info); + std::string ret = snd_rawmidi_info_get_name(info); + return ret; } - struct MIDIIn : public IMIDIIn - { - snd_rawmidi_t* m_midi; - std::thread m_midiThread; + size_t send(const void* buf, size_t len) const { return size_t(std::max(0l, snd_rawmidi_write(m_midi, buf, len))); } + }; - MIDIIn(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver) - : IMIDIIn(parent, virt, std::move(receiver)), m_midi(midi), - m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {} + struct MIDIInOut : public IMIDIInOut { + snd_rawmidi_t* m_midiIn; + snd_rawmidi_t* m_midiOut; + std::thread m_midiThread; - ~MIDIIn() - { - if (m_parent) - static_cast(m_parent)->_removeOpenHandle(this); - pthread_cancel(m_midiThread.native_handle()); - if (m_midiThread.joinable()) - m_midiThread.join(); - snd_rawmidi_close(m_midi); - } + MIDIInOut(LinuxMidi* parent, snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt, ReceiveFunctor&& receiver) + : IMIDIInOut(parent, virt, std::move(receiver)) + , m_midiIn(midiIn) + , m_midiOut(midiOut) + , m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {} - std::string description() const - { - snd_rawmidi_info_t* info; - snd_rawmidi_info_alloca(&info); - snd_rawmidi_info(m_midi, info); - std::string ret = snd_rawmidi_info_get_name(info); - return ret; - } - }; - - struct MIDIOut : public IMIDIOut - { - snd_rawmidi_t* m_midi; - MIDIOut(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt) - : IMIDIOut(parent, virt), m_midi(midi) {} - - ~MIDIOut() - { - if (m_parent) - static_cast(m_parent)->_removeOpenHandle(this); - snd_rawmidi_close(m_midi); - } - - std::string description() const - { - snd_rawmidi_info_t* info; - snd_rawmidi_info_alloca(&info); - snd_rawmidi_info(m_midi, info); - std::string ret = snd_rawmidi_info_get_name(info); - return ret; - } - - size_t send(const void* buf, size_t len) const - { - return size_t(std::max(0l, snd_rawmidi_write(m_midi, buf, len))); - } - }; - - struct MIDIInOut : public IMIDIInOut - { - snd_rawmidi_t* m_midiIn; - snd_rawmidi_t* m_midiOut; - std::thread m_midiThread; - - MIDIInOut(LinuxMidi* parent, snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt, ReceiveFunctor&& receiver) - : IMIDIInOut(parent, virt, std::move(receiver)), m_midiIn(midiIn), m_midiOut(midiOut), - m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {} - - ~MIDIInOut() - { - if (m_parent) - static_cast(m_parent)->_removeOpenHandle(this); - pthread_cancel(m_midiThread.native_handle()); - if (m_midiThread.joinable()) - m_midiThread.join(); - snd_rawmidi_close(m_midiIn); - snd_rawmidi_close(m_midiOut); - } - - std::string description() const - { - snd_rawmidi_info_t* info; - snd_rawmidi_info_alloca(&info); - snd_rawmidi_info(m_midiIn, info); - std::string ret = snd_rawmidi_info_get_name(info); - return ret; - } - - size_t send(const void* buf, size_t len) const - { - return size_t(std::max(0l, snd_rawmidi_write(m_midiOut, buf, len))); - } - }; - - std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) - { - int status; - snd_rawmidi_t* midi; - status = snd_rawmidi_open(&midi, nullptr, "virtual", 0); - if (status) - return {}; - return std::make_unique(nullptr, midi, true, std::move(receiver)); + ~MIDIInOut() { + if (m_parent) + static_cast(m_parent)->_removeOpenHandle(this); + pthread_cancel(m_midiThread.native_handle()); + if (m_midiThread.joinable()) + m_midiThread.join(); + snd_rawmidi_close(m_midiIn); + snd_rawmidi_close(m_midiOut); } - std::unique_ptr newVirtualMIDIOut() - { - int status; - snd_rawmidi_t* midi; - status = snd_rawmidi_open(nullptr, &midi, "virtual", 0); - if (status) - return {}; - return std::make_unique(nullptr, midi, true); + std::string description() const { + snd_rawmidi_info_t* info; + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info(m_midiIn, info); + std::string ret = snd_rawmidi_info_get_name(info); + return ret; } - std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) - { - int status; - snd_rawmidi_t* midiIn; - snd_rawmidi_t* midiOut; - status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", 0); - if (status) - return {}; - return std::make_unique(nullptr, midiIn, midiOut, true, std::move(receiver)); + size_t send(const void* buf, size_t len) const { + return size_t(std::max(0l, snd_rawmidi_write(m_midiOut, buf, len))); } + }; - std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) - { - snd_rawmidi_t* midi; - int status = snd_rawmidi_open(&midi, nullptr, name, 0); - if (status) - return {}; - auto ret = std::make_unique(this, midi, true, std::move(receiver)); - _addOpenHandle(name, ret.get()); - return ret; - } + std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) { + int status; + snd_rawmidi_t* midi; + status = snd_rawmidi_open(&midi, nullptr, "virtual", 0); + if (status) + return {}; + return std::make_unique(nullptr, midi, true, std::move(receiver)); + } - std::unique_ptr newRealMIDIOut(const char* name) - { - snd_rawmidi_t* midi; - int status = snd_rawmidi_open(nullptr, &midi, name, 0); - if (status) - return {}; - auto ret = std::make_unique(this, midi, true); - _addOpenHandle(name, ret.get()); - return ret; - } + std::unique_ptr newVirtualMIDIOut() { + int status; + snd_rawmidi_t* midi; + status = snd_rawmidi_open(nullptr, &midi, "virtual", 0); + if (status) + return {}; + return std::make_unique(nullptr, midi, true); + } - std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) - { - snd_rawmidi_t* midiIn; - snd_rawmidi_t* midiOut; - int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0); - if (status) - return {}; - auto ret = std::make_unique(this, midiIn, midiOut, true, std::move(receiver)); - _addOpenHandle(name, ret.get()); - return ret; - } + std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) { + int status; + snd_rawmidi_t* midiIn; + snd_rawmidi_t* midiOut; + status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", 0); + if (status) + return {}; + return std::make_unique(nullptr, midiIn, midiOut, true, std::move(receiver)); + } - bool useMIDILock() const {return true;} + std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { + snd_rawmidi_t* midi; + int status = snd_rawmidi_open(&midi, nullptr, name, 0); + if (status) + return {}; + auto ret = std::make_unique(this, midi, true, std::move(receiver)); + _addOpenHandle(name, ret.get()); + return ret; + } + + std::unique_ptr newRealMIDIOut(const char* name) { + snd_rawmidi_t* midi; + int status = snd_rawmidi_open(nullptr, &midi, name, 0); + if (status) + return {}; + auto ret = std::make_unique(this, midi, true); + _addOpenHandle(name, ret.get()); + return ret; + } + + std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { + snd_rawmidi_t* midiIn; + snd_rawmidi_t* midiOut; + int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0); + if (status) + return {}; + auto ret = std::make_unique(this, midiIn, midiOut, true, std::move(receiver)); + _addOpenHandle(name, ret.get()); + return ret; + } + + bool useMIDILock() const { return true; } }; -} - +} // namespace boo diff --git a/lib/audiodev/LtRtProcessing.cpp b/lib/audiodev/LtRtProcessing.cpp index 54de53a..aead982 100644 --- a/lib/audiodev/LtRtProcessing.cpp +++ b/lib/audiodev/LtRtProcessing.cpp @@ -5,28 +5,23 @@ #undef min #undef max -namespace boo -{ +namespace boo { template -inline T ClampFull(float in) -{ - if(std::is_floating_point()) - { - return std::min(std::max(in, -1.f), 1.f); - } - else - { - constexpr T MAX = std::numeric_limits::max(); - constexpr T MIN = std::numeric_limits::min(); +inline T ClampFull(float in) { + if (std::is_floating_point()) { + return std::min(std::max(in, -1.f), 1.f); + } else { + constexpr T MAX = std::numeric_limits::max(); + constexpr T MIN = std::numeric_limits::min(); - if (in < MIN) - return MIN; - else if (in > MAX) - return MAX; - else - return in; - } + if (in < MIN) + return MIN; + else if (in > MAX) + return MAX; + else + return in; + } } #if INTEL_IPP @@ -38,148 +33,130 @@ inline T ClampFull(float in) #if USE_LPF static constexpr int FirTaps = 27; -FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate) -{ - Ipp64f* taps = ippsMalloc_64f(FirTaps); - Ipp32f* taps32 = ippsMalloc_32f(FirTaps); - int sizeSpec, sizeBuf; +FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate) { + Ipp64f* taps = ippsMalloc_64f(FirTaps); + Ipp32f* taps32 = ippsMalloc_32f(FirTaps); + int sizeSpec, sizeBuf; - ippsFIRGenGetBufferSize(FirTaps, &sizeBuf); - m_firBuffer = ippsMalloc_8u(sizeBuf); - ippsFIRGenLowpass_64f(12000.0 / sampleRate, taps, FirTaps, ippWinBartlett, ippTrue, m_firBuffer); - ippsConvert_64f32f(taps, taps32, FirTaps); - ippsFree(taps); - ippsFree(m_firBuffer); + ippsFIRGenGetBufferSize(FirTaps, &sizeBuf); + m_firBuffer = ippsMalloc_8u(sizeBuf); + ippsFIRGenLowpass_64f(12000.0 / sampleRate, taps, FirTaps, ippWinBartlett, ippTrue, m_firBuffer); + ippsConvert_64f32f(taps, taps32, FirTaps); + ippsFree(taps); + ippsFree(m_firBuffer); - m_dlySrc = ippsMalloc_32f(FirTaps); + m_dlySrc = ippsMalloc_32f(FirTaps); - ippsFIRSRGetSize(FirTaps, ipp32f, &sizeSpec, &sizeBuf); - m_firSpec = (IppsFIRSpec_32f*)ippsMalloc_8u(sizeSpec); - m_firBuffer = ippsMalloc_8u(sizeBuf); - ippsFIRSRInit_32f(taps32, FirTaps, ippAlgDirect, m_firSpec); - ippsFree(taps32); + ippsFIRSRGetSize(FirTaps, ipp32f, &sizeSpec, &sizeBuf); + m_firSpec = (IppsFIRSpec_32f*)ippsMalloc_8u(sizeSpec); + m_firBuffer = ippsMalloc_8u(sizeBuf); + ippsFIRSRInit_32f(taps32, FirTaps, ippAlgDirect, m_firSpec); + ippsFree(taps32); - m_inBuf = ippsMalloc_32f(windowFrames); + m_inBuf = ippsMalloc_32f(windowFrames); } -FIRFilter12k::~FIRFilter12k() -{ - ippsFree(m_firSpec); - ippsFree(m_firBuffer); - ippsFree(m_dlySrc); - ippsFree(m_inBuf); +FIRFilter12k::~FIRFilter12k() { + ippsFree(m_firSpec); + ippsFree(m_firBuffer); + ippsFree(m_dlySrc); + ippsFree(m_inBuf); } -void FIRFilter12k::Process(Ipp32f* buf, int windowFrames) -{ - ippsZero_32f(m_dlySrc, FirTaps); - ippsMove_32f(buf, m_inBuf, windowFrames); - ippsFIRSR_32f(m_inBuf, buf, windowFrames, m_firSpec, m_dlySrc, nullptr, m_firBuffer); +void FIRFilter12k::Process(Ipp32f* buf, int windowFrames) { + ippsZero_32f(m_dlySrc, FirTaps); + ippsMove_32f(buf, m_inBuf, windowFrames); + ippsFIRSR_32f(m_inBuf, buf, windowFrames, m_firSpec, m_dlySrc, nullptr, m_firBuffer); } #endif -WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) : +WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) +: #if USE_LPF - m_fir(windowFrames, sampleRate), + m_fir(windowFrames, sampleRate) +, #endif - m_windowFrames(windowFrames), - m_halfFrames(windowFrames / 2), - m_inputBuf(ippsMalloc_32f(m_windowFrames * 2 + m_halfFrames)), - m_outputBuf(ippsMalloc_32fc(m_windowFrames * 4)), - m_hammingTable(ippsMalloc_32f(m_halfFrames)) -{ - ippsZero_32f(m_inputBuf, m_windowFrames * 2 + m_halfFrames); - ippsZero_32fc(m_outputBuf, m_windowFrames * 4); - m_output[0] = m_outputBuf; - m_output[1] = m_output[0] + m_windowFrames; - m_output[2] = m_output[1] + m_windowFrames; - m_output[3] = m_output[2] + m_windowFrames; - int sizeSpec, sizeBuf; - ippsHilbertGetSize_32f32fc(m_windowFrames, ippAlgHintFast, &sizeSpec, &sizeBuf); - m_spec = (IppsHilbertSpec*)ippMalloc(sizeSpec); - m_buffer = (Ipp8u*)ippMalloc(sizeBuf); - ippsHilbertInit_32f32fc(m_windowFrames, ippAlgHintFast, m_spec, m_buffer); + m_windowFrames(windowFrames) +, m_halfFrames(windowFrames / 2) +, m_inputBuf(ippsMalloc_32f(m_windowFrames * 2 + m_halfFrames)) +, m_outputBuf(ippsMalloc_32fc(m_windowFrames * 4)) +, m_hammingTable(ippsMalloc_32f(m_halfFrames)) { + ippsZero_32f(m_inputBuf, m_windowFrames * 2 + m_halfFrames); + ippsZero_32fc(m_outputBuf, m_windowFrames * 4); + m_output[0] = m_outputBuf; + m_output[1] = m_output[0] + m_windowFrames; + m_output[2] = m_output[1] + m_windowFrames; + m_output[3] = m_output[2] + m_windowFrames; + int sizeSpec, sizeBuf; + ippsHilbertGetSize_32f32fc(m_windowFrames, ippAlgHintFast, &sizeSpec, &sizeBuf); + m_spec = (IppsHilbertSpec*)ippMalloc(sizeSpec); + m_buffer = (Ipp8u*)ippMalloc(sizeBuf); + ippsHilbertInit_32f32fc(m_windowFrames, ippAlgHintFast, m_spec, m_buffer); - for (int i=0 ; i -void WindowedHilbert::Output(T* output, float lCoef, float rCoef) const -{ - int first, middle, last; - if (m_bufIdx) - { - first = 3; - middle = 0; - last = 1; - } - else - { - first = 1; - middle = 2; - last = 3; - } +void WindowedHilbert::Output(T* output, float lCoef, float rCoef) const { + int first, middle, last; + if (m_bufIdx) { + first = 3; + middle = 0; + last = 1; + } else { + first = 1; + middle = 2; + last = 3; + } #if 0 for (int i=0 ; i(output[i*2] + tmp * lCoef); - output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); - } - for (; i(output[i*2] + tmp * lCoef); - output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); - } - for (t=0 ; i(output[i*2] + tmp * lCoef); - output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); - } + int i, t; + for (i = 0, t = 0; i < m_halfFrames; ++i, ++t) { + float tmp = + m_output[first][m_halfFrames + i].im * (1.f - m_hammingTable[t]) + m_output[middle][i].im * m_hammingTable[t]; + output[i * 2] = ClampFull(output[i * 2] + tmp * lCoef); + output[i * 2 + 1] = ClampFull(output[i * 2 + 1] + tmp * rCoef); + } + for (; i < m_windowFrames - m_halfFrames; ++i) { + float tmp = m_output[middle][i].im; + output[i * 2] = ClampFull(output[i * 2] + tmp * lCoef); + output[i * 2 + 1] = ClampFull(output[i * 2 + 1] + tmp * rCoef); + } + for (t = 0; i < m_windowFrames; ++i, ++t) { + float tmp = m_output[middle][i].im * (1.f - m_hammingTable[t]) + m_output[last][t].im * m_hammingTable[t]; + output[i * 2] = ClampFull(output[i * 2] + tmp * lCoef); + output[i * 2 + 1] = ClampFull(output[i * 2 + 1] + tmp * rCoef); + } } template void WindowedHilbert::Output(int16_t* output, float lCoef, float rCoef) const; @@ -220,53 +193,71 @@ template void WindowedHilbert::Output(float* output, float lCoef, float r #endif -template <> int16_t* LtRtProcessing::_getInBuf() { return m_16Buffer.get(); } -template <> int32_t* LtRtProcessing::_getInBuf() { return m_32Buffer.get(); } -template <> float* LtRtProcessing::_getInBuf() { return m_fltBuffer.get(); } +template <> +int16_t* LtRtProcessing::_getInBuf() { + return m_16Buffer.get(); +} +template <> +int32_t* LtRtProcessing::_getInBuf() { + return m_32Buffer.get(); +} +template <> +float* LtRtProcessing::_getInBuf() { + return m_fltBuffer.get(); +} -template <> int16_t* LtRtProcessing::_getOutBuf() { return m_16Buffer.get() + m_outputOffset; } -template <> int32_t* LtRtProcessing::_getOutBuf() { return m_32Buffer.get() + m_outputOffset; } -template <> float* LtRtProcessing::_getOutBuf() { return m_fltBuffer.get() + m_outputOffset; } +template <> +int16_t* LtRtProcessing::_getOutBuf() { + return m_16Buffer.get() + m_outputOffset; +} +template <> +int32_t* LtRtProcessing::_getOutBuf() { + return m_32Buffer.get() + m_outputOffset; +} +template <> +float* LtRtProcessing::_getOutBuf() { + return m_fltBuffer.get() + m_outputOffset; +} LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo) -: m_inMixInfo(mixInfo), m_windowFrames(_5msFrames * 4), m_halfFrames(m_windowFrames / 2), - m_outputOffset(m_windowFrames * 5 * 2) +: m_inMixInfo(mixInfo) +, m_windowFrames(_5msFrames * 4) +, m_halfFrames(m_windowFrames / 2) +, m_outputOffset(m_windowFrames * 5 * 2) #if INTEL_IPP -, m_hilbertSL(m_windowFrames, mixInfo.m_sampleRate), - m_hilbertSR(m_windowFrames, mixInfo.m_sampleRate) +, m_hilbertSL(m_windowFrames, mixInfo.m_sampleRate) +, m_hilbertSR(m_windowFrames, mixInfo.m_sampleRate) #endif { - m_inMixInfo.m_channels = AudioChannelSet::Surround51; - m_inMixInfo.m_channelMap.m_channelCount = 5; - m_inMixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_inMixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - m_inMixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; - m_inMixInfo.m_channelMap.m_channels[3] = AudioChannel::RearLeft; - m_inMixInfo.m_channelMap.m_channels[4] = AudioChannel::RearRight; + m_inMixInfo.m_channels = AudioChannelSet::Surround51; + m_inMixInfo.m_channelMap.m_channelCount = 5; + m_inMixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_inMixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + m_inMixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; + m_inMixInfo.m_channelMap.m_channels[3] = AudioChannel::RearLeft; + m_inMixInfo.m_channelMap.m_channels[4] = AudioChannel::RearRight; - int samples = m_windowFrames * (5 * 2 + 2 * 2); - switch (mixInfo.m_sampleFormat) - { - case SOXR_INT16_I: - m_16Buffer.reset(new int16_t[samples]); - memset(m_16Buffer.get(), 0, sizeof(int16_t) * samples); - break; - case SOXR_INT32_I: - m_32Buffer.reset(new int32_t[samples]); - memset(m_32Buffer.get(), 0, sizeof(int32_t) * samples); - break; - case SOXR_FLOAT32_I: - m_fltBuffer.reset(new float[samples]); - memset(m_fltBuffer.get(), 0, sizeof(float) * samples); - break; - default: - break; - } + int samples = m_windowFrames * (5 * 2 + 2 * 2); + switch (mixInfo.m_sampleFormat) { + case SOXR_INT16_I: + m_16Buffer.reset(new int16_t[samples]); + memset(m_16Buffer.get(), 0, sizeof(int16_t) * samples); + break; + case SOXR_INT32_I: + m_32Buffer.reset(new int32_t[samples]); + memset(m_32Buffer.get(), 0, sizeof(int32_t) * samples); + break; + case SOXR_FLOAT32_I: + m_fltBuffer.reset(new float[samples]); + memset(m_fltBuffer.get(), 0, sizeof(float) * samples); + break; + default: + break; + } } template -void LtRtProcessing::Process(const T* input, T* output, int frameCount) -{ +void LtRtProcessing::Process(const T* input, T* output, int frameCount) { #if 0 for (int i=0 ; i(); - T* outBuf = _getOutBuf(); - int tail = std::min(m_windowFrames * 2, m_bufferTail + frameCount); - int samples = (tail - m_bufferTail) * 5; - memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(T)); - //printf("input %d to %d\n", tail - m_bufferTail, m_bufferTail); - input += samples; - frameCount -= tail - m_bufferTail; + int outFramesRem = frameCount; + T* inBuf = _getInBuf(); + T* outBuf = _getOutBuf(); + int tail = std::min(m_windowFrames * 2, m_bufferTail + frameCount); + int samples = (tail - m_bufferTail) * 5; + memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(T)); + // printf("input %d to %d\n", tail - m_bufferTail, m_bufferTail); + input += samples; + frameCount -= tail - m_bufferTail; - int head = std::min(m_windowFrames * 2, m_bufferHead + outFramesRem); - samples = (head - m_bufferHead) * 2; - memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(T)); - //printf("output %d from %d\n", head - m_bufferHead, m_bufferHead); - output += samples; - outFramesRem -= head - m_bufferHead; + int head = std::min(m_windowFrames * 2, m_bufferHead + outFramesRem); + samples = (head - m_bufferHead) * 2; + memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(T)); + // printf("output %d from %d\n", head - m_bufferHead, m_bufferHead); + output += samples; + outFramesRem -= head - m_bufferHead; - int bufIdx = m_bufferTail / m_windowFrames; - if (tail / m_windowFrames > bufIdx) - { - T* in = &inBuf[bufIdx * m_windowFrames * 5]; - T* out = &outBuf[bufIdx * m_windowFrames * 2]; + int bufIdx = m_bufferTail / m_windowFrames; + if (tail / m_windowFrames > bufIdx) { + T* in = &inBuf[bufIdx * m_windowFrames * 5]; + T* out = &outBuf[bufIdx * m_windowFrames * 2]; #if INTEL_IPP - m_hilbertSL.AddWindow(in + 3, 5); - m_hilbertSR.AddWindow(in + 4, 5); + m_hilbertSL.AddWindow(in + 3, 5); + m_hilbertSR.AddWindow(in + 4, 5); #endif - // x(:,1) + sqrt(.5)*x(:,3) + sqrt(19/25)*x(:,4) + sqrt(6/25)*x(:,5) - // x(:,2) + sqrt(.5)*x(:,3) - sqrt(6/25)*x(:,4) - sqrt(19/25)*x(:,5) - if (bufIdx) - { - int delayI = -m_halfFrames; - for (int i=0 ; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); - out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); - //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); - } - } - else - { - int delayI = m_windowFrames * 2 - m_halfFrames; - int i; - for (i=0 ; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); - out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); - //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); - } - delayI = 0; - for (; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); - out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); - //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); - } - } + // x(:,1) + sqrt(.5)*x(:,3) + sqrt(19/25)*x(:,4) + sqrt(6/25)*x(:,5) + // x(:,2) + sqrt(.5)*x(:,3) - sqrt(6/25)*x(:,4) - sqrt(19/25)*x(:,5) + if (bufIdx) { + int delayI = -m_halfFrames; + for (int i = 0; i < m_windowFrames; ++i, ++delayI) { + out[i * 2] = ClampFull(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); + out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); + } + } else { + int delayI = m_windowFrames * 2 - m_halfFrames; + int i; + for (i = 0; i < m_halfFrames; ++i, ++delayI) { + out[i * 2] = ClampFull(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); + out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); + } + delayI = 0; + for (; i < m_windowFrames; ++i, ++delayI) { + out[i * 2] = ClampFull(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); + out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); + } + } #if INTEL_IPP - m_hilbertSL.Output(out, 0.8717798f, 0.4898979f); - m_hilbertSR.Output(out, -0.4898979f, -0.8717798f); + m_hilbertSL.Output(out, 0.8717798f, 0.4898979f); + m_hilbertSR.Output(out, -0.4898979f, -0.8717798f); #endif - } - m_bufferTail = (tail == m_windowFrames * 2) ? 0 : tail; - m_bufferHead = (head == m_windowFrames * 2) ? 0 : head; + } + m_bufferTail = (tail == m_windowFrames * 2) ? 0 : tail; + m_bufferHead = (head == m_windowFrames * 2) ? 0 : head; - if (frameCount) - { - samples = frameCount * 5; - memmove(inBuf, input, samples * sizeof(T)); - //printf("input %d to %d\n", frameCount, 0); - m_bufferTail = frameCount; - } + if (frameCount) { + samples = frameCount * 5; + memmove(inBuf, input, samples * sizeof(T)); + // printf("input %d to %d\n", frameCount, 0); + m_bufferTail = frameCount; + } - if (outFramesRem) - { - samples = outFramesRem * 2; - memmove(output, outBuf, samples * sizeof(T)); - //printf("output %d from %d\n", outFramesRem, 0); - m_bufferHead = outFramesRem; - } + if (outFramesRem) { + samples = outFramesRem * 2; + memmove(output, outBuf, samples * sizeof(T)); + // printf("output %d from %d\n", outFramesRem, 0); + m_bufferHead = outFramesRem; + } } template void LtRtProcessing::Process(const int16_t* input, int16_t* output, int frameCount); template void LtRtProcessing::Process(const int32_t* input, int32_t* output, int frameCount); template void LtRtProcessing::Process(const float* input, float* output, int frameCount); -} +} // namespace boo diff --git a/lib/audiodev/LtRtProcessing.hpp b/lib/audiodev/LtRtProcessing.hpp index 564d38d..43ee660 100644 --- a/lib/audiodev/LtRtProcessing.hpp +++ b/lib/audiodev/LtRtProcessing.hpp @@ -9,73 +9,73 @@ #include "ipp.h" #endif -namespace boo -{ +namespace boo { #if INTEL_IPP #define USE_LPF 0 #if USE_LPF -class FIRFilter12k -{ - IppsFIRSpec_32f* m_firSpec; - Ipp8u* m_firBuffer; - Ipp32f* m_dlySrc; - Ipp32f* m_inBuf; +class FIRFilter12k { + IppsFIRSpec_32f* m_firSpec; + Ipp8u* m_firBuffer; + Ipp32f* m_dlySrc; + Ipp32f* m_inBuf; + public: - explicit FIRFilter12k(int windowFrames, double sampleRate); - ~FIRFilter12k(); - void Process(Ipp32f* buf, int windowFrames); + explicit FIRFilter12k(int windowFrames, double sampleRate); + ~FIRFilter12k(); + void Process(Ipp32f* buf, int windowFrames); }; #endif -class WindowedHilbert -{ +class WindowedHilbert { #if USE_LPF - FIRFilter12k m_fir; + FIRFilter12k m_fir; #endif - IppsHilbertSpec* m_spec; - Ipp8u* m_buffer; - int m_windowFrames, m_halfFrames; - int m_bufIdx = 0; - Ipp32f* m_inputBuf; - Ipp32fc* m_outputBuf; - Ipp32fc* m_output[4]; - Ipp32f* m_hammingTable; - void _AddWindow(); + IppsHilbertSpec* m_spec; + Ipp8u* m_buffer; + int m_windowFrames, m_halfFrames; + int m_bufIdx = 0; + Ipp32f* m_inputBuf; + Ipp32fc* m_outputBuf; + Ipp32fc* m_output[4]; + Ipp32f* m_hammingTable; + void _AddWindow(); + public: - explicit WindowedHilbert(int windowFrames, double sampleRate); - ~WindowedHilbert(); - void AddWindow(const float* input, int stride); - void AddWindow(const int32_t* input, int stride); - void AddWindow(const int16_t* input, int stride); - template - void Output(T* output, float lCoef, float rCoef) const; + explicit WindowedHilbert(int windowFrames, double sampleRate); + ~WindowedHilbert(); + void AddWindow(const float* input, int stride); + void AddWindow(const int32_t* input, int stride); + void AddWindow(const int16_t* input, int stride); + template + void Output(T* output, float lCoef, float rCoef) const; }; #endif -class LtRtProcessing -{ - AudioVoiceEngineMixInfo m_inMixInfo; - int m_windowFrames; - int m_halfFrames; - int m_outputOffset; - int m_bufferTail = 0; - int m_bufferHead = 0; - std::unique_ptr m_16Buffer; - std::unique_ptr m_32Buffer; - std::unique_ptr m_fltBuffer; +class LtRtProcessing { + AudioVoiceEngineMixInfo m_inMixInfo; + int m_windowFrames; + int m_halfFrames; + int m_outputOffset; + int m_bufferTail = 0; + int m_bufferHead = 0; + std::unique_ptr m_16Buffer; + std::unique_ptr m_32Buffer; + std::unique_ptr m_fltBuffer; #if INTEL_IPP - WindowedHilbert m_hilbertSL, m_hilbertSR; + WindowedHilbert m_hilbertSL, m_hilbertSR; #endif - template T* _getInBuf(); - template T* _getOutBuf(); + template + T* _getInBuf(); + template + T* _getOutBuf(); + public: - LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo); - template - void Process(const T* input, T* output, int frameCount); - const AudioVoiceEngineMixInfo& inMixInfo() const { return m_inMixInfo; } + LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo); + template + void Process(const T* input, T* output, int frameCount); + const AudioVoiceEngineMixInfo& inMixInfo() const { return m_inMixInfo; } }; -} - +} // namespace boo diff --git a/lib/audiodev/MIDICommon.cpp b/lib/audiodev/MIDICommon.cpp index d8cd072..468379a 100644 --- a/lib/audiodev/MIDICommon.cpp +++ b/lib/audiodev/MIDICommon.cpp @@ -1,12 +1,11 @@ #include "MIDICommon.hpp" #include "boo/audiodev/IMIDIPort.hpp" -namespace boo -{ +namespace boo { IMIDIPort::~IMIDIPort() {} IMIDIIn::~IMIDIIn() {} IMIDIOut::~IMIDIOut() {} IMIDIInOut::~IMIDIInOut() {} -} +} // namespace boo diff --git a/lib/audiodev/MIDICommon.hpp b/lib/audiodev/MIDICommon.hpp index 66e1222..9c6723a 100644 --- a/lib/audiodev/MIDICommon.hpp +++ b/lib/audiodev/MIDICommon.hpp @@ -1,30 +1,27 @@ #pragma once -namespace boo -{ +namespace boo { -enum class Status -{ - NoteOff = 0x80, - NoteOn = 0x90, - NotePressure = 0xA0, - ControlChange = 0xB0, - ProgramChange = 0xC0, - ChannelPressure = 0xD0, - PitchBend = 0xE0, - SysEx = 0xF0, - TimecodeQuarterFrame = 0xF1, - SongPositionPointer = 0xF2, - SongSelect = 0xF3, - TuneRequest = 0xF6, - SysExTerm = 0xF7, - TimingClock = 0xF8, - Start = 0xFA, - Continue = 0xFB, - Stop = 0xFC, - ActiveSensing = 0xFE, - Reset = 0xFF, +enum class Status { + NoteOff = 0x80, + NoteOn = 0x90, + NotePressure = 0xA0, + ControlChange = 0xB0, + ProgramChange = 0xC0, + ChannelPressure = 0xD0, + PitchBend = 0xE0, + SysEx = 0xF0, + TimecodeQuarterFrame = 0xF1, + SongPositionPointer = 0xF2, + SongSelect = 0xF3, + TuneRequest = 0xF6, + SysExTerm = 0xF7, + TimingClock = 0xF8, + Start = 0xFA, + Continue = 0xFB, + Stop = 0xFC, + ActiveSensing = 0xFE, + Reset = 0xFF, }; } - diff --git a/lib/audiodev/MIDIDecoder.cpp b/lib/audiodev/MIDIDecoder.cpp index 38dee6a..7fcd684 100644 --- a/lib/audiodev/MIDIDecoder.cpp +++ b/lib/audiodev/MIDIDecoder.cpp @@ -3,207 +3,183 @@ #include #include -namespace boo -{ +namespace boo { -static inline uint8_t clamp7(uint8_t val) {return std::max(0, std::min(127, int(val)));} +static inline uint8_t clamp7(uint8_t val) { return std::max(0, std::min(127, int(val))); } bool MIDIDecoder::_readContinuedValue(std::vector::const_iterator& it, - std::vector::const_iterator end, - uint32_t& valOut) -{ + std::vector::const_iterator end, uint32_t& valOut) { + uint8_t a = *it++; + valOut = a & 0x7f; + + if (a & 0x80) { + if (it == end) + return false; + valOut <<= 7; + a = *it++; + valOut |= a & 0x7f; + + if (a & 0x80) { + if (it == end) + return false; + valOut <<= 7; + a = *it++; + valOut |= a & 0x7f; + } + } + + return true; +} + +std::vector::const_iterator MIDIDecoder::receiveBytes(std::vector::const_iterator begin, + std::vector::const_iterator end) { + std::vector::const_iterator it = begin; + while (it != end) { uint8_t a = *it++; - valOut = a & 0x7f; - + uint8_t b; if (a & 0x80) - { + m_status = a; + else + it--; + + if (m_status == 0xff) { + /* Meta events (ignored for now) */ + if (it == end) + return begin; + a = *it++; + + uint32_t length; + _readContinuedValue(it, end, length); + it += length; + } else { + uint8_t chan = m_status & 0xf; + switch (Status(m_status & 0xf0)) { + case Status::NoteOff: { if (it == end) - return false; - valOut <<= 7; + return begin; a = *it++; - valOut |= a & 0x7f; - - if (a & 0x80) - { - if (it == end) - return false; - valOut <<= 7; - a = *it++; - valOut |= a & 0x7f; + if (it == end) + return begin; + b = *it++; + m_out.noteOff(chan, clamp7(a), clamp7(b)); + break; + } + case Status::NoteOn: { + if (it == end) + return begin; + a = *it++; + if (it == end) + return begin; + b = *it++; + m_out.noteOn(chan, clamp7(a), clamp7(b)); + break; + } + case Status::NotePressure: { + if (it == end) + return begin; + a = *it++; + if (it == end) + return begin; + b = *it++; + m_out.notePressure(chan, clamp7(a), clamp7(b)); + break; + } + case Status::ControlChange: { + if (it == end) + return begin; + a = *it++; + if (it == end) + return begin; + b = *it++; + m_out.controlChange(chan, clamp7(a), clamp7(b)); + break; + } + case Status::ProgramChange: { + if (it == end) + return begin; + a = *it++; + m_out.programChange(chan, clamp7(a)); + break; + } + case Status::ChannelPressure: { + if (it == end) + return begin; + a = *it++; + m_out.channelPressure(chan, clamp7(a)); + break; + } + case Status::PitchBend: { + if (it == end) + return begin; + a = *it++; + if (it == end) + return begin; + b = *it++; + m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a)); + break; + } + case Status::SysEx: { + switch (Status(m_status & 0xff)) { + case Status::SysEx: { + uint32_t len; + if (!_readContinuedValue(it, end, len) || end - it < len) + return begin; + m_out.sysex(&*it, len); + break; } - } - - return true; -} - -std::vector::const_iterator -MIDIDecoder::receiveBytes(std::vector::const_iterator begin, - std::vector::const_iterator end) -{ - std::vector::const_iterator it = begin; - while (it != end) - { - uint8_t a = *it++; - uint8_t b; - if (a & 0x80) - m_status = a; - else - it--; - - if (m_status == 0xff) - { - /* Meta events (ignored for now) */ - if (it == end) - return begin; - a = *it++; - - uint32_t length; - _readContinuedValue(it, end, length); - it += length; - } else - { - uint8_t chan = m_status & 0xf; - switch (Status(m_status & 0xf0)) - { - case Status::NoteOff: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.noteOff(chan, clamp7(a), clamp7(b)); - break; - } - case Status::NoteOn: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.noteOn(chan, clamp7(a), clamp7(b)); - break; - } - case Status::NotePressure: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.notePressure(chan, clamp7(a), clamp7(b)); - break; - } - case Status::ControlChange: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.controlChange(chan, clamp7(a), clamp7(b)); - break; - } - case Status::ProgramChange: - { - if (it == end) - return begin; - a = *it++; - m_out.programChange(chan, clamp7(a)); - break; - } - case Status::ChannelPressure: - { - if (it == end) - return begin; - a = *it++; - m_out.channelPressure(chan, clamp7(a)); - break; - } - case Status::PitchBend: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a)); - break; - } - case Status::SysEx: - { - switch (Status(m_status & 0xff)) - { - case Status::SysEx: - { - uint32_t len; - if (!_readContinuedValue(it, end, len) || end - it < len) - return begin; - m_out.sysex(&*it, len); - break; - } - case Status::TimecodeQuarterFrame: - { - if (it == end) - return begin; - a = *it++; - m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf); - break; - } - case Status::SongPositionPointer: - { - if (it == end) - return begin; - a = *it++; - if (it == end) - return begin; - b = *it++; - m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a)); - break; - } - case Status::SongSelect: - { - if (it == end) - return begin; - a = *it++; - m_out.songSelect(clamp7(a)); - break; - } - case Status::TuneRequest: - m_out.tuneRequest(); - break; - case Status::Start: - m_out.startSeq(); - break; - case Status::Continue: - m_out.continueSeq(); - break; - case Status::Stop: - m_out.stopSeq(); - break; - case Status::Reset: - m_out.reset(); - break; - case Status::SysExTerm: - case Status::TimingClock: - case Status::ActiveSensing: - default: - break; - } - break; - } - default: - break; - } + case Status::TimecodeQuarterFrame: { + if (it == end) + return begin; + a = *it++; + m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf); + break; } + case Status::SongPositionPointer: { + if (it == end) + return begin; + a = *it++; + if (it == end) + return begin; + b = *it++; + m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a)); + break; + } + case Status::SongSelect: { + if (it == end) + return begin; + a = *it++; + m_out.songSelect(clamp7(a)); + break; + } + case Status::TuneRequest: + m_out.tuneRequest(); + break; + case Status::Start: + m_out.startSeq(); + break; + case Status::Continue: + m_out.continueSeq(); + break; + case Status::Stop: + m_out.stopSeq(); + break; + case Status::Reset: + m_out.reset(); + break; + case Status::SysExTerm: + case Status::TimingClock: + case Status::ActiveSensing: + default: + break; + } + break; + } + default: + break; + } } - return it; + } + return it; } -} +} // namespace boo diff --git a/lib/audiodev/MIDIEncoder.cpp b/lib/audiodev/MIDIEncoder.cpp index 1a00f93..f13a395 100644 --- a/lib/audiodev/MIDIEncoder.cpp +++ b/lib/audiodev/MIDIEncoder.cpp @@ -1,228 +1,182 @@ #include "boo/audiodev/MIDIEncoder.hpp" #include "MIDICommon.hpp" -namespace boo -{ +namespace boo { template -void MIDIEncoder::_sendMessage(const uint8_t* data, size_t len) -{ - if (data[0] == m_status) - m_sender.send(data + 1, len - 1); - else - { - if (data[0] & 0x80) - m_status = data[0]; - m_sender.send(data, len); - } -} - -template -void MIDIEncoder::_sendContinuedValue(uint32_t val) -{ - uint8_t send[3] = {}; - uint8_t* ptr = nullptr; - if (val >= 0x4000) - { - ptr = &send[0]; - send[0] = 0x80 | ((val / 0x4000) & 0x7f); - send[1] = 0x80; - val &= 0x3fff; - } - - if (val >= 0x80) - { - if (!ptr) - ptr = &send[1]; - send[1] = 0x80 | ((val / 0x80) & 0x7f); - } - - if (!ptr) - ptr = &send[2]; - send[2] = val & 0x7f; - - m_sender.send(ptr, 3 - (ptr - send)); -} - -template -void MIDIEncoder::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) -{ - uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), - uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) -{ - uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), - uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) -{ - uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), - uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::controlChange(uint8_t chan, uint8_t control, uint8_t value) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - uint8_t(control & 0x7f), uint8_t(value & 0x7f)}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::programChange(uint8_t chan, uint8_t program) -{ - uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), - uint8_t(program & 0x7f)}; - _sendMessage(cmd, 2); -} - -template -void MIDIEncoder::channelPressure(uint8_t chan, uint8_t pressure) -{ - uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), - uint8_t(pressure & 0x7f)}; - _sendMessage(cmd, 2); -} - -template -void MIDIEncoder::pitchBend(uint8_t chan, int16_t pitch) -{ - uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), - uint8_t((pitch % 128) & 0x7f), uint8_t((pitch / 128) & 0x7f)}; - _sendMessage(cmd, 3); -} - - -template -void MIDIEncoder::allSoundOff(uint8_t chan) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - 120, 0}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::resetAllControllers(uint8_t chan) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - 121, 0}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::localControl(uint8_t chan, bool on) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - 122, uint8_t(on ? 127 : 0)}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::allNotesOff(uint8_t chan) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - 123, 0}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::omniMode(uint8_t chan, bool on) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - uint8_t(on ? 125 : 124), 0}; - _sendMessage(cmd, 3); -} - -template -void MIDIEncoder::polyMode(uint8_t chan, bool on) -{ - uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), - uint8_t(on ? 127 : 126), 0}; - _sendMessage(cmd, 3); -} - - -template -void MIDIEncoder::sysex(const void* data, size_t len) -{ - uint8_t cmd = uint8_t(Status::SysEx); - _sendMessage(&cmd, 1); - _sendContinuedValue(len); +void MIDIEncoder::_sendMessage(const uint8_t* data, size_t len) { + if (data[0] == m_status) + m_sender.send(data + 1, len - 1); + else { + if (data[0] & 0x80) + m_status = data[0]; m_sender.send(data, len); - cmd = uint8_t(Status::SysExTerm); - _sendMessage(&cmd, 1); + } } template -void MIDIEncoder::timeCodeQuarterFrame(uint8_t message, uint8_t value) -{ - uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), - uint8_t((message & 0x7 << 4) | (value & 0xf))}; - _sendMessage(cmd, 2); +void MIDIEncoder::_sendContinuedValue(uint32_t val) { + uint8_t send[3] = {}; + uint8_t* ptr = nullptr; + if (val >= 0x4000) { + ptr = &send[0]; + send[0] = 0x80 | ((val / 0x4000) & 0x7f); + send[1] = 0x80; + val &= 0x3fff; + } + + if (val >= 0x80) { + if (!ptr) + ptr = &send[1]; + send[1] = 0x80 | ((val / 0x80) & 0x7f); + } + + if (!ptr) + ptr = &send[2]; + send[2] = val & 0x7f; + + m_sender.send(ptr, 3 - (ptr - send)); } template -void MIDIEncoder::songPositionPointer(uint16_t pointer) -{ - uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), - uint8_t((pointer % 128) & 0x7f), uint8_t((pointer / 128) & 0x7f)}; - _sendMessage(cmd, 3); +void MIDIEncoder::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) { + uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; + _sendMessage(cmd, 3); } template -void MIDIEncoder::songSelect(uint8_t song) -{ - uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), - uint8_t(song & 0x7f)}; - _sendMessage(cmd, 2); +void MIDIEncoder::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) { + uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)}; + _sendMessage(cmd, 3); } template -void MIDIEncoder::tuneRequest() -{ - uint8_t cmd = uint8_t(Status::TuneRequest); - _sendMessage(&cmd, 1); -} - - -template -void MIDIEncoder::startSeq() -{ - uint8_t cmd = uint8_t(Status::Start); - _sendMessage(&cmd, 1); +void MIDIEncoder::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) { + uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)}; + _sendMessage(cmd, 3); } template -void MIDIEncoder::continueSeq() -{ - uint8_t cmd = uint8_t(Status::Continue); - _sendMessage(&cmd, 1); +void MIDIEncoder::controlChange(uint8_t chan, uint8_t control, uint8_t value) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(control & 0x7f), uint8_t(value & 0x7f)}; + _sendMessage(cmd, 3); } template -void MIDIEncoder::stopSeq() -{ - uint8_t cmd = uint8_t(Status::Stop); - _sendMessage(&cmd, 1); +void MIDIEncoder::programChange(uint8_t chan, uint8_t program) { + uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t(program & 0x7f)}; + _sendMessage(cmd, 2); } +template +void MIDIEncoder::channelPressure(uint8_t chan, uint8_t pressure) { + uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t(pressure & 0x7f)}; + _sendMessage(cmd, 2); +} template -void MIDIEncoder::reset() -{ - uint8_t cmd = uint8_t(Status::Reset); - _sendMessage(&cmd, 1); +void MIDIEncoder::pitchBend(uint8_t chan, int16_t pitch) { + uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch % 128) & 0x7f), + uint8_t((pitch / 128) & 0x7f)}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::allSoundOff(uint8_t chan) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 120, 0}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::resetAllControllers(uint8_t chan) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 121, 0}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::localControl(uint8_t chan, bool on) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 122, uint8_t(on ? 127 : 0)}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::allNotesOff(uint8_t chan) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 123, 0}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::omniMode(uint8_t chan, bool on) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 125 : 124), 0}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::polyMode(uint8_t chan, bool on) { + uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 127 : 126), 0}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::sysex(const void* data, size_t len) { + uint8_t cmd = uint8_t(Status::SysEx); + _sendMessage(&cmd, 1); + _sendContinuedValue(len); + m_sender.send(data, len); + cmd = uint8_t(Status::SysExTerm); + _sendMessage(&cmd, 1); +} + +template +void MIDIEncoder::timeCodeQuarterFrame(uint8_t message, uint8_t value) { + uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t((message & 0x7 << 4) | (value & 0xf))}; + _sendMessage(cmd, 2); +} + +template +void MIDIEncoder::songPositionPointer(uint16_t pointer) { + uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer % 128) & 0x7f), + uint8_t((pointer / 128) & 0x7f)}; + _sendMessage(cmd, 3); +} + +template +void MIDIEncoder::songSelect(uint8_t song) { + uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t(song & 0x7f)}; + _sendMessage(cmd, 2); +} + +template +void MIDIEncoder::tuneRequest() { + uint8_t cmd = uint8_t(Status::TuneRequest); + _sendMessage(&cmd, 1); +} + +template +void MIDIEncoder::startSeq() { + uint8_t cmd = uint8_t(Status::Start); + _sendMessage(&cmd, 1); +} + +template +void MIDIEncoder::continueSeq() { + uint8_t cmd = uint8_t(Status::Continue); + _sendMessage(&cmd, 1); +} + +template +void MIDIEncoder::stopSeq() { + uint8_t cmd = uint8_t(Status::Stop); + _sendMessage(&cmd, 1); +} + +template +void MIDIEncoder::reset() { + uint8_t cmd = uint8_t(Status::Reset); + _sendMessage(&cmd, 1); } template class MIDIEncoder; template class MIDIEncoder; -} +} // namespace boo diff --git a/lib/audiodev/PulseAudio.cpp b/lib/audiodev/PulseAudio.cpp index 68262ea..2e79405 100644 --- a/lib/audiodev/PulseAudio.cpp +++ b/lib/audiodev/PulseAudio.cpp @@ -6,420 +6,357 @@ #include #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::PulseAudio"); logvisor::Module ALSALog("boo::ALSA"); -static const uint64_t StereoChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | - (1 << PA_CHANNEL_POSITION_FRONT_RIGHT); +static const uint64_t StereoChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT); -static const uint64_t QuadChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | - (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | - (1 << PA_CHANNEL_POSITION_REAR_LEFT) | - (1 << PA_CHANNEL_POSITION_REAR_RIGHT); +static const uint64_t QuadChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | + (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT); -static const uint64_t S51Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | - (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | - (1 << PA_CHANNEL_POSITION_REAR_LEFT) | - (1 << PA_CHANNEL_POSITION_REAR_RIGHT) | - (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | - (1 << PA_CHANNEL_POSITION_LFE); +static const uint64_t S51Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | + (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT) | + (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | (1 << PA_CHANNEL_POSITION_LFE); -static const uint64_t S71Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | - (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | - (1 << PA_CHANNEL_POSITION_REAR_LEFT) | - (1 << PA_CHANNEL_POSITION_REAR_RIGHT) | - (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | - (1 << PA_CHANNEL_POSITION_LFE) | - (1 << PA_CHANNEL_POSITION_SIDE_LEFT) | - (1 << PA_CHANNEL_POSITION_SIDE_RIGHT); +static const uint64_t S71Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | + (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT) | + (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | (1 << PA_CHANNEL_POSITION_LFE) | + (1 << PA_CHANNEL_POSITION_SIDE_LEFT) | (1 << PA_CHANNEL_POSITION_SIDE_RIGHT); -struct PulseAudioVoiceEngine : LinuxMidi -{ - pa_mainloop* m_mainloop = nullptr; - pa_context* m_ctx = nullptr; - pa_stream* m_stream = nullptr; - std::string m_sinkName; - bool m_handleMove = false; - pa_sample_spec m_sampleSpec = {}; - pa_channel_map m_chanMap = {}; +struct PulseAudioVoiceEngine : LinuxMidi { + pa_mainloop* m_mainloop = nullptr; + pa_context* m_ctx = nullptr; + pa_stream* m_stream = nullptr; + std::string m_sinkName; + bool m_handleMove = false; + pa_sample_spec m_sampleSpec = {}; + pa_channel_map m_chanMap = {}; - int _paWaitReady() - { - int retval = 0; - while (pa_context_get_state(m_ctx) < PA_CONTEXT_READY) - pa_mainloop_iterate(m_mainloop, 1, &retval); - return retval; + int _paWaitReady() { + int retval = 0; + while (pa_context_get_state(m_ctx) < PA_CONTEXT_READY) + pa_mainloop_iterate(m_mainloop, 1, &retval); + return retval; + } + + int _paStreamWaitReady() { + int retval = 0; + while (pa_stream_get_state(m_stream) < PA_STREAM_READY) + pa_mainloop_iterate(m_mainloop, 1, &retval); + return retval; + } + + int _paIterate(pa_operation* op) const { + int retval = 0; + while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) + pa_mainloop_iterate(m_mainloop, 1, &retval); + return retval; + } + + bool _setupSink() { + if (m_stream) { + pa_stream_disconnect(m_stream); + pa_stream_unref(m_stream); + m_stream = nullptr; } - int _paStreamWaitReady() - { - int retval = 0; - while (pa_stream_get_state(m_stream) < PA_STREAM_READY) - pa_mainloop_iterate(m_mainloop, 1, &retval); - return retval; + pa_operation* op; + m_sampleSpec.format = PA_SAMPLE_INVALID; + op = pa_context_get_sink_info_by_name(m_ctx, m_sinkName.c_str(), pa_sink_info_cb_t(_getSinkInfoReply), this); + _paIterate(op); + pa_operation_unref(op); + + if (m_sampleSpec.format == PA_SAMPLE_INVALID) { + Log.report(logvisor::Error, "Unable to setup audio stream"); + goto err; } - int _paIterate(pa_operation* op) const - { - int retval = 0; - while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) - pa_mainloop_iterate(m_mainloop, 1, &retval); - return retval; + m_5msFrames = m_sampleSpec.rate * 5 / 1000; + + m_mixInfo.m_sampleRate = m_sampleSpec.rate; + m_mixInfo.m_sampleFormat = SOXR_FLOAT32; + m_mixInfo.m_bitsPerSample = 32; + m_mixInfo.m_periodFrames = m_5msFrames; + if (!(m_stream = pa_stream_new(m_ctx, "master", &m_sampleSpec, &m_chanMap))) { + Log.report(logvisor::Error, "Unable to pa_stream_new(): %s", pa_strerror(pa_context_errno(m_ctx))); + goto err; } - bool _setupSink() - { - if (m_stream) - { - pa_stream_disconnect(m_stream); - pa_stream_unref(m_stream); - m_stream = nullptr; - } + pa_buffer_attr bufAttr; + bufAttr.minreq = uint32_t(m_5msFrames * m_sampleSpec.channels * sizeof(float)); + bufAttr.maxlength = bufAttr.minreq * 24; + bufAttr.tlength = bufAttr.maxlength; + bufAttr.prebuf = UINT32_MAX; + bufAttr.fragsize = UINT32_MAX; - pa_operation* op; - m_sampleSpec.format = PA_SAMPLE_INVALID; - op = pa_context_get_sink_info_by_name(m_ctx, m_sinkName.c_str(), pa_sink_info_cb_t(_getSinkInfoReply), this); - _paIterate(op); - pa_operation_unref(op); - - if (m_sampleSpec.format == PA_SAMPLE_INVALID) - { - Log.report(logvisor::Error, "Unable to setup audio stream"); - goto err; - } - - m_5msFrames = m_sampleSpec.rate * 5 / 1000; - - m_mixInfo.m_sampleRate = m_sampleSpec.rate; - m_mixInfo.m_sampleFormat = SOXR_FLOAT32; - m_mixInfo.m_bitsPerSample = 32; - m_mixInfo.m_periodFrames = m_5msFrames; - if (!(m_stream = pa_stream_new(m_ctx, "master", &m_sampleSpec, &m_chanMap))) - { - Log.report(logvisor::Error, "Unable to pa_stream_new(): %s", pa_strerror(pa_context_errno(m_ctx))); - goto err; - } - - pa_buffer_attr bufAttr; - bufAttr.minreq = uint32_t(m_5msFrames * m_sampleSpec.channels * sizeof(float)); - bufAttr.maxlength = bufAttr.minreq * 24; - bufAttr.tlength = bufAttr.maxlength; - bufAttr.prebuf = UINT32_MAX; - bufAttr.fragsize = UINT32_MAX; - - if (pa_stream_connect_playback(m_stream, m_sinkName.c_str(), &bufAttr, - pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_EARLY_REQUESTS), - nullptr, nullptr)) - { - Log.report(logvisor::Error, "Unable to pa_stream_connect_playback()"); - goto err; - } - - pa_stream_set_moved_callback(m_stream, pa_stream_notify_cb_t(_streamMoved), this); - - _paStreamWaitReady(); - - _resetSampleRate(); - return true; - err: - if (m_stream) - { - pa_stream_disconnect(m_stream); - pa_stream_unref(m_stream); - m_stream = nullptr; - } - return false; + if (pa_stream_connect_playback(m_stream, m_sinkName.c_str(), &bufAttr, + pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_EARLY_REQUESTS), nullptr, + nullptr)) { + Log.report(logvisor::Error, "Unable to pa_stream_connect_playback()"); + goto err; } - PulseAudioVoiceEngine() - { - if (!(m_mainloop = pa_mainloop_new())) - { - Log.report(logvisor::Error, "Unable to pa_mainloop_new()"); - return; - } + pa_stream_set_moved_callback(m_stream, pa_stream_notify_cb_t(_streamMoved), this); - pa_mainloop_api* mlApi = pa_mainloop_get_api(m_mainloop); - pa_proplist* propList = pa_proplist_new(); - pa_proplist_sets(propList, PA_PROP_APPLICATION_ICON_NAME, APP->getUniqueName().data()); - char pidStr[16]; - snprintf(pidStr, 16, "%d", int(getpid())); - pa_proplist_sets(propList, PA_PROP_APPLICATION_PROCESS_ID, pidStr); - if (!(m_ctx = pa_context_new_with_proplist(mlApi, APP->getFriendlyName().data(), propList))) - { - Log.report(logvisor::Error, "Unable to pa_context_new_with_proplist()"); - pa_mainloop_free(m_mainloop); - m_mainloop = nullptr; - return; - } + _paStreamWaitReady(); - pa_operation* op; + _resetSampleRate(); + return true; + err: + if (m_stream) { + pa_stream_disconnect(m_stream); + pa_stream_unref(m_stream); + m_stream = nullptr; + } + return false; + } - if (pa_context_connect(m_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr)) - { - Log.report(logvisor::Error, "Unable to pa_context_connect()"); - goto err; - } - - _paWaitReady(); - - op = pa_context_get_server_info(m_ctx, pa_server_info_cb_t(_getServerInfoReply), this); - _paIterate(op); - pa_operation_unref(op); - - if (!_setupSink()) - goto err; - - return; - err: - pa_context_disconnect(m_ctx); - pa_context_unref(m_ctx); - m_ctx = nullptr; - pa_mainloop_free(m_mainloop); - m_mainloop = nullptr; + PulseAudioVoiceEngine() { + if (!(m_mainloop = pa_mainloop_new())) { + Log.report(logvisor::Error, "Unable to pa_mainloop_new()"); + return; } - ~PulseAudioVoiceEngine() - { - if (m_stream) - { - pa_stream_disconnect(m_stream); - pa_stream_unref(m_stream); + pa_mainloop_api* mlApi = pa_mainloop_get_api(m_mainloop); + pa_proplist* propList = pa_proplist_new(); + pa_proplist_sets(propList, PA_PROP_APPLICATION_ICON_NAME, APP->getUniqueName().data()); + char pidStr[16]; + snprintf(pidStr, 16, "%d", int(getpid())); + pa_proplist_sets(propList, PA_PROP_APPLICATION_PROCESS_ID, pidStr); + if (!(m_ctx = pa_context_new_with_proplist(mlApi, APP->getFriendlyName().data(), propList))) { + Log.report(logvisor::Error, "Unable to pa_context_new_with_proplist()"); + pa_mainloop_free(m_mainloop); + m_mainloop = nullptr; + return; + } + + pa_operation* op; + + if (pa_context_connect(m_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr)) { + Log.report(logvisor::Error, "Unable to pa_context_connect()"); + goto err; + } + + _paWaitReady(); + + op = pa_context_get_server_info(m_ctx, pa_server_info_cb_t(_getServerInfoReply), this); + _paIterate(op); + pa_operation_unref(op); + + if (!_setupSink()) + goto err; + + return; + err: + pa_context_disconnect(m_ctx); + pa_context_unref(m_ctx); + m_ctx = nullptr; + pa_mainloop_free(m_mainloop); + m_mainloop = nullptr; + } + + ~PulseAudioVoiceEngine() { + if (m_stream) { + pa_stream_disconnect(m_stream); + pa_stream_unref(m_stream); + } + if (m_ctx) { + pa_context_disconnect(m_ctx); + pa_context_unref(m_ctx); + } + if (m_mainloop) { + pa_mainloop_free(m_mainloop); + } + } + + static void _streamMoved(pa_stream* p, PulseAudioVoiceEngine* userdata) { + userdata->m_sinkName = pa_stream_get_device_name(p); + userdata->m_handleMove = true; + } + + static void _getServerInfoReply(pa_context* c, const pa_server_info* i, PulseAudioVoiceEngine* userdata) { + userdata->m_sinkName = i->default_sink_name; + } + + void _parseAudioChannelSet(const pa_channel_map* chm) { + m_chanMap = *chm; + + ChannelMap& chmapOut = m_mixInfo.m_channelMap; + m_mixInfo.m_channels = AudioChannelSet::Unknown; + + uint64_t chBits = 0; + chmapOut.m_channelCount = chm->channels; + for (unsigned c = 0; c < chm->channels; ++c) { + chBits |= 1 << chm->map[c]; + switch (chm->map[c]) { + case PA_CHANNEL_POSITION_FRONT_LEFT: + chmapOut.m_channels[c] = AudioChannel::FrontLeft; + break; + case PA_CHANNEL_POSITION_FRONT_RIGHT: + chmapOut.m_channels[c] = AudioChannel::FrontRight; + break; + case PA_CHANNEL_POSITION_REAR_LEFT: + chmapOut.m_channels[c] = AudioChannel::RearLeft; + break; + case PA_CHANNEL_POSITION_REAR_RIGHT: + chmapOut.m_channels[c] = AudioChannel::RearRight; + break; + case PA_CHANNEL_POSITION_FRONT_CENTER: + chmapOut.m_channels[c] = AudioChannel::FrontCenter; + break; + case PA_CHANNEL_POSITION_LFE: + chmapOut.m_channels[c] = AudioChannel::LFE; + break; + case PA_CHANNEL_POSITION_SIDE_LEFT: + chmapOut.m_channels[c] = AudioChannel::SideLeft; + break; + case PA_CHANNEL_POSITION_SIDE_RIGHT: + chmapOut.m_channels[c] = AudioChannel::SideRight; + break; + default: + chmapOut.m_channels[c] = AudioChannel::Unknown; + break; + } + } + + static const std::array testSets = { + {AudioChannelSet::Surround71, AudioChannelSet::Surround51, AudioChannelSet::Quad, AudioChannelSet::Stereo}}; + for (AudioChannelSet set : testSets) { + switch (set) { + case AudioChannelSet::Stereo: { + if ((chBits & StereoChans) == StereoChans) { + m_mixInfo.m_channels = AudioChannelSet::Stereo; + return; } - if (m_ctx) - { - pa_context_disconnect(m_ctx); - pa_context_unref(m_ctx); + break; + } + case AudioChannelSet::Quad: { + if ((chBits & QuadChans) == QuadChans) { + m_mixInfo.m_channels = AudioChannelSet::Quad; + return; } - if (m_mainloop) - { - pa_mainloop_free(m_mainloop); + break; + } + case AudioChannelSet::Surround51: { + if ((chBits & S51Chans) == S51Chans) { + m_mixInfo.m_channels = AudioChannelSet::Surround51; + return; } - } - - static void _streamMoved(pa_stream* p, PulseAudioVoiceEngine* userdata) - { - userdata->m_sinkName = pa_stream_get_device_name(p); - userdata->m_handleMove = true; - } - - static void _getServerInfoReply(pa_context* c, const pa_server_info* i, PulseAudioVoiceEngine* userdata) - { - userdata->m_sinkName = i->default_sink_name; - } - - void _parseAudioChannelSet(const pa_channel_map* chm) - { - m_chanMap = *chm; - - ChannelMap& chmapOut = m_mixInfo.m_channelMap; - m_mixInfo.m_channels = AudioChannelSet::Unknown; - - uint64_t chBits = 0; - chmapOut.m_channelCount = chm->channels; - for (unsigned c=0 ; cchannels ; ++c) - { - chBits |= 1 << chm->map[c]; - switch (chm->map[c]) - { - case PA_CHANNEL_POSITION_FRONT_LEFT: - chmapOut.m_channels[c] = AudioChannel::FrontLeft; - break; - case PA_CHANNEL_POSITION_FRONT_RIGHT: - chmapOut.m_channels[c] = AudioChannel::FrontRight; - break; - case PA_CHANNEL_POSITION_REAR_LEFT: - chmapOut.m_channels[c] = AudioChannel::RearLeft; - break; - case PA_CHANNEL_POSITION_REAR_RIGHT: - chmapOut.m_channels[c] = AudioChannel::RearRight; - break; - case PA_CHANNEL_POSITION_FRONT_CENTER: - chmapOut.m_channels[c] = AudioChannel::FrontCenter; - break; - case PA_CHANNEL_POSITION_LFE: - chmapOut.m_channels[c] = AudioChannel::LFE; - break; - case PA_CHANNEL_POSITION_SIDE_LEFT: - chmapOut.m_channels[c] = AudioChannel::SideLeft; - break; - case PA_CHANNEL_POSITION_SIDE_RIGHT: - chmapOut.m_channels[c] = AudioChannel::SideRight; - break; - default: - chmapOut.m_channels[c] = AudioChannel::Unknown; - break; - } + break; + } + case AudioChannelSet::Surround71: { + if ((chBits & S71Chans) == S71Chans) { + m_mixInfo.m_channels = AudioChannelSet::Surround71; + return; } + break; + } + default: + break; + } + } + } - static const std::array testSets = - {{AudioChannelSet::Surround71, AudioChannelSet::Surround51, - AudioChannelSet::Quad, AudioChannelSet::Stereo}}; - for (AudioChannelSet set : testSets) - { - switch (set) - { - case AudioChannelSet::Stereo: - { - if ((chBits & StereoChans) == StereoChans) - { - m_mixInfo.m_channels = AudioChannelSet::Stereo; - return; - } - break; - } - case AudioChannelSet::Quad: - { - if ((chBits & QuadChans) == QuadChans) - { - m_mixInfo.m_channels = AudioChannelSet::Quad; - return; - } - break; - } - case AudioChannelSet::Surround51: - { - if ((chBits & S51Chans) == S51Chans) - { - m_mixInfo.m_channels = AudioChannelSet::Surround51; - return; - } - break; - } - case AudioChannelSet::Surround71: - { - if ((chBits & S71Chans) == S71Chans) - { - m_mixInfo.m_channels = AudioChannelSet::Surround71; - return; - } - break; - } - default: break; - } - } + static void _getSinkInfoReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) { + if (!i) + return; + userdata->m_sampleSpec.format = PA_SAMPLE_FLOAT32; + userdata->m_sampleSpec.rate = i->sample_spec.rate; + userdata->m_sampleSpec.channels = i->sample_spec.channels; + userdata->_parseAudioChannelSet(&i->channel_map); + } + + mutable std::vector> m_sinks; + static void _getSinkInfoListReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) { + if (i) + userdata->m_sinks.push_back(std::make_pair(i->name, i->description)); + } + std::vector> enumerateAudioOutputs() const { + pa_operation* op = pa_context_get_sink_info_list(m_ctx, pa_sink_info_cb_t(_getSinkInfoListReply), (void*)this); + _paIterate(op); + pa_operation_unref(op); + std::vector> ret; + ret.swap(m_sinks); + return ret; + } + + std::string getCurrentAudioOutput() const { return m_sinkName; } + + bool m_sinkOk = false; + static void _checkAudioSinkReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) { + if (i) + userdata->m_sinkOk = true; + } + bool setCurrentAudioOutput(const char* name) { + m_sinkOk = false; + pa_operation* op; + op = pa_context_get_sink_info_by_name(m_ctx, name, pa_sink_info_cb_t(_checkAudioSinkReply), this); + _paIterate(op); + pa_operation_unref(op); + if (m_sinkOk) { + m_sinkName = name; + return _setupSink(); + } + return false; + } + + void _doIterate() { + int retval; + pa_mainloop_iterate(m_mainloop, 1, &retval); + if (m_handleMove) { + m_handleMove = false; + _setupSink(); + } + } + + void pumpAndMixVoices() { + if (!m_stream) { + /* Dummy pump mode - use failsafe defaults for 1/60sec of samples */ + m_mixInfo.m_sampleRate = 32000.0; + m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; + m_mixInfo.m_bitsPerSample = 32; + m_5msFrames = 32000 / 60; + m_mixInfo.m_periodFrames = m_5msFrames; + m_mixInfo.m_channels = AudioChannelSet::Stereo; + m_mixInfo.m_channelMap.m_channelCount = 2; + m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + _pumpAndMixVoices(m_5msFrames, (float*)nullptr); + return; } - static void _getSinkInfoReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) - { - if (!i) - return; - userdata->m_sampleSpec.format = PA_SAMPLE_FLOAT32; - userdata->m_sampleSpec.rate = i->sample_spec.rate; - userdata->m_sampleSpec.channels = i->sample_spec.channels; - userdata->_parseAudioChannelSet(&i->channel_map); + size_t writableSz = pa_stream_writable_size(m_stream); + size_t frameSz = m_mixInfo.m_channelMap.m_channelCount * sizeof(float); + size_t writableFrames = writableSz / frameSz; + size_t writablePeriods = writableFrames / m_mixInfo.m_periodFrames; + + if (!writablePeriods) { + _doIterate(); + return; } - mutable std::vector> m_sinks; - static void _getSinkInfoListReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) - { - if (i) - userdata->m_sinks.push_back(std::make_pair(i->name, i->description)); - } - std::vector> enumerateAudioOutputs() const - { - pa_operation* op = pa_context_get_sink_info_list(m_ctx, pa_sink_info_cb_t(_getSinkInfoListReply), (void*)this); - _paIterate(op); - pa_operation_unref(op); - std::vector> ret; - ret.swap(m_sinks); - return ret; + void* data; + size_t periodSz = m_mixInfo.m_periodFrames * frameSz; + size_t nbytes = writablePeriods * periodSz; + if (pa_stream_begin_write(m_stream, &data, &nbytes)) { + pa_stream_state_t st = pa_stream_get_state(m_stream); + Log.report(logvisor::Error, "Unable to pa_stream_begin_write(): %s %d", pa_strerror(pa_context_errno(m_ctx)), st); + _doIterate(); + return; } - std::string getCurrentAudioOutput() const - { - return m_sinkName; - } + writablePeriods = nbytes / periodSz; + size_t periodSamples = m_mixInfo.m_periodFrames * m_mixInfo.m_channelMap.m_channelCount; + _pumpAndMixVoices(m_mixInfo.m_periodFrames * writablePeriods, reinterpret_cast(data)); - bool m_sinkOk = false; - static void _checkAudioSinkReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) - { - if (i) - userdata->m_sinkOk = true; - } - bool setCurrentAudioOutput(const char* name) - { - m_sinkOk = false; - pa_operation* op; - op = pa_context_get_sink_info_by_name(m_ctx, name, pa_sink_info_cb_t(_checkAudioSinkReply), this); - _paIterate(op); - pa_operation_unref(op); - if (m_sinkOk) - { - m_sinkName = name; - return _setupSink(); - } - return false; - } + if (pa_stream_write(m_stream, data, nbytes, nullptr, 0, PA_SEEK_RELATIVE)) + Log.report(logvisor::Error, "Unable to pa_stream_write()"); - void _doIterate() - { - int retval; - pa_mainloop_iterate(m_mainloop, 1, &retval); - if (m_handleMove) - { - m_handleMove = false; - _setupSink(); - } - } - - void pumpAndMixVoices() - { - if (!m_stream) - { - /* Dummy pump mode - use failsafe defaults for 1/60sec of samples */ - m_mixInfo.m_sampleRate = 32000.0; - m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; - m_mixInfo.m_bitsPerSample = 32; - m_5msFrames = 32000 / 60; - m_mixInfo.m_periodFrames = m_5msFrames; - m_mixInfo.m_channels = AudioChannelSet::Stereo; - m_mixInfo.m_channelMap.m_channelCount = 2; - m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - _pumpAndMixVoices(m_5msFrames, (float*)nullptr); - return; - } - - size_t writableSz = pa_stream_writable_size(m_stream); - size_t frameSz = m_mixInfo.m_channelMap.m_channelCount * sizeof(float); - size_t writableFrames = writableSz / frameSz; - size_t writablePeriods = writableFrames / m_mixInfo.m_periodFrames; - - if (!writablePeriods) - { - _doIterate(); - return; - } - - void* data; - size_t periodSz = m_mixInfo.m_periodFrames * frameSz; - size_t nbytes = writablePeriods * periodSz; - if (pa_stream_begin_write(m_stream, &data, &nbytes)) - { - pa_stream_state_t st = pa_stream_get_state(m_stream); - Log.report(logvisor::Error, "Unable to pa_stream_begin_write(): %s %d", - pa_strerror(pa_context_errno(m_ctx)), st); - _doIterate(); - return; - } - - writablePeriods = nbytes / periodSz; - size_t periodSamples = m_mixInfo.m_periodFrames * m_mixInfo.m_channelMap.m_channelCount; - _pumpAndMixVoices(m_mixInfo.m_periodFrames * writablePeriods, reinterpret_cast(data)); - - if (pa_stream_write(m_stream, data, nbytes, nullptr, 0, PA_SEEK_RELATIVE)) - Log.report(logvisor::Error, "Unable to pa_stream_write()"); - - _doIterate(); - } + _doIterate(); + } }; -std::unique_ptr NewAudioVoiceEngine() -{ - return std::make_unique(); -} +std::unique_ptr NewAudioVoiceEngine() { return std::make_unique(); } -} +} // namespace boo diff --git a/lib/audiodev/WASAPI.cpp b/lib/audiodev/WASAPI.cpp index 186fa1a..507b0d1 100644 --- a/lib/audiodev/WASAPI.cpp +++ b/lib/audiodev/WASAPI.cpp @@ -12,11 +12,12 @@ #ifdef TE_VIRTUAL_MIDI #include -typedef LPVM_MIDI_PORT (CALLBACK *pfnvirtualMIDICreatePortEx2) -( LPCWSTR portName, LPVM_MIDI_DATA_CB callback, DWORD_PTR dwCallbackInstance, DWORD maxSysexLength, DWORD flags ); -typedef void (CALLBACK *pfnvirtualMIDIClosePort)( LPVM_MIDI_PORT midiPort ); -typedef BOOL (CALLBACK *pfnvirtualMIDISendData)( LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length ); -typedef LPCWSTR (CALLBACK *pfnvirtualMIDIGetDriverVersion)( PWORD major, PWORD minor, PWORD release, PWORD build ); +typedef LPVM_MIDI_PORT(CALLBACK* pfnvirtualMIDICreatePortEx2)(LPCWSTR portName, LPVM_MIDI_DATA_CB callback, + DWORD_PTR dwCallbackInstance, DWORD maxSysexLength, + DWORD flags); +typedef void(CALLBACK* pfnvirtualMIDIClosePort)(LPVM_MIDI_PORT midiPort); +typedef BOOL(CALLBACK* pfnvirtualMIDISendData)(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length); +typedef LPCWSTR(CALLBACK* pfnvirtualMIDIGetDriverVersion)(PWORD major, PWORD minor, PWORD release, PWORD build); static pfnvirtualMIDICreatePortEx2 virtualMIDICreatePortEx2PROC = nullptr; static pfnvirtualMIDIClosePort virtualMIDIClosePortPROC = nullptr; static pfnvirtualMIDISendData virtualMIDISendDataPROC = nullptr; @@ -33,601 +34,499 @@ using namespace Windows::Media::Devices; const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::WASAPI"); -#define SAFE_RELEASE(punk) \ - if ((punk) != NULL) \ - { (punk)->Release(); (punk) = NULL; } +#define SAFE_RELEASE(punk) \ + if ((punk) != NULL) { \ + (punk)->Release(); \ + (punk) = NULL; \ + } -struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine -{ +struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine { #if !WINDOWS_STORE - ComPtr m_enumerator; - ComPtr m_device; + ComPtr m_enumerator; + ComPtr m_device; #else - bool m_ready = false; + bool m_ready = false; #endif - ComPtr m_audClient; - ComPtr m_renderClient; - std::string m_sinkName; + ComPtr m_audClient; + ComPtr m_renderClient; + std::string m_sinkName; - size_t m_curBufFrame = 0; - std::vector m_5msBuffer; + size_t m_curBufFrame = 0; + std::vector m_5msBuffer; #if !WINDOWS_STORE - struct NotificationClient final : public IMMNotificationClient - { - WASAPIAudioVoiceEngine& m_parent; + struct NotificationClient final : public IMMNotificationClient { + WASAPIAudioVoiceEngine& m_parent; - LONG _cRef; - IMMDeviceEnumerator *_pEnumerator; + LONG _cRef; + IMMDeviceEnumerator* _pEnumerator; - NotificationClient(WASAPIAudioVoiceEngine& parent) - : m_parent(parent), - _cRef(1), - _pEnumerator(nullptr) - {} + NotificationClient(WASAPIAudioVoiceEngine& parent) : m_parent(parent), _cRef(1), _pEnumerator(nullptr) {} - ~NotificationClient() - { - SAFE_RELEASE(_pEnumerator) - } + ~NotificationClient(){SAFE_RELEASE(_pEnumerator)} + // IUnknown methods -- AddRef, Release, and QueryInterface - // IUnknown methods -- AddRef, Release, and QueryInterface - - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&_cRef); - } - - ULONG STDMETHODCALLTYPE Release() - { - ULONG ulRef = InterlockedDecrement(&_cRef); - if (0 == ulRef) - { - delete this; - } - return ulRef; - } - - HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID riid, VOID **ppvInterface) - { - if (IID_IUnknown == riid) - { - AddRef(); - *ppvInterface = (IUnknown*)this; - } - else if (__uuidof(IMMNotificationClient) == riid) - { - AddRef(); - *ppvInterface = (IMMNotificationClient*)this; - } - else - { - *ppvInterface = NULL; - return E_NOINTERFACE; - } - return S_OK; - } - - // Callback methods for device-event notifications. - - HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( - EDataFlow flow, ERole role, - LPCWSTR pwstrDeviceId) - { - m_parent.m_rebuild = true; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) - { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) - { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( - LPCWSTR pwstrDeviceId, - DWORD dwNewState) - { - return S_OK; - } - - HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( - LPCWSTR pwstrDeviceId, - const PROPERTYKEY key) - { - return S_OK; - } - } m_notificationClient; -#endif - - void _buildAudioRenderClient() - { -#if !WINDOWS_STORE - if (!m_device) - { - if (FAILED(m_enumerator->GetDevice(MBSTWCS(m_sinkName.c_str()).c_str(), &m_device))) - { - Log.report(logvisor::Error, "unable to obtain audio device %s", m_sinkName.c_str()); - m_device.Reset(); - return; - } - } - - if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &m_audClient))) - { - Log.report(logvisor::Error, L"unable to create audio client from device"); - m_device.Reset(); - return; - } -#endif - - WAVEFORMATEXTENSIBLE* pwfx; - if (FAILED(m_audClient->GetMixFormat((WAVEFORMATEX**)&pwfx))) - { - Log.report(logvisor::Error, L"unable to obtain audio mix format from device"); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - return; - } - - /* Get channel information */ - if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) - { - m_mixInfo.m_channels = AudioChannelSet::Stereo; - if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) == (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) - { - m_mixInfo.m_channels = AudioChannelSet::Quad; - if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) == (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) - { - m_mixInfo.m_channels = AudioChannelSet::Surround51; - if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) == (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) - { - m_mixInfo.m_channels = AudioChannelSet::Surround71; - } - } - } - } - - ChannelMap& chMapOut = m_mixInfo.m_channelMap; - switch (pwfx->Format.nChannels) - { - case 2: - chMapOut.m_channelCount = 2; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - break; - case 4: - chMapOut.m_channelCount = 4; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::RearLeft; - chMapOut.m_channels[3] = AudioChannel::RearRight; - break; - case 5: - chMapOut.m_channelCount = 5; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::FrontCenter; - chMapOut.m_channels[3] = AudioChannel::RearLeft; - chMapOut.m_channels[4] = AudioChannel::RearRight; - break; - case 6: - chMapOut.m_channelCount = 6; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::FrontCenter; - chMapOut.m_channels[3] = AudioChannel::LFE; - chMapOut.m_channels[4] = AudioChannel::RearLeft; - chMapOut.m_channels[5] = AudioChannel::RearRight; - break; - case 8: - chMapOut.m_channelCount = 8; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - chMapOut.m_channels[2] = AudioChannel::FrontCenter; - chMapOut.m_channels[3] = AudioChannel::LFE; - chMapOut.m_channels[4] = AudioChannel::RearLeft; - chMapOut.m_channels[5] = AudioChannel::RearRight; - chMapOut.m_channels[6] = AudioChannel::SideLeft; - chMapOut.m_channels[7] = AudioChannel::SideRight; - break; - default: - Log.report(logvisor::Warning, "unknown channel layout %u; using stereo", pwfx->Format.nChannels); - chMapOut.m_channelCount = 2; - chMapOut.m_channels[0] = AudioChannel::FrontLeft; - chMapOut.m_channels[1] = AudioChannel::FrontRight; - break; - } - - /* Initialize audio client */ - if (FAILED(m_audClient->Initialize( - AUDCLNT_SHAREMODE_SHARED, - 0, - 450000, /* 45ms */ - 0, - (WAVEFORMATEX*)pwfx, - nullptr))) - { - Log.report(logvisor::Error, L"unable to initialize audio client"); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - CoTaskMemFree(pwfx); - return; - } - m_mixInfo.m_sampleRate = pwfx->Format.nSamplesPerSec; - m_5msFrames = (m_mixInfo.m_sampleRate * 5 / 500 + 1) / 2; - m_curBufFrame = m_5msFrames; - m_5msBuffer.resize(m_5msFrames * chMapOut.m_channelCount); - - if (pwfx->Format.wFormatTag == WAVE_FORMAT_PCM || - (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)) - { - if (pwfx->Format.wBitsPerSample == 16) - { - m_mixInfo.m_sampleFormat = SOXR_INT16_I; - m_mixInfo.m_bitsPerSample = 16; - } - else if (pwfx->Format.wBitsPerSample == 32) - { - m_mixInfo.m_sampleFormat = SOXR_INT32_I; - m_mixInfo.m_bitsPerSample = 32; - } - else - { - Log.report(logvisor::Fatal, L"unsupported bits-per-sample %d", pwfx->Format.wBitsPerSample); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - return; - } - } - else if (pwfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - if (pwfx->Format.wBitsPerSample == 32) - { - m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; - m_mixInfo.m_bitsPerSample = 32; - } - else - { - Log.report(logvisor::Error, L"unsupported floating-point bits-per-sample %d", pwfx->Format.wBitsPerSample); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - return; - } - } - - CoTaskMemFree(pwfx); - - UINT32 bufferFrameCount; - if (FAILED(m_audClient->GetBufferSize(&bufferFrameCount))) - { - Log.report(logvisor::Error, L"unable to get audio buffer frame count"); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - return; - } - m_mixInfo.m_periodFrames = bufferFrameCount; - - if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient))) - { - Log.report(logvisor::Error, L"unable to create audio render client"); -#if !WINDOWS_STORE - m_device.Reset(); -#endif - return; - } + ULONG STDMETHODCALLTYPE AddRef() { + return InterlockedIncrement(&_cRef); } + ULONG STDMETHODCALLTYPE Release() { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) { + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown*)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + // Callback methods for device-event notifications. + + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) { + m_parent.m_rebuild = true; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) { return S_OK; } + + HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) { return S_OK; } + + HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { return S_OK; } + + HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { return S_OK; } + } m_notificationClient; +#endif + + void _buildAudioRenderClient() { +#if !WINDOWS_STORE + if (!m_device) { + if (FAILED(m_enumerator->GetDevice(MBSTWCS(m_sinkName.c_str()).c_str(), &m_device))) { + Log.report(logvisor::Error, "unable to obtain audio device %s", m_sinkName.c_str()); + m_device.Reset(); + return; + } + } + + if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &m_audClient))) { + Log.report(logvisor::Error, L"unable to create audio client from device"); + m_device.Reset(); + return; + } +#endif + + WAVEFORMATEXTENSIBLE* pwfx; + if (FAILED(m_audClient->GetMixFormat((WAVEFORMATEX**)&pwfx))) { + Log.report(logvisor::Error, L"unable to obtain audio mix format from device"); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + return; + } + + /* Get channel information */ + if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)) == + (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)) { + m_mixInfo.m_channels = AudioChannelSet::Stereo; + if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)) == + (SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)) { + m_mixInfo.m_channels = AudioChannelSet::Quad; + if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY)) == + (SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY)) { + m_mixInfo.m_channels = AudioChannelSet::Surround51; + if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)) == + (SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)) { + m_mixInfo.m_channels = AudioChannelSet::Surround71; + } + } + } + } + + ChannelMap& chMapOut = m_mixInfo.m_channelMap; + switch (pwfx->Format.nChannels) { + case 2: + chMapOut.m_channelCount = 2; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + break; + case 4: + chMapOut.m_channelCount = 4; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::RearLeft; + chMapOut.m_channels[3] = AudioChannel::RearRight; + break; + case 5: + chMapOut.m_channelCount = 5; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::FrontCenter; + chMapOut.m_channels[3] = AudioChannel::RearLeft; + chMapOut.m_channels[4] = AudioChannel::RearRight; + break; + case 6: + chMapOut.m_channelCount = 6; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::FrontCenter; + chMapOut.m_channels[3] = AudioChannel::LFE; + chMapOut.m_channels[4] = AudioChannel::RearLeft; + chMapOut.m_channels[5] = AudioChannel::RearRight; + break; + case 8: + chMapOut.m_channelCount = 8; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + chMapOut.m_channels[2] = AudioChannel::FrontCenter; + chMapOut.m_channels[3] = AudioChannel::LFE; + chMapOut.m_channels[4] = AudioChannel::RearLeft; + chMapOut.m_channels[5] = AudioChannel::RearRight; + chMapOut.m_channels[6] = AudioChannel::SideLeft; + chMapOut.m_channels[7] = AudioChannel::SideRight; + break; + default: + Log.report(logvisor::Warning, "unknown channel layout %u; using stereo", pwfx->Format.nChannels); + chMapOut.m_channelCount = 2; + chMapOut.m_channels[0] = AudioChannel::FrontLeft; + chMapOut.m_channels[1] = AudioChannel::FrontRight; + break; + } + + /* Initialize audio client */ + if (FAILED(m_audClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 450000, /* 45ms */ + 0, (WAVEFORMATEX*)pwfx, nullptr))) { + Log.report(logvisor::Error, L"unable to initialize audio client"); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + CoTaskMemFree(pwfx); + return; + } + m_mixInfo.m_sampleRate = pwfx->Format.nSamplesPerSec; + m_5msFrames = (m_mixInfo.m_sampleRate * 5 / 500 + 1) / 2; + m_curBufFrame = m_5msFrames; + m_5msBuffer.resize(m_5msFrames * chMapOut.m_channelCount); + + if (pwfx->Format.wFormatTag == WAVE_FORMAT_PCM || + (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)) { + if (pwfx->Format.wBitsPerSample == 16) { + m_mixInfo.m_sampleFormat = SOXR_INT16_I; + m_mixInfo.m_bitsPerSample = 16; + } else if (pwfx->Format.wBitsPerSample == 32) { + m_mixInfo.m_sampleFormat = SOXR_INT32_I; + m_mixInfo.m_bitsPerSample = 32; + } else { + Log.report(logvisor::Fatal, L"unsupported bits-per-sample %d", pwfx->Format.wBitsPerSample); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + return; + } + } else if (pwfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT || + (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && + pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { + if (pwfx->Format.wBitsPerSample == 32) { + m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; + m_mixInfo.m_bitsPerSample = 32; + } else { + Log.report(logvisor::Error, L"unsupported floating-point bits-per-sample %d", pwfx->Format.wBitsPerSample); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + return; + } + } + + CoTaskMemFree(pwfx); + + UINT32 bufferFrameCount; + if (FAILED(m_audClient->GetBufferSize(&bufferFrameCount))) { + Log.report(logvisor::Error, L"unable to get audio buffer frame count"); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + return; + } + m_mixInfo.m_periodFrames = bufferFrameCount; + + if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient))) { + Log.report(logvisor::Error, L"unable to create audio render client"); +#if !WINDOWS_STORE + m_device.Reset(); +#endif + return; + } + } + #if WINDOWS_STORE - struct CompletionHandler : IActivateAudioInterfaceCompletionHandler - { - WASAPIAudioVoiceEngine& e; - LONG _cRef = 1; + struct CompletionHandler : IActivateAudioInterfaceCompletionHandler { + WASAPIAudioVoiceEngine& e; + LONG _cRef = 1; - CompletionHandler(WASAPIAudioVoiceEngine& e) : e(e) {} - HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) - { - return e.ActivateCompleted(operation); - } - - ULONG STDMETHODCALLTYPE AddRef() - { - return InterlockedIncrement(&_cRef); - } - - ULONG STDMETHODCALLTYPE Release() - { - ULONG ulRef = InterlockedDecrement(&_cRef); - if (0 == ulRef) - { - delete this; - } - return ulRef; - } - - HRESULT STDMETHODCALLTYPE QueryInterface( - REFIID riid, VOID **ppvInterface) - { - if (IID_IUnknown == riid) - { - AddRef(); - *ppvInterface = (IUnknown*)this; - } - else if (__uuidof(IActivateAudioInterfaceCompletionHandler) == riid) - { - AddRef(); - *ppvInterface = (IActivateAudioInterfaceCompletionHandler*)this; - } - else - { - *ppvInterface = NULL; - return E_NOINTERFACE; - } - return S_OK; - } - } m_completion = {*this}; - HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) - { - ComPtr punkAudioInterface; - HRESULT hrActivateResult; - operation->GetActivateResult(&hrActivateResult, &punkAudioInterface); - punkAudioInterface.As(&m_audClient); - _buildAudioRenderClient(); - m_ready = true; - return ERROR_SUCCESS; + CompletionHandler(WASAPIAudioVoiceEngine& e) : e(e) {} + HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) { + return e.ActivateCompleted(operation); } + + ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&_cRef); } + + ULONG STDMETHODCALLTYPE Release() { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) { + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown*)this; + } else if (__uuidof(IActivateAudioInterfaceCompletionHandler) == riid) { + AddRef(); + *ppvInterface = (IActivateAudioInterfaceCompletionHandler*)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + } m_completion = {*this}; + HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) { + ComPtr punkAudioInterface; + HRESULT hrActivateResult; + operation->GetActivateResult(&hrActivateResult, &punkAudioInterface); + punkAudioInterface.As(&m_audClient); + _buildAudioRenderClient(); + m_ready = true; + return ERROR_SUCCESS; + } #endif - WASAPIAudioVoiceEngine() + WASAPIAudioVoiceEngine() #if !WINDOWS_STORE - : m_notificationClient(*this) + : m_notificationClient(*this) #endif - { + { #if !WINDOWS_STORE #ifdef TE_VIRTUAL_MIDI - HMODULE virtualMidiModule; - if (!virtualMIDICreatePortEx2PROC && (virtualMidiModule = LoadLibraryW(L"teVirtualMIDI64.dll"))) - { - virtualMIDICreatePortEx2PROC = (pfnvirtualMIDICreatePortEx2)GetProcAddress(virtualMidiModule, "virtualMIDICreatePortEx2"); - virtualMIDIClosePortPROC = (pfnvirtualMIDIClosePort)GetProcAddress(virtualMidiModule, "virtualMIDIClosePort"); - virtualMIDISendDataPROC = (pfnvirtualMIDISendData)GetProcAddress(virtualMidiModule, "virtualMIDISendData"); - virtualMIDIGetDriverVersionPROC = (pfnvirtualMIDIGetDriverVersion)GetProcAddress(virtualMidiModule, "virtualMIDIGetDriverVersion"); - LARGE_INTEGER pf; - QueryPerformanceFrequency(&pf); - PerfFrequency = double(pf.QuadPart); - } + HMODULE virtualMidiModule; + if (!virtualMIDICreatePortEx2PROC && (virtualMidiModule = LoadLibraryW(L"teVirtualMIDI64.dll"))) { + virtualMIDICreatePortEx2PROC = + (pfnvirtualMIDICreatePortEx2)GetProcAddress(virtualMidiModule, "virtualMIDICreatePortEx2"); + virtualMIDIClosePortPROC = (pfnvirtualMIDIClosePort)GetProcAddress(virtualMidiModule, "virtualMIDIClosePort"); + virtualMIDISendDataPROC = (pfnvirtualMIDISendData)GetProcAddress(virtualMidiModule, "virtualMIDISendData"); + virtualMIDIGetDriverVersionPROC = + (pfnvirtualMIDIGetDriverVersion)GetProcAddress(virtualMidiModule, "virtualMIDIGetDriverVersion"); + LARGE_INTEGER pf; + QueryPerformanceFrequency(&pf); + PerfFrequency = double(pf.QuadPart); + } #endif - /* Enumerate default audio device */ - if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, - CLSCTX_ALL, IID_IMMDeviceEnumerator, - &m_enumerator))) - { - Log.report(logvisor::Error, L"unable to create MMDeviceEnumerator instance"); - return; - } + /* Enumerate default audio device */ + if (FAILED( + CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, &m_enumerator))) { + Log.report(logvisor::Error, L"unable to create MMDeviceEnumerator instance"); + return; + } - if (FAILED(m_enumerator->RegisterEndpointNotificationCallback(&m_notificationClient))) - { - Log.report(logvisor::Error, L"unable to register multimedia event callback"); - m_device.Reset(); - return; - } + if (FAILED(m_enumerator->RegisterEndpointNotificationCallback(&m_notificationClient))) { + Log.report(logvisor::Error, L"unable to register multimedia event callback"); + m_device.Reset(); + return; + } - if (FAILED(m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device))) - { - Log.report(logvisor::Error, L"unable to obtain default audio device"); - m_device.Reset(); - return; - } - LPWSTR sinkName = nullptr; - m_device->GetId(&sinkName); - m_sinkName = WCSTMBS(sinkName); - CoTaskMemFree(sinkName); + if (FAILED(m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device))) { + Log.report(logvisor::Error, L"unable to obtain default audio device"); + m_device.Reset(); + return; + } + LPWSTR sinkName = nullptr; + m_device->GetId(&sinkName); + m_sinkName = WCSTMBS(sinkName); + CoTaskMemFree(sinkName); - _buildAudioRenderClient(); + _buildAudioRenderClient(); #else - auto deviceIdStr = MediaDevice::GetDefaultAudioRenderId(Windows::Media::Devices::AudioDeviceRole::Default); - ComPtr asyncOp; - ActivateAudioInterfaceAsync(deviceIdStr->Data(), __uuidof(IAudioClient3), nullptr, &m_completion, &asyncOp); + auto deviceIdStr = MediaDevice::GetDefaultAudioRenderId(Windows::Media::Devices::AudioDeviceRole::Default); + ComPtr asyncOp; + ActivateAudioInterfaceAsync(deviceIdStr->Data(), __uuidof(IAudioClient3), nullptr, &m_completion, &asyncOp); #endif - } + } - bool m_started = false; - bool m_rebuild = false; + bool m_started = false; + bool m_rebuild = false; - void _rebuildAudioRenderClient() - { - soxr_datatype_t oldFmt = m_mixInfo.m_sampleFormat; + void _rebuildAudioRenderClient() { + soxr_datatype_t oldFmt = m_mixInfo.m_sampleFormat; - _buildAudioRenderClient(); - m_rebuild = false; - m_started = false; + _buildAudioRenderClient(); + m_rebuild = false; + m_started = false; - if (m_mixInfo.m_sampleFormat != oldFmt) - Log.report(logvisor::Fatal, L"audio device sample format changed, boo doesn't support this!!"); + if (m_mixInfo.m_sampleFormat != oldFmt) + Log.report(logvisor::Fatal, L"audio device sample format changed, boo doesn't support this!!"); - _resetSampleRate(); - } + _resetSampleRate(); + } - void pumpAndMixVoices() - { + void pumpAndMixVoices() { #if WINDOWS_STORE - if (!m_ready) - return; + if (!m_ready) + return; #else - if (!m_device) - return; + if (!m_device) + return; #endif - int attempt = 0; - while (true) - { - if (attempt >= 10) - Log.report(logvisor::Fatal, L"unable to setup AudioRenderClient"); + int attempt = 0; + while (true) { + if (attempt >= 10) + Log.report(logvisor::Fatal, L"unable to setup AudioRenderClient"); - if (m_rebuild) - { - m_device.Reset(); - _rebuildAudioRenderClient(); - } - - HRESULT res; - if (!m_started) - { - res = m_audClient->Start(); - if (FAILED(res)) - { - m_rebuild = true; - ++attempt; - continue; - } - m_started = true; - } - - UINT32 numFramesPadding; - res = m_audClient->GetCurrentPadding(&numFramesPadding); - if (FAILED(res)) - { - m_rebuild = true; - ++attempt; - continue; - } - - size_t frames = m_mixInfo.m_periodFrames - numFramesPadding; - if (frames <= 0) - return; - - BYTE* bufOut; - res = m_renderClient->GetBuffer(frames, &bufOut); - if (FAILED(res)) - { - m_rebuild = true; - ++attempt; - continue; - } - - for (size_t f=0 ; f(bufOut) + m_mixInfo.m_channelMap.m_channelCount * f, - &m_5msBuffer[m_curBufFrame * m_mixInfo.m_channelMap.m_channelCount], - remRenderFrames * m_mixInfo.m_channelMap.m_channelCount * sizeof(float)); - m_curBufFrame += remRenderFrames; - f += remRenderFrames; - } - } - - res = m_renderClient->ReleaseBuffer(frames, 0); - if (FAILED(res)) - { - m_rebuild = true; - ++attempt; - continue; - } - - break; - } - } - - std::string getCurrentAudioOutput() const - { - return m_sinkName; - } - - bool setCurrentAudioOutput(const char* name) - { - ComPtr newDevice; - if (FAILED(m_enumerator->GetDevice(MBSTWCS(name).c_str(), &newDevice))) - { - Log.report(logvisor::Error, "unable to obtain audio device %s", name); - return false; - } - m_device = newDevice; - m_sinkName = name; + if (m_rebuild) { + m_device.Reset(); _rebuildAudioRenderClient(); - return true; - } + } - std::vector> enumerateAudioOutputs() const - { - std::vector> ret; + HRESULT res; + if (!m_started) { + res = m_audClient->Start(); + if (FAILED(res)) { + m_rebuild = true; + ++attempt; + continue; + } + m_started = true; + } - ComPtr collection; - if (FAILED(m_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection))) - { - Log.report(logvisor::Error, L"unable to enumerate audio outputs"); - return ret; + UINT32 numFramesPadding; + res = m_audClient->GetCurrentPadding(&numFramesPadding); + if (FAILED(res)) { + m_rebuild = true; + ++attempt; + continue; + } + + size_t frames = m_mixInfo.m_periodFrames - numFramesPadding; + if (frames <= 0) + return; + + BYTE* bufOut; + res = m_renderClient->GetBuffer(frames, &bufOut); + if (FAILED(res)) { + m_rebuild = true; + ++attempt; + continue; + } + + for (size_t f = 0; f < frames;) { + if (m_curBufFrame == m_5msFrames) { + _pumpAndMixVoices(m_5msFrames, m_5msBuffer.data()); + m_curBufFrame = 0; } - UINT count = 0; - collection->GetCount(&count); - for (UINT i = 0; i < count; ++i) - { - ComPtr device; - collection->Item(i, &device); - LPWSTR devName; - device->GetId(&devName); - ComPtr props; - device->OpenPropertyStore(STGM_READ, &props); - PROPVARIANT val = {}; - props->GetValue(PKEY_Device_FriendlyName, &val); - std::string friendlyName; - if (val.vt == VT_LPWSTR) - friendlyName = WCSTMBS(val.pwszVal); - ret.emplace_back(WCSTMBS(devName), std::move(friendlyName)); + size_t remRenderFrames = std::min(frames - f, m_5msFrames - m_curBufFrame); + if (remRenderFrames) { + memmove(reinterpret_cast(bufOut) + m_mixInfo.m_channelMap.m_channelCount * f, + &m_5msBuffer[m_curBufFrame * m_mixInfo.m_channelMap.m_channelCount], + remRenderFrames * m_mixInfo.m_channelMap.m_channelCount * sizeof(float)); + m_curBufFrame += remRenderFrames; + f += remRenderFrames; } + } - return ret; + res = m_renderClient->ReleaseBuffer(frames, 0); + if (FAILED(res)) { + m_rebuild = true; + ++attempt; + continue; + } + + break; } + } + + std::string getCurrentAudioOutput() const { return m_sinkName; } + + bool setCurrentAudioOutput(const char* name) { + ComPtr newDevice; + if (FAILED(m_enumerator->GetDevice(MBSTWCS(name).c_str(), &newDevice))) { + Log.report(logvisor::Error, "unable to obtain audio device %s", name); + return false; + } + m_device = newDevice; + m_sinkName = name; + _rebuildAudioRenderClient(); + return true; + } + + std::vector> enumerateAudioOutputs() const { + std::vector> ret; + + ComPtr collection; + if (FAILED(m_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection))) { + Log.report(logvisor::Error, L"unable to enumerate audio outputs"); + return ret; + } + + UINT count = 0; + collection->GetCount(&count); + for (UINT i = 0; i < count; ++i) { + ComPtr device; + collection->Item(i, &device); + LPWSTR devName; + device->GetId(&devName); + ComPtr props; + device->OpenPropertyStore(STGM_READ, &props); + PROPVARIANT val = {}; + props->GetValue(PKEY_Device_FriendlyName, &val); + std::string friendlyName; + if (val.vt == VT_LPWSTR) + friendlyName = WCSTMBS(val.pwszVal); + ret.emplace_back(WCSTMBS(devName), std::move(friendlyName)); + } + + return ret; + } #if !WINDOWS_STORE - std::vector> enumerateMIDIInputs() const - { - std::vector> ret; + std::vector> enumerateMIDIInputs() const { + std::vector> ret; - UINT numInDevices = midiInGetNumDevs(); - ret.reserve(numInDevices); + UINT numInDevices = midiInGetNumDevs(); + ret.reserve(numInDevices); - for (UINT i=0 ; i bytes; - bytes.resize(length); - memcpy(&bytes[0], midiDataBytes, length); + static void CALLBACK VirtualMIDIReceiveProc(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length, + IMIDIReceiver* dwInstance) { + std::vector bytes; + bytes.resize(length); + memcpy(&bytes[0], midiDataBytes, length); - double timestamp; - LARGE_INTEGER perf; - QueryPerformanceCounter(&perf); - timestamp = perf.QuadPart / PerfFrequency; + double timestamp; + LARGE_INTEGER perf; + QueryPerformanceCounter(&perf); + timestamp = perf.QuadPart / PerfFrequency; - dwInstance->m_receiver(std::move(bytes), timestamp); - } + dwInstance->m_receiver(std::move(bytes), timestamp); + } #endif - static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn, - UINT wMsg, - IMIDIReceiver* dwInstance, - DWORD_PTR dwParam1, - DWORD_PTR dwParam2) - { - if (wMsg == MIM_DATA) - { - uint8_t (&ptr)[3] = reinterpret_cast(dwParam1); - std::vector bytes(std::cbegin(ptr), std::cend(ptr)); - dwInstance->m_receiver(std::move(bytes), dwParam2 / 1000.0); - } + static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn, UINT wMsg, IMIDIReceiver* dwInstance, DWORD_PTR dwParam1, + DWORD_PTR dwParam2) { + if (wMsg == MIM_DATA) { + uint8_t(&ptr)[3] = reinterpret_cast(dwParam1); + std::vector bytes(std::cbegin(ptr), std::cend(ptr)); + dwInstance->m_receiver(std::move(bytes), dwParam2 / 1000.0); } + } #ifdef TE_VIRTUAL_MIDI - struct VMIDIIn : public IMIDIIn - { - LPVM_MIDI_PORT m_midi = 0; + struct VMIDIIn : public IMIDIIn { + LPVM_MIDI_PORT m_midi = 0; - VMIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) - : IMIDIIn(parent, true, std::move(receiver)) {} + VMIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) : IMIDIIn(parent, true, std::move(receiver)) {} - ~VMIDIIn() - { - virtualMIDIClosePortPROC(m_midi); - } + ~VMIDIIn() { virtualMIDIClosePortPROC(m_midi); } - std::string description() const - { - return "Virtual MIDI-In"; - } - }; + std::string description() const { return "Virtual MIDI-In"; } + }; - struct VMIDIOut : public IMIDIOut - { - LPVM_MIDI_PORT m_midi = 0; + struct VMIDIOut : public IMIDIOut { + LPVM_MIDI_PORT m_midi = 0; - VMIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, true) {} + VMIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, true) {} - ~VMIDIOut() - { - virtualMIDIClosePortPROC(m_midi); - } + ~VMIDIOut() { virtualMIDIClosePortPROC(m_midi); } - std::string description() const - { - return "Virtual MIDI-Out"; - } + std::string description() const { return "Virtual MIDI-Out"; } - size_t send(const void* buf, size_t len) const - { - return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; - } - }; + size_t send(const void* buf, size_t len) const { + return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; + } + }; - struct VMIDIInOut : public IMIDIInOut - { - LPVM_MIDI_PORT m_midi = 0; + struct VMIDIInOut : public IMIDIInOut { + LPVM_MIDI_PORT m_midi = 0; - VMIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) - : IMIDIInOut(parent, true, std::move(receiver)) {} + VMIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) + : IMIDIInOut(parent, true, std::move(receiver)) {} - ~VMIDIInOut() - { - virtualMIDIClosePortPROC(m_midi); - } + ~VMIDIInOut() { virtualMIDIClosePortPROC(m_midi); } - std::string description() const - { - return "Virtual MIDI-In/Out"; - } + std::string description() const { return "Virtual MIDI-In/Out"; } - size_t send(const void* buf, size_t len) const - { - return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; - } - }; + size_t send(const void* buf, size_t len) const { + return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; + } + }; #endif - struct MIDIIn : public IMIDIIn - { - HMIDIIN m_midi = 0; + struct MIDIIn : public IMIDIIn { + HMIDIIN m_midi = 0; - MIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) - : IMIDIIn(parent, false, std::move(receiver)) {} + MIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) : IMIDIIn(parent, false, std::move(receiver)) {} - ~MIDIIn() - { - midiInClose(m_midi); - } + ~MIDIIn() { midiInClose(m_midi); } - std::string description() const - { - UINT id = 0; - midiInGetID(m_midi, &id); - MIDIINCAPS caps; - if (FAILED(midiInGetDevCaps(id, &caps, sizeof(caps)))) - return {}; + std::string description() const { + UINT id = 0; + midiInGetID(m_midi, &id); + MIDIINCAPS caps; + if (FAILED(midiInGetDevCaps(id, &caps, sizeof(caps)))) + return {}; #ifdef UNICODE - return WCSTMBS(caps.szPname); + return WCSTMBS(caps.szPname); #else - return caps.szPname; + return caps.szPname; #endif - } - }; + } + }; - struct MIDIOut : public IMIDIOut - { - HMIDIOUT m_midi = 0; - HMIDISTRM m_strm = 0; - uint8_t m_buf[512]; - MIDIHDR m_hdr = {}; + struct MIDIOut : public IMIDIOut { + HMIDIOUT m_midi = 0; + HMIDISTRM m_strm = 0; + uint8_t m_buf[512]; + MIDIHDR m_hdr = {}; - MIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, false) {} + MIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, false) {} - void prepare() - { - UINT id = 0; - midiOutGetID(m_midi, &id); + void prepare() { + UINT id = 0; + midiOutGetID(m_midi, &id); - m_hdr.lpData = reinterpret_cast(m_buf); - m_hdr.dwBufferLength = 512; - m_hdr.dwFlags = MHDR_ISSTRM; - midiOutPrepareHeader(m_midi, &m_hdr, sizeof(m_hdr)); - midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); - } + m_hdr.lpData = reinterpret_cast(m_buf); + m_hdr.dwBufferLength = 512; + m_hdr.dwFlags = MHDR_ISSTRM; + midiOutPrepareHeader(m_midi, &m_hdr, sizeof(m_hdr)); + midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); + } - ~MIDIOut() - { - midiStreamClose(m_strm); - midiOutUnprepareHeader(m_midi, &m_hdr, sizeof(m_hdr)); - midiOutClose(m_midi); - } + ~MIDIOut() { + midiStreamClose(m_strm); + midiOutUnprepareHeader(m_midi, &m_hdr, sizeof(m_hdr)); + midiOutClose(m_midi); + } - std::string description() const - { - UINT id = 0; - midiOutGetID(m_midi, &id); - MIDIOUTCAPS caps; - if (FAILED(midiOutGetDevCaps(id, &caps, sizeof(caps)))) - return {}; + std::string description() const { + UINT id = 0; + midiOutGetID(m_midi, &id); + MIDIOUTCAPS caps; + if (FAILED(midiOutGetDevCaps(id, &caps, sizeof(caps)))) + return {}; #ifdef UNICODE - return WCSTMBS(caps.szPname); + return WCSTMBS(caps.szPname); #else - return caps.szPname; + return caps.szPname; #endif - } + } - size_t send(const void* buf, size_t len) const - { - memcpy(const_cast(this)->m_buf, buf, std::min(len, size_t(512))); - const_cast(this)->m_hdr.dwBytesRecorded = len; - midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); - return len; - } - }; + size_t send(const void* buf, size_t len) const { + memcpy(const_cast(this)->m_buf, buf, std::min(len, size_t(512))); + const_cast(this)->m_hdr.dwBytesRecorded = len; + midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); + return len; + } + }; - struct MIDIInOut : public IMIDIInOut - { - HMIDIIN m_midiIn = 0; - HMIDIOUT m_midiOut = 0; - HMIDISTRM m_strm = 0; - uint8_t m_buf[512]; - MIDIHDR m_hdr = {}; + struct MIDIInOut : public IMIDIInOut { + HMIDIIN m_midiIn = 0; + HMIDIOUT m_midiOut = 0; + HMIDISTRM m_strm = 0; + uint8_t m_buf[512]; + MIDIHDR m_hdr = {}; - MIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) - : IMIDIInOut(parent, false, std::move(receiver)) {} + MIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) + : IMIDIInOut(parent, false, std::move(receiver)) {} - void prepare() - { - UINT id = 0; - midiOutGetID(m_midiOut, &id); + void prepare() { + UINT id = 0; + midiOutGetID(m_midiOut, &id); - m_hdr.lpData = reinterpret_cast(m_buf); - m_hdr.dwBufferLength = 512; - m_hdr.dwFlags = MHDR_ISSTRM; - midiOutPrepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr)); - midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); - } + m_hdr.lpData = reinterpret_cast(m_buf); + m_hdr.dwBufferLength = 512; + m_hdr.dwFlags = MHDR_ISSTRM; + midiOutPrepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr)); + midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); + } - ~MIDIInOut() - { - midiInClose(m_midiIn); - midiStreamClose(m_strm); - midiOutUnprepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr)); - midiOutClose(m_midiOut); - } + ~MIDIInOut() { + midiInClose(m_midiIn); + midiStreamClose(m_strm); + midiOutUnprepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr)); + midiOutClose(m_midiOut); + } - std::string description() const - { - UINT id = 0; - midiOutGetID(m_midiOut, &id); - MIDIOUTCAPS caps; - if (FAILED(midiOutGetDevCaps(id, &caps, sizeof(caps)))) - return {}; + std::string description() const { + UINT id = 0; + midiOutGetID(m_midiOut, &id); + MIDIOUTCAPS caps; + if (FAILED(midiOutGetDevCaps(id, &caps, sizeof(caps)))) + return {}; #ifdef UNICODE - return WCSTMBS(caps.szPname); + return WCSTMBS(caps.szPname); #else - return caps.szPname; + return caps.szPname; #endif - } + } - size_t send(const void* buf, size_t len) const - { - memcpy(const_cast(m_buf), buf, std::min(len, size_t(512))); - const_cast(m_hdr).dwBytesRecorded = len; - midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); - return len; - } - }; + size_t send(const void* buf, size_t len) const { + memcpy(const_cast(m_buf), buf, std::min(len, size_t(512))); + const_cast(m_hdr).dwBytesRecorded = len; + midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); + return len; + } + }; - std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) - { + std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) { #ifdef TE_VIRTUAL_MIDI - if (!virtualMIDICreatePortEx2PROC) - return {}; + if (!virtualMIDICreatePortEx2PROC) + return {}; - std::unique_ptr ret = std::make_unique(this, std::move(receiver)); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this, std::move(receiver)); + if (!ret) + return {}; - SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In"); - auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc), - DWORD_PTR(static_cast(ret.get())), 512, - TE_VM_FLAGS_PARSE_RX | TE_VM_FLAGS_INSTANTIATE_RX_ONLY); - if (!port) - return {}; - static_cast(*ret).m_midi = port; - return ret; + SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In"); + auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc), + DWORD_PTR(static_cast(ret.get())), 512, + TE_VM_FLAGS_PARSE_RX | TE_VM_FLAGS_INSTANTIATE_RX_ONLY); + if (!port) + return {}; + static_cast(*ret).m_midi = port; + return ret; #else - return {}; + return {}; #endif - } + } - std::unique_ptr newVirtualMIDIOut() - { + std::unique_ptr newVirtualMIDIOut() { #ifdef TE_VIRTUAL_MIDI - if (!virtualMIDICreatePortEx2PROC) - return {}; + if (!virtualMIDICreatePortEx2PROC) + return {}; - std::unique_ptr ret = std::make_unique(this); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this); + if (!ret) + return {}; - SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-Out"); - auto port = virtualMIDICreatePortEx2PROC(name.c_str(), nullptr, 0, 512, - TE_VM_FLAGS_PARSE_TX | TE_VM_FLAGS_INSTANTIATE_TX_ONLY); - if (!port) - return {}; - static_cast(*ret).m_midi = port; - return ret; + SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-Out"); + auto port = virtualMIDICreatePortEx2PROC(name.c_str(), nullptr, 0, 512, + TE_VM_FLAGS_PARSE_TX | TE_VM_FLAGS_INSTANTIATE_TX_ONLY); + if (!port) + return {}; + static_cast(*ret).m_midi = port; + return ret; #else - return {}; + return {}; #endif - } + } - std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) - { + std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) { #ifdef TE_VIRTUAL_MIDI - if (!virtualMIDICreatePortEx2PROC) - return {}; + if (!virtualMIDICreatePortEx2PROC) + return {}; - std::unique_ptr ret = std::make_unique(this, std::move(receiver)); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this, std::move(receiver)); + if (!ret) + return {}; - SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In/Out"); - auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc), - DWORD_PTR(static_cast(ret.get())), 512, - TE_VM_FLAGS_SUPPORTED); - if (!port) - return {}; - static_cast(*ret).m_midi = port; - return ret; + SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In/Out"); + auto port = + virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc), + DWORD_PTR(static_cast(ret.get())), 512, TE_VM_FLAGS_SUPPORTED); + if (!port) + return {}; + static_cast(*ret).m_midi = port; + return ret; #else - return {}; + return {}; #endif - } + } - std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) - { - if (strncmp(name, "in", 2)) - return {}; - long id = strtol(name + 2, nullptr, 10); + std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { + if (strncmp(name, "in", 2)) + return {}; + long id = strtol(name + 2, nullptr, 10); - std::unique_ptr ret = std::make_unique(this, std::move(receiver)); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this, std::move(receiver)); + if (!ret) + return {}; - if (FAILED(midiInOpen(&static_cast(*ret).m_midi, id, DWORD_PTR(MIDIReceiveProc), - DWORD_PTR(static_cast(ret.get())), CALLBACK_FUNCTION))) - return {}; - midiInStart(static_cast(*ret).m_midi); + if (FAILED(midiInOpen(&static_cast(*ret).m_midi, id, DWORD_PTR(MIDIReceiveProc), + DWORD_PTR(static_cast(ret.get())), CALLBACK_FUNCTION))) + return {}; + midiInStart(static_cast(*ret).m_midi); - return ret; - } + return ret; + } - std::unique_ptr newRealMIDIOut(const char* name) - { - if (strncmp(name, "out", 3)) - return {}; - long id = strtol(name + 3, nullptr, 10); + std::unique_ptr newRealMIDIOut(const char* name) { + if (strncmp(name, "out", 3)) + return {}; + long id = strtol(name + 3, nullptr, 10); - std::unique_ptr ret = std::make_unique(this); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this); + if (!ret) + return {}; - if (FAILED(midiOutOpen(&static_cast(*ret).m_midi, id, NULL, - NULL, CALLBACK_NULL))) - return {}; + if (FAILED(midiOutOpen(&static_cast(*ret).m_midi, id, NULL, NULL, CALLBACK_NULL))) + return {}; - static_cast(*ret).prepare(); - return ret; - } + static_cast(*ret).prepare(); + return ret; + } - std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) - { - const char* in = strstr(name, "in"); - const char* out = strstr(name, "out"); + std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { + const char* in = strstr(name, "in"); + const char* out = strstr(name, "out"); - if (!in || !out) - return {}; + if (!in || !out) + return {}; - long inId = strtol(in + 2, nullptr, 10); - long outId = strtol(out + 3, nullptr, 10); + long inId = strtol(in + 2, nullptr, 10); + long outId = strtol(out + 3, nullptr, 10); - std::unique_ptr ret = std::make_unique(this, std::move(receiver)); - if (!ret) - return {}; + std::unique_ptr ret = std::make_unique(this, std::move(receiver)); + if (!ret) + return {}; - if (FAILED(midiInOpen(&static_cast(*ret).m_midiIn, inId, DWORD_PTR(MIDIReceiveProc), - DWORD_PTR(static_cast(ret.get())), CALLBACK_FUNCTION))) - return {}; - midiInStart(static_cast(*ret).m_midiIn); + if (FAILED(midiInOpen(&static_cast(*ret).m_midiIn, inId, DWORD_PTR(MIDIReceiveProc), + DWORD_PTR(static_cast(ret.get())), CALLBACK_FUNCTION))) + return {}; + midiInStart(static_cast(*ret).m_midiIn); - if (FAILED(midiOutOpen(&static_cast(*ret).m_midiOut, outId, NULL, - NULL, CALLBACK_NULL))) - return {}; + if (FAILED(midiOutOpen(&static_cast(*ret).m_midiOut, outId, NULL, NULL, CALLBACK_NULL))) + return {}; - static_cast(*ret).prepare(); - return ret; - } + static_cast(*ret).prepare(); + return ret; + } - bool useMIDILock() const {return true;} + bool useMIDILock() const { return true; } #else - std::vector> enumerateMIDIDevices() const - { - return {}; - } + std::vector> enumerateMIDIDevices() const { return {}; } - std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) - { - return {}; - } + std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) { return {}; } - std::unique_ptr newVirtualMIDIOut() - { - return {}; - } + std::unique_ptr newVirtualMIDIOut() { return {}; } - std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) - { - return {}; - } + std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) { return {}; } - std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) - { - return {}; - } + std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { return {}; } - std::unique_ptr newRealMIDIOut(const char* name) - { - return {}; - } + std::unique_ptr newRealMIDIOut(const char* name) { return {}; } - std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) - { - return {}; - } + std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { return {}; } - bool useMIDILock() const {return false;} + bool useMIDILock() const { return false; } #endif }; -std::unique_ptr NewAudioVoiceEngine() -{ - return std::make_unique(); -} +std::unique_ptr NewAudioVoiceEngine() { return std::make_unique(); } -} +} // namespace boo diff --git a/lib/audiodev/WAVOut.cpp b/lib/audiodev/WAVOut.cpp index 26117aa..895a3f5 100644 --- a/lib/audiodev/WAVOut.cpp +++ b/lib/audiodev/WAVOut.cpp @@ -2,305 +2,247 @@ #include "logvisor/logvisor.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp" -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::WAVOut"); -struct WAVOutVoiceEngine : BaseAudioVoiceEngine -{ - std::vector m_interleavedBuf; +struct WAVOutVoiceEngine : BaseAudioVoiceEngine { + std::vector m_interleavedBuf; - AudioChannelSet _getAvailableSet() - { - return AudioChannelSet::Stereo; + AudioChannelSet _getAvailableSet() { return AudioChannelSet::Stereo; } + + std::string getCurrentAudioOutput() const { return "wavout"; } + + bool setCurrentAudioOutput(const char* name) { return false; } + + std::vector> enumerateAudioOutputs() const { return {{"wavout", "WAVOut"}}; } + + std::vector> enumerateMIDIInputs() const { return {}; } + + bool supportsVirtualMIDIIn() const { return false; } + + ReceiveFunctor* m_midiReceiver = nullptr; + + struct MIDIIn : public IMIDIIn { + MIDIIn(WAVOutVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) + : IMIDIIn(parent, virt, std::move(receiver)) {} + + std::string description() const { return "WAVOut MIDI"; } + }; + + std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) { + std::unique_ptr ret = std::make_unique(nullptr, true, std::move(receiver)); + m_midiReceiver = &ret->m_receiver; + return ret; + } + + std::unique_ptr newVirtualMIDIOut() { return {}; } + + std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) { return {}; } + + std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { return {}; } + + std::unique_ptr newRealMIDIOut(const char* name) { return {}; } + + std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { return {}; } + + bool useMIDILock() const { return false; } + + FILE* m_fp = nullptr; + size_t m_bytesWritten = 0; + + void prepareWAV(double sampleRate, int numChans) { + uint32_t speakerMask = 0; + + switch (numChans) { + default: + case 2: + numChans = 2; + m_mixInfo.m_channels = AudioChannelSet::Stereo; + m_mixInfo.m_channelMap.m_channelCount = 2; + m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + speakerMask = 0x00000001 | 0x00000002; + break; + case 4: + numChans = 4; + m_mixInfo.m_channels = AudioChannelSet::Quad; + m_mixInfo.m_channelMap.m_channelCount = 4; + m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::RearLeft; + m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::RearRight; + speakerMask = 0x00000001 | 0x00000002 | 0x00000010 | 0x00000020; + break; + case 6: + numChans = 6; + m_mixInfo.m_channels = AudioChannelSet::Surround51; + m_mixInfo.m_channelMap.m_channelCount = 6; + m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; + m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::LFE; + m_mixInfo.m_channelMap.m_channels[4] = AudioChannel::RearLeft; + m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight; + speakerMask = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020; + break; + case 8: + numChans = 8; + m_mixInfo.m_channels = AudioChannelSet::Surround71; + m_mixInfo.m_channelMap.m_channelCount = 8; + m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; + m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; + m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; + m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::LFE; + m_mixInfo.m_channelMap.m_channels[4] = AudioChannel::RearLeft; + m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight; + m_mixInfo.m_channelMap.m_channels[6] = AudioChannel::SideLeft; + m_mixInfo.m_channelMap.m_channels[7] = AudioChannel::SideRight; + speakerMask = + 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020 | 0x00000200 | 0x00000400; + break; } - std::string getCurrentAudioOutput() const - { - return "wavout"; + if (numChans == 2) { + fwrite("RIFF", 1, 4, m_fp); + uint32_t dataSize = 0; + uint32_t chunkSize = 36 + dataSize; + fwrite(&chunkSize, 1, 4, m_fp); + + fwrite("WAVE", 1, 4, m_fp); + + fwrite("fmt ", 1, 4, m_fp); + uint32_t sixteen = 16; + fwrite(&sixteen, 1, 4, m_fp); + uint16_t audioFmt = 3; + fwrite(&audioFmt, 1, 2, m_fp); + uint16_t chCount = numChans; + fwrite(&chCount, 1, 2, m_fp); + uint32_t sampRate = sampleRate; + fwrite(&sampRate, 1, 4, m_fp); + uint16_t blockAlign = 4 * numChans; + uint32_t byteRate = sampRate * blockAlign; + fwrite(&byteRate, 1, 4, m_fp); + fwrite(&blockAlign, 1, 2, m_fp); + uint16_t bps = 32; + fwrite(&bps, 1, 2, m_fp); + + fwrite("data", 1, 4, m_fp); + fwrite(&dataSize, 1, 4, m_fp); + } else { + fwrite("RIFF", 1, 4, m_fp); + uint32_t dataSize = 0; + uint32_t chunkSize = 60 + dataSize; + fwrite(&chunkSize, 1, 4, m_fp); + + fwrite("WAVE", 1, 4, m_fp); + + fwrite("fmt ", 1, 4, m_fp); + uint32_t forty = 40; + fwrite(&forty, 1, 4, m_fp); + uint16_t audioFmt = 0xFFFE; + fwrite(&audioFmt, 1, 2, m_fp); + uint16_t chCount = numChans; + fwrite(&chCount, 1, 2, m_fp); + uint32_t sampRate = sampleRate; + fwrite(&sampRate, 1, 4, m_fp); + uint16_t blockAlign = 4 * numChans; + uint32_t byteRate = sampRate * blockAlign; + fwrite(&byteRate, 1, 4, m_fp); + fwrite(&blockAlign, 1, 2, m_fp); + uint16_t bps = 32; + fwrite(&bps, 1, 2, m_fp); + uint16_t extSize = 22; + fwrite(&extSize, 1, 2, m_fp); + fwrite(&bps, 1, 2, m_fp); + fwrite(&speakerMask, 1, 4, m_fp); + fwrite("\x03\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, m_fp); + + fwrite("data", 1, 4, m_fp); + fwrite(&dataSize, 1, 4, m_fp); } - bool setCurrentAudioOutput(const char* name) - { - return false; - } + m_mixInfo.m_periodFrames = 512; + m_mixInfo.m_sampleRate = sampleRate; + m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; + m_mixInfo.m_bitsPerSample = 32; + _buildAudioRenderClient(); + } - std::vector> enumerateAudioOutputs() const - { - return {{"wavout", "WAVOut"}}; - } - - std::vector> enumerateMIDIInputs() const - { - return {}; - } - - bool supportsVirtualMIDIIn() const - { - return false; - } - - ReceiveFunctor* m_midiReceiver = nullptr; - - struct MIDIIn : public IMIDIIn - { - MIDIIn(WAVOutVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) - : IMIDIIn(parent, virt, std::move(receiver)) {} - - std::string description() const - { - return "WAVOut MIDI"; - } - }; - - std::unique_ptr newVirtualMIDIIn(ReceiveFunctor&& receiver) - { - std::unique_ptr ret = std::make_unique(nullptr, true, std::move(receiver)); - m_midiReceiver = &ret->m_receiver; - return ret; - } - - std::unique_ptr newVirtualMIDIOut() - { - return {}; - } - - std::unique_ptr newVirtualMIDIInOut(ReceiveFunctor&& receiver) - { - return {}; - } - - std::unique_ptr newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) - { - return {}; - } - - std::unique_ptr newRealMIDIOut(const char* name) - { - return {}; - } - - std::unique_ptr newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) - { - return {}; - } - - bool useMIDILock() const {return false;} - - FILE* m_fp = nullptr; - size_t m_bytesWritten = 0; - - void prepareWAV(double sampleRate, int numChans) - { - uint32_t speakerMask = 0; - - switch (numChans) - { - default: - case 2: - numChans = 2; - m_mixInfo.m_channels = AudioChannelSet::Stereo; - m_mixInfo.m_channelMap.m_channelCount = 2; - m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - speakerMask = 0x00000001 | 0x00000002; - break; - case 4: - numChans = 4; - m_mixInfo.m_channels = AudioChannelSet::Quad; - m_mixInfo.m_channelMap.m_channelCount = 4; - m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::RearLeft; - m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::RearRight; - speakerMask = 0x00000001 | 0x00000002 | 0x00000010 | 0x00000020; - break; - case 6: - numChans = 6; - m_mixInfo.m_channels = AudioChannelSet::Surround51; - m_mixInfo.m_channelMap.m_channelCount = 6; - m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; - m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::LFE; - m_mixInfo.m_channelMap.m_channels[4] = AudioChannel::RearLeft; - m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight; - speakerMask = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020; - break; - case 8: - numChans = 8; - m_mixInfo.m_channels = AudioChannelSet::Surround71; - m_mixInfo.m_channelMap.m_channelCount = 8; - m_mixInfo.m_channelMap.m_channels[0] = AudioChannel::FrontLeft; - m_mixInfo.m_channelMap.m_channels[1] = AudioChannel::FrontRight; - m_mixInfo.m_channelMap.m_channels[2] = AudioChannel::FrontCenter; - m_mixInfo.m_channelMap.m_channels[3] = AudioChannel::LFE; - m_mixInfo.m_channelMap.m_channels[4] = AudioChannel::RearLeft; - m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight; - m_mixInfo.m_channelMap.m_channels[6] = AudioChannel::SideLeft; - m_mixInfo.m_channelMap.m_channels[7] = AudioChannel::SideRight; - speakerMask = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020 | 0x00000200 | 0x00000400; - break; - } - - if (numChans == 2) - { - fwrite("RIFF", 1, 4, m_fp); - uint32_t dataSize = 0; - uint32_t chunkSize = 36 + dataSize; - fwrite(&chunkSize, 1, 4, m_fp); - - fwrite("WAVE", 1, 4, m_fp); - - fwrite("fmt ", 1, 4, m_fp); - uint32_t sixteen = 16; - fwrite(&sixteen, 1, 4, m_fp); - uint16_t audioFmt = 3; - fwrite(&audioFmt, 1, 2, m_fp); - uint16_t chCount = numChans; - fwrite(&chCount, 1, 2, m_fp); - uint32_t sampRate = sampleRate; - fwrite(&sampRate, 1, 4, m_fp); - uint16_t blockAlign = 4 * numChans; - uint32_t byteRate = sampRate * blockAlign; - fwrite(&byteRate, 1, 4, m_fp); - fwrite(&blockAlign, 1, 2, m_fp); - uint16_t bps = 32; - fwrite(&bps, 1, 2, m_fp); - - fwrite("data", 1, 4, m_fp); - fwrite(&dataSize, 1, 4, m_fp); - } - else - { - fwrite("RIFF", 1, 4, m_fp); - uint32_t dataSize = 0; - uint32_t chunkSize = 60 + dataSize; - fwrite(&chunkSize, 1, 4, m_fp); - - fwrite("WAVE", 1, 4, m_fp); - - fwrite("fmt ", 1, 4, m_fp); - uint32_t forty = 40; - fwrite(&forty, 1, 4, m_fp); - uint16_t audioFmt = 0xFFFE; - fwrite(&audioFmt, 1, 2, m_fp); - uint16_t chCount = numChans; - fwrite(&chCount, 1, 2, m_fp); - uint32_t sampRate = sampleRate; - fwrite(&sampRate, 1, 4, m_fp); - uint16_t blockAlign = 4 * numChans; - uint32_t byteRate = sampRate * blockAlign; - fwrite(&byteRate, 1, 4, m_fp); - fwrite(&blockAlign, 1, 2, m_fp); - uint16_t bps = 32; - fwrite(&bps, 1, 2, m_fp); - uint16_t extSize = 22; - fwrite(&extSize, 1, 2, m_fp); - fwrite(&bps, 1, 2, m_fp); - fwrite(&speakerMask, 1, 4, m_fp); - fwrite("\x03\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, m_fp); - - fwrite("data", 1, 4, m_fp); - fwrite(&dataSize, 1, 4, m_fp); - } - - m_mixInfo.m_periodFrames = 512; - m_mixInfo.m_sampleRate = sampleRate; - m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; - m_mixInfo.m_bitsPerSample = 32; - _buildAudioRenderClient(); - } - - WAVOutVoiceEngine(const char* path, double sampleRate, int numChans) - { - m_fp = fopen(path, "wb"); - if (!m_fp) - return; - prepareWAV(sampleRate, numChans); - } + WAVOutVoiceEngine(const char* path, double sampleRate, int numChans) { + m_fp = fopen(path, "wb"); + if (!m_fp) + return; + prepareWAV(sampleRate, numChans); + } #if _WIN32 - WAVOutVoiceEngine(const wchar_t* path, double sampleRate, int numChans) - { - m_fp = _wfopen(path, L"wb"); - if (!m_fp) - return; - prepareWAV(sampleRate, numChans); - } + WAVOutVoiceEngine(const wchar_t* path, double sampleRate, int numChans) { + m_fp = _wfopen(path, L"wb"); + if (!m_fp) + return; + prepareWAV(sampleRate, numChans); + } #endif - void finishWav() - { - uint32_t dataSize = m_bytesWritten; + void finishWav() { + uint32_t dataSize = m_bytesWritten; - if (m_mixInfo.m_channelMap.m_channelCount == 2) - { - fseek(m_fp, 4, SEEK_SET); - uint32_t chunkSize = 36 + dataSize; - fwrite(&chunkSize, 1, 4, m_fp); + if (m_mixInfo.m_channelMap.m_channelCount == 2) { + fseek(m_fp, 4, SEEK_SET); + uint32_t chunkSize = 36 + dataSize; + fwrite(&chunkSize, 1, 4, m_fp); - fseek(m_fp, 40, SEEK_SET); - fwrite(&dataSize, 1, 4, m_fp); - } - else - { - fseek(m_fp, 4, SEEK_SET); - uint32_t chunkSize = 60 + dataSize; - fwrite(&chunkSize, 1, 4, m_fp); + fseek(m_fp, 40, SEEK_SET); + fwrite(&dataSize, 1, 4, m_fp); + } else { + fseek(m_fp, 4, SEEK_SET); + uint32_t chunkSize = 60 + dataSize; + fwrite(&chunkSize, 1, 4, m_fp); - fseek(m_fp, 64, SEEK_SET); - fwrite(&dataSize, 1, 4, m_fp); - } - - fclose(m_fp); + fseek(m_fp, 64, SEEK_SET); + fwrite(&dataSize, 1, 4, m_fp); } - ~WAVOutVoiceEngine() - { - finishWav(); - } + fclose(m_fp); + } - void _buildAudioRenderClient() - { - m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000; - m_interleavedBuf.resize(m_mixInfo.m_channelMap.m_channelCount * m_5msFrames); - } + ~WAVOutVoiceEngine() { finishWav(); } - void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames) - { - m_mixInfo.m_periodFrames = periodFrames; - m_mixInfo.m_sampleRate = sampleRate; - _buildAudioRenderClient(); - _resetSampleRate(); - } + void _buildAudioRenderClient() { + m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000; + m_interleavedBuf.resize(m_mixInfo.m_channelMap.m_channelCount * m_5msFrames); + } - void pumpAndMixVoices() - { - size_t frameSz = 4 * m_mixInfo.m_channelMap.m_channelCount; - _pumpAndMixVoices(m_5msFrames, m_interleavedBuf.data()); - fwrite(m_interleavedBuf.data(), 1, m_5msFrames * frameSz, m_fp); - m_bytesWritten += m_5msFrames * frameSz; - } + void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames) { + m_mixInfo.m_periodFrames = periodFrames; + m_mixInfo.m_sampleRate = sampleRate; + _buildAudioRenderClient(); + _resetSampleRate(); + } + + void pumpAndMixVoices() { + size_t frameSz = 4 * m_mixInfo.m_channelMap.m_channelCount; + _pumpAndMixVoices(m_5msFrames, m_interleavedBuf.data()); + fwrite(m_interleavedBuf.data(), 1, m_5msFrames * frameSz, m_fp); + m_bytesWritten += m_5msFrames * frameSz; + } }; -std::unique_ptr NewWAVAudioVoiceEngine(const char* path, double sampleRate, int numChans) -{ - std::unique_ptr ret = std::make_unique(path, sampleRate, numChans); - if (!static_cast(*ret).m_fp) - return {}; - return ret; +std::unique_ptr NewWAVAudioVoiceEngine(const char* path, double sampleRate, int numChans) { + std::unique_ptr ret = std::make_unique(path, sampleRate, numChans); + if (!static_cast(*ret).m_fp) + return {}; + return ret; } #if _WIN32 -std::unique_ptr NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans) -{ - std::unique_ptr ret = std::make_unique(path, sampleRate, numChans); - if (!static_cast(*ret).m_fp) - return {}; - return ret; +std::unique_ptr NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans) { + std::unique_ptr ret = std::make_unique(path, sampleRate, numChans); + if (!static_cast(*ret).m_fp) + return {}; + return ret; } #endif -} +} // namespace boo diff --git a/lib/graphicsdev/Common.cpp b/lib/graphicsdev/Common.cpp index e0a696e..9e1e8a7 100644 --- a/lib/graphicsdev/Common.cpp +++ b/lib/graphicsdev/Common.cpp @@ -1,18 +1,15 @@ #include "Common.hpp" #include -namespace boo -{ +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(data)[i] = level * 65535.f; - } - tex->unmap(); +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(data)[i] = level * 65535.f; + } + tex->unmap(); } -} +} // namespace boo diff --git a/lib/graphicsdev/Common.hpp b/lib/graphicsdev/Common.hpp index a16e3b3..5fdd962 100644 --- a/lib/graphicsdev/Common.hpp +++ b/lib/graphicsdev/Common.hpp @@ -10,155 +10,185 @@ #include "boo/graphicsdev/IGraphicsDataFactory.hpp" #include "../Common.hpp" -namespace boo -{ +namespace boo { struct BaseGraphicsData; struct BaseGraphicsPool; -template +template 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; +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"); - } + ~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 -{ - static BaseGraphicsData*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_dataHead; } - static std::unique_lock _getHeadLock(GraphicsDataFactoryHead* head) - { return std::unique_lock{head->m_dataMutex}; } +struct BaseGraphicsData : ListNode { + static BaseGraphicsData*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_dataHead; } + static std::unique_lock _getHeadLock(GraphicsDataFactoryHead* head) { + return std::unique_lock{head->m_dataMutex}; + } - __BooTraceFields + __BooTraceFields - GraphicsDataNode* m_Ss = nullptr; - GraphicsDataNode* m_SPs = nullptr; - GraphicsDataNode* m_SBinds = nullptr; - GraphicsDataNode* m_SBufs = nullptr; - GraphicsDataNode* m_DBufs = nullptr; - GraphicsDataNode* m_STexs = nullptr; - GraphicsDataNode* m_SATexs = nullptr; - GraphicsDataNode* m_DTexs = nullptr; - GraphicsDataNode* m_RTexs = nullptr; - template GraphicsDataNode*& getHead(); - template size_t countForward() - { auto* head = getHead(); return head ? head->countForward() : 0; } - std::unique_lock destructorLock() override - { return std::unique_lock{m_head->m_dataMutex}; } + GraphicsDataNode* m_Ss = nullptr; + GraphicsDataNode* m_SPs = nullptr; + GraphicsDataNode* m_SBinds = nullptr; + GraphicsDataNode* m_SBufs = nullptr; + GraphicsDataNode* m_DBufs = nullptr; + GraphicsDataNode* m_STexs = nullptr; + GraphicsDataNode* m_SATexs = nullptr; + GraphicsDataNode* m_DTexs = nullptr; + GraphicsDataNode* m_RTexs = nullptr; + template + GraphicsDataNode*& getHead(); + template + size_t countForward() { + auto* head = getHead(); + return head ? head->countForward() : 0; + } + std::unique_lock destructorLock() override { + return std::unique_lock{m_head->m_dataMutex}; + } - explicit BaseGraphicsData(GraphicsDataFactoryHead& head __BooTraceArgs) - : ListNode(&head) __BooTraceInitializer - {} + explicit BaseGraphicsData(GraphicsDataFactoryHead& head __BooTraceArgs) + : ListNode(&head) __BooTraceInitializer {} }; -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_Ss; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_SPs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_SBinds; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_SBufs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_DBufs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_STexs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_SATexs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_DTexs; } -template <> inline GraphicsDataNode*& -BaseGraphicsData::getHead() { return m_RTexs; } +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_Ss; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_SPs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_SBinds; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_SBufs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_DBufs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_STexs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_SATexs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_DTexs; +} +template <> +inline GraphicsDataNode*& BaseGraphicsData::getHead() { + return m_RTexs; +} /** Private generalized pool container class. * Keeps head pointer to exactly one dynamic buffer while otherwise conforming to BaseGraphicsData */ -struct BaseGraphicsPool : ListNode -{ - static BaseGraphicsPool*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_poolHead; } - static std::unique_lock _getHeadLock(GraphicsDataFactoryHead* head) - { return std::unique_lock{head->m_dataMutex}; } +struct BaseGraphicsPool : ListNode { + static BaseGraphicsPool*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_poolHead; } + static std::unique_lock _getHeadLock(GraphicsDataFactoryHead* head) { + return std::unique_lock{head->m_dataMutex}; + } - __BooTraceFields + __BooTraceFields - GraphicsDataNode* m_DBufs = nullptr; - template GraphicsDataNode*& getHead(); - template size_t countForward() - { auto* head = getHead(); return head ? head->countForward() : 0; } - std::unique_lock destructorLock() override - { return std::unique_lock{m_head->m_dataMutex}; } + GraphicsDataNode* m_DBufs = nullptr; + template + GraphicsDataNode*& getHead(); + template + size_t countForward() { + auto* head = getHead(); + return head ? head->countForward() : 0; + } + std::unique_lock destructorLock() override { + return std::unique_lock{m_head->m_dataMutex}; + } - explicit BaseGraphicsPool(GraphicsDataFactoryHead& head __BooTraceArgs) - : ListNode(&head) __BooTraceInitializer - {} + explicit BaseGraphicsPool(GraphicsDataFactoryHead& head __BooTraceArgs) + : ListNode(&head) __BooTraceInitializer {} }; -template <> inline GraphicsDataNode*& -BaseGraphicsPool::getHead() { return m_DBufs; } +template <> +inline GraphicsDataNode*& BaseGraphicsPool::getHead() { + 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 -struct GraphicsDataNode : ListNode, ObjToken, NodeCls> -{ - using base = ListNode, ObjToken, NodeCls>; - static GraphicsDataNode*& _getHeadPtr(ObjToken& head) - { return head->template getHead(); } - static std::unique_lock _getHeadLock(ObjToken& head) - { return std::unique_lock{head->m_head->m_dataMutex}; } +template +struct GraphicsDataNode : ListNode, ObjToken, NodeCls> { + using base = ListNode, ObjToken, NodeCls>; + static GraphicsDataNode*& _getHeadPtr(ObjToken& head) { + return head->template getHead(); + } + static std::unique_lock _getHeadLock(ObjToken& head) { + return std::unique_lock{head->m_head->m_dataMutex}; + } - std::unique_lock destructorLock() override - { return std::unique_lock{base::m_head->m_head->m_dataMutex}; } + std::unique_lock destructorLock() override { + return std::unique_lock{base::m_head->m_head->m_dataMutex}; + } - explicit GraphicsDataNode(const ObjToken& data) - : ListNode, ObjToken, NodeCls>(data) - {} + explicit GraphicsDataNode(const ObjToken& data) + : ListNode, ObjToken, NodeCls>(data) {} - class iterator - { - GraphicsDataNode* 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&; + class iterator { + GraphicsDataNode* m_node; - explicit iterator(GraphicsDataNode* 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; } - }; + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = NodeCls; + using difference_type = std::ptrdiff_t; + using pointer = NodeCls*; + using reference = NodeCls&; - iterator begin() { return iterator(this); } - iterator end() { return iterator(nullptr); } - - size_t countForward() - { - size_t ret = 0; - for (auto& n : *this) - ++ret; - return ret; + explicit iterator(GraphicsDataNode* 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); -} - +} // namespace boo diff --git a/lib/graphicsdev/D3D11.cpp b/lib/graphicsdev/D3D11.cpp index 8a315c9..4fa897e 100644 --- a/lib/graphicsdev/D3D11.cpp +++ b/lib/graphicsdev/D3D11.cpp @@ -20,1380 +20,1144 @@ extern pD3DCompile D3DCompilePROC; static const char* GammaVS = -"struct VertData\n" -"{\n" -" float4 posIn : POSITION;\n" -" float4 uvIn : UV;\n" -"};\n" -"\n" -"struct VertToFrag\n" -"{\n" -" float4 pos : SV_Position;\n" -" float2 uv : UV;\n" -"};\n" -"\n" -"VertToFrag main(in VertData v)\n" -"{\n" -" VertToFrag vtf;\n" -" vtf.uv = v.uvIn.xy;\n" -" vtf.pos = v.posIn;\n" -" return vtf;\n" -"}\n"; + "struct VertData\n" + "{\n" + " float4 posIn : POSITION;\n" + " float4 uvIn : UV;\n" + "};\n" + "\n" + "struct VertToFrag\n" + "{\n" + " float4 pos : SV_Position;\n" + " float2 uv : UV;\n" + "};\n" + "\n" + "VertToFrag main(in VertData v)\n" + "{\n" + " VertToFrag vtf;\n" + " vtf.uv = v.uvIn.xy;\n" + " vtf.pos = v.posIn;\n" + " return vtf;\n" + "}\n"; static const char* GammaFS = -"struct VertToFrag\n" -"{\n" -" float4 pos : SV_Position;\n" -" float2 uv : UV;\n" -"};\n" -"\n" -"Texture2D screenTex : register(t0);\n" -"Texture2D gammaLUT : register(t1);\n" -"SamplerState samp : register(s3);\n" -"float4 main(in VertToFrag vtf) : SV_Target0\n" -"{\n" -" int4 tex = int4(saturate(screenTex.Sample(samp, vtf.uv)) * float4(65535.0, 65535.0, 65535.0, 65535.0));\n" -" float4 colorOut;\n" -" for (int i=0 ; i<3 ; ++i)\n" -" colorOut[i] = gammaLUT.Load(int3(tex[i] % 256, tex[i] / 256, 0)).r;\n" -" return colorOut;\n" -"}\n"; + "struct VertToFrag\n" + "{\n" + " float4 pos : SV_Position;\n" + " float2 uv : UV;\n" + "};\n" + "\n" + "Texture2D screenTex : register(t0);\n" + "Texture2D gammaLUT : register(t1);\n" + "SamplerState samp : register(s3);\n" + "float4 main(in VertToFrag vtf) : SV_Target0\n" + "{\n" + " int4 tex = int4(saturate(screenTex.Sample(samp, vtf.uv)) * float4(65535.0, 65535.0, 65535.0, 65535.0));\n" + " float4 colorOut;\n" + " for (int i=0 ; i<3 ; ++i)\n" + " colorOut[i] = gammaLUT.Load(int3(tex[i] % 256, tex[i] / 256, 0)).r;\n" + " return colorOut;\n" + "}\n"; -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::D3D11"); class D3D11DataFactory; -static inline void ThrowIfFailed(HRESULT hr) -{ - if (FAILED(hr)) - { - // Set a breakpoint on this line to catch Win32 API errors. +static inline void ThrowIfFailed(HRESULT hr) { + if (FAILED(hr)) { + // Set a breakpoint on this line to catch Win32 API errors. #if !WINDOWS_STORE - _com_error err(hr); + _com_error err(hr); #else - _com_error err(hr, L"D3D11 fail"); + _com_error err(hr, L"D3D11 fail"); #endif - LPCTSTR errMsg = err.ErrorMessage(); - Log.report(logvisor::Fatal, errMsg); - } + LPCTSTR errMsg = err.ErrorMessage(); + Log.report(logvisor::Fatal, errMsg); + } } -static const D3D11_BIND_FLAG USE_TABLE[] = -{ - D3D11_BIND_VERTEX_BUFFER, - D3D11_BIND_VERTEX_BUFFER, - D3D11_BIND_INDEX_BUFFER, - D3D11_BIND_CONSTANT_BUFFER -}; +static const D3D11_BIND_FLAG USE_TABLE[] = {D3D11_BIND_VERTEX_BUFFER, D3D11_BIND_VERTEX_BUFFER, D3D11_BIND_INDEX_BUFFER, + D3D11_BIND_CONSTANT_BUFFER}; -class D3D11GraphicsBufferS : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; - friend struct D3D11CommandQueue; +class D3D11GraphicsBufferS : public GraphicsDataNode { + friend class D3D11DataFactory::Context; + friend struct D3D11CommandQueue; + + size_t m_sz; + D3D11GraphicsBufferS(const boo::ObjToken& parent, BufferUse use, D3D11Context* ctx, + const void* data, size_t stride, size_t count) + : GraphicsDataNode(parent), m_sz(stride * count), m_stride(stride), m_count(count) { + D3D11_SUBRESOURCE_DATA iData = {data}; + CD3D11_BUFFER_DESC desc(m_sz, USE_TABLE[int(use)], D3D11_USAGE_IMMUTABLE); + ThrowIfFailed(ctx->m_dev->CreateBuffer(&desc, &iData, &m_buf)); + } - size_t m_sz; - D3D11GraphicsBufferS(const boo::ObjToken& parent, - BufferUse use, D3D11Context* ctx, - const void* data, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_sz(stride * count), m_stride(stride), m_count(count) - { - D3D11_SUBRESOURCE_DATA iData = {data}; - CD3D11_BUFFER_DESC desc(m_sz, USE_TABLE[int(use)], D3D11_USAGE_IMMUTABLE); - ThrowIfFailed(ctx->m_dev->CreateBuffer(&desc, &iData, &m_buf)); - } public: - size_t m_stride; - size_t m_count; - ComPtr m_buf; - ~D3D11GraphicsBufferS() = default; + size_t m_stride; + size_t m_count; + ComPtr m_buf; + ~D3D11GraphicsBufferS() = default; }; template -class D3D11GraphicsBufferD : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; - friend class D3D11DataFactoryImpl; - friend struct D3D11CommandQueue; +class D3D11GraphicsBufferD : public GraphicsDataNode { + friend class D3D11DataFactory::Context; + friend class D3D11DataFactoryImpl; + friend struct D3D11CommandQueue; - D3D11CommandQueue* m_q; - std::unique_ptr m_cpuBuf; - size_t m_cpuSz; - int m_validSlots = 0; - D3D11GraphicsBufferD(const boo::ObjToken& parent, - D3D11CommandQueue* q, BufferUse use, - D3D11Context* ctx, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_q(q), m_stride(stride), m_count(count) - { - m_cpuSz = stride * count; - m_cpuBuf.reset(new uint8_t[m_cpuSz]); - for (int i=0 ; i<3 ; ++i) - { - CD3D11_BUFFER_DESC desc(m_cpuSz, USE_TABLE[int(use)], - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - ThrowIfFailed(ctx->m_dev->CreateBuffer(&desc, nullptr, &m_bufs[i])); - } + D3D11CommandQueue* m_q; + std::unique_ptr m_cpuBuf; + size_t m_cpuSz; + int m_validSlots = 0; + D3D11GraphicsBufferD(const boo::ObjToken& parent, D3D11CommandQueue* q, BufferUse use, D3D11Context* ctx, + size_t stride, size_t count) + : GraphicsDataNode(parent), m_q(q), m_stride(stride), m_count(count) { + m_cpuSz = stride * count; + m_cpuBuf.reset(new uint8_t[m_cpuSz]); + for (int i = 0; i < 3; ++i) { + CD3D11_BUFFER_DESC desc(m_cpuSz, USE_TABLE[int(use)], D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + ThrowIfFailed(ctx->m_dev->CreateBuffer(&desc, nullptr, &m_bufs[i])); } - void update(ID3D11DeviceContext* ctx, int b); -public: - size_t m_stride; - size_t m_count; - ComPtr m_bufs[3]; - ~D3D11GraphicsBufferD() = default; + } + void update(ID3D11DeviceContext* ctx, int b); - void load(const void* data, size_t sz); - void* map(size_t sz); - void unmap(); +public: + size_t m_stride; + size_t m_count; + ComPtr m_bufs[3]; + ~D3D11GraphicsBufferD() = default; + + void load(const void* data, size_t sz); + void* map(size_t sz); + void unmap(); }; -class D3D11TextureS : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; +class D3D11TextureS : public GraphicsDataNode { + friend class D3D11DataFactory::Context; - D3D11TextureS(const boo::ObjToken& parent, - D3D11Context* ctx, size_t width, size_t height, size_t mips, - TextureFormat fmt, const void* data, size_t sz) - : GraphicsDataNode(parent) - { - DXGI_FORMAT pfmt = DXGI_FORMAT_UNKNOWN; - int pxPitchNum = 1; - int pxPitchDenom = 1; - bool compressed = false; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = DXGI_FORMAT_R8G8B8A8_UNORM; - pxPitchNum = 4; - break; - case TextureFormat::I8: - pfmt = DXGI_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pfmt = DXGI_FORMAT_R16_UNORM; - pxPitchNum = 2; - break; - case TextureFormat::DXT1: - pfmt = DXGI_FORMAT_BC1_UNORM; - compressed = true; - pxPitchNum = 1; - pxPitchDenom = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - - CD3D11_TEXTURE2D_DESC desc(pfmt, width, height, 1, mips, - D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE); - - const uint8_t* dataIt = static_cast(data); - D3D11_SUBRESOURCE_DATA upData[16] = {}; - for (size_t i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - } - - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, upData, &m_tex)); - CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_tex.Get(), D3D_SRV_DIMENSION_TEXTURE2D, pfmt, 0, mips); - ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_tex.Get(), &srvDesc, &m_srv)); + D3D11TextureS(const boo::ObjToken& parent, D3D11Context* ctx, size_t width, size_t height, + size_t mips, TextureFormat fmt, const void* data, size_t sz) + : GraphicsDataNode(parent) { + DXGI_FORMAT pfmt = DXGI_FORMAT_UNKNOWN; + int pxPitchNum = 1; + int pxPitchDenom = 1; + bool compressed = false; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = DXGI_FORMAT_R8G8B8A8_UNORM; + pxPitchNum = 4; + break; + case TextureFormat::I8: + pfmt = DXGI_FORMAT_R8_UNORM; + break; + case TextureFormat::I16: + pfmt = DXGI_FORMAT_R16_UNORM; + pxPitchNum = 2; + break; + case TextureFormat::DXT1: + pfmt = DXGI_FORMAT_BC1_UNORM; + compressed = true; + pxPitchNum = 1; + pxPitchDenom = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); } + + CD3D11_TEXTURE2D_DESC desc(pfmt, width, height, 1, mips, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE); + + const uint8_t* dataIt = static_cast(data); + D3D11_SUBRESOURCE_DATA upData[16] = {}; + for (size_t i = 0; i < mips && i < 16; ++i) { + upData[i].pSysMem = dataIt; + upData[i].SysMemPitch = width * pxPitchNum / pxPitchDenom; + upData[i].SysMemSlicePitch = upData[i].SysMemPitch * height; + if (compressed) + upData[i].SysMemPitch = width * 2; + dataIt += upData[i].SysMemSlicePitch; + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + } + + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, upData, &m_tex)); + CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_tex.Get(), D3D_SRV_DIMENSION_TEXTURE2D, pfmt, 0, mips); + ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_tex.Get(), &srvDesc, &m_srv)); + } + public: - ComPtr m_tex; - ComPtr m_srv; - ~D3D11TextureS() = default; + ComPtr m_tex; + ComPtr m_srv; + ~D3D11TextureS() = default; }; -class D3D11TextureSA : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; +class D3D11TextureSA : public GraphicsDataNode { + friend class D3D11DataFactory::Context; - D3D11TextureSA(const boo::ObjToken& parent, - D3D11Context* ctx, size_t width, size_t height, size_t layers, - size_t mips, TextureFormat fmt, const void* data, size_t sz) - : GraphicsDataNode(parent) - { - size_t pixelPitch = 0; - DXGI_FORMAT pixelFmt = DXGI_FORMAT_UNKNOWN; - switch (fmt) - { - case TextureFormat::RGBA8: - pixelPitch = 4; - pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM; - break; - case TextureFormat::I8: - pixelPitch = 1; - pixelFmt = DXGI_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pixelPitch = 2; - pixelFmt = DXGI_FORMAT_R16_UNORM; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - - CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, layers, mips, - D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_IMMUTABLE); - - const uint8_t* dataIt = static_cast(data); - std::unique_ptr upData(new D3D11_SUBRESOURCE_DATA[layers * mips]); - D3D11_SUBRESOURCE_DATA* outIt = upData.get(); - for (size_t i=0 ; ipSysMem = dataIt; - outIt->SysMemPitch = width * pixelPitch; - outIt->SysMemSlicePitch = outIt->SysMemPitch * height; - dataIt += outIt->SysMemSlicePitch; - ++outIt; - } - if (width > 1) - width /= 2; - if (height > 1) - height /= 2; - } - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, upData.get(), &m_tex)); - - CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_tex.Get(), D3D_SRV_DIMENSION_TEXTURE2DARRAY, pixelFmt); - ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_tex.Get(), &srvDesc, &m_srv)); + D3D11TextureSA(const boo::ObjToken& parent, D3D11Context* ctx, size_t width, size_t height, + size_t layers, size_t mips, TextureFormat fmt, const void* data, size_t sz) + : GraphicsDataNode(parent) { + size_t pixelPitch = 0; + DXGI_FORMAT pixelFmt = DXGI_FORMAT_UNKNOWN; + switch (fmt) { + case TextureFormat::RGBA8: + pixelPitch = 4; + pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case TextureFormat::I8: + pixelPitch = 1; + pixelFmt = DXGI_FORMAT_R8_UNORM; + break; + case TextureFormat::I16: + pixelPitch = 2; + pixelFmt = DXGI_FORMAT_R16_UNORM; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); } + + CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, layers, mips, D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_IMMUTABLE); + + const uint8_t* dataIt = static_cast(data); + std::unique_ptr upData(new D3D11_SUBRESOURCE_DATA[layers * mips]); + D3D11_SUBRESOURCE_DATA* outIt = upData.get(); + for (size_t i = 0; i < mips; ++i) { + for (size_t j = 0; j < layers; ++j) { + outIt->pSysMem = dataIt; + outIt->SysMemPitch = width * pixelPitch; + outIt->SysMemSlicePitch = outIt->SysMemPitch * height; + dataIt += outIt->SysMemSlicePitch; + ++outIt; + } + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + } + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, upData.get(), &m_tex)); + + CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_tex.Get(), D3D_SRV_DIMENSION_TEXTURE2DARRAY, pixelFmt); + ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_tex.Get(), &srvDesc, &m_srv)); + } + public: - ComPtr m_tex; - ComPtr m_srv; - ~D3D11TextureSA() = default; + ComPtr m_tex; + ComPtr m_srv; + ~D3D11TextureSA() = default; }; -class D3D11TextureD : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; - friend struct D3D11CommandQueue; +class D3D11TextureD : public GraphicsDataNode { + friend class D3D11DataFactory::Context; + friend struct D3D11CommandQueue; - size_t m_width = 0; - D3D11CommandQueue* m_q; - std::unique_ptr m_cpuBuf; - size_t m_cpuSz; - size_t m_pxPitch; - int m_validSlots = 0; - D3D11TextureD(const boo::ObjToken& parent, - D3D11CommandQueue* q, D3D11Context* ctx, - size_t width, size_t height, TextureFormat fmt) - : GraphicsDataNode(parent), m_width(width), m_q(q) - { - DXGI_FORMAT pixelFmt = DXGI_FORMAT_UNKNOWN; - switch (fmt) - { - case TextureFormat::RGBA8: - pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM; - m_pxPitch = 4; - break; - case TextureFormat::I8: - pixelFmt = DXGI_FORMAT_R8_UNORM; - m_pxPitch = 1; - break; - case TextureFormat::I16: - pixelFmt = DXGI_FORMAT_R16_UNORM; - m_pxPitch = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - - m_cpuSz = width * height * m_pxPitch; - m_cpuBuf.reset(new uint8_t[m_cpuSz]); - - CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, 1, 1, - D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - for (int i=0 ; i<3 ; ++i) - { - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, nullptr, &m_texs[i])); - CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_texs[i].Get(), D3D_SRV_DIMENSION_TEXTURE2D, pixelFmt); - ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_texs[i].Get(), &srvDesc, &m_srvs[i])); - } + size_t m_width = 0; + D3D11CommandQueue* m_q; + std::unique_ptr m_cpuBuf; + size_t m_cpuSz; + size_t m_pxPitch; + int m_validSlots = 0; + D3D11TextureD(const boo::ObjToken& parent, D3D11CommandQueue* q, D3D11Context* ctx, size_t width, + size_t height, TextureFormat fmt) + : GraphicsDataNode(parent), m_width(width), m_q(q) { + DXGI_FORMAT pixelFmt = DXGI_FORMAT_UNKNOWN; + switch (fmt) { + case TextureFormat::RGBA8: + pixelFmt = DXGI_FORMAT_R8G8B8A8_UNORM; + m_pxPitch = 4; + break; + case TextureFormat::I8: + pixelFmt = DXGI_FORMAT_R8_UNORM; + m_pxPitch = 1; + break; + case TextureFormat::I16: + pixelFmt = DXGI_FORMAT_R16_UNORM; + m_pxPitch = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); } - void update(ID3D11DeviceContext* ctx, int b); -public: - ComPtr m_texs[3]; - ComPtr m_srvs[3]; - ~D3D11TextureD() = default; - void load(const void* data, size_t sz); - void* map(size_t sz); - void unmap(); + m_cpuSz = width * height * m_pxPitch; + m_cpuBuf.reset(new uint8_t[m_cpuSz]); + + CD3D11_TEXTURE2D_DESC desc(pixelFmt, width, height, 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, + D3D11_CPU_ACCESS_WRITE); + for (int i = 0; i < 3; ++i) { + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&desc, nullptr, &m_texs[i])); + CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(m_texs[i].Get(), D3D_SRV_DIMENSION_TEXTURE2D, pixelFmt); + ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_texs[i].Get(), &srvDesc, &m_srvs[i])); + } + } + void update(ID3D11DeviceContext* ctx, int b); + +public: + ComPtr m_texs[3]; + ComPtr m_srvs[3]; + ~D3D11TextureD() = default; + + void load(const void* data, size_t sz); + void* map(size_t sz); + void unmap(); }; #define MAX_BIND_TEXS 4 -class D3D11TextureR : public GraphicsDataNode -{ - friend class D3D11DataFactory::Context; - friend struct D3D11CommandQueue; +class D3D11TextureR : public GraphicsDataNode { + friend class D3D11DataFactory::Context; + friend struct D3D11CommandQueue; - size_t m_width = 0; - size_t m_height = 0; - size_t m_samples = 0; - size_t m_colorBindCount; - size_t m_depthBindCount; + size_t m_width = 0; + size_t m_height = 0; + size_t m_samples = 0; + size_t m_colorBindCount; + size_t m_depthBindCount; - void Setup(D3D11Context* ctx) - { - CD3D11_TEXTURE2D_DESC colorDesc(ctx->m_fbFormat, m_width, m_height, - 1, 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, m_samples); - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&colorDesc, nullptr, &m_colorTex)); - CD3D11_TEXTURE2D_DESC depthDesc(DXGI_FORMAT_D32_FLOAT, m_width, m_height, - 1, 1, D3D11_BIND_DEPTH_STENCIL, D3D11_USAGE_DEFAULT, 0, m_samples); - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&depthDesc, nullptr, &m_depthTex)); + void Setup(D3D11Context* ctx) { + CD3D11_TEXTURE2D_DESC colorDesc(ctx->m_fbFormat, m_width, m_height, 1, 1, D3D11_BIND_RENDER_TARGET, + D3D11_USAGE_DEFAULT, 0, m_samples); + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&colorDesc, nullptr, &m_colorTex)); + CD3D11_TEXTURE2D_DESC depthDesc(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 1, D3D11_BIND_DEPTH_STENCIL, + D3D11_USAGE_DEFAULT, 0, m_samples); + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&depthDesc, nullptr, &m_depthTex)); - D3D11_RTV_DIMENSION rtvDim; - D3D11_DSV_DIMENSION dsvDim; + D3D11_RTV_DIMENSION rtvDim; + D3D11_DSV_DIMENSION dsvDim; - if (m_samples > 1) - { - rtvDim = D3D11_RTV_DIMENSION_TEXTURE2DMS; - dsvDim = D3D11_DSV_DIMENSION_TEXTURE2DMS; - } - else - { - rtvDim = D3D11_RTV_DIMENSION_TEXTURE2D; - dsvDim = D3D11_DSV_DIMENSION_TEXTURE2D; - } - - CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(m_colorTex.Get(), rtvDim); - ThrowIfFailed(ctx->m_dev->CreateRenderTargetView(m_colorTex.Get(), &rtvDesc, &m_rtv)); - CD3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc(m_depthTex.Get(), dsvDim); - ThrowIfFailed(ctx->m_dev->CreateDepthStencilView(m_depthTex.Get(), &dsvDesc, &m_dsv)); - - for (size_t i=0 ; im_fbFormat, m_width, m_height, - 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1); - ThrowIfFailed(ctx->m_dev->CreateTexture2D(&colorBindDesc, nullptr, &m_colorBindTex[i])); - CD3D11_SHADER_RESOURCE_VIEW_DESC colorSrvDesc(m_colorBindTex[i].Get(), D3D11_SRV_DIMENSION_TEXTURE2D); - ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_colorBindTex[i].Get(), &colorSrvDesc, &m_colorSrv[i])); - } - - for (size_t i=0 ; im_dev->CreateTexture2D(&depthBindDesc, nullptr, &m_depthBindTex[i])); - CD3D11_SHADER_RESOURCE_VIEW_DESC depthSrvDesc(m_depthBindTex[i].Get(), D3D11_SRV_DIMENSION_TEXTURE2D, - DXGI_FORMAT_R32_FLOAT); - ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_depthBindTex[i].Get(), &depthSrvDesc, &m_depthSrv[i])); - } + if (m_samples > 1) { + rtvDim = D3D11_RTV_DIMENSION_TEXTURE2DMS; + dsvDim = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } else { + rtvDim = D3D11_RTV_DIMENSION_TEXTURE2D; + dsvDim = D3D11_DSV_DIMENSION_TEXTURE2D; } - D3D11TextureR(const boo::ObjToken& parent, - D3D11Context* ctx, size_t width, size_t height, size_t samples, - size_t colorBindCount, size_t depthBindCount) - : GraphicsDataNode(parent), m_width(width), m_height(height), m_samples(samples), - m_colorBindCount(colorBindCount), m_depthBindCount(depthBindCount) - { - if (colorBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many color bindings for render texture"); - if (depthBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many depth bindings for render texture"); + CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(m_colorTex.Get(), rtvDim); + ThrowIfFailed(ctx->m_dev->CreateRenderTargetView(m_colorTex.Get(), &rtvDesc, &m_rtv)); + CD3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc(m_depthTex.Get(), dsvDim); + ThrowIfFailed(ctx->m_dev->CreateDepthStencilView(m_depthTex.Get(), &dsvDesc, &m_dsv)); - if (samples == 0) m_samples = 1; - Setup(ctx); + for (size_t i = 0; i < m_colorBindCount; ++i) { + CD3D11_TEXTURE2D_DESC colorBindDesc(ctx->m_fbFormat, m_width, m_height, 1, 1, D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DEFAULT, 0, 1); + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&colorBindDesc, nullptr, &m_colorBindTex[i])); + CD3D11_SHADER_RESOURCE_VIEW_DESC colorSrvDesc(m_colorBindTex[i].Get(), D3D11_SRV_DIMENSION_TEXTURE2D); + ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_colorBindTex[i].Get(), &colorSrvDesc, &m_colorSrv[i])); } + + for (size_t i = 0; i < m_depthBindCount; ++i) { + CD3D11_TEXTURE2D_DESC depthBindDesc(DXGI_FORMAT_R32_FLOAT, m_width, m_height, 1, 1, D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DEFAULT, 0, 1); + ThrowIfFailed(ctx->m_dev->CreateTexture2D(&depthBindDesc, nullptr, &m_depthBindTex[i])); + CD3D11_SHADER_RESOURCE_VIEW_DESC depthSrvDesc(m_depthBindTex[i].Get(), D3D11_SRV_DIMENSION_TEXTURE2D, + DXGI_FORMAT_R32_FLOAT); + ThrowIfFailed(ctx->m_dev->CreateShaderResourceView(m_depthBindTex[i].Get(), &depthSrvDesc, &m_depthSrv[i])); + } + } + + D3D11TextureR(const boo::ObjToken& parent, D3D11Context* ctx, size_t width, size_t height, + size_t samples, size_t colorBindCount, size_t depthBindCount) + : GraphicsDataNode(parent) + , m_width(width) + , m_height(height) + , m_samples(samples) + , m_colorBindCount(colorBindCount) + , m_depthBindCount(depthBindCount) { + if (colorBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many color bindings for render texture"); + if (depthBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many depth bindings for render texture"); + + if (samples == 0) + m_samples = 1; + Setup(ctx); + } + public: - size_t samples() const {return m_samples;} - ComPtr m_colorTex; - ComPtr m_rtv; + size_t samples() const { return m_samples; } + ComPtr m_colorTex; + ComPtr m_rtv; - ComPtr m_depthTex; - ComPtr m_dsv; + ComPtr m_depthTex; + ComPtr m_dsv; - ComPtr m_colorBindTex[MAX_BIND_TEXS]; - ComPtr m_colorSrv[MAX_BIND_TEXS]; + ComPtr m_colorBindTex[MAX_BIND_TEXS]; + ComPtr m_colorSrv[MAX_BIND_TEXS]; - ComPtr m_depthBindTex[MAX_BIND_TEXS]; - ComPtr m_depthSrv[MAX_BIND_TEXS]; + ComPtr m_depthBindTex[MAX_BIND_TEXS]; + ComPtr m_depthSrv[MAX_BIND_TEXS]; - ~D3D11TextureR() = default; + ~D3D11TextureR() = default; - void resize(D3D11Context* ctx, size_t width, size_t height) - { - if (width < 1) - width = 1; - if (height < 1) - height = 1; - m_width = width; - m_height = height; - Setup(ctx); + void resize(D3D11Context* ctx, size_t width, size_t height) { + if (width < 1) + width = 1; + if (height < 1) + height = 1; + m_width = width; + m_height = height; + Setup(ctx); + } +}; + +static const size_t SEMANTIC_SIZE_TABLE[] = {0, 12, 16, 12, 16, 16, 4, 8, 16, 16, 16}; + +static const char* SEMANTIC_NAME_TABLE[] = {nullptr, "POSITION", "POSITION", "NORMAL", "NORMAL", "COLOR", + "COLOR", "UV", "UV", "WEIGHT", "MODELVIEW"}; + +static const DXGI_FORMAT SEMANTIC_TYPE_TABLE[] = {DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT}; + +static const D3D11_PRIMITIVE_TOPOLOGY PRIMITIVE_TABLE[] = {D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST}; + +static const D3D11_BLEND BLEND_FACTOR_TABLE[] = { + D3D11_BLEND_ZERO, D3D11_BLEND_ONE, D3D11_BLEND_SRC_COLOR, + D3D11_BLEND_INV_SRC_COLOR, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_DEST_ALPHA, + D3D11_BLEND_INV_DEST_ALPHA, D3D11_BLEND_SRC1_COLOR, D3D11_BLEND_INV_SRC1_COLOR}; + +class D3D11ShaderStage : public GraphicsDataNode { + friend class D3D11DataFactory; + ComPtr m_shader; + D3D11ShaderStage(const boo::ObjToken& parent, D3D11Context* ctx, const uint8_t* data, size_t size, + PipelineStage stage) + : GraphicsDataNode(parent) { + switch (stage) { + case PipelineStage::Vertex: { + ThrowIfFailed(D3DCreateBlobPROC(size, &m_vtxBlob)); + memcpy(m_vtxBlob->GetBufferPointer(), data, size); + ComPtr vShader; + ThrowIfFailed(ctx->m_dev->CreateVertexShader(data, size, nullptr, &vShader)); + m_shader = vShader; + break; } -}; - -static const size_t SEMANTIC_SIZE_TABLE[] = -{ - 0, - 12, - 16, - 12, - 16, - 16, - 4, - 8, - 16, - 16, - 16 -}; - -static const char* SEMANTIC_NAME_TABLE[] = -{ - nullptr, - "POSITION", - "POSITION", - "NORMAL", - "NORMAL", - "COLOR", - "COLOR", - "UV", - "UV", - "WEIGHT", - "MODELVIEW" -}; - -static const DXGI_FORMAT SEMANTIC_TYPE_TABLE[] = -{ - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_R32G32B32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R32G32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT -}; - -static const D3D11_PRIMITIVE_TOPOLOGY PRIMITIVE_TABLE[] = -{ - D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, - D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST -}; - -static const D3D11_BLEND BLEND_FACTOR_TABLE[] = -{ - D3D11_BLEND_ZERO, - D3D11_BLEND_ONE, - D3D11_BLEND_SRC_COLOR, - D3D11_BLEND_INV_SRC_COLOR, - D3D11_BLEND_DEST_COLOR, - D3D11_BLEND_INV_DEST_COLOR, - D3D11_BLEND_SRC_ALPHA, - D3D11_BLEND_INV_SRC_ALPHA, - D3D11_BLEND_DEST_ALPHA, - D3D11_BLEND_INV_DEST_ALPHA, - D3D11_BLEND_SRC1_COLOR, - D3D11_BLEND_INV_SRC1_COLOR -}; - -class D3D11ShaderStage : public GraphicsDataNode -{ - friend class D3D11DataFactory; - ComPtr m_shader; - D3D11ShaderStage(const boo::ObjToken& parent, D3D11Context* ctx, - const uint8_t* data, size_t size, PipelineStage stage) - : GraphicsDataNode(parent) - { - switch (stage) - { - case PipelineStage::Vertex: - { - ThrowIfFailed(D3DCreateBlobPROC(size, &m_vtxBlob)); - memcpy(m_vtxBlob->GetBufferPointer(), data, size); - ComPtr vShader; - ThrowIfFailed(ctx->m_dev->CreateVertexShader(data, size, nullptr, &vShader)); - m_shader = vShader; - break; - } - case PipelineStage::Fragment: - { - ComPtr pShader; - ThrowIfFailed(ctx->m_dev->CreatePixelShader(data, size, nullptr, &pShader)); - m_shader = pShader; - break; - } - case PipelineStage::Geometry: - { - ComPtr gShader; - ThrowIfFailed(ctx->m_dev->CreateGeometryShader(data, size, nullptr, &gShader)); - m_shader = gShader; - break; - } - case PipelineStage::Control: - { - ComPtr hShader; - ThrowIfFailed(ctx->m_dev->CreateHullShader(data, size, nullptr, &hShader)); - m_shader = hShader; - break; - } - case PipelineStage::Evaluation: - { - ComPtr dShader; - ThrowIfFailed(ctx->m_dev->CreateDomainShader(data, size, nullptr, &dShader)); - m_shader = dShader; - break; - } - default: - break; - } + case PipelineStage::Fragment: { + ComPtr pShader; + ThrowIfFailed(ctx->m_dev->CreatePixelShader(data, size, nullptr, &pShader)); + m_shader = pShader; + break; } + case PipelineStage::Geometry: { + ComPtr gShader; + ThrowIfFailed(ctx->m_dev->CreateGeometryShader(data, size, nullptr, &gShader)); + m_shader = gShader; + break; + } + case PipelineStage::Control: { + ComPtr hShader; + ThrowIfFailed(ctx->m_dev->CreateHullShader(data, size, nullptr, &hShader)); + m_shader = hShader; + break; + } + case PipelineStage::Evaluation: { + ComPtr dShader; + ThrowIfFailed(ctx->m_dev->CreateDomainShader(data, size, nullptr, &dShader)); + m_shader = dShader; + break; + } + default: + break; + } + } + public: - ComPtr m_vtxBlob; - template - void shader(ComPtr& ret) const { m_shader.As(&ret); } + ComPtr m_vtxBlob; + template + void shader(ComPtr& ret) const { + m_shader.As(&ret); + } }; -class D3D11ShaderPipeline : public GraphicsDataNode -{ - friend class D3D11DataFactory; - friend struct D3D11ShaderDataBinding; +class D3D11ShaderPipeline : public GraphicsDataNode { + friend class D3D11DataFactory; + friend struct D3D11ShaderDataBinding; - D3D11ShaderPipeline(const boo::ObjToken& parent, - D3D11Context* ctx, - ObjToken vertex, - ObjToken fragment, - ObjToken geometry, - ObjToken control, - ObjToken evaluation, - const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& info) - : GraphicsDataNode(parent), - m_topology(PRIMITIVE_TABLE[int(info.prim)]) - { - if (auto* s = vertex.cast()) - s->shader(m_vShader); - if (auto* s = fragment.cast()) - s->shader(m_pShader); - if (auto* s = geometry.cast()) - s->shader(m_gShader); - if (auto* s = control.cast()) - s->shader(m_hShader); - if (auto* s = evaluation.cast()) - s->shader(m_dShader); + D3D11ShaderPipeline(const boo::ObjToken& parent, D3D11Context* ctx, ObjToken vertex, + ObjToken fragment, ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) + : GraphicsDataNode(parent), m_topology(PRIMITIVE_TABLE[int(info.prim)]) { + if (auto* s = vertex.cast()) + s->shader(m_vShader); + if (auto* s = fragment.cast()) + s->shader(m_pShader); + if (auto* s = geometry.cast()) + s->shader(m_gShader); + if (auto* s = control.cast()) + s->shader(m_hShader); + if (auto* s = evaluation.cast()) + s->shader(m_dShader); - if (control && evaluation) - m_topology = D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + info.patchSize - 1); + if (control && evaluation) + m_topology = D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + info.patchSize - 1); - D3D11_CULL_MODE cullMode; - switch (info.culling) - { - case CullMode::None: - default: - cullMode = D3D11_CULL_NONE; - break; - case CullMode::Backface: - cullMode = D3D11_CULL_BACK; - break; - case CullMode::Frontface: - cullMode = D3D11_CULL_FRONT; - break; - } - - CD3D11_RASTERIZER_DESC rasDesc(D3D11_FILL_SOLID, cullMode, true, - D3D11_DEFAULT_DEPTH_BIAS, D3D11_DEFAULT_DEPTH_BIAS_CLAMP, - D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, true, true, false, false); - ThrowIfFailed(ctx->m_dev->CreateRasterizerState(&rasDesc, &m_rasState)); - - CD3D11_DEPTH_STENCIL_DESC dsDesc(D3D11_DEFAULT); - dsDesc.DepthEnable = info.depthTest != ZTest::None; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK(info.depthWrite); - switch (info.depthTest) - { - case ZTest::None: - default: - dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - break; - case ZTest::LEqual: - dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; - break; - case ZTest::Greater: - dsDesc.DepthFunc = D3D11_COMPARISON_LESS; - break; - case ZTest::GEqual: - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - break; - case ZTest::Equal: - dsDesc.DepthFunc = D3D11_COMPARISON_EQUAL; - break; - } - ThrowIfFailed(ctx->m_dev->CreateDepthStencilState(&dsDesc, &m_dsState)); - - CD3D11_BLEND_DESC blDesc(D3D11_DEFAULT); - blDesc.RenderTarget[0].BlendEnable = (info.dstFac != BlendFactor::Zero); - if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) - { - blDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; - blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT; - if (info.overwriteAlpha) - { - blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - } - else - { - blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; - blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_REV_SUBTRACT; - } - } - else - { - blDesc.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(info.srcFac)]; - blDesc.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(info.dstFac)]; - blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - if (info.overwriteAlpha) - { - blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - } - else - { - blDesc.RenderTarget[0].SrcBlendAlpha = BLEND_FACTOR_TABLE[int(info.srcFac)]; - blDesc.RenderTarget[0].DestBlendAlpha = BLEND_FACTOR_TABLE[int(info.dstFac)]; - } - blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - } - blDesc.RenderTarget[0].RenderTargetWriteMask = - (info.colorWrite ? (D3D11_COLOR_WRITE_ENABLE_RED | - D3D11_COLOR_WRITE_ENABLE_GREEN | - D3D11_COLOR_WRITE_ENABLE_BLUE) : 0) | - (info.alphaWrite ? D3D11_COLOR_WRITE_ENABLE_ALPHA : 0); - ThrowIfFailed(ctx->m_dev->CreateBlendState(&blDesc, &m_blState)); - - { - std::vector elements(vtxFmt.elementCount); - - for (size_t i=0 ; isemantic & boo::VertexSemantic::SemanticMask); - elem.SemanticName = SEMANTIC_NAME_TABLE[semantic]; - elem.SemanticIndex = elemin->semanticIdx; - elem.Format = SEMANTIC_TYPE_TABLE[semantic]; - if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) - { - elem.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; - elem.InstanceDataStepRate = 1; - elem.InputSlot = 1; - elem.AlignedByteOffset = m_instStride; - m_instStride += SEMANTIC_SIZE_TABLE[semantic]; - } - else - { - elem.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - elem.AlignedByteOffset = m_stride; - m_stride += SEMANTIC_SIZE_TABLE[semantic]; - } - } - - const auto& vertBuf = vertex.cast()->m_vtxBlob; - ThrowIfFailed(ctx->m_dev->CreateInputLayout(elements.data(), vtxFmt.elementCount, - vertBuf->GetBufferPointer(), vertBuf->GetBufferSize(), &m_inLayout)); - } + D3D11_CULL_MODE cullMode; + switch (info.culling) { + case CullMode::None: + default: + cullMode = D3D11_CULL_NONE; + break; + case CullMode::Backface: + cullMode = D3D11_CULL_BACK; + break; + case CullMode::Frontface: + cullMode = D3D11_CULL_FRONT; + break; } + + CD3D11_RASTERIZER_DESC rasDesc(D3D11_FILL_SOLID, cullMode, true, D3D11_DEFAULT_DEPTH_BIAS, + D3D11_DEFAULT_DEPTH_BIAS_CLAMP, D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, true, true, + false, false); + ThrowIfFailed(ctx->m_dev->CreateRasterizerState(&rasDesc, &m_rasState)); + + CD3D11_DEPTH_STENCIL_DESC dsDesc(D3D11_DEFAULT); + dsDesc.DepthEnable = info.depthTest != ZTest::None; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK(info.depthWrite); + switch (info.depthTest) { + case ZTest::None: + default: + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + break; + case ZTest::LEqual: + dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; + break; + case ZTest::Greater: + dsDesc.DepthFunc = D3D11_COMPARISON_LESS; + break; + case ZTest::GEqual: + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + break; + case ZTest::Equal: + dsDesc.DepthFunc = D3D11_COMPARISON_EQUAL; + break; + } + ThrowIfFailed(ctx->m_dev->CreateDepthStencilState(&dsDesc, &m_dsState)); + + CD3D11_BLEND_DESC blDesc(D3D11_DEFAULT); + blDesc.RenderTarget[0].BlendEnable = (info.dstFac != BlendFactor::Zero); + if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) { + blDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT; + if (info.overwriteAlpha) { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } else { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_REV_SUBTRACT; + } + } else { + blDesc.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(info.srcFac)]; + blDesc.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(info.dstFac)]; + blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + if (info.overwriteAlpha) { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + } else { + blDesc.RenderTarget[0].SrcBlendAlpha = BLEND_FACTOR_TABLE[int(info.srcFac)]; + blDesc.RenderTarget[0].DestBlendAlpha = BLEND_FACTOR_TABLE[int(info.dstFac)]; + } + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } + blDesc.RenderTarget[0].RenderTargetWriteMask = + (info.colorWrite + ? (D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE) + : 0) | + (info.alphaWrite ? D3D11_COLOR_WRITE_ENABLE_ALPHA : 0); + ThrowIfFailed(ctx->m_dev->CreateBlendState(&blDesc, &m_blState)); + + { + std::vector elements(vtxFmt.elementCount); + + for (size_t i = 0; i < vtxFmt.elementCount; ++i) { + const VertexElementDescriptor* elemin = &vtxFmt.elements[i]; + D3D11_INPUT_ELEMENT_DESC& elem = elements[i]; + int semantic = int(elemin->semantic & boo::VertexSemantic::SemanticMask); + elem.SemanticName = SEMANTIC_NAME_TABLE[semantic]; + elem.SemanticIndex = elemin->semanticIdx; + elem.Format = SEMANTIC_TYPE_TABLE[semantic]; + if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) { + elem.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; + elem.InstanceDataStepRate = 1; + elem.InputSlot = 1; + elem.AlignedByteOffset = m_instStride; + m_instStride += SEMANTIC_SIZE_TABLE[semantic]; + } else { + elem.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + elem.AlignedByteOffset = m_stride; + m_stride += SEMANTIC_SIZE_TABLE[semantic]; + } + } + + const auto& vertBuf = vertex.cast()->m_vtxBlob; + ThrowIfFailed(ctx->m_dev->CreateInputLayout(elements.data(), vtxFmt.elementCount, vertBuf->GetBufferPointer(), + vertBuf->GetBufferSize(), &m_inLayout)); + } + } + public: - ComPtr m_vShader; - ComPtr m_pShader; - ComPtr m_gShader; - ComPtr m_hShader; - ComPtr m_dShader; - ComPtr m_rasState; - ComPtr m_dsState; - ComPtr m_blState; - ComPtr m_inLayout; - D3D11_PRIMITIVE_TOPOLOGY m_topology; - size_t m_stride = 0; - size_t m_instStride = 0; - ~D3D11ShaderPipeline() = default; - D3D11ShaderPipeline& operator=(const D3D11ShaderPipeline&) = delete; - D3D11ShaderPipeline(const D3D11ShaderPipeline&) = delete; + ComPtr m_vShader; + ComPtr m_pShader; + ComPtr m_gShader; + ComPtr m_hShader; + ComPtr m_dShader; + ComPtr m_rasState; + ComPtr m_dsState; + ComPtr m_blState; + ComPtr m_inLayout; + D3D11_PRIMITIVE_TOPOLOGY m_topology; + size_t m_stride = 0; + size_t m_instStride = 0; + ~D3D11ShaderPipeline() = default; + D3D11ShaderPipeline& operator=(const D3D11ShaderPipeline&) = delete; + D3D11ShaderPipeline(const D3D11ShaderPipeline&) = delete; - void bind(ID3D11DeviceContext* ctx) - { - ctx->VSSetShader(m_vShader.Get(), nullptr, 0); - ctx->PSSetShader(m_pShader.Get(), nullptr, 0); - ctx->GSSetShader(m_gShader.Get(), nullptr, 0); - ctx->HSSetShader(m_hShader.Get(), nullptr, 0); - ctx->DSSetShader(m_dShader.Get(), nullptr, 0); - ctx->RSSetState(m_rasState.Get()); - ctx->OMSetDepthStencilState(m_dsState.Get(), 0); - ctx->OMSetBlendState(m_blState.Get(), nullptr, 0xffffffff); - ctx->IASetInputLayout(m_inLayout.Get()); - ctx->IASetPrimitiveTopology(m_topology); - } + void bind(ID3D11DeviceContext* ctx) { + ctx->VSSetShader(m_vShader.Get(), nullptr, 0); + ctx->PSSetShader(m_pShader.Get(), nullptr, 0); + ctx->GSSetShader(m_gShader.Get(), nullptr, 0); + ctx->HSSetShader(m_hShader.Get(), nullptr, 0); + ctx->DSSetShader(m_dShader.Get(), nullptr, 0); + ctx->RSSetState(m_rasState.Get()); + ctx->OMSetDepthStencilState(m_dsState.Get(), 0); + ctx->OMSetBlendState(m_blState.Get(), nullptr, 0xffffffff); + ctx->IASetInputLayout(m_inLayout.Get()); + ctx->IASetPrimitiveTopology(m_topology); + } }; -struct D3D11ShaderDataBinding : public GraphicsDataNode -{ - boo::ObjToken m_pipeline; - boo::ObjToken m_vbuf; - boo::ObjToken m_instVbuf; - boo::ObjToken m_ibuf; - std::vector> m_ubufs; - std::unique_ptr m_ubufFirstConsts; - std::unique_ptr m_ubufNumConsts; - std::unique_ptr m_pubufs; - struct BoundTex - { - boo::ObjToken tex; - int idx; - bool depth; - }; - std::vector m_texs; - UINT m_baseOffsets[2]; +struct D3D11ShaderDataBinding : public GraphicsDataNode { + boo::ObjToken m_pipeline; + boo::ObjToken m_vbuf; + boo::ObjToken m_instVbuf; + boo::ObjToken m_ibuf; + std::vector> m_ubufs; + std::unique_ptr m_ubufFirstConsts; + std::unique_ptr m_ubufNumConsts; + std::unique_ptr m_pubufs; + struct BoundTex { + boo::ObjToken tex; + int idx; + bool depth; + }; + std::vector m_texs; + UINT m_baseOffsets[2]; - D3D11ShaderDataBinding(const boo::ObjToken& d, - D3D11Context* ctx, - const boo::ObjToken& pipeline, - const boo::ObjToken& vbuf, - const boo::ObjToken& instVbuf, - const boo::ObjToken& ibuf, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* texBindIdx, const bool* depthBind, - size_t baseVert, size_t baseInst) - : GraphicsDataNode(d), - m_pipeline(pipeline), - m_vbuf(vbuf), - m_instVbuf(instVbuf), - m_ibuf(ibuf) - { - m_ubufs.reserve(ubufCount); - m_texs.reserve(texCount); + D3D11ShaderDataBinding(const boo::ObjToken& d, D3D11Context* ctx, + const boo::ObjToken& pipeline, const boo::ObjToken& vbuf, + const boo::ObjToken& instVbuf, const boo::ObjToken& ibuf, + size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, + const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, + const boo::ObjToken* texs, const int* texBindIdx, const bool* depthBind, + size_t baseVert, size_t baseInst) + : GraphicsDataNode(d), m_pipeline(pipeline), m_vbuf(vbuf), m_instVbuf(instVbuf), m_ibuf(ibuf) { + m_ubufs.reserve(ubufCount); + m_texs.reserve(texCount); - D3D11ShaderPipeline* cpipeline = m_pipeline.cast(); - m_baseOffsets[0] = UINT(baseVert * cpipeline->m_stride); - m_baseOffsets[1] = UINT(baseInst * cpipeline->m_instStride); + D3D11ShaderPipeline* cpipeline = m_pipeline.cast(); + m_baseOffsets[0] = UINT(baseVert * cpipeline->m_stride); + m_baseOffsets[1] = UINT(baseInst * cpipeline->m_instStride); - if (ubufStages) - { - m_pubufs.reset(new bool[ubufCount]); - for (size_t i=0 ; i()->bind(ctx); + + ID3D11Buffer* bufs[2] = {}; + UINT strides[2] = {}; + + if (m_vbuf) { + if (m_vbuf->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_vbuf.cast>(); + bufs[0] = cbuf->m_bufs[b].Get(); + strides[0] = UINT(cbuf->m_stride); + } else { + D3D11GraphicsBufferS* cbuf = m_vbuf.cast(); + bufs[0] = cbuf->m_buf.Get(); + strides[0] = UINT(cbuf->m_stride); + } } - void bind(ID3D11DeviceContext1* ctx, int b) - { - m_pipeline.cast()->bind(ctx); - - ID3D11Buffer* bufs[2] = {}; - UINT strides[2] = {}; - - if (m_vbuf) - { - if (m_vbuf->dynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_vbuf.cast>(); - bufs[0] = cbuf->m_bufs[b].Get(); - strides[0] = UINT(cbuf->m_stride); - } - else - { - D3D11GraphicsBufferS* cbuf = m_vbuf.cast(); - bufs[0] = cbuf->m_buf.Get(); - strides[0] = UINT(cbuf->m_stride); - } - } - - if (m_instVbuf) - { - if (m_instVbuf->dynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_instVbuf.cast>(); - bufs[1] = cbuf->m_bufs[b].Get(); - strides[1] = UINT(cbuf->m_stride); - } - else - { - D3D11GraphicsBufferS* cbuf = m_instVbuf.cast(); - bufs[1] = cbuf->m_buf.Get(); - strides[1] = UINT(cbuf->m_stride); - } - } - - ctx->IASetVertexBuffers(0, 2, bufs, strides, m_baseOffsets); - - if (m_ibuf) - { - if (m_ibuf->dynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_ibuf.cast>(); - ctx->IASetIndexBuffer(cbuf->m_bufs[b].Get(), DXGI_FORMAT_R32_UINT, 0); - } - else - { - D3D11GraphicsBufferS* cbuf = m_ibuf.cast(); - ctx->IASetIndexBuffer(cbuf->m_buf.Get(), DXGI_FORMAT_R32_UINT, 0); - } - } - - if (m_ubufs.size()) - { - if (m_ubufFirstConsts) - { - ID3D11Buffer* constBufs[8] = {}; - ctx->VSSetConstantBuffers(0, m_ubufs.size(), constBufs); - ctx->DSSetConstantBuffers(0, m_ubufs.size(), constBufs); - for (int i=0 ; i<8 && idynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_ubufs[i].cast>(); - constBufs[i] = cbuf->m_bufs[b].Get(); - } - else - { - D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); - constBufs[i] = cbuf->m_buf.Get(); - } - } - ctx->VSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); - ctx->DSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); - - if (m_pubufs) - { - ID3D11Buffer* constBufs[8] = {}; - ctx->PSSetConstantBuffers(0, m_ubufs.size(), constBufs); - for (int i=0 ; i<8 && idynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_ubufs[i].cast>(); - constBufs[i] = cbuf->m_bufs[b].Get(); - } - else - { - D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); - constBufs[i] = cbuf->m_buf.Get(); - } - } - ctx->PSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); - } - } - else - { - ID3D11Buffer* constBufs[8] = {}; - for (int i=0 ; i<8 && idynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_ubufs[i].cast>(); - constBufs[i] = cbuf->m_bufs[b].Get(); - } - else - { - D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); - constBufs[i] = cbuf->m_buf.Get(); - } - } - ctx->VSSetConstantBuffers(0, m_ubufs.size(), constBufs); - ctx->DSSetConstantBuffers(0, m_ubufs.size(), constBufs); - - if (m_pubufs) - { - ID3D11Buffer* constBufs[8] = {}; - for (int i=0 ; i<8 && idynamic()) - { - D3D11GraphicsBufferD* cbuf = - m_ubufs[i].cast>(); - constBufs[i] = cbuf->m_bufs[b].Get(); - } - else - { - D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); - constBufs[i] = cbuf->m_buf.Get(); - } - } - ctx->PSSetConstantBuffers(0, m_ubufs.size(), constBufs); - } - } - } - - if (m_texs.size()) - { - ID3D11ShaderResourceView* srvs[8] = {}; - for (int i=0 ; i<8 && itype()) - { - case TextureType::Dynamic: - { - D3D11TextureD* ctex = m_texs[i].tex.cast(); - srvs[i] = ctex->m_srvs[b].Get(); - break; - } - case TextureType::Static: - { - D3D11TextureS* ctex = m_texs[i].tex.cast(); - srvs[i] = ctex->m_srv.Get(); - break; - } - case TextureType::StaticArray: - { - D3D11TextureSA* ctex = m_texs[i].tex.cast(); - srvs[i] = ctex->m_srv.Get(); - break; - } - case TextureType::Render: - { - D3D11TextureR* ctex = m_texs[i].tex.cast(); - srvs[i] = m_texs[i].depth ? ctex->m_depthSrv[m_texs[i].idx].Get() : - ctex->m_colorSrv[m_texs[i].idx].Get(); - break; - } - } - } - } - ctx->PSSetShaderResources(0, m_texs.size(), srvs); - ctx->DSSetShaderResources(0, m_texs.size(), srvs); - } + if (m_instVbuf) { + if (m_instVbuf->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_instVbuf.cast>(); + bufs[1] = cbuf->m_bufs[b].Get(); + strides[1] = UINT(cbuf->m_stride); + } else { + D3D11GraphicsBufferS* cbuf = m_instVbuf.cast(); + bufs[1] = cbuf->m_buf.Get(); + strides[1] = UINT(cbuf->m_stride); + } } + + ctx->IASetVertexBuffers(0, 2, bufs, strides, m_baseOffsets); + + if (m_ibuf) { + if (m_ibuf->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_ibuf.cast>(); + ctx->IASetIndexBuffer(cbuf->m_bufs[b].Get(), DXGI_FORMAT_R32_UINT, 0); + } else { + D3D11GraphicsBufferS* cbuf = m_ibuf.cast(); + ctx->IASetIndexBuffer(cbuf->m_buf.Get(), DXGI_FORMAT_R32_UINT, 0); + } + } + + if (m_ubufs.size()) { + if (m_ubufFirstConsts) { + ID3D11Buffer* constBufs[8] = {}; + ctx->VSSetConstantBuffers(0, m_ubufs.size(), constBufs); + ctx->DSSetConstantBuffers(0, m_ubufs.size(), constBufs); + for (int i = 0; i < 8 && i < m_ubufs.size(); ++i) { + if (m_pubufs && m_pubufs[i]) + continue; + if (m_ubufs[i]->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_ubufs[i].cast>(); + constBufs[i] = cbuf->m_bufs[b].Get(); + } else { + D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); + constBufs[i] = cbuf->m_buf.Get(); + } + } + ctx->VSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); + ctx->DSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); + + if (m_pubufs) { + ID3D11Buffer* constBufs[8] = {}; + ctx->PSSetConstantBuffers(0, m_ubufs.size(), constBufs); + for (int i = 0; i < 8 && i < m_ubufs.size(); ++i) { + if (!m_pubufs[i]) + continue; + if (m_ubufs[i]->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_ubufs[i].cast>(); + constBufs[i] = cbuf->m_bufs[b].Get(); + } else { + D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); + constBufs[i] = cbuf->m_buf.Get(); + } + } + ctx->PSSetConstantBuffers1(0, m_ubufs.size(), constBufs, m_ubufFirstConsts.get(), m_ubufNumConsts.get()); + } + } else { + ID3D11Buffer* constBufs[8] = {}; + for (int i = 0; i < 8 && i < m_ubufs.size(); ++i) { + if (m_pubufs && m_pubufs[i]) + continue; + if (m_ubufs[i]->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_ubufs[i].cast>(); + constBufs[i] = cbuf->m_bufs[b].Get(); + } else { + D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); + constBufs[i] = cbuf->m_buf.Get(); + } + } + ctx->VSSetConstantBuffers(0, m_ubufs.size(), constBufs); + ctx->DSSetConstantBuffers(0, m_ubufs.size(), constBufs); + + if (m_pubufs) { + ID3D11Buffer* constBufs[8] = {}; + for (int i = 0; i < 8 && i < m_ubufs.size(); ++i) { + if (!m_pubufs[i]) + continue; + if (m_ubufs[i]->dynamic()) { + D3D11GraphicsBufferD* cbuf = m_ubufs[i].cast>(); + constBufs[i] = cbuf->m_bufs[b].Get(); + } else { + D3D11GraphicsBufferS* cbuf = m_ubufs[i].cast(); + constBufs[i] = cbuf->m_buf.Get(); + } + } + ctx->PSSetConstantBuffers(0, m_ubufs.size(), constBufs); + } + } + } + + if (m_texs.size()) { + ID3D11ShaderResourceView* srvs[8] = {}; + for (int i = 0; i < 8 && i < m_texs.size(); ++i) { + if (m_texs[i].tex) { + switch (m_texs[i].tex->type()) { + case TextureType::Dynamic: { + D3D11TextureD* ctex = m_texs[i].tex.cast(); + srvs[i] = ctex->m_srvs[b].Get(); + break; + } + case TextureType::Static: { + D3D11TextureS* ctex = m_texs[i].tex.cast(); + srvs[i] = ctex->m_srv.Get(); + break; + } + case TextureType::StaticArray: { + D3D11TextureSA* ctex = m_texs[i].tex.cast(); + srvs[i] = ctex->m_srv.Get(); + break; + } + case TextureType::Render: { + D3D11TextureR* ctex = m_texs[i].tex.cast(); + srvs[i] = m_texs[i].depth ? ctex->m_depthSrv[m_texs[i].idx].Get() : ctex->m_colorSrv[m_texs[i].idx].Get(); + break; + } + } + } + } + ctx->PSSetShaderResources(0, m_texs.size(), srvs); + ctx->DSSetShaderResources(0, m_texs.size(), srvs); + } + } }; -struct D3D11CommandQueue : IGraphicsCommandQueue -{ - Platform platform() const {return IGraphicsDataFactory::Platform::D3D11;} - const SystemChar* platformName() const {return _SYS_STR("D3D11");} - D3D11Context* m_ctx; - D3D11Context::Window* m_windowCtx; - IGraphicsContext* m_parent; - ComPtr m_deferredCtx; +struct D3D11CommandQueue : IGraphicsCommandQueue { + Platform platform() const { return IGraphicsDataFactory::Platform::D3D11; } + const SystemChar* platformName() const { return _SYS_STR("D3D11"); } + D3D11Context* m_ctx; + D3D11Context::Window* m_windowCtx; + IGraphicsContext* m_parent; + ComPtr m_deferredCtx; - size_t m_fillBuf = 0; - size_t m_completeBuf = 0; - size_t m_drawBuf = 0; - bool m_running = true; + size_t m_fillBuf = 0; + size_t m_completeBuf = 0; + size_t m_drawBuf = 0; + bool m_running = true; - std::mutex m_mt; - std::condition_variable m_cv; - std::mutex m_initmt; - std::condition_variable m_initcv; - std::unique_lock m_initlk; - std::thread m_thr; + std::mutex m_mt; + std::condition_variable m_cv; + std::mutex m_initmt; + std::condition_variable m_initcv; + std::unique_lock m_initlk; + std::thread m_thr; - struct CommandList - { - ComPtr list; - std::vector> resTokens; - boo::ObjToken workDoPresent; + struct CommandList { + ComPtr list; + std::vector> resTokens; + boo::ObjToken workDoPresent; - void reset() - { - list.Reset(); - resTokens.clear(); - workDoPresent.reset(); - } - }; - CommandList m_cmdLists[3]; - - std::recursive_mutex m_dynamicLock; - void ProcessDynamicLoads(ID3D11DeviceContext* ctx); - static void RenderingWorker(D3D11CommandQueue* self); - - D3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, IGraphicsContext* parent) - : m_ctx(ctx), m_windowCtx(windowCtx), m_parent(parent), - m_initlk(m_initmt), - m_thr(RenderingWorker, this) - { - m_initcv.wait(m_initlk); - m_initlk.unlock(); - ThrowIfFailed(ctx->m_dev->CreateDeferredContext1(0, &m_deferredCtx)); + void reset() { + list.Reset(); + resTokens.clear(); + workDoPresent.reset(); } + }; + CommandList m_cmdLists[3]; - void startRenderer(); + std::recursive_mutex m_dynamicLock; + void ProcessDynamicLoads(ID3D11DeviceContext* ctx); + static void RenderingWorker(D3D11CommandQueue* self); - void stopRenderer() - { - m_running = false; - m_cv.notify_one(); - m_thr.join(); + D3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, IGraphicsContext* parent) + : m_ctx(ctx), m_windowCtx(windowCtx), m_parent(parent), m_initlk(m_initmt), m_thr(RenderingWorker, this) { + m_initcv.wait(m_initlk); + m_initlk.unlock(); + ThrowIfFailed(ctx->m_dev->CreateDeferredContext1(0, &m_deferredCtx)); + } + + void startRenderer(); + + void stopRenderer() { + m_running = false; + m_cv.notify_one(); + m_thr.join(); + } + + ~D3D11CommandQueue() { + if (m_running) + stopRenderer(); + } + + void setShaderDataBinding(const boo::ObjToken& binding) { + D3D11ShaderDataBinding* cbind = binding.cast(); + cbind->bind(m_deferredCtx.Get(), m_fillBuf); + m_cmdLists[m_fillBuf].resTokens.push_back(binding.get()); + + ID3D11SamplerState* samp[] = {m_ctx->m_ss[0].Get(), m_ctx->m_ss[1].Get(), m_ctx->m_ss[2].Get(), + m_ctx->m_ss[3].Get(), m_ctx->m_ss[4].Get()}; + m_deferredCtx->PSSetSamplers(0, 5, samp); + m_deferredCtx->DSSetSamplers(0, 5, samp); + } + + boo::ObjToken m_boundTarget; + void setRenderTarget(const boo::ObjToken& target) { + D3D11TextureR* ctarget = target.cast(); + ID3D11RenderTargetView* view[] = {ctarget->m_rtv.Get()}; + m_deferredCtx->OMSetRenderTargets(1, view, ctarget->m_dsv.Get()); + m_boundTarget = target; + } + + void setViewport(const SWindowRect& rect, float znear, float zfar) { + if (m_boundTarget) { + D3D11TextureR* ctarget = m_boundTarget.cast(); + int boundHeight = ctarget->m_height; + D3D11_VIEWPORT vp = {FLOAT(rect.location[0]), + FLOAT(boundHeight - rect.location[1] - rect.size[1]), + FLOAT(rect.size[0]), + FLOAT(rect.size[1]), + 1.f - zfar, + 1.f - znear}; + m_deferredCtx->RSSetViewports(1, &vp); } + } - ~D3D11CommandQueue() - { - if (m_running) stopRenderer(); + void setScissor(const SWindowRect& rect) { + if (m_boundTarget) { + D3D11TextureR* ctarget = m_boundTarget.cast(); + int boundHeight = ctarget->m_height; + D3D11_RECT d3drect = {LONG(rect.location[0]), LONG(boundHeight - rect.location[1] - rect.size[1]), + LONG(rect.location[0] + rect.size[0]), LONG(boundHeight - rect.location[1])}; + m_deferredCtx->RSSetScissorRects(1, &d3drect); } + } - void setShaderDataBinding(const boo::ObjToken& binding) - { - D3D11ShaderDataBinding* cbind = binding.cast(); - cbind->bind(m_deferredCtx.Get(), m_fillBuf); - m_cmdLists[m_fillBuf].resTokens.push_back(binding.get()); + std::unordered_map> m_texResizes; + void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) { + D3D11TextureR* ctex = tex.cast(); + std::unique_lock lk(m_mt); + m_texResizes[ctex] = std::make_pair(width, height); + } - ID3D11SamplerState* samp[] = {m_ctx->m_ss[0].Get(), - m_ctx->m_ss[1].Get(), - m_ctx->m_ss[2].Get(), - m_ctx->m_ss[3].Get(), - m_ctx->m_ss[4].Get()}; - m_deferredCtx->PSSetSamplers(0, 5, samp); - m_deferredCtx->DSSetSamplers(0, 5, samp); + void schedulePostFrameHandler(std::function&& func) { func(); } + + float m_clearColor[4] = {0.0, 0.0, 0.0, 0.0}; + void setClearColor(const float rgba[4]) { + m_clearColor[0] = rgba[0]; + m_clearColor[1] = rgba[1]; + m_clearColor[2] = rgba[2]; + m_clearColor[3] = rgba[3]; + } + + void clearTarget(bool render = true, bool depth = true) { + if (!m_boundTarget) + return; + D3D11TextureR* ctarget = m_boundTarget.cast(); + if (render) + m_deferredCtx->ClearRenderTargetView(ctarget->m_rtv.Get(), m_clearColor); + if (depth) + m_deferredCtx->ClearDepthStencilView(ctarget->m_dsv.Get(), D3D11_CLEAR_DEPTH, 0.0f, 0); + } + + void draw(size_t start, size_t count) { m_deferredCtx->Draw(count, start); } + + void drawIndexed(size_t start, size_t count) { m_deferredCtx->DrawIndexed(count, start, 0); } + + void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) { + m_deferredCtx->DrawInstanced(count, instCount, start, startInst); + } + + void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) { + m_deferredCtx->DrawIndexedInstanced(count, instCount, start, 0, startInst); + } + + void _resolveBindTexture(ID3D11DeviceContext1* ctx, const D3D11TextureR* tex, const SWindowRect& rect, bool tlOrigin, + int bindIdx, bool color, bool depth) { + if (color && tex->m_colorBindCount) { + if (tex->m_samples > 1) { + ctx->ResolveSubresource(tex->m_colorBindTex[bindIdx].Get(), 0, tex->m_colorTex.Get(), 0, m_ctx->m_fbFormat); + } else { + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); + int y = + tlOrigin ? intersectRect.location[1] : (tex->m_height - intersectRect.size[1] - intersectRect.location[1]); + D3D11_BOX box = { + UINT(intersectRect.location[0]), UINT(y), 0, UINT(intersectRect.location[0] + intersectRect.size[0]), + UINT(y + intersectRect.size[1]), 1}; + ctx->CopySubresourceRegion1(tex->m_colorBindTex[bindIdx].Get(), 0, box.left, box.top, 0, tex->m_colorTex.Get(), + 0, &box, D3D11_COPY_DISCARD); + } } - - boo::ObjToken m_boundTarget; - void setRenderTarget(const boo::ObjToken& target) - { - D3D11TextureR* ctarget = target.cast(); - ID3D11RenderTargetView* view[] = {ctarget->m_rtv.Get()}; - m_deferredCtx->OMSetRenderTargets(1, view, ctarget->m_dsv.Get()); - m_boundTarget = target; + if (depth && tex->m_depthBindCount) { + if (tex->m_samples > 1) { + ctx->ResolveSubresource(tex->m_depthBindTex[bindIdx].Get(), 0, tex->m_depthTex.Get(), 0, DXGI_FORMAT_D32_FLOAT); + } else { + ctx->CopyResource(tex->m_depthBindTex[bindIdx].Get(), tex->m_depthTex.Get()); + } } + } - void setViewport(const SWindowRect& rect, float znear, float zfar) - { - if (m_boundTarget) - { - D3D11TextureR* ctarget = m_boundTarget.cast(); - int boundHeight = ctarget->m_height; - D3D11_VIEWPORT vp = {FLOAT(rect.location[0]), FLOAT(boundHeight - rect.location[1] - rect.size[1]), - FLOAT(rect.size[0]), FLOAT(rect.size[1]), 1.f - zfar, 1.f - znear}; - m_deferredCtx->RSSetViewports(1, &vp); - } - } + void resolveBindTexture(const boo::ObjToken& texture, const SWindowRect& rect, bool tlOrigin, int bindIdx, + bool color, bool depth, bool clearDepth) { + const D3D11TextureR* tex = texture.cast(); + _resolveBindTexture(m_deferredCtx.Get(), tex, rect, tlOrigin, bindIdx, color, depth); + if (clearDepth) + m_deferredCtx->ClearDepthStencilView(tex->m_dsv.Get(), D3D11_CLEAR_DEPTH, 0.0f, 0); + } - void setScissor(const SWindowRect& rect) - { - if (m_boundTarget) - { - D3D11TextureR* ctarget = m_boundTarget.cast(); - int boundHeight = ctarget->m_height; - D3D11_RECT d3drect = {LONG(rect.location[0]), LONG(boundHeight - rect.location[1] - rect.size[1]), - LONG(rect.location[0] + rect.size[0]), LONG(boundHeight - rect.location[1])}; - m_deferredCtx->RSSetScissorRects(1, &d3drect); - } - } + boo::ObjToken m_doPresent; + void resolveDisplay(const boo::ObjToken& source) { m_doPresent = source; } - std::unordered_map> m_texResizes; - void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) - { - D3D11TextureR* ctex = tex.cast(); - std::unique_lock lk(m_mt); - m_texResizes[ctex] = std::make_pair(width, height); - } - - void schedulePostFrameHandler(std::function&& func) - { - func(); - } - - float m_clearColor[4] = {0.0,0.0,0.0,0.0}; - void setClearColor(const float rgba[4]) - { - m_clearColor[0] = rgba[0]; - m_clearColor[1] = rgba[1]; - m_clearColor[2] = rgba[2]; - m_clearColor[3] = rgba[3]; - } - - void clearTarget(bool render=true, bool depth=true) - { - if (!m_boundTarget) - return; - D3D11TextureR* ctarget = m_boundTarget.cast(); - if (render) - m_deferredCtx->ClearRenderTargetView(ctarget->m_rtv.Get(), m_clearColor); - if (depth) - m_deferredCtx->ClearDepthStencilView(ctarget->m_dsv.Get(), D3D11_CLEAR_DEPTH, 0.0f, 0); - } - - void draw(size_t start, size_t count) - { - m_deferredCtx->Draw(count, start); - } - - void drawIndexed(size_t start, size_t count) - { - m_deferredCtx->DrawIndexed(count, start, 0); - } - - void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) - { - m_deferredCtx->DrawInstanced(count, instCount, start, startInst); - } - - void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) - { - m_deferredCtx->DrawIndexedInstanced(count, instCount, start, 0, startInst); - } - - void _resolveBindTexture(ID3D11DeviceContext1* ctx, const D3D11TextureR* tex, const SWindowRect& rect, - bool tlOrigin, int bindIdx, bool color, bool depth) - { - if (color && tex->m_colorBindCount) - { - if (tex->m_samples > 1) - { - ctx->ResolveSubresource(tex->m_colorBindTex[bindIdx].Get(), 0, tex->m_colorTex.Get(), 0, - m_ctx->m_fbFormat); - } - else - { - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); - int y = tlOrigin ? intersectRect.location[1] : (tex->m_height - intersectRect.size[1] - intersectRect.location[1]); - D3D11_BOX box = {UINT(intersectRect.location[0]), UINT(y), 0, - UINT(intersectRect.location[0] + intersectRect.size[0]), UINT(y + intersectRect.size[1]), 1}; - ctx->CopySubresourceRegion1(tex->m_colorBindTex[bindIdx].Get(), 0, box.left, box.top, 0, - tex->m_colorTex.Get(), 0, &box, D3D11_COPY_DISCARD); - } - } - if (depth && tex->m_depthBindCount) - { - if (tex->m_samples > 1) - { - ctx->ResolveSubresource(tex->m_depthBindTex[bindIdx].Get(), 0, tex->m_depthTex.Get(), 0, - DXGI_FORMAT_D32_FLOAT); - } - else - { - ctx->CopyResource(tex->m_depthBindTex[bindIdx].Get(), tex->m_depthTex.Get()); - } - } - } - - void resolveBindTexture(const boo::ObjToken& texture, const SWindowRect& rect, - bool tlOrigin, int bindIdx, bool color, bool depth, bool clearDepth) - { - const D3D11TextureR* tex = texture.cast(); - _resolveBindTexture(m_deferredCtx.Get(), tex, rect, tlOrigin, bindIdx, color, depth); - if (clearDepth) - m_deferredCtx->ClearDepthStencilView(tex->m_dsv.Get(), D3D11_CLEAR_DEPTH, 0.0f, 0); - } - - boo::ObjToken m_doPresent; - void resolveDisplay(const boo::ObjToken& source) - { - m_doPresent = source; - } - - void execute(); + void execute(); }; template -void D3D11GraphicsBufferD::update(ID3D11DeviceContext* ctx, int b) -{ - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - ID3D11Buffer* res = m_bufs[b].Get(); - D3D11_MAPPED_SUBRESOURCE d; - if (SUCCEEDED(ctx->Map(res, 0, D3D11_MAP_WRITE_DISCARD, 0, &d))) - { - memcpy(d.pData, m_cpuBuf.get(), m_cpuSz); - ctx->Unmap(res, 0); - } - m_validSlots |= slot; +void D3D11GraphicsBufferD::update(ID3D11DeviceContext* ctx, int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + ID3D11Buffer* res = m_bufs[b].Get(); + D3D11_MAPPED_SUBRESOURCE d; + if (SUCCEEDED(ctx->Map(res, 0, D3D11_MAP_WRITE_DISCARD, 0, &d))) { + memcpy(d.pData, m_cpuBuf.get(), m_cpuSz); + ctx->Unmap(res, 0); } + m_validSlots |= slot; + } } template -void D3D11GraphicsBufferD::load(const void* data, size_t sz) -{ - std::unique_lock lk(m_q->m_dynamicLock); - size_t bufSz = std::min(sz, m_cpuSz); - memcpy(m_cpuBuf.get(), data, bufSz); - m_validSlots = 0; +void D3D11GraphicsBufferD::load(const void* data, size_t sz) { + std::unique_lock lk(m_q->m_dynamicLock); + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validSlots = 0; } template -void* D3D11GraphicsBufferD::map(size_t sz) -{ - if (sz > m_cpuSz) - return nullptr; - m_q->m_dynamicLock.lock(); - return m_cpuBuf.get(); +void* D3D11GraphicsBufferD::map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + m_q->m_dynamicLock.lock(); + return m_cpuBuf.get(); } template -void D3D11GraphicsBufferD::unmap() -{ - m_validSlots = 0; - m_q->m_dynamicLock.unlock(); +void D3D11GraphicsBufferD::unmap() { + m_validSlots = 0; + m_q->m_dynamicLock.unlock(); } -void D3D11TextureD::update(ID3D11DeviceContext* ctx, int b) -{ - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - ID3D11Texture2D* res = m_texs[b].Get(); - D3D11_MAPPED_SUBRESOURCE d; - ctx->Map(res, 0, D3D11_MAP_WRITE_DISCARD, 0, &d); - size_t rowSz = m_pxPitch * m_width; - for (size_t i=0 ; i(d.pData)+=d.RowPitch) - memmove(d.pData, m_cpuBuf.get() + i, rowSz); - ctx->Unmap(res, 0); - m_validSlots |= slot; - } +void D3D11TextureD::update(ID3D11DeviceContext* ctx, int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + ID3D11Texture2D* res = m_texs[b].Get(); + D3D11_MAPPED_SUBRESOURCE d; + ctx->Map(res, 0, D3D11_MAP_WRITE_DISCARD, 0, &d); + size_t rowSz = m_pxPitch * m_width; + for (size_t i = 0; i < m_cpuSz; i += rowSz, reinterpret_cast(d.pData) += d.RowPitch) + memmove(d.pData, m_cpuBuf.get() + i, rowSz); + ctx->Unmap(res, 0); + m_validSlots |= slot; + } } -void D3D11TextureD::load(const void* data, size_t sz) -{ - std::unique_lock lk(m_q->m_dynamicLock); - size_t bufSz = std::min(sz, m_cpuSz); - memcpy(m_cpuBuf.get(), data, bufSz); - m_validSlots = 0; +void D3D11TextureD::load(const void* data, size_t sz) { + std::unique_lock lk(m_q->m_dynamicLock); + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validSlots = 0; } -void* D3D11TextureD::map(size_t sz) -{ - if (sz > m_cpuSz) - return nullptr; - m_q->m_dynamicLock.lock(); - return m_cpuBuf.get(); +void* D3D11TextureD::map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + m_q->m_dynamicLock.lock(); + return m_cpuBuf.get(); } -void D3D11TextureD::unmap() -{ - m_validSlots = 0; - m_q->m_dynamicLock.unlock(); +void D3D11TextureD::unmap() { + m_validSlots = 0; + m_q->m_dynamicLock.unlock(); } -class D3D11DataFactoryImpl : public D3D11DataFactory, public GraphicsDataFactoryHead -{ - friend struct D3D11CommandQueue; - friend class D3D11DataFactory::Context; - IGraphicsContext* m_parent; - struct D3D11Context* m_ctx; +class D3D11DataFactoryImpl : public D3D11DataFactory, public GraphicsDataFactoryHead { + friend struct D3D11CommandQueue; + friend class D3D11DataFactory::Context; + IGraphicsContext* m_parent; + struct D3D11Context* m_ctx; - float m_gamma = 1.f; - ObjToken m_gammaShader; - ObjToken m_gammaLUT; - ObjToken m_gammaVBO; - ObjToken m_gammaBinding; - void SetupGammaResources() - { - commitTransaction([this](IGraphicsDataFactory::Context& ctx) - { - auto vertexHlsl = D3D11DataFactory::CompileHLSL(GammaVS, PipelineStage::Vertex); - auto vertexShader = ctx.newShaderStage(vertexHlsl, PipelineStage::Vertex); - auto fragmentHlsl = D3D11DataFactory::CompileHLSL(GammaFS, PipelineStage::Fragment); - auto fragmentShader = ctx.newShaderStage(fragmentHlsl, PipelineStage::Fragment); - const VertexElementDescriptor vfmt[] = { - {VertexSemantic::Position4}, - {VertexSemantic::UV4} - }; - AdditionalPipelineInfo info = - { - BlendFactor::One, BlendFactor::Zero, - Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None - }; - m_gammaShader = ctx.newShaderPipeline(vertexShader, fragmentShader, vfmt, info); - m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); - setDisplayGamma(1.f); - const struct Vert { - float pos[4]; - float uv[4]; - } verts[4] = { - {{-1.f, 1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, - {{ 1.f, 1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, - {{-1.f, -1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, - {{ 1.f, -1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}} - }; - m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); - ObjToken texs[] = {{}, m_gammaLUT.get()}; - m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, - 0, nullptr, nullptr, 2, texs, nullptr, nullptr); - return true; - } BooTrace); - } + float m_gamma = 1.f; + ObjToken m_gammaShader; + ObjToken m_gammaLUT; + ObjToken m_gammaVBO; + ObjToken m_gammaBinding; + void SetupGammaResources() { + commitTransaction([this](IGraphicsDataFactory::Context& ctx) { + auto vertexHlsl = D3D11DataFactory::CompileHLSL(GammaVS, PipelineStage::Vertex); + auto vertexShader = ctx.newShaderStage(vertexHlsl, PipelineStage::Vertex); + auto fragmentHlsl = D3D11DataFactory::CompileHLSL(GammaFS, PipelineStage::Fragment); + auto fragmentShader = ctx.newShaderStage(fragmentHlsl, PipelineStage::Fragment); + const VertexElementDescriptor vfmt[] = {{VertexSemantic::Position4}, {VertexSemantic::UV4}}; + AdditionalPipelineInfo info = { + BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None}; + m_gammaShader = ctx.newShaderPipeline(vertexShader, fragmentShader, vfmt, info); + m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); + setDisplayGamma(1.f); + const struct Vert { + float pos[4]; + float uv[4]; + } verts[4] = {{{-1.f, 1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, + {{1.f, 1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, + {{-1.f, -1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, + {{1.f, -1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}}}; + m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); + ObjToken texs[] = {{}, m_gammaLUT.get()}; + m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, 0, nullptr, nullptr, 2, texs, + nullptr, nullptr); + return true; + } BooTrace); + } public: - D3D11DataFactoryImpl(IGraphicsContext* parent, D3D11Context* ctx) - : m_parent(parent), m_ctx(ctx) - { - UINT qLevels; - while (SUCCEEDED(ctx->m_dev->CheckMultisampleQualityLevels - (m_ctx->m_fbFormat, m_ctx->m_sampleCount, &qLevels)) && !qLevels) - m_ctx->m_sampleCount = flp2(m_ctx->m_sampleCount - 1); - } + D3D11DataFactoryImpl(IGraphicsContext* parent, D3D11Context* ctx) : m_parent(parent), m_ctx(ctx) { + UINT qLevels; + while (SUCCEEDED(ctx->m_dev->CheckMultisampleQualityLevels(m_ctx->m_fbFormat, m_ctx->m_sampleCount, &qLevels)) && + !qLevels) + m_ctx->m_sampleCount = flp2(m_ctx->m_sampleCount - 1); + } - boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) - { - D3D11CommandQueue* q = static_cast(m_parent->getCommandQueue()); - boo::ObjToken pool(new BaseGraphicsPool(*this __BooTraceArgsUse)); - return {new D3D11GraphicsBufferD(pool, q, use, m_ctx, stride, count)}; - } + boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) { + D3D11CommandQueue* q = static_cast(m_parent->getCommandQueue()); + boo::ObjToken pool(new BaseGraphicsPool(*this __BooTraceArgsUse)); + return {new D3D11GraphicsBufferD(pool, q, use, m_ctx, stride, count)}; + } - void commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs) - { - D3D11DataFactory::Context ctx(*this __BooTraceArgsUse); - trans(ctx); - } + void commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs) { + D3D11DataFactory::Context ctx(*this __BooTraceArgsUse); + trans(ctx); + } - void setDisplayGamma(float gamma) - { - if (m_ctx->m_fbFormat == DXGI_FORMAT_R16G16B16A16_FLOAT) - m_gamma = gamma * 2.2f; - else - m_gamma = gamma; - if (m_gamma != 1.f) - UpdateGammaLUT(m_gammaLUT.get(), m_gamma); - } + void setDisplayGamma(float gamma) { + if (m_ctx->m_fbFormat == DXGI_FORMAT_R16G16B16A16_FLOAT) + m_gamma = gamma * 2.2f; + else + m_gamma = gamma; + if (m_gamma != 1.f) + UpdateGammaLUT(m_gammaLUT.get(), m_gamma); + } - bool isTessellationSupported(uint32_t& maxPatchSizeOut) - { - maxPatchSizeOut = 32; - return true; - } + bool isTessellationSupported(uint32_t& maxPatchSizeOut) { + maxPatchSizeOut = 32; + return true; + } }; D3D11DataFactory::Context::Context(D3D11DataFactory& parent __BooTraceArgs) @@ -1401,280 +1165,231 @@ D3D11DataFactory::Context::Context(D3D11DataFactory& parent __BooTraceArgs) D3D11DataFactory::Context::~Context() {} -boo::ObjToken D3D11DataFactory::Context::newStaticBuffer( - BufferUse use, const void* data, size_t stride, size_t count) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11GraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; +boo::ObjToken D3D11DataFactory::Context::newStaticBuffer(BufferUse use, const void* data, + size_t stride, size_t count) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11GraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; } -boo::ObjToken D3D11DataFactory::Context::newDynamicBuffer( - BufferUse use, size_t stride, size_t count) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - D3D11CommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - return {new D3D11GraphicsBufferD(m_data, q, use, factory.m_ctx, stride, count)}; +boo::ObjToken D3D11DataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, + size_t count) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + D3D11CommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + return {new D3D11GraphicsBufferD(m_data, q, use, factory.m_ctx, stride, count)}; } -boo::ObjToken D3D11DataFactory::Context::newStaticTexture( - size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11TextureS(m_data, factory.m_ctx, width, height, mips, fmt, data, sz)}; +boo::ObjToken D3D11DataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, + const void* data, size_t sz) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11TextureS(m_data, factory.m_ctx, width, height, mips, fmt, data, sz)}; } -boo::ObjToken D3D11DataFactory::Context::newStaticArrayTexture( - size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11TextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, data, sz)}; +boo::ObjToken D3D11DataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, + size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, + size_t sz) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11TextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, data, sz)}; } -boo::ObjToken D3D11DataFactory::Context::newDynamicTexture( - size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - D3D11CommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - return {new D3D11TextureD(m_data, q, factory.m_ctx, width, height, fmt)}; +boo::ObjToken D3D11DataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + D3D11CommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + return {new D3D11TextureD(m_data, q, factory.m_ctx, width, height, fmt)}; } -boo::ObjToken D3D11DataFactory::Context::newRenderTexture( - size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11TextureR(m_data, factory.m_ctx, width, height, factory.m_ctx->m_sampleCount, - colorBindCount, depthBindCount)}; +boo::ObjToken D3D11DataFactory::Context::newRenderTexture(size_t width, size_t height, + TextureClampMode clampMode, size_t colorBindCount, + size_t depthBindCount) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11TextureR(m_data, factory.m_ctx, width, height, factory.m_ctx->m_sampleCount, colorBindCount, + depthBindCount)}; } -boo::ObjToken D3D11DataFactory::Context::newShaderStage( - const uint8_t* data, size_t size, PipelineStage stage) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11ShaderStage(m_data, factory.m_ctx, data, size, stage)}; +boo::ObjToken D3D11DataFactory::Context::newShaderStage(const uint8_t* data, size_t size, + PipelineStage stage) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11ShaderStage(m_data, factory.m_ctx, data, size, stage)}; } -boo::ObjToken D3D11DataFactory::Context::newShaderPipeline - (ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - struct D3D11Context* ctx = factory.m_ctx; - return {new D3D11ShaderPipeline(m_data, ctx, vertex, fragment, geometry, control, evaluation, vtxFmt, additionalInfo)}; +boo::ObjToken D3D11DataFactory::Context::newShaderPipeline( + ObjToken vertex, ObjToken fragment, ObjToken geometry, + ObjToken control, ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + struct D3D11Context* ctx = factory.m_ctx; + return { + new D3D11ShaderPipeline(m_data, ctx, vertex, fragment, geometry, control, evaluation, vtxFmt, additionalInfo)}; } boo::ObjToken D3D11DataFactory::Context::newShaderDataBinding( - const boo::ObjToken& pipeline, - const boo::ObjToken& vbuf, - const boo::ObjToken& instVbo, - const boo::ObjToken& ibuf, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* texBindIdx, const bool* depthBind, - size_t baseVert, size_t baseInst) -{ - D3D11DataFactoryImpl& factory = static_cast(m_parent); - return {new D3D11ShaderDataBinding(m_data, factory.m_ctx, pipeline, vbuf, instVbo, ibuf, - ubufCount, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, - texBindIdx, depthBind, baseVert, baseInst)}; + const boo::ObjToken& pipeline, const boo::ObjToken& vbuf, + const boo::ObjToken& instVbo, const boo::ObjToken& ibuf, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* texBindIdx, + const bool* depthBind, size_t baseVert, size_t baseInst) { + D3D11DataFactoryImpl& factory = static_cast(m_parent); + return {new D3D11ShaderDataBinding(m_data, factory.m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, ubufStages, + ubufOffs, ubufSizes, texCount, texs, texBindIdx, depthBind, baseVert, baseInst)}; } -void D3D11CommandQueue::RenderingWorker(D3D11CommandQueue* self) -{ +void D3D11CommandQueue::RenderingWorker(D3D11CommandQueue* self) { + { std::unique_lock lk(self->m_initmt); } + self->m_initcv.notify_one(); + D3D11DataFactoryImpl* dataFactory = static_cast(self->m_parent->getDataFactory()); + while (self->m_running) { { - std::unique_lock lk(self->m_initmt); + std::unique_lock lk(self->m_mt); + self->m_cv.wait(lk); + if (!self->m_running) + break; + self->m_drawBuf = self->m_completeBuf; + auto& CmdList = self->m_cmdLists[self->m_drawBuf]; + + self->ProcessDynamicLoads(self->m_ctx->m_devCtx.Get()); + + if (self->m_texResizes.size()) { + for (const auto& resize : self->m_texResizes) + resize.first->resize(self->m_ctx, resize.second.first, resize.second.second); + self->m_texResizes.clear(); + CmdList.reset(); + continue; + } + + if (self->m_windowCtx->m_needsFSTransition) { + if (self->m_windowCtx->m_fs) { + self->m_windowCtx->m_swapChain->SetFullscreenState(true, nullptr); + self->m_windowCtx->m_swapChain->ResizeTarget(&self->m_windowCtx->m_fsdesc); + } else + self->m_windowCtx->m_swapChain->SetFullscreenState(false, nullptr); + + self->m_windowCtx->m_needsFSTransition = false; + CmdList.reset(); + continue; + } + + if (self->m_windowCtx->m_needsResize) { + self->m_windowCtx->clearRTV(); + self->m_windowCtx->m_swapChain->ResizeBuffers(2, self->m_windowCtx->width, self->m_windowCtx->height, + self->m_ctx->m_fbFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); + self->m_windowCtx->setupRTV(self->m_windowCtx->m_swapChain, self->m_ctx->m_dev.Get()); + self->m_windowCtx->m_needsResize = false; + CmdList.reset(); + continue; + } } - self->m_initcv.notify_one(); - D3D11DataFactoryImpl* dataFactory = static_cast(self->m_parent->getDataFactory()); - while (self->m_running) - { - { - std::unique_lock lk(self->m_mt); - self->m_cv.wait(lk); - if (!self->m_running) - break; - self->m_drawBuf = self->m_completeBuf; - auto& CmdList = self->m_cmdLists[self->m_drawBuf]; - self->ProcessDynamicLoads(self->m_ctx->m_devCtx.Get()); + auto& CmdList = self->m_cmdLists[self->m_drawBuf]; + ID3D11CommandList* list = CmdList.list.Get(); + self->m_ctx->m_devCtx->ExecuteCommandList(list, false); - if (self->m_texResizes.size()) - { - for (const auto& resize : self->m_texResizes) - resize.first->resize(self->m_ctx, resize.second.first, resize.second.second); - self->m_texResizes.clear(); - CmdList.reset(); - continue; - } - - if (self->m_windowCtx->m_needsFSTransition) - { - if (self->m_windowCtx->m_fs) - { - self->m_windowCtx->m_swapChain->SetFullscreenState(true, nullptr); - self->m_windowCtx->m_swapChain->ResizeTarget(&self->m_windowCtx->m_fsdesc); - } - else - self->m_windowCtx->m_swapChain->SetFullscreenState(false, nullptr); - - self->m_windowCtx->m_needsFSTransition = false; - CmdList.reset(); - continue; - } - - if (self->m_windowCtx->m_needsResize) - { - self->m_windowCtx->clearRTV(); - self->m_windowCtx->m_swapChain->ResizeBuffers(2, - self->m_windowCtx->width, self->m_windowCtx->height, - self->m_ctx->m_fbFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); - self->m_windowCtx->setupRTV(self->m_windowCtx->m_swapChain, self->m_ctx->m_dev.Get()); - self->m_windowCtx->m_needsResize = false; - CmdList.reset(); - continue; - } - } - - auto& CmdList = self->m_cmdLists[self->m_drawBuf]; - ID3D11CommandList* list = CmdList.list.Get(); - self->m_ctx->m_devCtx->ExecuteCommandList(list, false); - - if (D3D11TextureR* csource = CmdList.workDoPresent.cast()) - { + if (D3D11TextureR* csource = CmdList.workDoPresent.cast()) { #ifndef NDEBUG - if (!csource->m_colorBindCount) - Log.report(logvisor::Fatal, - "texture provided to resolveDisplay() must have at least 1 color binding"); + if (!csource->m_colorBindCount) + Log.report(logvisor::Fatal, "texture provided to resolveDisplay() must have at least 1 color binding"); #endif - if (dataFactory->m_gamma != 1.f) - { - SWindowRect rect(0, 0, csource->m_width, csource->m_height); - self->_resolveBindTexture(self->m_ctx->m_devCtx.Get(), csource, rect, true, 0, true, false); - ID3D11RenderTargetView* rtv = self->m_windowCtx->m_swapChainRTV.Get(); - self->m_ctx->m_devCtx->OMSetRenderTargets(1, &rtv, nullptr); + if (dataFactory->m_gamma != 1.f) { + SWindowRect rect(0, 0, csource->m_width, csource->m_height); + self->_resolveBindTexture(self->m_ctx->m_devCtx.Get(), csource, rect, true, 0, true, false); + ID3D11RenderTargetView* rtv = self->m_windowCtx->m_swapChainRTV.Get(); + self->m_ctx->m_devCtx->OMSetRenderTargets(1, &rtv, nullptr); - D3D11_VIEWPORT vp = {0.f, 0.f, FLOAT(csource->m_width), FLOAT(csource->m_height), 0.f, 1.f}; - self->m_ctx->m_devCtx->RSSetViewports(1, &vp); - D3D11_RECT d3drect = {0, 0, LONG(csource->m_width), LONG(csource->m_height)}; - self->m_ctx->m_devCtx->RSSetScissorRects(1, &d3drect); - ID3D11SamplerState* samp[] = {self->m_ctx->m_ss[0].Get(), - self->m_ctx->m_ss[1].Get(), - self->m_ctx->m_ss[2].Get(), - self->m_ctx->m_ss[3].Get(), - self->m_ctx->m_ss[4].Get()}; - self->m_ctx->m_devCtx->PSSetSamplers(0, 5, samp); - self->m_ctx->m_devCtx->DSSetSamplers(0, 5, samp); + D3D11_VIEWPORT vp = {0.f, 0.f, FLOAT(csource->m_width), FLOAT(csource->m_height), 0.f, 1.f}; + self->m_ctx->m_devCtx->RSSetViewports(1, &vp); + D3D11_RECT d3drect = {0, 0, LONG(csource->m_width), LONG(csource->m_height)}; + self->m_ctx->m_devCtx->RSSetScissorRects(1, &d3drect); + ID3D11SamplerState* samp[] = {self->m_ctx->m_ss[0].Get(), self->m_ctx->m_ss[1].Get(), + self->m_ctx->m_ss[2].Get(), self->m_ctx->m_ss[3].Get(), + self->m_ctx->m_ss[4].Get()}; + self->m_ctx->m_devCtx->PSSetSamplers(0, 5, samp); + self->m_ctx->m_devCtx->DSSetSamplers(0, 5, samp); - D3D11ShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); - gammaBinding->m_texs[0].tex = CmdList.workDoPresent.get(); - gammaBinding->bind(self->m_ctx->m_devCtx.Get(), self->m_drawBuf); - self->m_ctx->m_devCtx->Draw(4, 0); - gammaBinding->m_texs[0].tex.reset(); - } - else - { - ComPtr dest = self->m_windowCtx->m_swapChainTex; - ID3D11Texture2D* src = csource->m_colorTex.Get(); - if (csource->m_samples > 1) - self->m_ctx->m_devCtx->ResolveSubresource(dest.Get(), 0, src, 0, self->m_ctx->m_fbFormat); - else - self->m_ctx->m_devCtx->CopyResource(dest.Get(), src); - } + D3D11ShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); + gammaBinding->m_texs[0].tex = CmdList.workDoPresent.get(); + gammaBinding->bind(self->m_ctx->m_devCtx.Get(), self->m_drawBuf); + self->m_ctx->m_devCtx->Draw(4, 0); + gammaBinding->m_texs[0].tex.reset(); + } else { + ComPtr dest = self->m_windowCtx->m_swapChainTex; + ID3D11Texture2D* src = csource->m_colorTex.Get(); + if (csource->m_samples > 1) + self->m_ctx->m_devCtx->ResolveSubresource(dest.Get(), 0, src, 0, self->m_ctx->m_fbFormat); + else + self->m_ctx->m_devCtx->CopyResource(dest.Get(), src); + } - self->m_windowCtx->m_swapChain->Present(1, 0); - } - - CmdList.reset(); - } -} - -void D3D11CommandQueue::startRenderer() -{ - static_cast(m_parent->getDataFactory())->SetupGammaResources(); -} - -void D3D11CommandQueue::execute() -{ - /* Finish command list */ - auto& CmdList = m_cmdLists[m_fillBuf]; - ThrowIfFailed(m_deferredCtx->FinishCommandList(false, &CmdList.list)); - CmdList.workDoPresent = m_doPresent; - m_doPresent = nullptr; - - /* Wait for worker thread to become ready */ - std::unique_lock lk(m_mt); - - /* Ready for next frame */ - m_completeBuf = m_fillBuf; - for (size_t i=0 ; i<3 ; ++i) - { - if (i == m_completeBuf || i == m_drawBuf) - continue; - m_fillBuf = i; - break; + self->m_windowCtx->m_swapChain->Present(1, 0); } - /* Return control to worker thread */ - lk.unlock(); - m_cv.notify_one(); + CmdList.reset(); + } } -void D3D11CommandQueue::ProcessDynamicLoads(ID3D11DeviceContext* ctx) -{ - D3D11DataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); - std::unique_lock lk(m_dynamicLock); - std::unique_lock datalk(gfxF->m_dataMutex); +void D3D11CommandQueue::startRenderer() { + static_cast(m_parent->getDataFactory())->SetupGammaResources(); +} - if (gfxF->m_dataHead) - { - for (BaseGraphicsData& d : *gfxF->m_dataHead) - { - if (d.m_DBufs) - for (IGraphicsBufferD& b : *d.m_DBufs) - static_cast&>(b).update(ctx, m_drawBuf); - if (d.m_DTexs) - for (ITextureD& t : *d.m_DTexs) - static_cast(t).update(ctx, m_drawBuf); - } +void D3D11CommandQueue::execute() { + /* Finish command list */ + auto& CmdList = m_cmdLists[m_fillBuf]; + ThrowIfFailed(m_deferredCtx->FinishCommandList(false, &CmdList.list)); + CmdList.workDoPresent = m_doPresent; + m_doPresent = nullptr; + + /* Wait for worker thread to become ready */ + std::unique_lock lk(m_mt); + + /* Ready for next frame */ + m_completeBuf = m_fillBuf; + for (size_t i = 0; i < 3; ++i) { + if (i == m_completeBuf || i == m_drawBuf) + continue; + m_fillBuf = i; + break; + } + + /* Return control to worker thread */ + lk.unlock(); + m_cv.notify_one(); +} + +void D3D11CommandQueue::ProcessDynamicLoads(ID3D11DeviceContext* ctx) { + D3D11DataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); + std::unique_lock lk(m_dynamicLock); + std::unique_lock datalk(gfxF->m_dataMutex); + + if (gfxF->m_dataHead) { + for (BaseGraphicsData& d : *gfxF->m_dataHead) { + if (d.m_DBufs) + for (IGraphicsBufferD& b : *d.m_DBufs) + static_cast&>(b).update(ctx, m_drawBuf); + if (d.m_DTexs) + for (ITextureD& t : *d.m_DTexs) + static_cast(t).update(ctx, m_drawBuf); } - if (gfxF->m_poolHead) - { - for (BaseGraphicsPool& p : *gfxF->m_poolHead) - { - if (p.m_DBufs) - for (IGraphicsBufferD& b : *p.m_DBufs) - static_cast&>(b).update(ctx, m_drawBuf); - } + } + if (gfxF->m_poolHead) { + for (BaseGraphicsPool& p : *gfxF->m_poolHead) { + if (p.m_DBufs) + for (IGraphicsBufferD& b : *p.m_DBufs) + static_cast&>(b).update(ctx, m_drawBuf); } + } } -std::unique_ptr -_NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, IGraphicsContext* parent) -{ - return std::make_unique(ctx, windowCtx, parent); +std::unique_ptr _NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, + IGraphicsContext* parent) { + return std::make_unique(ctx, windowCtx, parent); } -std::unique_ptr -_NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent) -{ - return std::make_unique(parent, ctx); +std::unique_ptr _NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent) { + return std::make_unique(parent, ctx); } -static const char* D3DShaderTypes[] = -{ - nullptr, - "vs_5_0", - "ps_5_0", - "gs_5_0", - "hs_5_0", - "ds_5_0" -}; +static const char* D3DShaderTypes[] = {nullptr, "vs_5_0", "ps_5_0", "gs_5_0", "hs_5_0", "ds_5_0"}; #if _DEBUG && 0 #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0 @@ -1682,20 +1397,18 @@ static const char* D3DShaderTypes[] = #define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif -std::vector D3D11DataFactory::CompileHLSL(const char* source, PipelineStage stage) -{ - ComPtr errBlob; - ComPtr blobOut; - if (FAILED(D3DCompilePROC(source, strlen(source), "Boo HLSL Source", nullptr, nullptr, "main", - D3DShaderTypes[int(stage)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) - { - printf("%s\n", source); - Log.report(logvisor::Fatal, "error compiling shader: %s", errBlob->GetBufferPointer()); - return {}; - } - std::vector ret(blobOut->GetBufferSize()); - memcpy(ret.data(), blobOut->GetBufferPointer(), ret.size()); - return ret; +std::vector D3D11DataFactory::CompileHLSL(const char* source, PipelineStage stage) { + ComPtr errBlob; + ComPtr blobOut; + if (FAILED(D3DCompilePROC(source, strlen(source), "Boo HLSL Source", nullptr, nullptr, "main", + D3DShaderTypes[int(stage)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) { + printf("%s\n", source); + Log.report(logvisor::Fatal, "error compiling shader: %s", errBlob->GetBufferPointer()); + return {}; + } + std::vector ret(blobOut->GetBufferSize()); + memcpy(ret.data(), blobOut->GetBufferPointer(), ret.size()); + return ret; } -} +} // namespace boo diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 45a3819..dbe9bc3 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -21,2007 +21,1691 @@ #undef min #undef max -static const char* GammaVS = -"#version 330\n" -BOO_GLSL_BINDING_HEAD -"layout(location=0) in vec4 posIn;\n" -"layout(location=1) in vec4 uvIn;\n" -"\n" -"struct VertToFrag\n" -"{\n" -" vec2 uv;\n" -"};\n" -"\n" -"SBINDING(0) out VertToFrag vtf;\n" -"void main()\n" -"{\n" -" vtf.uv = uvIn.xy;\n" -" gl_Position = posIn;\n" -"}\n"; +static const char* GammaVS = "#version 330\n" BOO_GLSL_BINDING_HEAD + "layout(location=0) in vec4 posIn;\n" + "layout(location=1) in vec4 uvIn;\n" + "\n" + "struct VertToFrag\n" + "{\n" + " vec2 uv;\n" + "};\n" + "\n" + "SBINDING(0) out VertToFrag vtf;\n" + "void main()\n" + "{\n" + " vtf.uv = uvIn.xy;\n" + " gl_Position = posIn;\n" + "}\n"; -static const char* GammaFS = -"#version 330\n" -BOO_GLSL_BINDING_HEAD -"struct VertToFrag\n" -"{\n" -" vec2 uv;\n" -"};\n" -"\n" -"SBINDING(0) in VertToFrag vtf;\n" -"layout(location=0) out vec4 colorOut;\n" -"TBINDING0 uniform sampler2D screenTex;\n" -"TBINDING1 uniform sampler2D gammaLUT;\n" -"void main()\n" -"{\n" -" ivec4 tex = ivec4(texture(screenTex, vtf.uv) * 65535.0);\n" -" for (int i=0 ; i<3 ; ++i)\n" -" colorOut[i] = texelFetch(gammaLUT, ivec2(tex[i] % 256, tex[i] / 256), 0).r;\n" -"}\n"; +static const char* GammaFS = "#version 330\n" BOO_GLSL_BINDING_HEAD + "struct VertToFrag\n" + "{\n" + " vec2 uv;\n" + "};\n" + "\n" + "SBINDING(0) in VertToFrag vtf;\n" + "layout(location=0) out vec4 colorOut;\n" + "TBINDING0 uniform sampler2D screenTex;\n" + "TBINDING1 uniform sampler2D gammaLUT;\n" + "void main()\n" + "{\n" + " ivec4 tex = ivec4(texture(screenTex, vtf.uv) * 65535.0);\n" + " for (int i=0 ; i<3 ; ++i)\n" + " colorOut[i] = texelFetch(gammaLUT, ivec2(tex[i] % 256, tex[i] / 256), 0).r;\n" + "}\n"; -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::GL"); class GLDataFactoryImpl; -class GLDataFactoryImpl : public GLDataFactory, public GraphicsDataFactoryHead -{ - friend struct GLCommandQueue; - friend class GLDataFactory::Context; - IGraphicsContext* m_parent; - GLContext* m_glCtx; +class GLDataFactoryImpl : public GLDataFactory, public GraphicsDataFactoryHead { + friend struct GLCommandQueue; + friend class GLDataFactory::Context; + IGraphicsContext* m_parent; + GLContext* m_glCtx; - bool m_hasTessellation = false; - uint32_t m_maxPatchSize = 0; + bool m_hasTessellation = false; + uint32_t m_maxPatchSize = 0; - float m_gamma = 1.f; - ObjToken m_gammaShader; - ObjToken m_gammaLUT; - ObjToken m_gammaVBO; - ObjToken m_gammaBinding; - void SetupGammaResources() - { - /* Good enough place for this */ - if (!glslang::InitializeProcess()) - Log.report(logvisor::Error, "unable to initialize glslang"); + float m_gamma = 1.f; + ObjToken m_gammaShader; + ObjToken m_gammaLUT; + ObjToken m_gammaVBO; + ObjToken m_gammaBinding; + void SetupGammaResources() { + /* Good enough place for this */ + if (!glslang::InitializeProcess()) + Log.report(logvisor::Error, "unable to initialize glslang"); - if (GLEW_ARB_tessellation_shader) - { - m_hasTessellation = true; - GLint maxPVerts; - glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPVerts); - m_maxPatchSize = uint32_t(maxPVerts); - } - - commitTransaction([this](IGraphicsDataFactory::Context& ctx) - { - auto vertex = ctx.newShaderStage((uint8_t*)GammaVS, 0, PipelineStage::Vertex); - auto fragment = ctx.newShaderStage((uint8_t*)GammaFS, 0, PipelineStage::Fragment); - AdditionalPipelineInfo info = - { - BlendFactor::One, BlendFactor::Zero, - Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None - }; - const VertexElementDescriptor vfmt[] = { - {VertexSemantic::Position4}, - {VertexSemantic::UV4} - }; - m_gammaShader = ctx.newShaderPipeline(vertex, fragment, vfmt, info); - m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); - const struct Vert { - float pos[4]; - float uv[4]; - } verts[4] = { - {{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, - {{ 1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, - {{-1.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, - {{ 1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}} - }; - m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); - ObjToken texs[] = {{}, m_gammaLUT.get()}; - m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, - 0, nullptr, nullptr, 2, texs, nullptr, nullptr); - return true; - } BooTrace); + if (GLEW_ARB_tessellation_shader) { + m_hasTessellation = true; + GLint maxPVerts; + glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPVerts); + m_maxPatchSize = uint32_t(maxPVerts); } + commitTransaction([this](IGraphicsDataFactory::Context& ctx) { + auto vertex = ctx.newShaderStage((uint8_t*)GammaVS, 0, PipelineStage::Vertex); + auto fragment = ctx.newShaderStage((uint8_t*)GammaFS, 0, PipelineStage::Fragment); + AdditionalPipelineInfo info = { + BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None}; + const VertexElementDescriptor vfmt[] = {{VertexSemantic::Position4}, {VertexSemantic::UV4}}; + m_gammaShader = ctx.newShaderPipeline(vertex, fragment, vfmt, info); + m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); + const struct Vert { + float pos[4]; + float uv[4]; + } verts[4] = {{{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, + {{1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, + {{-1.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, + {{1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}}}; + m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); + ObjToken texs[] = {{}, m_gammaLUT.get()}; + m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, 0, nullptr, nullptr, 2, texs, + nullptr, nullptr); + return true; + } BooTrace); + } + public: - GLDataFactoryImpl(IGraphicsContext* parent, GLContext* glCtx) - : m_parent(parent), m_glCtx(glCtx) {} + GLDataFactoryImpl(IGraphicsContext* parent, GLContext* glCtx) : m_parent(parent), m_glCtx(glCtx) {} - Platform platform() const { return Platform::OpenGL; } - const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } - void commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs); - ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); + Platform platform() const { return Platform::OpenGL; } + const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } + void commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs); + ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); - void setDisplayGamma(float gamma) - { - m_gamma = gamma; - if (gamma != 1.f) - UpdateGammaLUT(m_gammaLUT.get(), gamma); - } + void setDisplayGamma(float gamma) { + m_gamma = gamma; + if (gamma != 1.f) + UpdateGammaLUT(m_gammaLUT.get(), gamma); + } - bool isTessellationSupported(uint32_t& maxPatchSizeOut) - { - maxPatchSizeOut = m_maxPatchSize; - return m_hasTessellation; - } + bool isTessellationSupported(uint32_t& maxPatchSizeOut) { + maxPatchSizeOut = m_maxPatchSize; + return m_hasTessellation; + } }; -static const GLenum USE_TABLE[] = -{ - GL_INVALID_ENUM, - GL_ARRAY_BUFFER, - GL_ELEMENT_ARRAY_BUFFER, - GL_UNIFORM_BUFFER -}; +static const GLenum USE_TABLE[] = {GL_INVALID_ENUM, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_UNIFORM_BUFFER}; + +class GLGraphicsBufferS : public GraphicsDataNode { + friend class GLDataFactory; + friend struct GLCommandQueue; + GLuint m_buf; + GLenum m_target; + GLGraphicsBufferS(const ObjToken& parent, BufferUse use, const void* data, size_t sz) + : GraphicsDataNode(parent) { + m_target = USE_TABLE[int(use)]; + glGenBuffers(1, &m_buf); + glBindBuffer(m_target, m_buf); + glBufferData(m_target, sz, data, GL_STATIC_DRAW); + } -class GLGraphicsBufferS : public GraphicsDataNode -{ - friend class GLDataFactory; - friend struct GLCommandQueue; - GLuint m_buf; - GLenum m_target; - GLGraphicsBufferS(const ObjToken& parent, BufferUse use, const void* data, size_t sz) - : GraphicsDataNode(parent) - { - m_target = USE_TABLE[int(use)]; - glGenBuffers(1, &m_buf); - glBindBuffer(m_target, m_buf); - glBufferData(m_target, sz, data, GL_STATIC_DRAW); - } public: - ~GLGraphicsBufferS() { glDeleteBuffers(1, &m_buf); } + ~GLGraphicsBufferS() { glDeleteBuffers(1, &m_buf); } - void bindVertex() const - {glBindBuffer(GL_ARRAY_BUFFER, m_buf);} - void bindIndex() const - {glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buf);} - void bindUniform(size_t idx) const - {glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_buf);} - void bindUniformRange(size_t idx, GLintptr off, GLsizeiptr size) const - {glBindBufferRange(GL_UNIFORM_BUFFER, idx, m_buf, off, size);} + void bindVertex() const { glBindBuffer(GL_ARRAY_BUFFER, m_buf); } + void bindIndex() const { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buf); } + void bindUniform(size_t idx) const { glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_buf); } + void bindUniformRange(size_t idx, GLintptr off, GLsizeiptr size) const { + glBindBufferRange(GL_UNIFORM_BUFFER, idx, m_buf, off, size); + } }; -template -class GLGraphicsBufferD : public GraphicsDataNode -{ - friend class GLDataFactory; - friend class GLDataFactoryImpl; - friend struct GLCommandQueue; - GLuint m_bufs[3]; - GLenum m_target; - std::unique_ptr m_cpuBuf; - size_t m_cpuSz = 0; - int m_validMask = 0; - GLGraphicsBufferD(const ObjToken& parent, BufferUse use, size_t sz) - : GraphicsDataNode(parent), - m_target(USE_TABLE[int(use)]), m_cpuBuf(new uint8_t[sz]), m_cpuSz(sz) - { - glGenBuffers(3, m_bufs); - for (int i=0 ; i<3 ; ++i) - { - glBindBuffer(m_target, m_bufs[i]); - glBufferData(m_target, m_cpuSz, nullptr, GL_STREAM_DRAW); - } +template +class GLGraphicsBufferD : public GraphicsDataNode { + friend class GLDataFactory; + friend class GLDataFactoryImpl; + friend struct GLCommandQueue; + GLuint m_bufs[3]; + GLenum m_target; + std::unique_ptr m_cpuBuf; + size_t m_cpuSz = 0; + int m_validMask = 0; + GLGraphicsBufferD(const ObjToken& parent, BufferUse use, size_t sz) + : GraphicsDataNode(parent) + , m_target(USE_TABLE[int(use)]) + , m_cpuBuf(new uint8_t[sz]) + , m_cpuSz(sz) { + glGenBuffers(3, m_bufs); + for (int i = 0; i < 3; ++i) { + glBindBuffer(m_target, m_bufs[i]); + glBufferData(m_target, m_cpuSz, nullptr, GL_STREAM_DRAW); } + } + public: - ~GLGraphicsBufferD() { glDeleteBuffers(3, m_bufs); } + ~GLGraphicsBufferD() { glDeleteBuffers(3, m_bufs); } - void update(int b) - { - int slot = 1 << b; - if ((slot & m_validMask) == 0) - { - glBindBuffer(m_target, m_bufs[b]); - glBufferSubData(m_target, 0, m_cpuSz, m_cpuBuf.get()); - m_validMask |= slot; - } + void update(int b) { + int slot = 1 << b; + if ((slot & m_validMask) == 0) { + glBindBuffer(m_target, m_bufs[b]); + glBufferSubData(m_target, 0, m_cpuSz, m_cpuBuf.get()); + m_validMask |= slot; } + } - void load(const void* data, size_t sz) - { - size_t bufSz = std::min(sz, m_cpuSz); - memcpy(m_cpuBuf.get(), data, bufSz); - m_validMask = 0; - } - void* map(size_t sz) - { - if (sz > m_cpuSz) - return nullptr; - return m_cpuBuf.get(); - } - void unmap() - { - m_validMask = 0; - } - void bindVertex(int b) - {glBindBuffer(GL_ARRAY_BUFFER, m_bufs[b]);} - void bindIndex(int b) - {glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bufs[b]);} - void bindUniform(size_t idx, int b) - {glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_bufs[b]);} - void bindUniformRange(size_t idx, GLintptr off, GLsizeiptr size, int b) - {glBindBufferRange(GL_UNIFORM_BUFFER, idx, m_bufs[b], off, size);} + void load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validMask = 0; + } + void* map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_cpuBuf.get(); + } + void unmap() { m_validMask = 0; } + void bindVertex(int b) { glBindBuffer(GL_ARRAY_BUFFER, m_bufs[b]); } + void bindIndex(int b) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bufs[b]); } + void bindUniform(size_t idx, int b) { glBindBufferBase(GL_UNIFORM_BUFFER, idx, m_bufs[b]); } + void bindUniformRange(size_t idx, GLintptr off, GLsizeiptr size, int b) { + glBindBufferRange(GL_UNIFORM_BUFFER, idx, m_bufs[b], off, size); + } }; -ObjToken -GLDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) -{ - return {new GLGraphicsBufferS(m_data, use, data, stride * count)}; +ObjToken GLDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, + size_t count) { + return {new GLGraphicsBufferS(m_data, use, data, stride * count)}; } -static void SetClampMode(GLenum target, TextureClampMode clampMode) -{ - switch (clampMode) - { - case TextureClampMode::Repeat: - { - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); - break; - } - case TextureClampMode::ClampToWhite: - { - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - GLfloat color[] = {1.f, 1.f, 1.f, 1.f}; - glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); - break; - } - case TextureClampMode::ClampToBlack: - { - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - GLfloat color[] = {0.f, 0.f, 0.f, 1.f}; - glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); - break; - } - case TextureClampMode::ClampToEdge: - { - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - break; - } - case TextureClampMode::ClampToEdgeNearest: - { - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - } +static void SetClampMode(GLenum target, TextureClampMode clampMode) { + switch (clampMode) { + case TextureClampMode::Repeat: { + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); + break; + } + case TextureClampMode::ClampToWhite: { + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + GLfloat color[] = {1.f, 1.f, 1.f, 1.f}; + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); + break; + } + case TextureClampMode::ClampToBlack: { + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + GLfloat color[] = {0.f, 0.f, 0.f, 1.f}; + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); + break; + } + case TextureClampMode::ClampToEdge: { + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + break; + } + case TextureClampMode::ClampToEdgeNearest: { + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + } + default: + break; + } +} + +class GLTextureS : public GraphicsDataNode { + friend class GLDataFactory; + GLuint m_tex; + TextureClampMode m_clampMode = TextureClampMode::Invalid; + GLTextureS(const ObjToken& parent, size_t width, size_t height, size_t mips, TextureFormat fmt, + TextureClampMode clampMode, GLint aniso, const void* data, size_t sz) + : GraphicsDataNode(parent) { + const uint8_t* dataIt = static_cast(data); + glGenTextures(1, &m_tex); + glBindTexture(GL_TEXTURE_2D, m_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (mips > 1) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mips - 1); + } else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (GLEW_EXT_texture_filter_anisotropic) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + + SetClampMode(GL_TEXTURE_2D, clampMode); + + GLenum intFormat, format; + int pxPitch; + bool compressed = false; + switch (fmt) { + case TextureFormat::RGBA8: + intFormat = GL_RGBA8; + format = GL_RGBA; + pxPitch = 4; + break; + case TextureFormat::I8: + intFormat = GL_R8; + format = GL_RED; + pxPitch = 1; + break; + case TextureFormat::I16: + intFormat = GL_R16; + format = GL_RED; + pxPitch = 2; + break; + case TextureFormat::DXT1: + intFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + compressed = true; + break; default: - break; + Log.report(logvisor::Fatal, "unsupported tex format"); } -} -class GLTextureS : public GraphicsDataNode -{ - friend class GLDataFactory; - GLuint m_tex; - TextureClampMode m_clampMode = TextureClampMode::Invalid; - GLTextureS(const ObjToken& parent, size_t width, size_t height, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, GLint aniso, const void* data, size_t sz) - : GraphicsDataNode(parent) - { - const uint8_t* dataIt = static_cast(data); - glGenTextures(1, &m_tex); - glBindTexture(GL_TEXTURE_2D, m_tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (mips > 1) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mips-1); - } - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - if (GLEW_EXT_texture_filter_anisotropic) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); - - SetClampMode(GL_TEXTURE_2D, clampMode); - - GLenum intFormat, format; - int pxPitch; - bool compressed = false; - switch (fmt) - { - case TextureFormat::RGBA8: - intFormat = GL_RGBA8; - format = GL_RGBA; - pxPitch = 4; - break; - case TextureFormat::I8: - intFormat = GL_R8; - format = GL_RED; - pxPitch = 1; - break; - case TextureFormat::I16: - intFormat = GL_R16; - format = GL_RED; - pxPitch = 2; - break; - case TextureFormat::DXT1: - intFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - compressed = true; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - - if (compressed) - { - for (size_t i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - } - } - else - { - GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - for (size_t i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - } - } + if (compressed) { + for (size_t i = 0; i < mips; ++i) { + size_t dataSz = width * height / 2; + glCompressedTexImage2D(GL_TEXTURE_2D, i, intFormat, width, height, 0, dataSz, dataIt); + dataIt += dataSz; + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + } + } else { + GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + for (size_t i = 0; i < mips; ++i) { + glTexImage2D(GL_TEXTURE_2D, i, intFormat, width, height, 0, format, compType, dataIt); + dataIt += width * height * pxPitch; + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + } } + } + public: - ~GLTextureS() { glDeleteTextures(1, &m_tex); } + ~GLTextureS() { glDeleteTextures(1, &m_tex); } - void setClampMode(TextureClampMode mode) - { - if (m_clampMode == mode) - return; - m_clampMode = mode; - glBindTexture(GL_TEXTURE_2D, m_tex); - SetClampMode(GL_TEXTURE_2D, mode); - } + void setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + glBindTexture(GL_TEXTURE_2D, m_tex); + SetClampMode(GL_TEXTURE_2D, mode); + } - void bind(size_t idx) const - { - glActiveTexture(GL_TEXTURE0 + idx); - glBindTexture(GL_TEXTURE_2D, m_tex); - } + void bind(size_t idx) const { + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, m_tex); + } }; -class GLTextureSA : public GraphicsDataNode -{ - friend class GLDataFactory; - GLuint m_tex; - TextureClampMode m_clampMode = TextureClampMode::Invalid; - GLTextureSA(const ObjToken& parent, size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, GLint aniso, const void* data, size_t sz) - : GraphicsDataNode(parent) - { - const uint8_t* dataIt = static_cast(data); - glGenTextures(1, &m_tex); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (mips > 1) - { - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mips-1); - } - else - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +class GLTextureSA : public GraphicsDataNode { + friend class GLDataFactory; + GLuint m_tex; + TextureClampMode m_clampMode = TextureClampMode::Invalid; + GLTextureSA(const ObjToken& parent, size_t width, size_t height, size_t layers, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, GLint aniso, const void* data, size_t sz) + : GraphicsDataNode(parent) { + const uint8_t* dataIt = static_cast(data); + glGenTextures(1, &m_tex); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (mips > 1) { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mips - 1); + } else + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - if (GLEW_EXT_texture_filter_anisotropic) - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); + if (GLEW_EXT_texture_filter_anisotropic) + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso); - SetClampMode(GL_TEXTURE_2D_ARRAY, clampMode); + SetClampMode(GL_TEXTURE_2D_ARRAY, clampMode); - GLenum intFormat = 0, format = 0; - int pxPitch = 0; - switch (fmt) - { - case TextureFormat::RGBA8: - intFormat = GL_RGBA8; - format = GL_RGBA; - pxPitch = 4; - break; - case TextureFormat::I8: - intFormat = GL_R8; - format = GL_RED; - pxPitch = 1; - break; - case TextureFormat::I16: - intFormat = GL_R16; - format = GL_RED; - pxPitch = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - - GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - for (size_t i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - } + GLenum intFormat = 0, format = 0; + int pxPitch = 0; + switch (fmt) { + case TextureFormat::RGBA8: + intFormat = GL_RGBA8; + format = GL_RGBA; + pxPitch = 4; + break; + case TextureFormat::I8: + intFormat = GL_R8; + format = GL_RED; + pxPitch = 1; + break; + case TextureFormat::I16: + intFormat = GL_R16; + format = GL_RED; + pxPitch = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); } + + GLenum compType = intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + for (size_t i = 0; i < mips; ++i) { + glTexImage3D(GL_TEXTURE_2D_ARRAY, i, intFormat, width, height, layers, 0, format, compType, dataIt); + dataIt += width * height * layers * pxPitch; + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + } + } + public: - ~GLTextureSA() { glDeleteTextures(1, &m_tex); } + ~GLTextureSA() { glDeleteTextures(1, &m_tex); } - void setClampMode(TextureClampMode mode) - { - if (m_clampMode == mode) - return; - m_clampMode = mode; - glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); - SetClampMode(GL_TEXTURE_2D_ARRAY, mode); - } + void setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); + SetClampMode(GL_TEXTURE_2D_ARRAY, mode); + } - void bind(size_t idx) const - { - glActiveTexture(GL_TEXTURE0 + idx); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); - } + void bind(size_t idx) const { + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_tex); + } }; -class GLTextureD : public GraphicsDataNode -{ - friend class GLDataFactory; - friend struct GLCommandQueue; - GLuint m_texs[3]; - std::unique_ptr m_cpuBuf; - size_t m_cpuSz = 0; - GLenum m_intFormat, m_format; - size_t m_width = 0; - size_t m_height = 0; - int m_validMask = 0; - TextureClampMode m_clampMode = TextureClampMode::Invalid; - GLTextureD(const ObjToken& parent, size_t width, size_t height, - TextureFormat fmt, TextureClampMode clampMode) - : GraphicsDataNode(parent), m_width(width), m_height(height) - { - int pxPitch = 4; - switch (fmt) - { - case TextureFormat::RGBA8: - m_intFormat = GL_RGBA8; - m_format = GL_RGBA; - pxPitch = 4; - break; - case TextureFormat::I8: - m_intFormat = GL_R8; - m_format = GL_RED; - pxPitch = 1; - break; - case TextureFormat::I16: - m_intFormat = GL_R16; - m_format = GL_RED; - pxPitch = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_cpuSz = width * height * pxPitch; - m_cpuBuf.reset(new uint8_t[m_cpuSz]); - - GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - glGenTextures(3, m_texs); - for (int i=0 ; i<3 ; ++i) - { - glBindTexture(GL_TEXTURE_2D, m_texs[i]); - glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, compType, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - SetClampMode(GL_TEXTURE_2D, clampMode); - } +class GLTextureD : public GraphicsDataNode { + friend class GLDataFactory; + friend struct GLCommandQueue; + GLuint m_texs[3]; + std::unique_ptr m_cpuBuf; + size_t m_cpuSz = 0; + GLenum m_intFormat, m_format; + size_t m_width = 0; + size_t m_height = 0; + int m_validMask = 0; + TextureClampMode m_clampMode = TextureClampMode::Invalid; + GLTextureD(const ObjToken& parent, size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) + : GraphicsDataNode(parent), m_width(width), m_height(height) { + int pxPitch = 4; + switch (fmt) { + case TextureFormat::RGBA8: + m_intFormat = GL_RGBA8; + m_format = GL_RGBA; + pxPitch = 4; + break; + case TextureFormat::I8: + m_intFormat = GL_R8; + m_format = GL_RED; + pxPitch = 1; + break; + case TextureFormat::I16: + m_intFormat = GL_R16; + m_format = GL_RED; + pxPitch = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); } + m_cpuSz = width * height * pxPitch; + m_cpuBuf.reset(new uint8_t[m_cpuSz]); + + GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + glGenTextures(3, m_texs); + for (int i = 0; i < 3; ++i) { + glBindTexture(GL_TEXTURE_2D, m_texs[i]); + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, width, height, 0, m_format, compType, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + SetClampMode(GL_TEXTURE_2D, clampMode); + } + } public: - ~GLTextureD() { glDeleteTextures(3, m_texs); } + ~GLTextureD() { glDeleteTextures(3, m_texs); } - void update(int b) - { - int slot = 1 << b; - if ((slot & m_validMask) == 0) - { - glBindTexture(GL_TEXTURE_2D, m_texs[b]); - GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, m_width, m_height, 0, m_format, compType, m_cpuBuf.get()); - m_validMask |= slot; - } + void update(int b) { + int slot = 1 << b; + if ((slot & m_validMask) == 0) { + glBindTexture(GL_TEXTURE_2D, m_texs[b]); + GLenum compType = m_intFormat == GL_R16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + glTexImage2D(GL_TEXTURE_2D, 0, m_intFormat, m_width, m_height, 0, m_format, compType, m_cpuBuf.get()); + m_validMask |= slot; } + } - void load(const void* data, size_t sz) - { - size_t bufSz = std::min(sz, m_cpuSz); - memcpy(m_cpuBuf.get(), data, bufSz); - m_validMask = 0; - } - void* map(size_t sz) - { - if (sz > m_cpuSz) - return nullptr; - return m_cpuBuf.get(); - } - void unmap() - { - m_validMask = 0; - } + void load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memcpy(m_cpuBuf.get(), data, bufSz); + m_validMask = 0; + } + void* map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_cpuBuf.get(); + } + void unmap() { m_validMask = 0; } - void setClampMode(TextureClampMode mode) - { - if (m_clampMode == mode) - return; - m_clampMode = mode; - for (int i=0 ; i<3 ; ++i) - { - glBindTexture(GL_TEXTURE_2D, m_texs[i]); - SetClampMode(GL_TEXTURE_2D, mode); - } + void setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + for (int i = 0; i < 3; ++i) { + glBindTexture(GL_TEXTURE_2D, m_texs[i]); + SetClampMode(GL_TEXTURE_2D, mode); } + } - void bind(size_t idx, int b) - { - glActiveTexture(GL_TEXTURE0 + idx); - glBindTexture(GL_TEXTURE_2D, m_texs[b]); - } + void bind(size_t idx, int b) { + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, m_texs[b]); + } }; #define MAX_BIND_TEXS 4 -class GLTextureR : public GraphicsDataNode -{ - friend class GLDataFactory; - friend struct GLCommandQueue; - struct GLCommandQueue* m_q; - GLuint m_texs[2] = {}; - GLuint m_bindTexs[2][MAX_BIND_TEXS] = {}; - GLuint m_bindFBOs[2][MAX_BIND_TEXS] = {}; - GLuint m_fbo = 0; - size_t m_width = 0; - size_t m_height = 0; - size_t m_samples = 0; - GLenum m_colorFormat; - size_t m_colorBindCount; - size_t m_depthBindCount; - GLTextureR(const ObjToken& parent, GLCommandQueue* q, size_t width, size_t height, - size_t samples, GLenum colorFormat, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); +class GLTextureR : public GraphicsDataNode { + friend class GLDataFactory; + friend struct GLCommandQueue; + struct GLCommandQueue* m_q; + GLuint m_texs[2] = {}; + GLuint m_bindTexs[2][MAX_BIND_TEXS] = {}; + GLuint m_bindFBOs[2][MAX_BIND_TEXS] = {}; + GLuint m_fbo = 0; + size_t m_width = 0; + size_t m_height = 0; + size_t m_samples = 0; + GLenum m_colorFormat; + size_t m_colorBindCount; + size_t m_depthBindCount; + GLTextureR(const ObjToken& parent, GLCommandQueue* q, size_t width, size_t height, size_t samples, + GLenum colorFormat, TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount); + public: - ~GLTextureR() - { - glDeleteTextures(2, m_texs); - glDeleteTextures(MAX_BIND_TEXS * 2, m_bindTexs[0]); - if (m_samples > 1) - glDeleteFramebuffers(MAX_BIND_TEXS * 2, m_bindFBOs[0]); - glDeleteFramebuffers(1, &m_fbo); + ~GLTextureR() { + glDeleteTextures(2, m_texs); + glDeleteTextures(MAX_BIND_TEXS * 2, m_bindTexs[0]); + if (m_samples > 1) + glDeleteFramebuffers(MAX_BIND_TEXS * 2, m_bindFBOs[0]); + glDeleteFramebuffers(1, &m_fbo); + } + + void setClampMode(TextureClampMode mode) { + for (int i = 0; i < m_colorBindCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_bindTexs[0][i]); + SetClampMode(GL_TEXTURE_2D, mode); + } + for (int i = 0; i < m_depthBindCount; ++i) { + glBindTexture(GL_TEXTURE_2D, m_bindTexs[1][i]); + SetClampMode(GL_TEXTURE_2D, mode); + } + } + + void bind(size_t idx, int bindIdx, bool depth) const { + glActiveTexture(GL_TEXTURE0 + idx); + glBindTexture(GL_TEXTURE_2D, m_bindTexs[depth][bindIdx]); + } + + void resize(size_t width, size_t height) { + m_width = width; + m_height = height; + + GLenum compType = m_colorFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + if (m_samples > 1) { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_colorFormat, width, height, GL_FALSE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT32F, width, height, GL_FALSE); + } else { + glBindTexture(GL_TEXTURE_2D, m_texs[0]); + glTexImage2D(GL_TEXTURE_2D, 0, m_colorFormat, width, height, 0, GL_RGBA, compType, nullptr); + glBindTexture(GL_TEXTURE_2D, m_texs[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, + nullptr); + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glDepthMask(GL_TRUE); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - void setClampMode(TextureClampMode mode) - { - for (int i=0 ; i 1) - { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_colorFormat, width, height, GL_FALSE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_DEPTH_COMPONENT32F, width, height, GL_FALSE); - } - else - { - glBindTexture(GL_TEXTURE_2D, m_texs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, m_colorFormat, width, height, 0, GL_RGBA, compType, nullptr); - glBindTexture(GL_TEXTURE_2D, m_texs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glDepthMask(GL_TRUE); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - for (int i=0 ; i -GLDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); - return {new GLTextureS(m_data, width, height, mips, fmt, clampMode, - factory.m_glCtx->m_anisotropy, data, sz)}; +ObjToken GLDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, + const void* data, size_t sz) { + GLDataFactoryImpl& factory = static_cast(m_parent); + return {new GLTextureS(m_data, width, height, mips, fmt, clampMode, factory.m_glCtx->m_anisotropy, data, sz)}; } -ObjToken -GLDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void *data, size_t sz) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); - return {new GLTextureSA(m_data, width, height, layers, mips, fmt, clampMode, - factory.m_glCtx->m_anisotropy, data, sz)}; +ObjToken GLDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, + size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, + size_t sz) { + GLDataFactoryImpl& factory = static_cast(m_parent); + return { + new GLTextureSA(m_data, width, height, layers, mips, fmt, clampMode, factory.m_glCtx->m_anisotropy, data, sz)}; } -static const GLenum PRIMITIVE_TABLE[] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_PATCHES -}; +static const GLenum PRIMITIVE_TABLE[] = {GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_PATCHES}; -static const GLenum BLEND_FACTOR_TABLE[] = -{ - GL_ZERO, - GL_ONE, - GL_SRC_COLOR, - GL_ONE_MINUS_SRC_COLOR, - GL_DST_COLOR, - GL_ONE_MINUS_DST_COLOR, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_DST_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_SRC1_COLOR, - GL_ONE_MINUS_SRC1_COLOR -}; +static const GLenum BLEND_FACTOR_TABLE[] = {GL_ZERO, GL_ONE, + GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, + GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, + GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR}; -static const GLenum SHADER_STAGE_TABLE[] = -{ - 0, - GL_VERTEX_SHADER, - GL_FRAGMENT_SHADER, - GL_GEOMETRY_SHADER, - GL_TESS_CONTROL_SHADER, - GL_TESS_EVALUATION_SHADER -}; +static const GLenum SHADER_STAGE_TABLE[] = { + 0, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER}; -class GLShaderStage : public GraphicsDataNode -{ - friend class GLDataFactory; - GLuint m_shad = 0; - std::vector> m_texNames; - std::vector> m_blockNames; +class GLShaderStage : public GraphicsDataNode { + friend class GLDataFactory; + GLuint m_shad = 0; + std::vector> m_texNames; + std::vector> m_blockNames; - static constexpr EShLanguage ShaderTypes[] = - { - EShLangVertex, - EShLangVertex, - EShLangFragment, - EShLangGeometry, - EShLangTessControl, - EShLangTessEvaluation - }; + static constexpr EShLanguage ShaderTypes[] = {EShLangVertex, EShLangVertex, EShLangFragment, + EShLangGeometry, EShLangTessControl, EShLangTessEvaluation}; - /* Use glslang's reflection API to pull out uniform indices from Vulkan - * version of shader. Aids in glGetUniformBlockIndex and glGetUniformLocation calls */ - void BuildNameLists(const char* source, PipelineStage stage) - { - EShLanguage lang = ShaderTypes[int(stage)]; - const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); - glslang::TShader shader(lang); - shader.setStrings(&source, 1); - if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) - { - printf("%s\n", source); - Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog()); - } - - glslang::TProgram prog; - prog.addShader(&shader); - if (!prog.link(messages)) - { - printf("%s\n", source); - Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); - } - - prog.buildReflection(); - int count = prog.getNumLiveUniformVariables(); - for (int i = 0; i < count; ++i) - { - const glslang::TType* tp = prog.getUniformTType(i); - if (tp->getBasicType() != glslang::TBasicType::EbtSampler) - continue; - const auto& qual = tp->getQualifier(); - if (!qual.hasBinding()) - Log.report(logvisor::Fatal, "shader uniform %s does not have layout binding", prog.getUniformName(i)); - m_texNames.emplace_back(std::make_pair(prog.getUniformName(i), - qual.layoutBinding - BOO_GLSL_MAX_UNIFORM_COUNT)); - } - count = prog.getNumLiveUniformBlocks(); - m_blockNames.reserve(count); - for (int i = 0; i < count; ++i) - { - const glslang::TType* tp = prog.getUniformBlockTType(i); - const auto& qual = tp->getQualifier(); - if (!qual.hasBinding()) - Log.report(logvisor::Fatal, "shader uniform %s does not have layout binding", prog.getUniformBlockName(i)); - m_blockNames.emplace_back(std::make_pair(prog.getUniformBlockName(i), qual.layoutBinding)); - } + /* Use glslang's reflection API to pull out uniform indices from Vulkan + * version of shader. Aids in glGetUniformBlockIndex and glGetUniformLocation calls */ + void BuildNameLists(const char* source, PipelineStage stage) { + EShLanguage lang = ShaderTypes[int(stage)]; + const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); + glslang::TShader shader(lang); + shader.setStrings(&source, 1); + if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) { + printf("%s\n", source); + Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog()); } - GLShaderStage(const ObjToken& parent, const char* source, PipelineStage stage) - : GraphicsDataNode(parent) - { - BuildNameLists(source, stage); - - m_shad = glCreateShader(SHADER_STAGE_TABLE[int(stage)]); - if (!m_shad) - { - Log.report(logvisor::Fatal, "unable to create shader"); - return; - } - - glShaderSource(m_shad, 1, &source, nullptr); - glCompileShader(m_shad); - GLint status; - glGetShaderiv(m_shad, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) - { - GLint logLen; - glGetShaderiv(m_shad, GL_INFO_LOG_LENGTH, &logLen); - std::unique_ptr log(new char[logLen]); - glGetShaderInfoLog(m_shad, logLen, nullptr, log.get()); - Log.report(logvisor::Fatal, "unable to compile source\n%s\n%s\n", log.get(), source); - return; - } + glslang::TProgram prog; + prog.addShader(&shader); + if (!prog.link(messages)) { + printf("%s\n", source); + Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); } + + prog.buildReflection(); + int count = prog.getNumLiveUniformVariables(); + for (int i = 0; i < count; ++i) { + const glslang::TType* tp = prog.getUniformTType(i); + if (tp->getBasicType() != glslang::TBasicType::EbtSampler) + continue; + const auto& qual = tp->getQualifier(); + if (!qual.hasBinding()) + Log.report(logvisor::Fatal, "shader uniform %s does not have layout binding", prog.getUniformName(i)); + m_texNames.emplace_back(std::make_pair(prog.getUniformName(i), qual.layoutBinding - BOO_GLSL_MAX_UNIFORM_COUNT)); + } + count = prog.getNumLiveUniformBlocks(); + m_blockNames.reserve(count); + for (int i = 0; i < count; ++i) { + const glslang::TType* tp = prog.getUniformBlockTType(i); + const auto& qual = tp->getQualifier(); + if (!qual.hasBinding()) + Log.report(logvisor::Fatal, "shader uniform %s does not have layout binding", prog.getUniformBlockName(i)); + m_blockNames.emplace_back(std::make_pair(prog.getUniformBlockName(i), qual.layoutBinding)); + } + } + + GLShaderStage(const ObjToken& parent, const char* source, PipelineStage stage) + : GraphicsDataNode(parent) { + BuildNameLists(source, stage); + + m_shad = glCreateShader(SHADER_STAGE_TABLE[int(stage)]); + if (!m_shad) { + Log.report(logvisor::Fatal, "unable to create shader"); + return; + } + + glShaderSource(m_shad, 1, &source, nullptr); + glCompileShader(m_shad); + GLint status; + glGetShaderiv(m_shad, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + GLint logLen; + glGetShaderiv(m_shad, GL_INFO_LOG_LENGTH, &logLen); + std::unique_ptr log(new char[logLen]); + glGetShaderInfoLog(m_shad, logLen, nullptr, log.get()); + Log.report(logvisor::Fatal, "unable to compile source\n%s\n%s\n", log.get(), source); + return; + } + } + public: - ~GLShaderStage() { if (m_shad) glDeleteShader(m_shad); } - GLuint getShader() const { return m_shad; } - const std::vector>& getTexNames() const { return m_texNames; } - const std::vector>& getBlockNames() const { return m_blockNames; } + ~GLShaderStage() { + if (m_shad) + glDeleteShader(m_shad); + } + GLuint getShader() const { return m_shad; } + const std::vector>& getTexNames() const { return m_texNames; } + const std::vector>& getBlockNames() const { return m_blockNames; } }; -class GLShaderPipeline : public GraphicsDataNode -{ +class GLShaderPipeline : public GraphicsDataNode { protected: - friend class GLDataFactory; - friend struct GLCommandQueue; - friend struct GLShaderDataBinding; - mutable ObjToken m_vertex; - mutable ObjToken m_fragment; - mutable ObjToken m_geometry; - mutable ObjToken m_control; - mutable ObjToken m_evaluation; - std::vector m_elements; - size_t baseVert = 0; - size_t baseInst = 0; - mutable GLuint m_prog = 0; - GLenum m_sfactor = GL_ONE; - GLenum m_dfactor = GL_ZERO; - GLenum m_drawPrim = GL_TRIANGLES; - ZTest m_depthTest = ZTest::LEqual; - bool m_depthWrite = true; - bool m_colorWrite = true; - bool m_alphaWrite = true; - bool m_subtractBlend = false; - bool m_overwriteAlpha = false; - CullMode m_culling; - uint32_t m_patchSize = 0; - mutable GLint m_uniLocs[BOO_GLSL_MAX_UNIFORM_COUNT]; - GLShaderPipeline(const ObjToken& parent, - ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& info) - : GraphicsDataNode(parent) - { - std::fill(std::begin(m_uniLocs), std::end(m_uniLocs), -1); + friend class GLDataFactory; + friend struct GLCommandQueue; + friend struct GLShaderDataBinding; + mutable ObjToken m_vertex; + mutable ObjToken m_fragment; + mutable ObjToken m_geometry; + mutable ObjToken m_control; + mutable ObjToken m_evaluation; + std::vector m_elements; + size_t baseVert = 0; + size_t baseInst = 0; + mutable GLuint m_prog = 0; + GLenum m_sfactor = GL_ONE; + GLenum m_dfactor = GL_ZERO; + GLenum m_drawPrim = GL_TRIANGLES; + ZTest m_depthTest = ZTest::LEqual; + bool m_depthWrite = true; + bool m_colorWrite = true; + bool m_alphaWrite = true; + bool m_subtractBlend = false; + bool m_overwriteAlpha = false; + CullMode m_culling; + uint32_t m_patchSize = 0; + mutable GLint m_uniLocs[BOO_GLSL_MAX_UNIFORM_COUNT]; + GLShaderPipeline(const ObjToken& parent, ObjToken vertex, + ObjToken fragment, ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) + : GraphicsDataNode(parent) { + std::fill(std::begin(m_uniLocs), std::end(m_uniLocs), -1); - if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) - { - m_sfactor = GL_SRC_ALPHA; - m_dfactor = GL_ONE; - m_subtractBlend = true; - } - else - { - m_sfactor = BLEND_FACTOR_TABLE[int(info.srcFac)]; - m_dfactor = BLEND_FACTOR_TABLE[int(info.dstFac)]; - m_subtractBlend = false; - } - - m_depthTest = info.depthTest; - m_depthWrite = info.depthWrite; - m_colorWrite = info.colorWrite; - m_alphaWrite = info.alphaWrite; - m_overwriteAlpha = info.overwriteAlpha; - m_culling = info.culling; - m_drawPrim = PRIMITIVE_TABLE[int(info.prim)]; - m_patchSize = info.patchSize; - - m_vertex = vertex; - m_fragment = fragment; - m_geometry = geometry; - m_control = control; - m_evaluation = evaluation; - - if (control && evaluation) - m_drawPrim = GL_PATCHES; - - m_elements.reserve(vtxFmt.elementCount); - for (size_t i=0 ; i()->getShader()); - if (m_fragment) - glAttachShader(m_prog, m_fragment.cast()->getShader()); - if (m_geometry) - glAttachShader(m_prog, m_geometry.cast()->getShader()); - if (m_control) - glAttachShader(m_prog, m_control.cast()->getShader()); - if (m_evaluation) - glAttachShader(m_prog, m_evaluation.cast()->getShader()); + if (m_vertex) + glAttachShader(m_prog, m_vertex.cast()->getShader()); + if (m_fragment) + glAttachShader(m_prog, m_fragment.cast()->getShader()); + if (m_geometry) + glAttachShader(m_prog, m_geometry.cast()->getShader()); + if (m_control) + glAttachShader(m_prog, m_control.cast()->getShader()); + if (m_evaluation) + glAttachShader(m_prog, m_evaluation.cast()->getShader()); - glLinkProgram(m_prog); + glLinkProgram(m_prog); - if (m_vertex) - glDetachShader(m_prog, m_vertex.cast()->getShader()); - if (m_fragment) - glDetachShader(m_prog, m_fragment.cast()->getShader()); - if (m_geometry) - glDetachShader(m_prog, m_geometry.cast()->getShader()); - if (m_control) - glDetachShader(m_prog, m_control.cast()->getShader()); - if (m_evaluation) - glDetachShader(m_prog, m_evaluation.cast()->getShader()); + if (m_vertex) + glDetachShader(m_prog, m_vertex.cast()->getShader()); + if (m_fragment) + glDetachShader(m_prog, m_fragment.cast()->getShader()); + if (m_geometry) + glDetachShader(m_prog, m_geometry.cast()->getShader()); + if (m_control) + glDetachShader(m_prog, m_control.cast()->getShader()); + if (m_evaluation) + glDetachShader(m_prog, m_evaluation.cast()->getShader()); - GLint status; - glGetProgramiv(m_prog, GL_LINK_STATUS, &status); - if (status != GL_TRUE) - { - GLint logLen; - glGetProgramiv(m_prog, GL_INFO_LOG_LENGTH, &logLen); - std::unique_ptr log(new char[logLen]); - glGetProgramInfoLog(m_prog, logLen, nullptr, log.get()); - Log.report(logvisor::Fatal, "unable to link shader program\n%s\n", log.get()); - return 0; - } + GLint status; + glGetProgramiv(m_prog, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + GLint logLen; + glGetProgramiv(m_prog, GL_INFO_LOG_LENGTH, &logLen); + std::unique_ptr log(new char[logLen]); + glGetProgramInfoLog(m_prog, logLen, nullptr, log.get()); + Log.report(logvisor::Fatal, "unable to link shader program\n%s\n", log.get()); + return 0; + } - glUseProgram(m_prog); + glUseProgram(m_prog); - for (const auto& shader : {m_vertex, m_fragment, m_geometry, m_control, m_evaluation}) - { - if (const GLShaderStage* stage = shader.cast()) - { - for (const auto& name : stage->getBlockNames()) - { - GLint uniLoc = glGetUniformBlockIndex(m_prog, name.first.c_str()); - //if (uniLoc < 0) - // Log.report(logvisor::Warning, "unable to find uniform block '%s'", uniformBlockNames[i]); - m_uniLocs[name.second] = uniLoc; - } - for (const auto& name : stage->getTexNames()) - { - GLint texLoc = glGetUniformLocation(m_prog, name.first.c_str()); - if (texLoc < 0) - { /* Log.report(logvisor::Warning, "unable to find sampler variable '%s'", texNames[i]); */ } - else - glUniform1i(texLoc, name.second); - } - } - } - - m_vertex.reset(); - m_fragment.reset(); - m_geometry.reset(); - m_control.reset(); - m_evaluation.reset(); - } - else - { - glUseProgram(m_prog); + for (const auto& shader : {m_vertex, m_fragment, m_geometry, m_control, m_evaluation}) { + if (const GLShaderStage* stage = shader.cast()) { + for (const auto& name : stage->getBlockNames()) { + GLint uniLoc = glGetUniformBlockIndex(m_prog, name.first.c_str()); + // if (uniLoc < 0) + // Log.report(logvisor::Warning, "unable to find uniform block '%s'", uniformBlockNames[i]); + m_uniLocs[name.second] = uniLoc; + } + for (const auto& name : stage->getTexNames()) { + GLint texLoc = glGetUniformLocation(m_prog, name.first.c_str()); + if (texLoc < 0) { /* Log.report(logvisor::Warning, "unable to find sampler variable '%s'", texNames[i]); */ + } else + glUniform1i(texLoc, name.second); + } } + } - if (m_dfactor != GL_ZERO) - { - glEnable(GL_BLEND); - if (m_overwriteAlpha) - glBlendFuncSeparate(m_sfactor, m_dfactor, GL_ONE, GL_ZERO); - else - glBlendFuncSeparate(m_sfactor, m_dfactor, m_sfactor, m_dfactor); - if (m_subtractBlend) - glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, - m_overwriteAlpha ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT); - else - glBlendEquation(GL_FUNC_ADD); - } - else - glDisable(GL_BLEND); - - if (m_depthTest != ZTest::None) - { - glEnable(GL_DEPTH_TEST); - switch (m_depthTest) - { - case ZTest::LEqual: - default: - glDepthFunc(GL_LEQUAL); - break; - case ZTest::Greater: - glDepthFunc(GL_GREATER); - break; - case ZTest::GEqual: - glDepthFunc(GL_GEQUAL); - break; - case ZTest::Equal: - glDepthFunc(GL_EQUAL); - break; - } - } - else - glDisable(GL_DEPTH_TEST); - glDepthMask(m_depthWrite); - glColorMask(m_colorWrite, m_colorWrite, m_colorWrite, m_alphaWrite); - - if (m_culling != CullMode::None) - { - glEnable(GL_CULL_FACE); - glCullFace(m_culling == CullMode::Backface ? GL_BACK : GL_FRONT); - } - else - glDisable(GL_CULL_FACE); - - glPatchParameteri(GL_PATCH_VERTICES, m_patchSize); - - return m_prog; + m_vertex.reset(); + m_fragment.reset(); + m_geometry.reset(); + m_control.reset(); + m_evaluation.reset(); + } else { + glUseProgram(m_prog); } + + if (m_dfactor != GL_ZERO) { + glEnable(GL_BLEND); + if (m_overwriteAlpha) + glBlendFuncSeparate(m_sfactor, m_dfactor, GL_ONE, GL_ZERO); + else + glBlendFuncSeparate(m_sfactor, m_dfactor, m_sfactor, m_dfactor); + if (m_subtractBlend) + glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, m_overwriteAlpha ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT); + else + glBlendEquation(GL_FUNC_ADD); + } else + glDisable(GL_BLEND); + + if (m_depthTest != ZTest::None) { + glEnable(GL_DEPTH_TEST); + switch (m_depthTest) { + case ZTest::LEqual: + default: + glDepthFunc(GL_LEQUAL); + break; + case ZTest::Greater: + glDepthFunc(GL_GREATER); + break; + case ZTest::GEqual: + glDepthFunc(GL_GEQUAL); + break; + case ZTest::Equal: + glDepthFunc(GL_EQUAL); + break; + } + } else + glDisable(GL_DEPTH_TEST); + glDepthMask(m_depthWrite); + glColorMask(m_colorWrite, m_colorWrite, m_colorWrite, m_alphaWrite); + + if (m_culling != CullMode::None) { + glEnable(GL_CULL_FACE); + glCullFace(m_culling == CullMode::Backface ? GL_BACK : GL_FRONT); + } else + glDisable(GL_CULL_FACE); + + glPatchParameteri(GL_PATCH_VERTICES, m_patchSize); + + return m_prog; + } }; -ObjToken -GLDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); +ObjToken GLDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) { + GLDataFactoryImpl& factory = static_cast(m_parent); - if (stage == PipelineStage::Control || stage == PipelineStage::Evaluation) - { - if (!factory.m_hasTessellation) - Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); - } + if (stage == PipelineStage::Control || stage == PipelineStage::Evaluation) { + if (!factory.m_hasTessellation) + Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); + } - return {new GLShaderStage(m_data, (char*)data, stage)}; + return {new GLShaderStage(m_data, (char*)data, stage)}; } -ObjToken -GLDataFactory::Context::newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); +ObjToken GLDataFactory::Context::newShaderPipeline( + ObjToken vertex, ObjToken fragment, ObjToken geometry, + ObjToken control, ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) { + GLDataFactoryImpl& factory = static_cast(m_parent); - if (control || evaluation) - { - if (!factory.m_hasTessellation) - Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); - if (additionalInfo.patchSize > factory.m_maxPatchSize) - Log.report(logvisor::Fatal, "Device supports %d patch vertices, %d requested", - int(factory.m_maxPatchSize), int(additionalInfo.patchSize)); - } + if (control || evaluation) { + if (!factory.m_hasTessellation) + Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); + if (additionalInfo.patchSize > factory.m_maxPatchSize) + Log.report(logvisor::Fatal, "Device supports %d patch vertices, %d requested", int(factory.m_maxPatchSize), + int(additionalInfo.patchSize)); + } - return {new GLShaderPipeline(m_data, vertex, fragment, geometry, control, - evaluation, vtxFmt, additionalInfo)}; + return {new GLShaderPipeline(m_data, vertex, fragment, geometry, control, evaluation, vtxFmt, additionalInfo)}; } -struct GLShaderDataBinding : GraphicsDataNode -{ - ObjToken m_pipeline; - ObjToken m_vbo; - ObjToken m_instVbo; - ObjToken m_ibo; - std::vector> m_ubufs; - std::vector> m_ubufOffs; - struct BoundTex - { - ObjToken tex; - int idx; - bool depth; - }; - std::vector m_texs; - size_t m_baseVert; - size_t m_baseInst; - GLuint m_vao[3] = {}; +struct GLShaderDataBinding : GraphicsDataNode { + ObjToken m_pipeline; + ObjToken m_vbo; + ObjToken m_instVbo; + ObjToken m_ibo; + std::vector> m_ubufs; + std::vector> m_ubufOffs; + struct BoundTex { + ObjToken tex; + int idx; + bool depth; + }; + std::vector m_texs; + size_t m_baseVert; + size_t m_baseInst; + GLuint m_vao[3] = {}; - GLShaderDataBinding(const ObjToken& d, - const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const ObjToken* texs, - const int* bindTexIdx, const bool* depthBind, - size_t baseVert, size_t baseInst) - : GraphicsDataNode(d), - m_pipeline(pipeline), m_vbo(vbo), m_instVbo(instVbo), m_ibo(ibo), m_baseVert(baseVert), m_baseInst(baseInst) - { - if (ubufOffs && ubufSizes) - { - m_ubufOffs.reserve(ubufCount); - for (size_t i=0 ; i& d, const ObjToken& pipeline, + const ObjToken& vbo, const ObjToken& instVbo, + const ObjToken& ibo, size_t ubufCount, const ObjToken* ubufs, + const size_t* ubufOffs, const size_t* ubufSizes, size_t texCount, const ObjToken* texs, + const int* bindTexIdx, const bool* depthBind, size_t baseVert, size_t baseInst) + : GraphicsDataNode(d) + , m_pipeline(pipeline) + , m_vbo(vbo) + , m_instVbo(instVbo) + , m_ibo(ibo) + , m_baseVert(baseVert) + , m_baseInst(baseInst) { + if (ubufOffs && ubufSizes) { + m_ubufOffs.reserve(ubufCount); + for (size_t i = 0; i < ubufCount; ++i) { #ifndef NDEBUG - if (ubufOffs[i] % 256) - Log.report(logvisor::Fatal, "non-256-byte-aligned uniform-offset %d provided to newShaderDataBinding", int(i)); + if (ubufOffs[i] % 256) + Log.report(logvisor::Fatal, "non-256-byte-aligned uniform-offset %d provided to newShaderDataBinding", + int(i)); #endif - m_ubufOffs.emplace_back(ubufOffs[i], (ubufSizes[i] + 255) & ~255); - } - } - m_ubufs.reserve(ubufCount); - for (size_t i=0 ; i(); - GLuint prog = pipeline.bind(); - glBindVertexArray(m_vao[b]); - if (m_ubufOffs.size()) - { - for (size_t i=0 ; i& offset = m_ubufOffs[i]; - if (ubuf->dynamic()) - static_cast*>(ubuf)->bindUniformRange(i, offset.first, offset.second, b); - else - static_cast(ubuf)->bindUniformRange(i, offset.first, offset.second); - glUniformBlockBinding(prog, loc, i); - } - } + ~GLShaderDataBinding() { glDeleteVertexArrays(3, m_vao); } + + void bind(int b) const { + GLShaderPipeline& pipeline = *m_pipeline.cast(); + GLuint prog = pipeline.bind(); + glBindVertexArray(m_vao[b]); + if (m_ubufOffs.size()) { + for (size_t i = 0; i < m_ubufs.size(); ++i) { + GLint loc = pipeline.m_uniLocs[i]; + if (loc < 0) + continue; + IGraphicsBuffer* ubuf = m_ubufs[i].get(); + const std::pair& offset = m_ubufOffs[i]; + if (ubuf->dynamic()) + static_cast*>(ubuf)->bindUniformRange(i, offset.first, offset.second, b); else - { - for (size_t i=0 ; idynamic()) - static_cast*>(ubuf)->bindUniform(i, b); - else - static_cast(ubuf)->bindUniform(i); - glUniformBlockBinding(prog, loc, i); - } - } - for (size_t i=0 ; itype()) - { - case TextureType::Dynamic: - tex.tex.cast()->bind(i, b); - break; - case TextureType::Static: - tex.tex.cast()->bind(i); - break; - case TextureType::StaticArray: - tex.tex.cast()->bind(i); - break; - case TextureType::Render: - tex.tex.cast()->bind(i, tex.idx, tex.depth); - break; - default: break; - } - } - } + static_cast(ubuf)->bindUniformRange(i, offset.first, offset.second); + glUniformBlockBinding(prog, loc, i); + } + } else { + for (size_t i = 0; i < m_ubufs.size(); ++i) { + GLint loc = pipeline.m_uniLocs[i]; + if (loc < 0) + continue; + IGraphicsBuffer* ubuf = m_ubufs[i].get(); + if (ubuf->dynamic()) + static_cast*>(ubuf)->bindUniform(i, b); + else + static_cast(ubuf)->bindUniform(i); + glUniformBlockBinding(prog, loc, i); + } } + for (size_t i = 0; i < m_texs.size(); ++i) { + const BoundTex& tex = m_texs[i]; + if (tex.tex) { + switch (tex.tex->type()) { + case TextureType::Dynamic: + tex.tex.cast()->bind(i, b); + break; + case TextureType::Static: + tex.tex.cast()->bind(i); + break; + case TextureType::StaticArray: + tex.tex.cast()->bind(i); + break; + case TextureType::Render: + tex.tex.cast()->bind(i, tex.idx, tex.depth); + break; + default: + break; + } + } + } + } }; GLDataFactory::Context::Context(GLDataFactory& parent __BooTraceArgs) -: m_parent(parent), m_data(new BaseGraphicsData(static_cast(parent) __BooTraceArgsUse)) -{} +: m_parent(parent), m_data(new BaseGraphicsData(static_cast(parent) __BooTraceArgsUse)) {} GLDataFactory::Context::~Context() {} -void GLDataFactoryImpl::commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs) -{ - GLDataFactory::Context ctx(*this __BooTraceArgsUse); - if (!trans(ctx)) - return; +void GLDataFactoryImpl::commitTransaction(const FactoryCommitFunc& trans __BooTraceArgs) { + GLDataFactory::Context ctx(*this __BooTraceArgsUse); + if (!trans(ctx)) + return; - /* Let's go ahead and flush to ensure our data gets to the GPU - While this isn't strictly required, some drivers might behave - differently */ - //glFlush(); + /* Let's go ahead and flush to ensure our data gets to the GPU + While this isn't strictly required, some drivers might behave + differently */ + // glFlush(); } -ObjToken GLDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) -{ - ObjToken pool(new BaseGraphicsPool(*this __BooTraceArgsUse)); - return {new GLGraphicsBufferD(pool, use, stride * count)}; +ObjToken GLDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) { + ObjToken pool(new BaseGraphicsPool(*this __BooTraceArgsUse)); + return {new GLGraphicsBufferD(pool, use, stride * count)}; } -static const GLint SEMANTIC_COUNT_TABLE[] = -{ - 0, - 3, - 4, - 3, - 4, - 4, - 4, - 2, - 4, - 4, - 4 -}; +static const GLint SEMANTIC_COUNT_TABLE[] = {0, 3, 4, 3, 4, 4, 4, 2, 4, 4, 4}; -static const size_t SEMANTIC_SIZE_TABLE[] = -{ - 0, - 12, - 16, - 12, - 16, - 16, - 4, - 8, - 16, - 16, - 16 -}; +static const size_t SEMANTIC_SIZE_TABLE[] = {0, 12, 16, 12, 16, 16, 4, 8, 16, 16, 16}; -static const GLenum SEMANTIC_TYPE_TABLE[] = -{ - GL_INVALID_ENUM, - GL_FLOAT, - GL_FLOAT, - GL_FLOAT, - GL_FLOAT, - GL_FLOAT, - GL_UNSIGNED_BYTE, - GL_FLOAT, - GL_FLOAT, - GL_FLOAT, - GL_FLOAT -}; +static const GLenum SEMANTIC_TYPE_TABLE[] = {GL_INVALID_ENUM, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, + GL_UNSIGNED_BYTE, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT}; -struct GLCommandQueue : IGraphicsCommandQueue -{ - Platform platform() const { return IGraphicsDataFactory::Platform::OpenGL; } - const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } - IGraphicsContext* m_parent = nullptr; - GLContext* m_glCtx = nullptr; +struct GLCommandQueue : IGraphicsCommandQueue { + Platform platform() const { return IGraphicsDataFactory::Platform::OpenGL; } + const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } + IGraphicsContext* m_parent = nullptr; + GLContext* m_glCtx = nullptr; - std::mutex m_mt; - std::condition_variable m_cv; - std::mutex m_initmt; - std::condition_variable m_initcv; - std::thread m_thr; - - struct Command - { - enum class Op - { - SetShaderDataBinding, - SetRenderTarget, - SetViewport, - SetScissor, - SetClearColor, - ClearTarget, - Draw, - DrawIndexed, - DrawInstances, - DrawInstancesIndexed, - ResolveBindTexture, - Present - } m_op; - union - { - struct - { - SWindowRect rect; - float znear, zfar; - } viewport; - float rgba[4]; - GLbitfield flags; - struct - { - size_t start; - size_t count; - size_t instCount; - size_t startInst; - }; - }; - ObjToken binding; - ObjToken target; - ObjToken source; - ObjToken resolveTex; - int bindIdx; - bool resolveColor : 1; - bool resolveDepth : 1; - bool clearDepth : 1; - Command(Op op) : m_op(op) {} - Command(const Command&) = delete; - Command& operator=(const Command&) = delete; - Command(Command&&) = default; - Command& operator=(Command&&) = default; + std::mutex m_mt; + std::condition_variable m_cv; + std::mutex m_initmt; + std::condition_variable m_initcv; + std::thread m_thr; + + struct Command { + enum class Op { + SetShaderDataBinding, + SetRenderTarget, + SetViewport, + SetScissor, + SetClearColor, + ClearTarget, + Draw, + DrawIndexed, + DrawInstances, + DrawInstancesIndexed, + ResolveBindTexture, + Present + } m_op; + union { + struct { + SWindowRect rect; + float znear, zfar; + } viewport; + float rgba[4]; + GLbitfield flags; + struct { + size_t start; + size_t count; + size_t instCount; + size_t startInst; + }; }; - std::vector m_cmdBufs[3]; - int m_fillBuf = 0; - int m_completeBuf = 0; - int m_drawBuf = 0; - bool m_running = true; + ObjToken binding; + ObjToken target; + ObjToken source; + ObjToken resolveTex; + int bindIdx; + bool resolveColor : 1; + bool resolveDepth : 1; + bool clearDepth : 1; + Command(Op op) : m_op(op) {} + Command(const Command&) = delete; + Command& operator=(const Command&) = delete; + Command(Command&&) = default; + Command& operator=(Command&&) = default; + }; + std::vector m_cmdBufs[3]; + int m_fillBuf = 0; + int m_completeBuf = 0; + int m_drawBuf = 0; + bool m_running = true; - struct RenderTextureResize - { - ObjToken tex; - size_t width; - size_t height; - }; + struct RenderTextureResize { + ObjToken tex; + size_t width; + size_t height; + }; - /* These members are locked for multithreaded access */ - std::vector m_pendingResizes; - std::vector> m_pendingPosts1; - std::vector> m_pendingPosts2; - std::vector> m_pendingFmtAdds; - std::vector> m_pendingFboAdds; + /* These members are locked for multithreaded access */ + std::vector m_pendingResizes; + std::vector> m_pendingPosts1; + std::vector> m_pendingPosts2; + std::vector> m_pendingFmtAdds; + std::vector> m_pendingFboAdds; - static void ConfigureVertexFormat(GLShaderDataBinding* fmt) - { - glGenVertexArrays(3, fmt->m_vao); + static void ConfigureVertexFormat(GLShaderDataBinding* fmt) { + glGenVertexArrays(3, fmt->m_vao); - size_t stride = 0; - size_t instStride = 0; - auto pipeline = fmt->m_pipeline.cast(); - for (size_t i=0 ; im_elements.size() ; ++i) - { - const VertexElementDescriptor& desc = pipeline->m_elements[i]; - if ((desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None) - instStride += SEMANTIC_SIZE_TABLE[int(desc.semantic & VertexSemantic::SemanticMask)]; - else - stride += SEMANTIC_SIZE_TABLE[int(desc.semantic & VertexSemantic::SemanticMask)]; - } - - for (int b=0 ; b<3 ; ++b) - { - size_t offset = fmt->m_baseVert * stride; - size_t instOffset = fmt->m_baseInst * instStride; - glBindVertexArray(fmt->m_vao[b]); - IGraphicsBuffer* lastVBO = nullptr; - IGraphicsBuffer* lastEBO = nullptr; - for (size_t i=0 ; im_elements.size() ; ++i) - { - const VertexElementDescriptor& desc = pipeline->m_elements[i]; - IGraphicsBuffer* vbo = (desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None - ? fmt->m_instVbo.get() : fmt->m_vbo.get(); - IGraphicsBuffer* ebo = fmt->m_ibo.get(); - if (vbo != lastVBO) - { - lastVBO = vbo; - if (lastVBO->dynamic()) - static_cast*>(lastVBO)->bindVertex(b); - else - static_cast(lastVBO)->bindVertex(); - } - if (ebo != lastEBO) - { - lastEBO = ebo; - if (lastEBO->dynamic()) - static_cast*>(lastEBO)->bindIndex(b); - else - static_cast(lastEBO)->bindIndex(); - } - glEnableVertexAttribArray(i); - int maskedSem = int(desc.semantic & VertexSemantic::SemanticMask); - if ((desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None) - { - glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[maskedSem], - SEMANTIC_TYPE_TABLE[maskedSem], GL_TRUE, instStride, (void*)instOffset); - glVertexAttribDivisor(i, 1); - instOffset += SEMANTIC_SIZE_TABLE[maskedSem]; - } - else - { - glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[maskedSem], - SEMANTIC_TYPE_TABLE[maskedSem], GL_TRUE, stride, (void*)offset); - offset += SEMANTIC_SIZE_TABLE[maskedSem]; - } - } - } + size_t stride = 0; + size_t instStride = 0; + auto pipeline = fmt->m_pipeline.cast(); + for (size_t i = 0; i < pipeline->m_elements.size(); ++i) { + const VertexElementDescriptor& desc = pipeline->m_elements[i]; + if ((desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None) + instStride += SEMANTIC_SIZE_TABLE[int(desc.semantic & VertexSemantic::SemanticMask)]; + else + stride += SEMANTIC_SIZE_TABLE[int(desc.semantic & VertexSemantic::SemanticMask)]; } - static void ConfigureFBO(GLTextureR* tex) - { - glGenFramebuffers(1, &tex->m_fbo); - glBindFramebuffer(GL_FRAMEBUFFER, tex->m_fbo); - GLenum target = tex->m_samples > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex->m_texs[0], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, tex->m_texs[1], 0); - - if (tex->m_samples > 1) - { - if (tex->m_colorBindCount) - { - glGenFramebuffers(tex->m_colorBindCount, tex->m_bindFBOs[0]); - for (int i=0 ; im_colorBindCount ; ++i) - { - glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[0][i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->m_bindTexs[0][i], 0); - } - } - if (tex->m_depthBindCount) - { - glGenFramebuffers(tex->m_depthBindCount, tex->m_bindFBOs[1]); - for (int i=0 ; im_depthBindCount ; ++i) - { - glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[1][i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex->m_bindTexs[1][i], 0); - } - } + for (int b = 0; b < 3; ++b) { + size_t offset = fmt->m_baseVert * stride; + size_t instOffset = fmt->m_baseInst * instStride; + glBindVertexArray(fmt->m_vao[b]); + IGraphicsBuffer* lastVBO = nullptr; + IGraphicsBuffer* lastEBO = nullptr; + for (size_t i = 0; i < pipeline->m_elements.size(); ++i) { + const VertexElementDescriptor& desc = pipeline->m_elements[i]; + IGraphicsBuffer* vbo = (desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None + ? fmt->m_instVbo.get() + : fmt->m_vbo.get(); + IGraphicsBuffer* ebo = fmt->m_ibo.get(); + if (vbo != lastVBO) { + lastVBO = vbo; + if (lastVBO->dynamic()) + static_cast*>(lastVBO)->bindVertex(b); + else + static_cast(lastVBO)->bindVertex(); } + if (ebo != lastEBO) { + lastEBO = ebo; + if (lastEBO->dynamic()) + static_cast*>(lastEBO)->bindIndex(b); + else + static_cast(lastEBO)->bindIndex(); + } + glEnableVertexAttribArray(i); + int maskedSem = int(desc.semantic & VertexSemantic::SemanticMask); + if ((desc.semantic & VertexSemantic::Instanced) != VertexSemantic::None) { + glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[maskedSem], SEMANTIC_TYPE_TABLE[maskedSem], GL_TRUE, instStride, + (void*)instOffset); + glVertexAttribDivisor(i, 1); + instOffset += SEMANTIC_SIZE_TABLE[maskedSem]; + } else { + glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[maskedSem], SEMANTIC_TYPE_TABLE[maskedSem], GL_TRUE, stride, + (void*)offset); + offset += SEMANTIC_SIZE_TABLE[maskedSem]; + } + } } + } - static void RenderingWorker(GLCommandQueue* self) - { + static void ConfigureFBO(GLTextureR* tex) { + glGenFramebuffers(1, &tex->m_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, tex->m_fbo); + GLenum target = tex->m_samples > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex->m_texs[0], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, tex->m_texs[1], 0); + + if (tex->m_samples > 1) { + if (tex->m_colorBindCount) { + glGenFramebuffers(tex->m_colorBindCount, tex->m_bindFBOs[0]); + for (int i = 0; i < tex->m_colorBindCount; ++i) { + glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[0][i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->m_bindTexs[0][i], 0); + } + } + if (tex->m_depthBindCount) { + glGenFramebuffers(tex->m_depthBindCount, tex->m_bindFBOs[1]); + for (int i = 0; i < tex->m_depthBindCount; ++i) { + glBindFramebuffer(GL_FRAMEBUFFER, tex->m_bindFBOs[1][i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex->m_bindTexs[1][i], 0); + } + } + } + } + + static void RenderingWorker(GLCommandQueue* self) { #if _WIN32 - std::string thrName = WCSTMBS(APP->getFriendlyName().data()) + " Render"; + std::string thrName = WCSTMBS(APP->getFriendlyName().data()) + " Render"; #else - std::string thrName = std::string(APP->getFriendlyName()) + " Render"; + std::string thrName = std::string(APP->getFriendlyName()) + " Render"; #endif - logvisor::RegisterThreadName(thrName.c_str()); - GLDataFactoryImpl* dataFactory = static_cast(self->m_parent->getDataFactory()); - { - std::unique_lock lk(self->m_initmt); - self->m_parent->makeCurrent(); - const GLubyte* version = glGetString(GL_VERSION); - Log.report(logvisor::Info, "OpenGL Version: %s", version); - self->m_parent->postInit(); - glClearColor(0.f, 0.f, 0.f, 0.f); - if (GLEW_EXT_texture_filter_anisotropic) - { - GLint maxAniso; - glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); - self->m_glCtx->m_anisotropy = std::min(uint32_t(maxAniso), self->m_glCtx->m_anisotropy); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso); - } - GLint maxSamples; - glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); - self->m_glCtx->m_sampleCount = - flp2(std::min(uint32_t(maxSamples), std::max(uint32_t(1), self->m_glCtx->m_sampleCount)) - 1); + logvisor::RegisterThreadName(thrName.c_str()); + GLDataFactoryImpl* dataFactory = static_cast(self->m_parent->getDataFactory()); + { + std::unique_lock lk(self->m_initmt); + self->m_parent->makeCurrent(); + const GLubyte* version = glGetString(GL_VERSION); + Log.report(logvisor::Info, "OpenGL Version: %s", version); + self->m_parent->postInit(); + glClearColor(0.f, 0.f, 0.f, 0.f); + if (GLEW_EXT_texture_filter_anisotropic) { + GLint maxAniso; + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); + self->m_glCtx->m_anisotropy = std::min(uint32_t(maxAniso), self->m_glCtx->m_anisotropy); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso); + } + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + self->m_glCtx->m_sampleCount = + flp2(std::min(uint32_t(maxSamples), std::max(uint32_t(1), self->m_glCtx->m_sampleCount)) - 1); - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex(0xffffffff); + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(0xffffffff); - dataFactory->SetupGammaResources(); + dataFactory->SetupGammaResources(); + } + self->m_initcv.notify_one(); + while (self->m_running) { + std::vector> posts; + { + std::unique_lock lk(self->m_mt); + self->m_cv.wait(lk); + if (!self->m_running) + break; + self->m_drawBuf = self->m_completeBuf; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (self->m_pendingFboAdds.size()) { + for (ObjToken& tex : self->m_pendingFboAdds) + ConfigureFBO(tex.cast()); + self->m_pendingFboAdds.clear(); } - self->m_initcv.notify_one(); - while (self->m_running) - { - std::vector> posts; - { - std::unique_lock lk(self->m_mt); - self->m_cv.wait(lk); - if (!self->m_running) - break; - self->m_drawBuf = self->m_completeBuf; - glBindFramebuffer(GL_FRAMEBUFFER, 0); + if (self->m_pendingResizes.size()) { + for (const RenderTextureResize& resize : self->m_pendingResizes) + resize.tex.cast()->resize(resize.width, resize.height); + self->m_pendingResizes.clear(); + } - if (self->m_pendingFboAdds.size()) - { - for (ObjToken& tex : self->m_pendingFboAdds) - ConfigureFBO(tex.cast()); - self->m_pendingFboAdds.clear(); - } + if (self->m_pendingFmtAdds.size()) { + for (ObjToken& fmt : self->m_pendingFmtAdds) + if (fmt) + ConfigureVertexFormat(fmt.cast()); + self->m_pendingFmtAdds.clear(); + } - if (self->m_pendingResizes.size()) - { - for (const RenderTextureResize& resize : self->m_pendingResizes) - resize.tex.cast()->resize(resize.width, resize.height); - self->m_pendingResizes.clear(); - } - - if (self->m_pendingFmtAdds.size()) - { - for (ObjToken& fmt : self->m_pendingFmtAdds) - if (fmt) ConfigureVertexFormat(fmt.cast()); - self->m_pendingFmtAdds.clear(); - } - - if (self->m_pendingPosts2.size()) - posts.swap(self->m_pendingPosts2); + if (self->m_pendingPosts2.size()) + posts.swap(self->m_pendingPosts2); + } + std::vector& cmds = self->m_cmdBufs[self->m_drawBuf]; + GLenum currentPrim = GL_TRIANGLES; + const GLShaderDataBinding* curBinding = nullptr; + GLuint curFBO = 0; + for (const Command& cmd : cmds) { + switch (cmd.m_op) { + case Command::Op::SetShaderDataBinding: { + const GLShaderDataBinding* binding = cmd.binding.cast(); + binding->bind(self->m_drawBuf); + curBinding = binding; + currentPrim = binding->m_pipeline.cast()->m_drawPrim; + break; + } + case Command::Op::SetRenderTarget: { + const GLTextureR* tex = cmd.target.cast(); + curFBO = (!tex) ? 0 : tex->m_fbo; + glBindFramebuffer(GL_FRAMEBUFFER, curFBO); + break; + } + case Command::Op::SetViewport: + glViewport(cmd.viewport.rect.location[0], cmd.viewport.rect.location[1], cmd.viewport.rect.size[0], + cmd.viewport.rect.size[1]); + glDepthRange(cmd.viewport.znear, cmd.viewport.zfar); + break; + case Command::Op::SetScissor: + if (cmd.viewport.rect.size[0] == 0 && cmd.viewport.rect.size[1] == 0) + glDisable(GL_SCISSOR_TEST); + else { + glEnable(GL_SCISSOR_TEST); + glScissor(cmd.viewport.rect.location[0], cmd.viewport.rect.location[1], cmd.viewport.rect.size[0], + cmd.viewport.rect.size[1]); + } + break; + case Command::Op::SetClearColor: + glClearColor(cmd.rgba[0], cmd.rgba[1], cmd.rgba[2], cmd.rgba[3]); + break; + case Command::Op::ClearTarget: + if (cmd.flags & GL_COLOR_BUFFER_BIT) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + if (cmd.flags & GL_DEPTH_BUFFER_BIT) + glDepthMask(GL_TRUE); + glClear(cmd.flags); + break; + case Command::Op::Draw: + glDrawArrays(currentPrim, cmd.start, cmd.count); + break; + case Command::Op::DrawIndexed: + glDrawElements(currentPrim, cmd.count, GL_UNSIGNED_INT, reinterpret_cast(cmd.start * 4)); + break; + case Command::Op::DrawInstances: + if (cmd.startInst) + glDrawArraysInstancedBaseInstance(currentPrim, cmd.start, cmd.count, cmd.instCount, cmd.startInst); + else + glDrawArraysInstanced(currentPrim, cmd.start, cmd.count, cmd.instCount); + break; + case Command::Op::DrawInstancesIndexed: + if (cmd.startInst) + glDrawElementsInstancedBaseInstance(currentPrim, cmd.count, GL_UNSIGNED_INT, + reinterpret_cast(cmd.start * 4), cmd.instCount, cmd.startInst); + else + glDrawElementsInstanced(currentPrim, cmd.count, GL_UNSIGNED_INT, reinterpret_cast(cmd.start * 4), + cmd.instCount); + break; + case Command::Op::ResolveBindTexture: { + const SWindowRect& rect = cmd.viewport.rect; + const GLTextureR* tex = cmd.resolveTex.cast(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); + if (tex->m_samples <= 1) { + glActiveTexture(GL_TEXTURE9); + if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx]) { + glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[0][cmd.bindIdx]); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, rect.location[0], rect.location[1], rect.location[0], + rect.location[1], rect.size[0], rect.size[1]); } - std::vector& cmds = self->m_cmdBufs[self->m_drawBuf]; - GLenum currentPrim = GL_TRIANGLES; - const GLShaderDataBinding* curBinding = nullptr; - GLuint curFBO = 0; - for (const Command& cmd : cmds) - { - switch (cmd.m_op) - { - case Command::Op::SetShaderDataBinding: - { - const GLShaderDataBinding* binding = cmd.binding.cast(); - binding->bind(self->m_drawBuf); - curBinding = binding; - currentPrim = binding->m_pipeline.cast()->m_drawPrim; - break; - } - case Command::Op::SetRenderTarget: - { - const GLTextureR* tex = cmd.target.cast(); - curFBO = (!tex) ? 0 : tex->m_fbo; - glBindFramebuffer(GL_FRAMEBUFFER, curFBO); - break; - } - case Command::Op::SetViewport: - glViewport(cmd.viewport.rect.location[0], cmd.viewport.rect.location[1], - cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]); - glDepthRange(cmd.viewport.znear, cmd.viewport.zfar); - break; - case Command::Op::SetScissor: - if (cmd.viewport.rect.size[0] == 0 && cmd.viewport.rect.size[1] == 0) - glDisable(GL_SCISSOR_TEST); - else - { - glEnable(GL_SCISSOR_TEST); - glScissor(cmd.viewport.rect.location[0], cmd.viewport.rect.location[1], - cmd.viewport.rect.size[0], cmd.viewport.rect.size[1]); - } - break; - case Command::Op::SetClearColor: - glClearColor(cmd.rgba[0], cmd.rgba[1], cmd.rgba[2], cmd.rgba[3]); - break; - case Command::Op::ClearTarget: - if (cmd.flags & GL_COLOR_BUFFER_BIT) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - if (cmd.flags & GL_DEPTH_BUFFER_BIT) - glDepthMask(GL_TRUE); - glClear(cmd.flags); - break; - case Command::Op::Draw: - glDrawArrays(currentPrim, cmd.start, cmd.count); - break; - case Command::Op::DrawIndexed: - glDrawElements(currentPrim, cmd.count, GL_UNSIGNED_INT, - reinterpret_cast(cmd.start * 4)); - break; - case Command::Op::DrawInstances: - if (cmd.startInst) - glDrawArraysInstancedBaseInstance(currentPrim, cmd.start, cmd.count, cmd.instCount, cmd.startInst); - else - glDrawArraysInstanced(currentPrim, cmd.start, cmd.count, cmd.instCount); - break; - case Command::Op::DrawInstancesIndexed: - if (cmd.startInst) - glDrawElementsInstancedBaseInstance(currentPrim, cmd.count, GL_UNSIGNED_INT, - reinterpret_cast(cmd.start * 4), cmd.instCount, cmd.startInst); - else - glDrawElementsInstanced(currentPrim, cmd.count, GL_UNSIGNED_INT, - reinterpret_cast(cmd.start * 4), cmd.instCount); - break; - case Command::Op::ResolveBindTexture: - { - const SWindowRect& rect = cmd.viewport.rect; - const GLTextureR* tex = cmd.resolveTex.cast(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); - if (tex->m_samples <= 1) - { - glActiveTexture(GL_TEXTURE9); - if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx]) - { - glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[0][cmd.bindIdx]); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, - rect.location[0], rect.location[1], - rect.location[0], rect.location[1], - rect.size[0], rect.size[1]); - } - if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx]) - { - glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[1][cmd.bindIdx]); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, - rect.location[0], rect.location[1], - rect.location[0], rect.location[1], - rect.size[0], rect.size[1]); - } - } - else - { - if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx]) - { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][cmd.bindIdx]); - glBlitFramebuffer(rect.location[0], rect.location[1], - rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], - rect.location[0], rect.location[1], - rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx]) - { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[1][cmd.bindIdx]); - glBlitFramebuffer(rect.location[0], rect.location[1], - rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], - rect.location[0], rect.location[1], - rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], - GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - } - if (cmd.clearDepth) - { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_fbo); - glDepthMask(GL_TRUE); - glClear(GL_DEPTH_BUFFER_BIT); - } - glBindFramebuffer(GL_FRAMEBUFFER, curFBO); - break; - } - case Command::Op::Present: - { - if (const GLTextureR* tex = cmd.source.cast()) - { + if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx]) { + glBindTexture(GL_TEXTURE_2D, tex->m_bindTexs[1][cmd.bindIdx]); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, rect.location[0], rect.location[1], rect.location[0], + rect.location[1], rect.size[0], rect.size[1]); + } + } else { + if (cmd.resolveColor && tex->m_bindTexs[0][cmd.bindIdx]) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][cmd.bindIdx]); + glBlitFramebuffer(rect.location[0], rect.location[1], rect.location[0] + rect.size[0], + rect.location[1] + rect.size[1], rect.location[0], rect.location[1], + rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], GL_COLOR_BUFFER_BIT, + GL_NEAREST); + } + if (cmd.resolveDepth && tex->m_bindTexs[1][cmd.bindIdx]) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[1][cmd.bindIdx]); + glBlitFramebuffer(rect.location[0], rect.location[1], rect.location[0] + rect.size[0], + rect.location[1] + rect.size[1], rect.location[0], rect.location[1], + rect.location[0] + rect.size[0], rect.location[1] + rect.size[1], GL_DEPTH_BUFFER_BIT, + GL_NEAREST); + } + } + if (cmd.clearDepth) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_fbo); + glDepthMask(GL_TRUE); + glClear(GL_DEPTH_BUFFER_BIT); + } + glBindFramebuffer(GL_FRAMEBUFFER, curFBO); + break; + } + case Command::Op::Present: { + if (const GLTextureR* tex = cmd.source.cast()) { #ifndef NDEBUG - if (!tex->m_colorBindCount) - Log.report(logvisor::Fatal, - "texture provided to resolveDisplay() must have at least 1 color binding"); + if (!tex->m_colorBindCount) + Log.report(logvisor::Fatal, "texture provided to resolveDisplay() must have at least 1 color binding"); #endif - if (dataFactory->m_gamma != 1.f) - { - glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); - if (tex->m_samples <= 1) - { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex->m_texs[0]); - } - else - { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][0]); - glBlitFramebuffer(0, 0, - tex->m_width, tex->m_height, - 0, 0, - tex->m_width, tex->m_height, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - tex->bind(0, 0, false); - } + if (dataFactory->m_gamma != 1.f) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); + if (tex->m_samples <= 1) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex->m_texs[0]); + } else { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex->m_bindFBOs[0][0]); + glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0, tex->m_width, tex->m_height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + tex->bind(0, 0, false); + } - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - dataFactory->m_gammaBinding.cast()->bind(self->m_drawBuf); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } - else - { - glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0, - tex->m_width, tex->m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - } - } - self->m_parent->present(); - break; - } - default: break; - } + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + dataFactory->m_gammaBinding.cast()->bind(self->m_drawBuf); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } else { + glBindFramebuffer(GL_READ_FRAMEBUFFER, tex->m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBlitFramebuffer(0, 0, tex->m_width, tex->m_height, 0, 0, tex->m_width, tex->m_height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); } - for (auto& p : posts) - p(); - cmds.clear(); + } + self->m_parent->present(); + break; } - } - - GLCommandQueue(IGraphicsContext* parent, GLContext* glCtx) - : m_parent(parent), - m_glCtx(glCtx) - {} - - void startRenderer() - { - std::unique_lock lk(m_initmt); - m_thr = std::thread(RenderingWorker, this); - m_initcv.wait(lk); - } - - void stopRenderer() - { - if (m_running) - { - m_running = false; - m_cv.notify_one(); - if (m_thr.joinable()) - m_thr.join(); - for (int i=0 ; i<3 ; ++i) - m_cmdBufs[i].clear(); + default: + break; } + } + for (auto& p : posts) + p(); + cmds.clear(); + } + } + + GLCommandQueue(IGraphicsContext* parent, GLContext* glCtx) : m_parent(parent), m_glCtx(glCtx) {} + + void startRenderer() { + std::unique_lock lk(m_initmt); + m_thr = std::thread(RenderingWorker, this); + m_initcv.wait(lk); + } + + void stopRenderer() { + if (m_running) { + m_running = false; + m_cv.notify_one(); + if (m_thr.joinable()) + m_thr.join(); + for (int i = 0; i < 3; ++i) + m_cmdBufs[i].clear(); + } + } + + ~GLCommandQueue() { stopRenderer(); } + + void setShaderDataBinding(const ObjToken& binding) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::SetShaderDataBinding); + cmds.back().binding = binding; + } + + void setRenderTarget(const ObjToken& target) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::SetRenderTarget); + cmds.back().target = target; + } + + void setViewport(const SWindowRect& rect, float znear, float zfar) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::SetViewport); + cmds.back().viewport.rect = rect; + cmds.back().viewport.znear = znear; + cmds.back().viewport.zfar = zfar; + } + + void setScissor(const SWindowRect& rect) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::SetScissor); + cmds.back().viewport.rect = rect; + } + + void resizeRenderTexture(const ObjToken& tex, size_t width, size_t height) { + std::unique_lock lk(m_mt); + GLTextureR* texgl = tex.cast(); + m_pendingResizes.push_back({texgl, width, height}); + } + + void schedulePostFrameHandler(std::function&& func) { m_pendingPosts1.push_back(std::move(func)); } + + void setClearColor(const float rgba[4]) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::SetClearColor); + cmds.back().rgba[0] = rgba[0]; + cmds.back().rgba[1] = rgba[1]; + cmds.back().rgba[2] = rgba[2]; + cmds.back().rgba[3] = rgba[3]; + } + + void clearTarget(bool render = true, bool depth = true) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::ClearTarget); + cmds.back().flags = 0; + if (render) + cmds.back().flags |= GL_COLOR_BUFFER_BIT; + if (depth) + cmds.back().flags |= GL_DEPTH_BUFFER_BIT; + } + + void draw(size_t start, size_t count) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::Draw); + cmds.back().start = start; + cmds.back().count = count; + } + + void drawIndexed(size_t start, size_t count) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::DrawIndexed); + cmds.back().start = start; + cmds.back().count = count; + } + + void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::DrawInstances); + cmds.back().start = start; + cmds.back().count = count; + cmds.back().instCount = instCount; + cmds.back().startInst = startInst; + } + + void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::DrawInstancesIndexed); + cmds.back().start = start; + cmds.back().count = count; + cmds.back().instCount = instCount; + cmds.back().startInst = startInst; + } + + void resolveBindTexture(const ObjToken& texture, const SWindowRect& rect, bool tlOrigin, int bindIdx, + bool color, bool depth, bool clearDepth) { + GLTextureR* tex = texture.cast(); + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::ResolveBindTexture); + cmds.back().resolveTex = texture; + cmds.back().bindIdx = bindIdx; + cmds.back().resolveColor = color; + cmds.back().resolveDepth = depth; + cmds.back().clearDepth = clearDepth; + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); + SWindowRect& targetRect = cmds.back().viewport.rect; + targetRect.location[0] = intersectRect.location[0]; + if (tlOrigin) + targetRect.location[1] = tex->m_height - intersectRect.location[1] - intersectRect.size[1]; + else + targetRect.location[1] = intersectRect.location[1]; + targetRect.size[0] = intersectRect.size[0]; + targetRect.size[1] = intersectRect.size[1]; + } + + void resolveDisplay(const ObjToken& source) { + std::vector& cmds = m_cmdBufs[m_fillBuf]; + cmds.emplace_back(Command::Op::Present); + cmds.back().source = source; + } + + void addVertexFormat(const ObjToken& fmt) { + std::unique_lock lk(m_mt); + m_pendingFmtAdds.push_back(fmt); + } + + void addFBO(const ObjToken& tex) { + std::unique_lock lk(m_mt); + m_pendingFboAdds.push_back(tex); + } + + void execute() { + std::unique_lock lk(m_mt); + m_completeBuf = m_fillBuf; + for (int i = 0; i < 3; ++i) { + if (i == m_completeBuf || i == m_drawBuf) + continue; + m_fillBuf = i; + break; } - ~GLCommandQueue() - { - stopRenderer(); + /* Update dynamic data here */ + GLDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); + std::unique_lock datalk(gfxF->m_dataMutex); + if (gfxF->m_dataHead) { + for (BaseGraphicsData& d : *gfxF->m_dataHead) { + if (d.m_DBufs) + for (IGraphicsBufferD& b : *d.m_DBufs) + static_cast&>(b).update(m_completeBuf); + if (d.m_DTexs) + for (ITextureD& t : *d.m_DTexs) + static_cast(t).update(m_completeBuf); + } } - - void setShaderDataBinding(const ObjToken& binding) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::SetShaderDataBinding); - cmds.back().binding = binding; + if (gfxF->m_poolHead) { + for (BaseGraphicsPool& p : *gfxF->m_poolHead) { + if (p.m_DBufs) + for (IGraphicsBufferD& b : *p.m_DBufs) + static_cast&>(b).update(m_completeBuf); + } } + datalk.unlock(); + glFlush(); - void setRenderTarget(const ObjToken& target) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::SetRenderTarget); - cmds.back().target = target; - } + for (auto& p : m_pendingPosts1) + m_pendingPosts2.push_back(std::move(p)); + m_pendingPosts1.clear(); - void setViewport(const SWindowRect& rect, float znear, float zfar) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::SetViewport); - cmds.back().viewport.rect = rect; - cmds.back().viewport.znear = znear; - cmds.back().viewport.zfar = zfar; - } - - void setScissor(const SWindowRect& rect) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::SetScissor); - cmds.back().viewport.rect = rect; - } - - void resizeRenderTexture(const ObjToken& tex, size_t width, size_t height) - { - std::unique_lock lk(m_mt); - GLTextureR* texgl = tex.cast(); - m_pendingResizes.push_back({texgl, width, height}); - } - - void schedulePostFrameHandler(std::function&& func) - { - m_pendingPosts1.push_back(std::move(func)); - } - - void setClearColor(const float rgba[4]) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::SetClearColor); - cmds.back().rgba[0] = rgba[0]; - cmds.back().rgba[1] = rgba[1]; - cmds.back().rgba[2] = rgba[2]; - cmds.back().rgba[3] = rgba[3]; - } - - void clearTarget(bool render=true, bool depth=true) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::ClearTarget); - cmds.back().flags = 0; - if (render) - cmds.back().flags |= GL_COLOR_BUFFER_BIT; - if (depth) - cmds.back().flags |= GL_DEPTH_BUFFER_BIT; - } - - void draw(size_t start, size_t count) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::Draw); - cmds.back().start = start; - cmds.back().count = count; - } - - void drawIndexed(size_t start, size_t count) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::DrawIndexed); - cmds.back().start = start; - cmds.back().count = count; - } - - void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::DrawInstances); - cmds.back().start = start; - cmds.back().count = count; - cmds.back().instCount = instCount; - cmds.back().startInst = startInst; - } - - void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::DrawInstancesIndexed); - cmds.back().start = start; - cmds.back().count = count; - cmds.back().instCount = instCount; - cmds.back().startInst = startInst; - } - - void resolveBindTexture(const ObjToken& texture, const SWindowRect& rect, bool tlOrigin, - int bindIdx, bool color, bool depth, bool clearDepth) - { - GLTextureR* tex = texture.cast(); - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::ResolveBindTexture); - cmds.back().resolveTex = texture; - cmds.back().bindIdx = bindIdx; - cmds.back().resolveColor = color; - cmds.back().resolveDepth = depth; - cmds.back().clearDepth = clearDepth; - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height)); - SWindowRect& targetRect = cmds.back().viewport.rect; - targetRect.location[0] = intersectRect.location[0]; - if (tlOrigin) - targetRect.location[1] = tex->m_height - intersectRect.location[1] - intersectRect.size[1]; - else - targetRect.location[1] = intersectRect.location[1]; - targetRect.size[0] = intersectRect.size[0]; - targetRect.size[1] = intersectRect.size[1]; - } - - void resolveDisplay(const ObjToken& source) - { - std::vector& cmds = m_cmdBufs[m_fillBuf]; - cmds.emplace_back(Command::Op::Present); - cmds.back().source = source; - } - - void addVertexFormat(const ObjToken& fmt) - { - std::unique_lock lk(m_mt); - m_pendingFmtAdds.push_back(fmt); - } - - void addFBO(const ObjToken& tex) - { - std::unique_lock lk(m_mt); - m_pendingFboAdds.push_back(tex); - } - - void execute() - { - std::unique_lock lk(m_mt); - m_completeBuf = m_fillBuf; - for (int i=0 ; i<3 ; ++i) - { - if (i == m_completeBuf || i == m_drawBuf) - continue; - m_fillBuf = i; - break; - } - - /* Update dynamic data here */ - GLDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); - std::unique_lock datalk(gfxF->m_dataMutex); - if (gfxF->m_dataHead) - { - for (BaseGraphicsData& d : *gfxF->m_dataHead) - { - if (d.m_DBufs) - for (IGraphicsBufferD& b : *d.m_DBufs) - static_cast&>(b).update(m_completeBuf); - if (d.m_DTexs) - for (ITextureD& t : *d.m_DTexs) - static_cast(t).update(m_completeBuf); - } - } - if (gfxF->m_poolHead) - { - for (BaseGraphicsPool& p : *gfxF->m_poolHead) - { - if (p.m_DBufs) - for (IGraphicsBufferD& b : *p.m_DBufs) - static_cast&>(b).update(m_completeBuf); - } - } - datalk.unlock(); - glFlush(); - - for (auto& p : m_pendingPosts1) - m_pendingPosts2.push_back(std::move(p)); - m_pendingPosts1.clear(); - - lk.unlock(); - m_cv.notify_one(); - m_cmdBufs[m_fillBuf].clear(); - } + lk.unlock(); + m_cv.notify_one(); + m_cmdBufs[m_fillBuf].clear(); + } }; -ObjToken -GLDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) -{ - return {new GLGraphicsBufferD(m_data, use, stride * count)}; +ObjToken GLDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) { + return {new GLGraphicsBufferD(m_data, use, stride * count)}; } -ObjToken -GLDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode) -{ - return {new GLTextureD(m_data, width, height, fmt, clampMode)}; +ObjToken GLDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) { + return {new GLTextureD(m_data, width, height, fmt, clampMode)}; } GLTextureR::GLTextureR(const ObjToken& parent, GLCommandQueue* q, size_t width, size_t height, - size_t samples, GLenum colorFormat, TextureClampMode clampMode, - size_t colorBindingCount, size_t depthBindingCount) -: GraphicsDataNode(parent), m_q(q), m_width(width), m_height(height), m_samples(samples), - m_colorFormat(colorFormat), m_colorBindCount(colorBindingCount), m_depthBindCount(depthBindingCount) -{ - glGenTextures(2, m_texs); - if (colorBindingCount) - { - if (colorBindingCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many color bindings for render texture"); - glGenTextures(colorBindingCount, m_bindTexs[0]); - } - if (depthBindingCount) - { - if (depthBindingCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many depth bindings for render texture"); - glGenTextures(depthBindingCount, m_bindTexs[1]); - } + size_t samples, GLenum colorFormat, TextureClampMode clampMode, size_t colorBindingCount, + size_t depthBindingCount) +: GraphicsDataNode(parent) +, m_q(q) +, m_width(width) +, m_height(height) +, m_samples(samples) +, m_colorFormat(colorFormat) +, m_colorBindCount(colorBindingCount) +, m_depthBindCount(depthBindingCount) { + glGenTextures(2, m_texs); + if (colorBindingCount) { + if (colorBindingCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many color bindings for render texture"); + glGenTextures(colorBindingCount, m_bindTexs[0]); + } + if (depthBindingCount) { + if (depthBindingCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many depth bindings for render texture"); + glGenTextures(depthBindingCount, m_bindTexs[1]); + } - GLenum compType = colorFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - if (samples > 1) - { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, colorFormat, width, height, GL_FALSE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT32F, width, height, GL_FALSE); - } - else - { - glBindTexture(GL_TEXTURE_2D, m_texs[0]); - glTexImage2D(GL_TEXTURE_2D, 0, colorFormat, width, height, 0, GL_RGBA, compType, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, m_texs[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); - } + GLenum compType = colorFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + if (samples > 1) { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, colorFormat, width, height, GL_FALSE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[1]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT32F, width, height, GL_FALSE); + } else { + glBindTexture(GL_TEXTURE_2D, m_texs[0]); + glTexImage2D(GL_TEXTURE_2D, 0, colorFormat, width, height, 0, GL_RGBA, compType, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, m_texs[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, + nullptr); + } - for (int i=0 ; iaddFBO(this); + m_q->addFBO(this); } -ObjToken -GLDataFactory::Context::newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindingCount, size_t depthBindingCount) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); - GLCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - ObjToken retval(new GLTextureR(m_data, q, width, height, factory.m_glCtx->m_sampleCount, - factory.m_glCtx->m_deepColor ? GL_RGBA16 : GL_RGBA8, clampMode, - colorBindingCount, depthBindingCount)); - q->resizeRenderTexture(retval, width, height); - return retval; +ObjToken GLDataFactory::Context::newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, + size_t colorBindingCount, size_t depthBindingCount) { + GLDataFactoryImpl& factory = static_cast(m_parent); + GLCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + ObjToken retval(new GLTextureR(m_data, q, width, height, factory.m_glCtx->m_sampleCount, + factory.m_glCtx->m_deepColor ? GL_RGBA16 : GL_RGBA8, clampMode, + colorBindingCount, depthBindingCount)); + q->resizeRenderTexture(retval, width, height); + return retval; } -ObjToken -GLDataFactory::Context::newShaderDataBinding(const ObjToken& pipeline, - const ObjToken& vbo, - const ObjToken& instVbo, - const ObjToken& ibo, - size_t ubufCount, const ObjToken* ubufs, - const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const ObjToken* texs, - const int* texBindIdx, const bool* depthBind, - size_t baseVert, size_t baseInst) -{ - GLDataFactoryImpl& factory = static_cast(m_parent); - GLCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - ObjToken ret = {new GLShaderDataBinding(m_data, pipeline, vbo, instVbo, ibo, ubufCount, ubufs, - ubufOffs, ubufSizes, texCount, texs, texBindIdx, depthBind, baseVert, baseInst)}; - q->addVertexFormat(ret.get()); - return ret.get(); +ObjToken GLDataFactory::Context::newShaderDataBinding( + const ObjToken& pipeline, const ObjToken& vbo, + const ObjToken& instVbo, const ObjToken& ibo, size_t ubufCount, + const ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const ObjToken* texs, const int* texBindIdx, + const bool* depthBind, size_t baseVert, size_t baseInst) { + GLDataFactoryImpl& factory = static_cast(m_parent); + GLCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + ObjToken ret = {new GLShaderDataBinding(m_data, pipeline, vbo, instVbo, ibo, ubufCount, ubufs, + ubufOffs, ubufSizes, texCount, texs, texBindIdx, + depthBind, baseVert, baseInst)}; + q->addVertexFormat(ret.get()); + return ret.get(); } -std::unique_ptr _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx) -{ - return std::make_unique(parent, glCtx); +std::unique_ptr _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx) { + return std::make_unique(parent, glCtx); } -std::unique_ptr _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx) -{ - return std::make_unique(parent, glCtx); +std::unique_ptr _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx) { + return std::make_unique(parent, glCtx); } -} +} // namespace boo diff --git a/lib/graphicsdev/GLX.cpp b/lib/graphicsdev/GLX.cpp index 7191805..dd3b6e9 100644 --- a/lib/graphicsdev/GLX.cpp +++ b/lib/graphicsdev/GLX.cpp @@ -1,26 +1,23 @@ #include "boo/graphicsdev/glxew.h" #include "logvisor/logvisor.hpp" -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::GLX"); -void GLXExtensionCheck() -{ - if (!GLXEW_SGI_video_sync) - Log.report(logvisor::Fatal, "GLX_SGI_video_sync not available"); - if (!GLXEW_EXT_swap_control && !GLXEW_MESA_swap_control && !GLXEW_SGI_swap_control) - Log.report(logvisor::Fatal, "swap_control not available"); +void GLXExtensionCheck() { + if (!GLXEW_SGI_video_sync) + Log.report(logvisor::Fatal, "GLX_SGI_video_sync not available"); + if (!GLXEW_EXT_swap_control && !GLXEW_MESA_swap_control && !GLXEW_SGI_swap_control) + Log.report(logvisor::Fatal, "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); +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 diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index 90a17b1..f61e0e5 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -25,297 +25,262 @@ #undef max #undef None -static const char* GammaVS = -"#version 330\n" -BOO_GLSL_BINDING_HEAD -"layout(location=0) in vec4 posIn;\n" -"layout(location=1) in vec4 uvIn;\n" -"\n" -"struct VertToFrag\n" -"{\n" -" vec2 uv;\n" -"};\n" -"\n" -"SBINDING(0) out VertToFrag vtf;\n" -"void main()\n" -"{\n" -" vtf.uv = uvIn.xy;\n" -" gl_Position = posIn;\n" -"}\n"; +static const char* GammaVS = "#version 330\n" BOO_GLSL_BINDING_HEAD + "layout(location=0) in vec4 posIn;\n" + "layout(location=1) in vec4 uvIn;\n" + "\n" + "struct VertToFrag\n" + "{\n" + " vec2 uv;\n" + "};\n" + "\n" + "SBINDING(0) out VertToFrag vtf;\n" + "void main()\n" + "{\n" + " vtf.uv = uvIn.xy;\n" + " gl_Position = posIn;\n" + "}\n"; -static const char* GammaFS = -"#version 330\n" -BOO_GLSL_BINDING_HEAD -"struct VertToFrag\n" -"{\n" -" vec2 uv;\n" -"};\n" -"\n" -"SBINDING(0) in VertToFrag vtf;\n" -"layout(location=0) out vec4 colorOut;\n" -"TBINDING0 uniform sampler2D screenTex;\n" -"TBINDING1 uniform sampler2D gammaLUT;\n" -"void main()\n" -"{\n" -" ivec4 tex = ivec4(texture(screenTex, vtf.uv) * 65535.0);\n" -" for (int i=0 ; i<3 ; ++i)\n" -" colorOut[i] = texelFetch(gammaLUT, ivec2(tex[i] % 256, tex[i] / 256), 0).r;\n" -"}\n"; +static const char* GammaFS = "#version 330\n" BOO_GLSL_BINDING_HEAD + "struct VertToFrag\n" + "{\n" + " vec2 uv;\n" + "};\n" + "\n" + "SBINDING(0) in VertToFrag vtf;\n" + "layout(location=0) out vec4 colorOut;\n" + "TBINDING0 uniform sampler2D screenTex;\n" + "TBINDING1 uniform sampler2D gammaLUT;\n" + "void main()\n" + "{\n" + " ivec4 tex = ivec4(texture(screenTex, vtf.uv) * 65535.0);\n" + " for (int i=0 ; i<3 ; ++i)\n" + " colorOut[i] = texelFetch(gammaLUT, ivec2(tex[i] % 256, tex[i] / 256), 0).r;\n" + "}\n"; -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::Vulkan"); VulkanContext g_VulkanContext; class VulkanDataFactoryImpl; struct VulkanCommandQueue; struct VulkanDescriptorPool; -class VulkanDataFactoryImpl : public VulkanDataFactory, public GraphicsDataFactoryHead -{ - friend struct VulkanCommandQueue; - friend class VulkanDataFactory::Context; - friend struct VulkanData; - friend struct VulkanPool; - friend struct VulkanDescriptorPool; - friend struct VulkanShaderDataBinding; - IGraphicsContext* m_parent; - VulkanContext* m_ctx; - VulkanDescriptorPool* m_descPoolHead = nullptr; +class VulkanDataFactoryImpl : public VulkanDataFactory, public GraphicsDataFactoryHead { + friend struct VulkanCommandQueue; + friend class VulkanDataFactory::Context; + friend struct VulkanData; + friend struct VulkanPool; + friend struct VulkanDescriptorPool; + friend struct VulkanShaderDataBinding; + IGraphicsContext* m_parent; + VulkanContext* m_ctx; + VulkanDescriptorPool* m_descPoolHead = nullptr; - float m_gamma = 1.f; - ObjToken m_gammaShader; - ObjToken m_gammaLUT; - ObjToken m_gammaVBO; - ObjToken m_gammaBinding; - void SetupGammaResources() - { - commitTransaction([this](IGraphicsDataFactory::Context& ctx) - { - auto vertexSiprv = VulkanDataFactory::CompileGLSL(GammaVS, PipelineStage::Vertex); - auto vertexShader = ctx.newShaderStage(vertexSiprv, PipelineStage::Vertex); - auto fragmentSiprv = VulkanDataFactory::CompileGLSL(GammaFS, PipelineStage::Fragment); - auto fragmentShader = ctx.newShaderStage(fragmentSiprv, PipelineStage::Fragment); - const VertexElementDescriptor vfmt[] = { - {VertexSemantic::Position4}, - {VertexSemantic::UV4} - }; - AdditionalPipelineInfo info = - { - BlendFactor::One, BlendFactor::Zero, - Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None - }; - m_gammaShader = ctx.newShaderPipeline(vertexShader, fragmentShader, vfmt, info); - m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); - setDisplayGamma(1.f); - const struct Vert { - float pos[4]; - float uv[4]; - } verts[4] = { - {{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, - {{ 1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, - {{-1.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, - {{ 1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}} - }; - m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); - ObjToken texs[] = {{}, m_gammaLUT.get()}; - m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, - 0, nullptr, nullptr, 2, texs, nullptr, nullptr); - return true; - } BooTrace); - } + float m_gamma = 1.f; + ObjToken m_gammaShader; + ObjToken m_gammaLUT; + ObjToken m_gammaVBO; + ObjToken m_gammaBinding; + void SetupGammaResources() { + commitTransaction([this](IGraphicsDataFactory::Context& ctx) { + auto vertexSiprv = VulkanDataFactory::CompileGLSL(GammaVS, PipelineStage::Vertex); + auto vertexShader = ctx.newShaderStage(vertexSiprv, PipelineStage::Vertex); + auto fragmentSiprv = VulkanDataFactory::CompileGLSL(GammaFS, PipelineStage::Fragment); + auto fragmentShader = ctx.newShaderStage(fragmentSiprv, PipelineStage::Fragment); + const VertexElementDescriptor vfmt[] = {{VertexSemantic::Position4}, {VertexSemantic::UV4}}; + AdditionalPipelineInfo info = { + BlendFactor::One, BlendFactor::Zero, Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None}; + m_gammaShader = ctx.newShaderPipeline(vertexShader, fragmentShader, vfmt, info); + m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); + setDisplayGamma(1.f); + const struct Vert { + float pos[4]; + float uv[4]; + } verts[4] = {{{-1.f, -1.f, 0.f, 1.f}, {0.f, 0.f, 0.f, 0.f}}, + {{1.f, -1.f, 0.f, 1.f}, {1.f, 0.f, 0.f, 0.f}}, + {{-1.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 0.f, 0.f}}, + {{1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 0.f}}}; + m_gammaVBO = ctx.newStaticBuffer(BufferUse::Vertex, verts, 32, 4); + ObjToken texs[] = {{}, m_gammaLUT.get()}; + m_gammaBinding = ctx.newShaderDataBinding(m_gammaShader, m_gammaVBO.get(), {}, {}, 0, nullptr, nullptr, 2, texs, + nullptr, nullptr); + return true; + } BooTrace); + } - void DestroyGammaResources() - { - m_gammaBinding.reset(); - m_gammaVBO.reset(); - m_gammaLUT.reset(); - m_gammaShader.reset(); - } + void DestroyGammaResources() { + m_gammaBinding.reset(); + m_gammaVBO.reset(); + m_gammaLUT.reset(); + m_gammaShader.reset(); + } public: - VulkanDataFactoryImpl(IGraphicsContext* parent, VulkanContext* ctx); - ~VulkanDataFactoryImpl() - { - assert(m_descPoolHead == nullptr && "Dangling descriptor pools detected"); - } + VulkanDataFactoryImpl(IGraphicsContext* parent, VulkanContext* ctx); + ~VulkanDataFactoryImpl() { assert(m_descPoolHead == nullptr && "Dangling descriptor pools detected"); } - Platform platform() const {return Platform::Vulkan;} - const SystemChar* platformName() const {return _SYS_STR("Vulkan");} + Platform platform() const { return Platform::Vulkan; } + const SystemChar* platformName() const { return _SYS_STR("Vulkan"); } - boo::ObjToken allocateDescriptorSets(VkDescriptorSet* out); + boo::ObjToken allocateDescriptorSets(VkDescriptorSet* out); - void commitTransaction(const FactoryCommitFunc& __BooTraceArgs); + void commitTransaction(const FactoryCommitFunc& __BooTraceArgs); - boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); + boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); - void setDisplayGamma(float gamma) - { - m_gamma = gamma; - UpdateGammaLUT(m_gammaLUT.get(), gamma); - } + void setDisplayGamma(float gamma) { + m_gamma = gamma; + UpdateGammaLUT(m_gammaLUT.get(), gamma); + } - bool isTessellationSupported(uint32_t& maxPatchSizeOut) - { - maxPatchSizeOut = 0; - if (!m_ctx->m_features.tessellationShader) - return false; - maxPatchSizeOut = m_ctx->m_gpuProps.limits.maxTessellationPatchSize; - return true; - } + bool isTessellationSupported(uint32_t& maxPatchSizeOut) { + maxPatchSizeOut = 0; + if (!m_ctx->m_features.tessellationShader) + return false; + maxPatchSizeOut = m_ctx->m_gpuProps.limits.maxTessellationPatchSize; + return true; + } }; -static inline void ThrowIfFailed(VkResult res) -{ - if (res != VK_SUCCESS) - Log.report(logvisor::Fatal, "%d\n", res); +static inline void ThrowIfFailed(VkResult res) { + if (res != VK_SUCCESS) + Log.report(logvisor::Fatal, "%d\n", res); } -static inline void ThrowIfFalse(bool res) -{ - if (!res) - Log.report(logvisor::Fatal, "operation failed\n", res); +static inline void ThrowIfFalse(bool res) { + if (!res) + Log.report(logvisor::Fatal, "operation failed\n", res); } -static VKAPI_ATTR VkBool32 VKAPI_CALL -dbgFunc(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, - uint64_t srcObject, size_t location, int32_t msgCode, - const char *pLayerPrefix, const char *pMsg, void *pUserData) -{ - if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - Log.report(logvisor::Error, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); - } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - Log.report(logvisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); - } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - Log.report(logvisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); - } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - Log.report(logvisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); - } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - Log.report(logvisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); - } +static VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType, + uint64_t srcObject, size_t location, int32_t msgCode, + const char* pLayerPrefix, const char* pMsg, void* pUserData) { + if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + Log.report(logvisor::Error, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + Log.report(logvisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { + Log.report(logvisor::Warning, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { + Log.report(logvisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + Log.report(logvisor::Info, "[%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); + } - /* - * false indicates that layer should not bail-out of an - * API call that had validation failures. This may mean that the - * app dies inside the driver due to invalid parameter(s). - * That's what would happen without validation layers, so we'll - * keep that behavior here. - */ - return VK_FALSE; + /* + * false indicates that layer should not bail-out of an + * API call that had validation failures. This may mean that the + * app dies inside the driver due to invalid parameter(s). + * That's what would happen without validation layers, so we'll + * keep that behavior here. + */ + return VK_FALSE; } -static void SetImageLayout(VkCommandBuffer cmd, VkImage image, - VkImageAspectFlags aspectMask, - VkImageLayout old_image_layout, - VkImageLayout new_image_layout, - uint32_t mipCount, uint32_t layerCount) -{ - VkImageMemoryBarrier imageMemoryBarrier = {}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.pNext = NULL; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = 0; - imageMemoryBarrier.oldLayout = old_image_layout; - imageMemoryBarrier.newLayout = new_image_layout; - imageMemoryBarrier.image = image; - imageMemoryBarrier.subresourceRange.aspectMask = aspectMask; - imageMemoryBarrier.subresourceRange.baseMipLevel = 0; - imageMemoryBarrier.subresourceRange.levelCount = mipCount; - imageMemoryBarrier.subresourceRange.layerCount = layerCount; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; +static void SetImageLayout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, + VkImageLayout old_image_layout, VkImageLayout new_image_layout, uint32_t mipCount, + uint32_t layerCount) { + VkImageMemoryBarrier imageMemoryBarrier = {}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.pNext = NULL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.oldLayout = old_image_layout; + imageMemoryBarrier.newLayout = new_image_layout; + imageMemoryBarrier.image = image; + imageMemoryBarrier.subresourceRange.aspectMask = aspectMask; + imageMemoryBarrier.subresourceRange.baseMipLevel = 0; + imageMemoryBarrier.subresourceRange.levelCount = mipCount; + imageMemoryBarrier.subresourceRange.layerCount = layerCount; + imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - switch (old_image_layout) - { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - imageMemoryBarrier.srcAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - case VK_IMAGE_LAYOUT_PREINITIALIZED: - imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - src_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - src_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - default: break; - } + switch (old_image_layout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + src_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + src_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + src_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + default: + break; + } - switch (new_image_layout) - { - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dest_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dest_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - imageMemoryBarrier.dstAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - imageMemoryBarrier.dstAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - break; - default: break; - } + switch (new_image_layout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dest_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dest_stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dest_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + break; + default: + break; + } - vk::CmdPipelineBarrier(cmd, src_stages, dest_stages, 0, 0, NULL, 0, NULL, - 1, &imageMemoryBarrier); + vk::CmdPipelineBarrier(cmd, src_stages, dest_stages, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier); } static VkResult InitGlobalExtensionProperties(VulkanContext::LayerProperties& layerProps) { - VkExtensionProperties *instance_extensions; - uint32_t instance_extension_count; - VkResult res; - char *layer_name = nullptr; + VkExtensionProperties* instance_extensions; + uint32_t instance_extension_count; + VkResult res; + char* layer_name = nullptr; - layer_name = layerProps.properties.layerName; + layer_name = layerProps.properties.layerName; - do { - res = vk::EnumerateInstanceExtensionProperties( - layer_name, &instance_extension_count, nullptr); - if (res) - return res; + do { + res = vk::EnumerateInstanceExtensionProperties(layer_name, &instance_extension_count, nullptr); + if (res) + return res; - if (instance_extension_count == 0) { - return VK_SUCCESS; - } + if (instance_extension_count == 0) { + return VK_SUCCESS; + } - layerProps.extensions.resize(instance_extension_count); - instance_extensions = layerProps.extensions.data(); - res = vk::EnumerateInstanceExtensionProperties( - layer_name, &instance_extension_count, instance_extensions); - } while (res == VK_INCOMPLETE); + layerProps.extensions.resize(instance_extension_count); + instance_extensions = layerProps.extensions.data(); + res = vk::EnumerateInstanceExtensionProperties(layer_name, &instance_extension_count, instance_extensions); + } while (res == VK_INCOMPLETE); - return res; + return res; } /* @@ -323,438 +288,1512 @@ static VkResult InitGlobalExtensionProperties(VulkanContext::LayerProperties& la * can be found in given layer properties. */ static void demo_check_layers(const std::vector& layerProps, - const std::vector &layerNames) { - uint32_t check_count = layerNames.size(); - uint32_t layer_count = layerProps.size(); - for (uint32_t i = 0; i < check_count; i++) { - VkBool32 found = 0; - for (uint32_t j = 0; j < layer_count; j++) { - if (!strcmp(layerNames[i], layerProps[j].properties.layerName)) { - found = 1; - } - } - if (!found) { - Log.report(logvisor::Fatal, "Cannot find layer: %s", layerNames[i]); - } + const std::vector& layerNames) { + uint32_t check_count = layerNames.size(); + uint32_t layer_count = layerProps.size(); + for (uint32_t i = 0; i < check_count; i++) { + VkBool32 found = 0; + for (uint32_t j = 0; j < layer_count; j++) { + if (!strcmp(layerNames[i], layerProps[j].properties.layerName)) { + found = 1; + } } + if (!found) { + Log.report(logvisor::Fatal, "Cannot find layer: %s", layerNames[i]); + } + } } -bool VulkanContext::initVulkan(std::string_view appName, PFN_vkGetInstanceProcAddr getVkProc) -{ - vk::init_dispatch_table_top(getVkProc); +bool VulkanContext::initVulkan(std::string_view appName, PFN_vkGetInstanceProcAddr getVkProc) { + vk::init_dispatch_table_top(getVkProc); - if (!glslang::InitializeProcess()) - { - Log.report(logvisor::Error, "unable to initialize glslang"); - return false; - } + if (!glslang::InitializeProcess()) { + Log.report(logvisor::Error, "unable to initialize glslang"); + return false; + } - uint32_t instanceLayerCount; - VkLayerProperties* vkProps = nullptr; - VkResult res; + uint32_t instanceLayerCount; + VkLayerProperties* vkProps = nullptr; + VkResult res; - /* - * It's possible, though very rare, that the number of - * instance layers could change. For example, installing something - * could include new layers that the loader would pick up - * between the initial query for the count and the - * request for VkLayerProperties. The loader indicates that - * by returning a VK_INCOMPLETE status and will update the - * the count parameter. - * The count parameter will be updated with the number of - * entries loaded into the data pointer - in case the number - * of layers went down or is smaller than the size given. - */ + /* + * It's possible, though very rare, that the number of + * instance layers could change. For example, installing something + * could include new layers that the loader would pick up + * between the initial query for the count and the + * request for VkLayerProperties. The loader indicates that + * by returning a VK_INCOMPLETE status and will update the + * the count parameter. + * The count parameter will be updated with the number of + * entries loaded into the data pointer - in case the number + * of layers went down or is smaller than the size given. + */ #ifdef _WIN32 - char* vkSdkPath = getenv("VK_SDK_PATH"); - if (vkSdkPath) - { - std::string str = "VK_LAYER_PATH="; - str += vkSdkPath; - str += "\\Bin"; - _putenv(str.c_str()); - } + char* vkSdkPath = getenv("VK_SDK_PATH"); + if (vkSdkPath) { + std::string str = "VK_LAYER_PATH="; + str += vkSdkPath; + str += "\\Bin"; + _putenv(str.c_str()); + } #else - setenv("VK_LAYER_PATH", "/usr/share/vulkan/explicit_layer.d", 1); + setenv("VK_LAYER_PATH", "/usr/share/vulkan/explicit_layer.d", 1); #endif - do { - ThrowIfFailed(vk::EnumerateInstanceLayerProperties(&instanceLayerCount, nullptr)); + do { + ThrowIfFailed(vk::EnumerateInstanceLayerProperties(&instanceLayerCount, nullptr)); - if (instanceLayerCount == 0) - break; + if (instanceLayerCount == 0) + break; - vkProps = (VkLayerProperties *)realloc(vkProps, instanceLayerCount * sizeof(VkLayerProperties)); + vkProps = (VkLayerProperties*)realloc(vkProps, instanceLayerCount * sizeof(VkLayerProperties)); - res = vk::EnumerateInstanceLayerProperties(&instanceLayerCount, vkProps); - } while (res == VK_INCOMPLETE); + res = vk::EnumerateInstanceLayerProperties(&instanceLayerCount, vkProps); + } while (res == VK_INCOMPLETE); - /* - * Now gather the extension list for each instance layer. - */ - for (uint32_t i=0 ; i extensions(extCount); + vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, extensions.data()); + bool hasGetMemReq2 = false; + bool hasDedicatedAllocation = false; + for (const VkExtensionProperties& ext : extensions) { + if (!hasGetMemReq2 && !strcmp(ext.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) + hasGetMemReq2 = true; + else if (!hasDedicatedAllocation && !strcmp(ext.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME)) + hasDedicatedAllocation = true; + } + VmaAllocatorCreateFlags allocFlags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; + if (hasGetMemReq2 && hasDedicatedAllocation) { + m_deviceExtensionNames.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + m_deviceExtensionNames.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + allocFlags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + } + + VkDeviceCreateInfo deviceInfo = {}; + deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceInfo.pNext = nullptr; + deviceInfo.queueCreateInfoCount = 1; + deviceInfo.pQueueCreateInfos = &queueInfo; + deviceInfo.enabledLayerCount = m_layerNames.size(); + deviceInfo.ppEnabledLayerNames = deviceInfo.enabledLayerCount ? m_layerNames.data() : nullptr; + deviceInfo.enabledExtensionCount = m_deviceExtensionNames.size(); + deviceInfo.ppEnabledExtensionNames = deviceInfo.enabledExtensionCount ? m_deviceExtensionNames.data() : nullptr; + deviceInfo.pEnabledFeatures = &features; + + ThrowIfFailed(vk::CreateDevice(m_gpus[0], &deviceInfo, nullptr, &m_dev)); + + vk::init_dispatch_table_bottom(m_instance, m_dev); + + /* allocator */ + VmaVulkanFunctions vulkanFunctions = {}; + vulkanFunctions.vkGetPhysicalDeviceProperties = vk::GetPhysicalDeviceProperties; + vulkanFunctions.vkGetPhysicalDeviceMemoryProperties = vk::GetPhysicalDeviceMemoryProperties; + vulkanFunctions.vkAllocateMemory = vk::AllocateMemory; + vulkanFunctions.vkFreeMemory = vk::FreeMemory; + vulkanFunctions.vkMapMemory = vk::MapMemory; + vulkanFunctions.vkUnmapMemory = vk::UnmapMemory; + vulkanFunctions.vkBindBufferMemory = vk::BindBufferMemory; + vulkanFunctions.vkBindImageMemory = vk::BindImageMemory; + vulkanFunctions.vkGetBufferMemoryRequirements = vk::GetBufferMemoryRequirements; + vulkanFunctions.vkGetImageMemoryRequirements = vk::GetImageMemoryRequirements; + vulkanFunctions.vkCreateBuffer = vk::CreateBuffer; + vulkanFunctions.vkDestroyBuffer = vk::DestroyBuffer; + vulkanFunctions.vkCreateImage = vk::CreateImage; + vulkanFunctions.vkDestroyImage = vk::DestroyImage; + if (hasGetMemReq2 && hasDedicatedAllocation) { + vulkanFunctions.vkGetBufferMemoryRequirements2KHR = reinterpret_cast( + vk::GetDeviceProcAddr(m_dev, "vkGetBufferMemoryRequirements2KHR")); + vulkanFunctions.vkGetImageMemoryRequirements2KHR = reinterpret_cast( + vk::GetDeviceProcAddr(m_dev, "vkGetImageMemoryRequirements2KHR")); + } + VmaAllocatorCreateInfo allocatorInfo = {}; + allocatorInfo.flags = allocFlags; + allocatorInfo.physicalDevice = m_gpus[0]; + allocatorInfo.device = m_dev; + allocatorInfo.pVulkanFunctions = &vulkanFunctions; + ThrowIfFailed(vmaCreateAllocator(&allocatorInfo, &m_allocator)); + + // Going to need a command buffer to send the memory barriers in + // set_image_layout but we couldn't have created one before we knew + // what our graphics_queue_family_index is, but now that we have it, + // create the command buffer + + VkCommandPoolCreateInfo cmdPoolInfo = {}; + cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmdPoolInfo.pNext = nullptr; + cmdPoolInfo.queueFamilyIndex = m_graphicsQueueFamilyIndex; + cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + ThrowIfFailed(vk::CreateCommandPool(m_dev, &cmdPoolInfo, nullptr, &m_loadPool)); + + VkCommandBufferAllocateInfo cmd = {}; + cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmd.pNext = nullptr; + cmd.commandPool = m_loadPool; + cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmd.commandBufferCount = 1; + ThrowIfFailed(vk::AllocateCommandBuffers(m_dev, &cmd, &m_loadCmdBuf)); + + vk::GetDeviceQueue(m_dev, m_graphicsQueueFamilyIndex, 0, &m_queue); + + /* Begin load command buffer here */ + VkCommandBufferBeginInfo cmdBufBeginInfo = {}; + cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + ThrowIfFailed(vk::BeginCommandBuffer(m_loadCmdBuf, &cmdBufBeginInfo)); + + m_sampleCountColor = flp2(std::min(m_gpuProps.limits.framebufferColorSampleCounts, m_sampleCountColor)); + m_sampleCountDepth = flp2(std::min(m_gpuProps.limits.framebufferDepthSampleCounts, m_sampleCountDepth)); + + if (m_features.samplerAnisotropy) + m_anisotropy = std::min(m_gpuProps.limits.maxSamplerAnisotropy, m_anisotropy); + else + m_anisotropy = 1; + + VkDescriptorSetLayoutBinding layoutBindings[BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT]; + for (int i = 0; i < BOO_GLSL_MAX_UNIFORM_COUNT; ++i) { + layoutBindings[i].binding = i; + layoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layoutBindings[i].descriptorCount = 1; + layoutBindings[i].stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | tessellationDescriptorBit; + layoutBindings[i].pImmutableSamplers = nullptr; + } + for (int i = BOO_GLSL_MAX_UNIFORM_COUNT; i < BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT; ++i) { + layoutBindings[i].binding = i; + layoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBindings[i].descriptorCount = 1; + layoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT | tessellationDescriptorBit; + layoutBindings[i].pImmutableSamplers = nullptr; + } + + VkDescriptorSetLayoutCreateInfo descriptorLayout = {}; + descriptorLayout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorLayout.pNext = nullptr; + descriptorLayout.bindingCount = BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT; + descriptorLayout.pBindings = layoutBindings; + + ThrowIfFailed(vk::CreateDescriptorSetLayout(m_dev, &descriptorLayout, nullptr, &m_descSetLayout)); + + VkPipelineLayoutCreateInfo pipelineLayout = {}; + pipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayout.setLayoutCount = 1; + pipelineLayout.pSetLayouts = &m_descSetLayout; + ThrowIfFailed(vk::CreatePipelineLayout(m_dev, &pipelineLayout, nullptr, &m_pipelinelayout)); + + std::string gpuName = m_gpuProps.deviceName; + Log.report(logvisor::Info, "Initialized %s", gpuName.c_str()); + Log.report(logvisor::Info, "Vulkan version %d.%d.%d", m_gpuProps.apiVersion >> 22, + (m_gpuProps.apiVersion >> 12) & 0b1111111111, m_gpuProps.apiVersion & 0b111111111111); + Log.report(logvisor::Info, "Driver version %d.%d.%d", m_gpuProps.driverVersion >> 22, + (m_gpuProps.driverVersion >> 12) & 0b1111111111, m_gpuProps.driverVersion & 0b111111111111); +} + +void VulkanContext::destroyDevice() { + if (m_passColorOnly) { + vk::DestroyRenderPass(m_dev, m_passColorOnly, nullptr); + m_passColorOnly = VK_NULL_HANDLE; + } + + if (m_pass) { + vk::DestroyRenderPass(m_dev, m_pass, nullptr); + m_pass = VK_NULL_HANDLE; + } + + if (m_pipelinelayout) { + vk::DestroyPipelineLayout(m_dev, m_pipelinelayout, nullptr); + m_pipelinelayout = VK_NULL_HANDLE; + } + + if (m_descSetLayout) { + vk::DestroyDescriptorSetLayout(m_dev, m_descSetLayout, nullptr); + m_descSetLayout = VK_NULL_HANDLE; + } + + if (m_loadPool) { + vk::DestroyCommandPool(m_dev, m_loadPool, nullptr); + m_loadPool = VK_NULL_HANDLE; + } + + if (m_allocator) { + vmaDestroyAllocator(m_allocator); + m_allocator = VK_NULL_HANDLE; + } + + if (m_dev) { + vk::DestroyDevice(m_dev, nullptr); + m_dev = VK_NULL_HANDLE; + } + + if (m_instance) { + vk::DestroyInstance(m_instance, nullptr); + m_instance = VK_NULL_HANDLE; + } +} + +void VulkanContext::Window::SwapChain::Buffer::setImage(VulkanContext* ctx, VkImage image, uint32_t width, + uint32_t height) { + m_image = image; + if (m_colorView) + vk::DestroyImageView(ctx->m_dev, m_colorView, nullptr); + if (m_framebuffer) + vk::DestroyFramebuffer(ctx->m_dev, m_framebuffer, nullptr); + + /* Create resource views */ + VkImageViewCreateInfo viewCreateInfo = {}; + viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCreateInfo.pNext = nullptr; + viewCreateInfo.image = m_image; + viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCreateInfo.format = ctx->m_displayFormat; + viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewCreateInfo.subresourceRange.baseMipLevel = 0; + viewCreateInfo.subresourceRange.levelCount = 1; + viewCreateInfo.subresourceRange.baseArrayLayer = 0; + viewCreateInfo.subresourceRange.layerCount = 1; + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_colorView)); + + /* framebuffer */ + VkFramebufferCreateInfo fbCreateInfo = {}; + fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbCreateInfo.pNext = nullptr; + fbCreateInfo.renderPass = ctx->m_passColorOnly; + fbCreateInfo.attachmentCount = 1; + fbCreateInfo.width = width; + fbCreateInfo.height = height; + fbCreateInfo.layers = 1; + fbCreateInfo.pAttachments = &m_colorView; + ThrowIfFailed(vk::CreateFramebuffer(ctx->m_dev, &fbCreateInfo, nullptr, &m_framebuffer)); + + m_passBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + m_passBeginInfo.pNext = nullptr; + m_passBeginInfo.renderPass = ctx->m_passColorOnly; + m_passBeginInfo.framebuffer = m_framebuffer; + m_passBeginInfo.renderArea.offset.x = 0; + m_passBeginInfo.renderArea.offset.y = 0; + m_passBeginInfo.renderArea.extent.width = width; + m_passBeginInfo.renderArea.extent.height = height; + m_passBeginInfo.clearValueCount = 0; + m_passBeginInfo.pClearValues = nullptr; +} + +void VulkanContext::Window::SwapChain::Buffer::destroy(VkDevice dev) { + if (m_colorView) + vk::DestroyImageView(dev, m_colorView, nullptr); + if (m_framebuffer) + vk::DestroyFramebuffer(dev, m_framebuffer, nullptr); +} + +void VulkanContext::initSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface, VkFormat format, + VkColorSpaceKHR colorspace) { + m_internalFormat = m_displayFormat = format; + if (m_deepColor) + m_internalFormat = VK_FORMAT_R16G16B16A16_UNORM; + + /* bootstrap render passes if needed */ + if (!m_pass) { + VkAttachmentDescription attachments[2] = {}; + + /* color attachment */ + attachments[0].format = m_internalFormat; + attachments[0].samples = VkSampleCountFlagBits(m_sampleCountColor); + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference colorAttachmentRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + /* depth attachment */ + attachments[1].format = VK_FORMAT_D32_SFLOAT; + attachments[1].samples = VkSampleCountFlagBits(m_sampleCountDepth); + attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentReference depthAttachmentRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + /* render subpass */ + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + /* render pass */ + VkRenderPassCreateInfo renderPass = {}; + renderPass.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPass.attachmentCount = 2; + renderPass.pAttachments = attachments; + renderPass.subpassCount = 1; + renderPass.pSubpasses = &subpass; + ThrowIfFailed(vk::CreateRenderPass(m_dev, &renderPass, nullptr, &m_pass)); + + /* render pass color only */ + attachments[0].format = m_displayFormat; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + renderPass.attachmentCount = 1; + subpass.pDepthStencilAttachment = nullptr; + ThrowIfFailed(vk::CreateRenderPass(m_dev, &renderPass, nullptr, &m_passColorOnly)); + } + + VkSurfaceCapabilitiesKHR surfCapabilities; + ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], surface, &surfCapabilities)); + + uint32_t presentModeCount; + ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, nullptr)); + std::unique_ptr presentModes(new VkPresentModeKHR[presentModeCount]); + + ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, presentModes.get())); + + VkExtent2D swapChainExtent; + // width and height are either both -1, or both not -1. + if (surfCapabilities.currentExtent.width == (uint32_t)-1) { + // If the surface size is undefined, the size is set to + // the size of the images requested. + swapChainExtent.width = 50; + swapChainExtent.height = 50; + } else { + // If the surface size is defined, the swap chain size must match + swapChainExtent = surfCapabilities.currentExtent; + } + + // If mailbox mode is available, use it, as is the lowest-latency non- + // tearing mode. If not, try IMMEDIATE which will usually be available, + // and is fastest (though it tears). If not, fall back to FIFO which is + // always available. + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (size_t i = 0; i < presentModeCount; ++i) { + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; + break; + } + if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { + swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } + } + + // Determine the number of VkImage's to use in the swap chain (we desire to + // own only 1 image at a time, besides the images being displayed and + // queued for display): + uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1; + if ((surfCapabilities.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) { + // Application must settle for fewer images than desired: + desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; + } + + VkSurfaceTransformFlagBitsKHR preTransform; + if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + else + preTransform = surfCapabilities.currentTransform; + + VkSwapchainCreateInfoKHR swapChainInfo = {}; + swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapChainInfo.pNext = nullptr; + swapChainInfo.surface = surface; + swapChainInfo.minImageCount = desiredNumberOfSwapChainImages; + swapChainInfo.imageFormat = format; + swapChainInfo.imageExtent.width = swapChainExtent.width; + swapChainInfo.imageExtent.height = swapChainExtent.height; + swapChainInfo.preTransform = preTransform; + swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapChainInfo.imageArrayLayers = 1; + swapChainInfo.presentMode = swapchainPresentMode; + swapChainInfo.oldSwapchain = nullptr; + swapChainInfo.clipped = true; + swapChainInfo.imageColorSpace = colorspace; + swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainInfo.queueFamilyIndexCount = 0; + swapChainInfo.pQueueFamilyIndices = nullptr; + + Window::SwapChain& sc = windowCtx.m_swapChains[windowCtx.m_activeSwapChain]; + ThrowIfFailed(vk::CreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &sc.m_swapChain)); + sc.m_format = format; + + uint32_t swapchainImageCount; + ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, nullptr)); + + std::unique_ptr swapchainImages(new VkImage[swapchainImageCount]); + ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, swapchainImages.get())); + + /* images */ + sc.m_bufs.resize(swapchainImageCount); + for (uint32_t i = 0; i < swapchainImageCount; ++i) { + Window::SwapChain::Buffer& buf = sc.m_bufs[i]; + buf.setImage(this, swapchainImages[i], swapChainExtent.width, swapChainExtent.height); + } +} + +void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface, VkFormat format, + VkColorSpaceKHR colorspace, const SWindowRect& rect) { + std::unique_lock lk(m_resizeLock); + m_deferredResizes.emplace(windowCtx, surface, format, colorspace, rect); +} + +bool VulkanContext::_resizeSwapChains() { + std::unique_lock lk(m_resizeLock); + if (m_deferredResizes.empty()) + return false; + + while (m_deferredResizes.size()) { + SwapChainResize& resize = m_deferredResizes.front(); + + VkSurfaceCapabilitiesKHR surfCapabilities; + ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], resize.m_surface, &surfCapabilities)); + + uint32_t presentModeCount; + ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, nullptr)); + std::unique_ptr presentModes(new VkPresentModeKHR[presentModeCount]); + + ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, + presentModes.get())); + + VkExtent2D swapChainExtent; + // width and height are either both -1, or both not -1. + if (surfCapabilities.currentExtent.width == (uint32_t)-1) { + // If the surface size is undefined, the size is set to + // the size of the images requested. + swapChainExtent.width = 50; + swapChainExtent.height = 50; + } else { + // If the surface size is defined, the swap chain size must match + swapChainExtent = surfCapabilities.currentExtent; } - uint32_t extCount = 0; - vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, nullptr); - std::vector extensions(extCount); - vk::EnumerateDeviceExtensionProperties(m_gpus[0], nullptr, &extCount, extensions.data()); - bool hasGetMemReq2 = false; - bool hasDedicatedAllocation = false; - for (const VkExtensionProperties& ext : extensions) - { - if (!hasGetMemReq2 && !strcmp(ext.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) - hasGetMemReq2 = true; - else if (!hasDedicatedAllocation && !strcmp(ext.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME)) - hasDedicatedAllocation = true; - } - VmaAllocatorCreateFlags allocFlags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; - if (hasGetMemReq2 && hasDedicatedAllocation) - { - m_deviceExtensionNames.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - m_deviceExtensionNames.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); - allocFlags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + // If mailbox mode is available, use it, as is the lowest-latency non- + // tearing mode. If not, try IMMEDIATE which will usually be available, + // and is fastest (though it tears). If not, fall back to FIFO which is + // always available. + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (size_t i = 0; i < presentModeCount; ++i) { + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; + break; + } + if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { + swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } } - VkDeviceCreateInfo deviceInfo = {}; - deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceInfo.pNext = nullptr; - deviceInfo.queueCreateInfoCount = 1; - deviceInfo.pQueueCreateInfos = &queueInfo; - deviceInfo.enabledLayerCount = m_layerNames.size(); - deviceInfo.ppEnabledLayerNames = - deviceInfo.enabledLayerCount ? m_layerNames.data() : nullptr; - deviceInfo.enabledExtensionCount = m_deviceExtensionNames.size(); - deviceInfo.ppEnabledExtensionNames = - deviceInfo.enabledExtensionCount ? m_deviceExtensionNames.data() : nullptr; - deviceInfo.pEnabledFeatures = &features; - - ThrowIfFailed(vk::CreateDevice(m_gpus[0], &deviceInfo, nullptr, &m_dev)); - - vk::init_dispatch_table_bottom(m_instance, m_dev); - - /* allocator */ - VmaVulkanFunctions vulkanFunctions = {}; - vulkanFunctions.vkGetPhysicalDeviceProperties = vk::GetPhysicalDeviceProperties; - vulkanFunctions.vkGetPhysicalDeviceMemoryProperties = vk::GetPhysicalDeviceMemoryProperties; - vulkanFunctions.vkAllocateMemory = vk::AllocateMemory; - vulkanFunctions.vkFreeMemory = vk::FreeMemory; - vulkanFunctions.vkMapMemory = vk::MapMemory; - vulkanFunctions.vkUnmapMemory = vk::UnmapMemory; - vulkanFunctions.vkBindBufferMemory = vk::BindBufferMemory; - vulkanFunctions.vkBindImageMemory = vk::BindImageMemory; - vulkanFunctions.vkGetBufferMemoryRequirements = vk::GetBufferMemoryRequirements; - vulkanFunctions.vkGetImageMemoryRequirements = vk::GetImageMemoryRequirements; - vulkanFunctions.vkCreateBuffer = vk::CreateBuffer; - vulkanFunctions.vkDestroyBuffer = vk::DestroyBuffer; - vulkanFunctions.vkCreateImage = vk::CreateImage; - vulkanFunctions.vkDestroyImage = vk::DestroyImage; - if (hasGetMemReq2 && hasDedicatedAllocation) - { - vulkanFunctions.vkGetBufferMemoryRequirements2KHR = reinterpret_cast( - vk::GetDeviceProcAddr(m_dev, "vkGetBufferMemoryRequirements2KHR")); - vulkanFunctions.vkGetImageMemoryRequirements2KHR = reinterpret_cast( - vk::GetDeviceProcAddr(m_dev, "vkGetImageMemoryRequirements2KHR")); + // Determine the number of VkImage's to use in the swap chain (we desire to + // own only 1 image at a time, besides the images being displayed and + // queued for display): + uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1; + if ((surfCapabilities.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) { + // Application must settle for fewer images than desired: + desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; } - VmaAllocatorCreateInfo allocatorInfo = {}; - allocatorInfo.flags = allocFlags; - allocatorInfo.physicalDevice = m_gpus[0]; - allocatorInfo.device = m_dev; - allocatorInfo.pVulkanFunctions = &vulkanFunctions; - ThrowIfFailed(vmaCreateAllocator(&allocatorInfo, &m_allocator)); - // Going to need a command buffer to send the memory barriers in - // set_image_layout but we couldn't have created one before we knew - // what our graphics_queue_family_index is, but now that we have it, - // create the command buffer - - VkCommandPoolCreateInfo cmdPoolInfo = {}; - cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmdPoolInfo.pNext = nullptr; - cmdPoolInfo.queueFamilyIndex = m_graphicsQueueFamilyIndex; - cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - ThrowIfFailed(vk::CreateCommandPool(m_dev, &cmdPoolInfo, nullptr, &m_loadPool)); - - VkCommandBufferAllocateInfo cmd = {}; - cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmd.pNext = nullptr; - cmd.commandPool = m_loadPool; - cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmd.commandBufferCount = 1; - ThrowIfFailed(vk::AllocateCommandBuffers(m_dev, &cmd, &m_loadCmdBuf)); - - vk::GetDeviceQueue(m_dev, m_graphicsQueueFamilyIndex, 0, &m_queue); - - /* Begin load command buffer here */ - VkCommandBufferBeginInfo cmdBufBeginInfo = {}; - cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - ThrowIfFailed(vk::BeginCommandBuffer(m_loadCmdBuf, &cmdBufBeginInfo)); - - m_sampleCountColor = flp2(std::min(m_gpuProps.limits.framebufferColorSampleCounts, m_sampleCountColor)); - m_sampleCountDepth = flp2(std::min(m_gpuProps.limits.framebufferDepthSampleCounts, m_sampleCountDepth)); - - if (m_features.samplerAnisotropy) - m_anisotropy = std::min(m_gpuProps.limits.maxSamplerAnisotropy, m_anisotropy); + VkSurfaceTransformFlagBitsKHR preTransform; + if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; else - m_anisotropy = 1; + preTransform = surfCapabilities.currentTransform; - VkDescriptorSetLayoutBinding layoutBindings[BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT]; - for (int i=0 ; i swapchainImages(new VkImage[swapchainImageCount]); + ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, swapchainImages.get())); + + /* images */ + sc.m_bufs.resize(swapchainImageCount); + for (uint32_t i = 0; i < swapchainImageCount; ++i) { + Window::SwapChain::Buffer& buf = sc.m_bufs[i]; + buf.setImage(this, swapchainImages[i], swapChainExtent.width, swapChainExtent.height); } - VkDescriptorSetLayoutCreateInfo descriptorLayout = {}; - descriptorLayout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorLayout.pNext = nullptr; - descriptorLayout.bindingCount = BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT; - descriptorLayout.pBindings = layoutBindings; + m_deferredResizes.pop(); + } - ThrowIfFailed(vk::CreateDescriptorSetLayout(m_dev, &descriptorLayout, nullptr, - &m_descSetLayout)); - - VkPipelineLayoutCreateInfo pipelineLayout = {}; - pipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayout.setLayoutCount = 1; - pipelineLayout.pSetLayouts = &m_descSetLayout; - ThrowIfFailed(vk::CreatePipelineLayout(m_dev, &pipelineLayout, nullptr, &m_pipelinelayout)); - - std::string gpuName = m_gpuProps.deviceName; - Log.report(logvisor::Info, "Initialized %s", gpuName.c_str()); - Log.report(logvisor::Info, "Vulkan version %d.%d.%d", - m_gpuProps.apiVersion >> 22, - (m_gpuProps.apiVersion >> 12) & 0b1111111111, - m_gpuProps.apiVersion & 0b111111111111); - Log.report(logvisor::Info, "Driver version %d.%d.%d", - m_gpuProps.driverVersion >> 22, - (m_gpuProps.driverVersion >> 12) & 0b1111111111, - m_gpuProps.driverVersion & 0b111111111111); + return true; } -void VulkanContext::destroyDevice() -{ - if (m_passColorOnly) - { - vk::DestroyRenderPass(m_dev, m_passColorOnly, nullptr); - m_passColorOnly = VK_NULL_HANDLE; - } +struct VulkanDescriptorPool : ListNode { + VkDescriptorPool m_descPool; + int m_allocatedSets = 0; - if (m_pass) - { - vk::DestroyRenderPass(m_dev, m_pass, nullptr); - m_pass = VK_NULL_HANDLE; - } + VulkanDescriptorPool(VulkanDataFactoryImpl* factory) + : ListNode(factory) { + VkDescriptorPoolSize poolSizes[2] = {}; + VkDescriptorPoolCreateInfo descriptorPoolInfo = {}; + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.pNext = nullptr; + descriptorPoolInfo.maxSets = BOO_VK_MAX_DESCRIPTOR_SETS; + descriptorPoolInfo.poolSizeCount = 2; + descriptorPoolInfo.pPoolSizes = poolSizes; - if (m_pipelinelayout) - { - vk::DestroyPipelineLayout(m_dev, m_pipelinelayout, nullptr); - m_pipelinelayout = VK_NULL_HANDLE; - } + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = BOO_GLSL_MAX_UNIFORM_COUNT * BOO_VK_MAX_DESCRIPTOR_SETS; - if (m_descSetLayout) - { - vk::DestroyDescriptorSetLayout(m_dev, m_descSetLayout, nullptr); - m_descSetLayout = VK_NULL_HANDLE; - } + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = BOO_GLSL_MAX_TEXTURE_COUNT * BOO_VK_MAX_DESCRIPTOR_SETS; - if (m_loadPool) - { - vk::DestroyCommandPool(m_dev, m_loadPool, nullptr); - m_loadPool = VK_NULL_HANDLE; - } + ThrowIfFailed(vk::CreateDescriptorPool(factory->m_ctx->m_dev, &descriptorPoolInfo, nullptr, &m_descPool)); + } - if (m_allocator) - { - vmaDestroyAllocator(m_allocator); - m_allocator = VK_NULL_HANDLE; - } + ~VulkanDescriptorPool() { vk::DestroyDescriptorPool(m_head->m_ctx->m_dev, m_descPool, nullptr); } - if (m_dev) - { - vk::DestroyDevice(m_dev, nullptr); - m_dev = VK_NULL_HANDLE; - } + std::unique_lock destructorLock() override { + return std::unique_lock{m_head->m_dataMutex}; + } + static std::unique_lock _getHeadLock(VulkanDataFactoryImpl* factory) { + return std::unique_lock{factory->m_dataMutex}; + } + static VulkanDescriptorPool*& _getHeadPtr(VulkanDataFactoryImpl* factory) { return factory->m_descPoolHead; } +}; - if (m_instance) - { - vk::DestroyInstance(m_instance, nullptr); - m_instance = VK_NULL_HANDLE; - } +boo::ObjToken VulkanDataFactoryImpl::allocateDescriptorSets(VkDescriptorSet* out) { + std::lock_guard lk(m_dataMutex); + boo::ObjToken pool; + if (!m_descPoolHead || m_descPoolHead->m_allocatedSets == BOO_VK_MAX_DESCRIPTOR_SETS) + pool = new VulkanDescriptorPool(this); + else + pool = m_descPoolHead; + + VkDescriptorSetLayout layouts[] = {m_ctx->m_descSetLayout, m_ctx->m_descSetLayout}; + VkDescriptorSetAllocateInfo descAllocInfo; + descAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descAllocInfo.pNext = nullptr; + descAllocInfo.descriptorPool = pool->m_descPool; + descAllocInfo.descriptorSetCount = 2; + descAllocInfo.pSetLayouts = layouts; + ThrowIfFailed(vk::AllocateDescriptorSets(m_ctx->m_dev, &descAllocInfo, out)); + pool->m_allocatedSets += 2; + + return pool; } -void VulkanContext::Window::SwapChain::Buffer::setImage -(VulkanContext* ctx, VkImage image, uint32_t width, uint32_t height) -{ - m_image = image; - if (m_colorView) - vk::DestroyImageView(ctx->m_dev, m_colorView, nullptr); - if (m_framebuffer) - vk::DestroyFramebuffer(ctx->m_dev, m_framebuffer, nullptr); +struct AllocatedBuffer { + VkBuffer m_buffer = VK_NULL_HANDLE; + VmaAllocation m_allocation; + + void* _create(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo, VmaMemoryUsage usage) { + assert(m_buffer == VK_NULL_HANDLE && "create may only be called once"); + VmaAllocationCreateInfo bufAllocInfo = {}; + bufAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + bufAllocInfo.usage = usage; + + VmaAllocationInfo allocInfo; + ThrowIfFailed( + vmaCreateBuffer(ctx->m_allocator, pBufferCreateInfo, &bufAllocInfo, &m_buffer, &m_allocation, &allocInfo)); + return allocInfo.pMappedData; + } + + void* createCPU(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo) { + return _create(ctx, pBufferCreateInfo, VMA_MEMORY_USAGE_CPU_ONLY); + } + + void* createCPUtoGPU(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo) { + return _create(ctx, pBufferCreateInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + } + + void destroy(VulkanContext* ctx) { + if (m_buffer) { + vmaDestroyBuffer(ctx->m_allocator, m_buffer, m_allocation); + m_buffer = VK_NULL_HANDLE; + } + } +}; + +struct AllocatedImage { + VkImage m_image = VK_NULL_HANDLE; + VmaAllocation m_allocation; + + void _create(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInfo, VmaAllocationCreateFlags flags) { + assert(m_image == VK_NULL_HANDLE && "create may only be called once"); + VmaAllocationCreateInfo bufAllocInfo = {}; + bufAllocInfo.flags = flags; + bufAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + ThrowIfFailed(vmaCreateImage(ctx->m_allocator, pImageCreateInfo, &bufAllocInfo, &m_image, &m_allocation, nullptr)); + } + + void create(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInf) { _create(ctx, pImageCreateInf, 0); } + + void createFB(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInf) { + _create(ctx, pImageCreateInf, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT); + } + + void destroy(VulkanContext* ctx) { + if (m_image) { + vmaDestroyImage(ctx->m_allocator, m_image, m_allocation); + m_image = VK_NULL_HANDLE; + } + } +}; + +struct VulkanData : BaseGraphicsData { + VulkanContext* m_ctx; + + /* Vertex, Index, Uniform */ + AllocatedBuffer m_constantBuffers[3]; + AllocatedBuffer m_texStagingBuffer; + + explicit VulkanData(VulkanDataFactoryImpl& head __BooTraceArgs) + : BaseGraphicsData(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} + ~VulkanData() { + for (int i = 0; i < 3; ++i) + m_constantBuffers[i].destroy(m_ctx); + m_texStagingBuffer.destroy(m_ctx); + } +}; + +struct VulkanPool : BaseGraphicsPool { + VulkanContext* m_ctx; + AllocatedBuffer m_constantBuffer; + + explicit VulkanPool(VulkanDataFactoryImpl& head __BooTraceArgs) + : BaseGraphicsPool(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} + ~VulkanPool() { m_constantBuffer.destroy(m_ctx); } +}; + +static const VkBufferUsageFlagBits USE_TABLE[] = {VkBufferUsageFlagBits(0), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT}; + +class VulkanGraphicsBufferS : public GraphicsDataNode { + friend class VulkanDataFactory; + friend struct VulkanCommandQueue; + VulkanContext* m_ctx; + size_t m_sz; + std::unique_ptr m_stagingBuf; + VulkanGraphicsBufferS(const boo::ObjToken& parent, BufferUse use, VulkanContext* ctx, + const void* data, size_t stride, size_t count) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_sz(stride * count) + , m_stagingBuf(new uint8_t[m_sz]) + , m_use(use) { + memmove(m_stagingBuf.get(), data, m_sz); + m_bufferInfo.range = m_sz; + } + +public: + size_t size() const { return m_sz; } + VkDescriptorBufferInfo m_bufferInfo; + BufferUse m_use; + + VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) { + m_bufferInfo.offset = offset; + offset += m_sz; + + if (m_use == BufferUse::Uniform) { + size_t minOffset = std::max(VkDeviceSize(256), ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); + } + + return offset; + } + + void placeForGPU(VkBuffer bufObj, uint8_t* buf) { + m_bufferInfo.buffer = bufObj; + memmove(buf + m_bufferInfo.offset, m_stagingBuf.get(), m_sz); + m_stagingBuf.reset(); + } +}; + +template +class VulkanGraphicsBufferD : public GraphicsDataNode { + friend class VulkanDataFactory; + friend class VulkanDataFactoryImpl; + friend struct VulkanCommandQueue; + VulkanContext* m_ctx; + size_t m_cpuSz; + std::unique_ptr m_cpuBuf; + int m_validSlots = 0; + VulkanGraphicsBufferD(const boo::ObjToken& parent, BufferUse use, VulkanContext* ctx, size_t stride, + size_t count) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_cpuSz(stride * count) + , m_cpuBuf(new uint8_t[m_cpuSz]) + , m_use(use) { + m_bufferInfo[0].range = m_cpuSz; + m_bufferInfo[1].range = m_cpuSz; + } + void update(int b); + +public: + VkDescriptorBufferInfo m_bufferInfo[2]; + uint8_t* m_bufferPtrs[2] = {}; + BufferUse m_use; + void load(const void* data, size_t sz); + void* map(size_t sz); + void unmap(); + + VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) { + for (int i = 0; i < 2; ++i) { + m_bufferInfo[i].offset = offset; + offset += m_cpuSz; + + if (m_use == BufferUse::Uniform) { + size_t minOffset = std::max(VkDeviceSize(256), ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); + } + } + + return offset; + } + + void placeForGPU(VkBuffer bufObj, uint8_t* buf) { + m_bufferInfo[0].buffer = bufObj; + m_bufferInfo[1].buffer = bufObj; + m_bufferPtrs[0] = buf + m_bufferInfo[0].offset; + m_bufferPtrs[1] = buf + m_bufferInfo[1].offset; + } +}; + +static void MakeSampler(VulkanContext* ctx, VkSampler& sampOut, TextureClampMode mode, int mips) { + uint32_t key = (uint32_t(mode) << 16) | mips; + auto search = ctx->m_samplers.find(key); + if (search != ctx->m_samplers.end()) { + sampOut = search->second; + return; + } + + /* Create linear sampler */ + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.pNext = nullptr; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.anisotropyEnable = ctx->m_features.samplerAnisotropy; + samplerInfo.maxAnisotropy = ctx->m_anisotropy; + samplerInfo.maxLod = mips - 1; + switch (mode) { + case TextureClampMode::Repeat: + default: + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + break; + case TextureClampMode::ClampToWhite: + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + break; + case TextureClampMode::ClampToBlack: + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + break; + case TextureClampMode::ClampToEdge: + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + case TextureClampMode::ClampToEdgeNearest: + samplerInfo.magFilter = VK_FILTER_NEAREST; + samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + } + ThrowIfFailed(vk::CreateSampler(ctx->m_dev, &samplerInfo, nullptr, &sampOut)); + ctx->m_samplers[key] = sampOut; +} + +class VulkanTextureS : public GraphicsDataNode { + friend class VulkanDataFactory; + VulkanContext* m_ctx; + TextureFormat m_fmt; + size_t m_sz; + size_t m_width, m_height, m_mips; + TextureClampMode m_clampMode; + VkFormat m_vkFmt; + int m_pixelPitchNum = 1; + int m_pixelPitchDenom = 1; + + VulkanTextureS(const boo::ObjToken& parent, VulkanContext* ctx, size_t width, size_t height, + size_t mips, TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_fmt(fmt) + , m_sz(sz) + , m_width(width) + , m_height(height) + , m_mips(mips) + , m_clampMode(clampMode) { + VkFormat pfmt; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = VK_FORMAT_R8G8B8A8_UNORM; + m_pixelPitchNum = 4; + break; + case TextureFormat::I8: + pfmt = VK_FORMAT_R8_UNORM; + break; + case TextureFormat::I16: + pfmt = VK_FORMAT_R16_UNORM; + m_pixelPitchNum = 2; + break; + case TextureFormat::DXT1: + pfmt = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + m_pixelPitchNum = 1; + m_pixelPitchDenom = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); + } + m_vkFmt = pfmt; + + /* create cpu image buffer */ + VkBufferCreateInfo bufCreateInfo = {}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = sz; + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + void* mappedData = m_cpuBuf.createCPU(ctx, &bufCreateInfo); + memmove(mappedData, data, sz); + } + +public: + AllocatedBuffer m_cpuBuf; + AllocatedImage m_gpuTex; + VkImageView m_gpuView = VK_NULL_HANDLE; + VkSampler m_sampler = VK_NULL_HANDLE; + VkDescriptorImageInfo m_descInfo; + ~VulkanTextureS() { + vk::DestroyImageView(m_ctx->m_dev, m_gpuView, nullptr); + m_gpuTex.destroy(m_ctx); + m_cpuBuf.destroy(m_ctx); + } + + void _setClampMode(TextureClampMode mode) { + MakeSampler(m_ctx, m_sampler, mode, m_mips); + m_descInfo.sampler = m_sampler; + } + + void setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + _setClampMode(mode); + } + + void deleteUploadObjects() { m_cpuBuf.destroy(m_ctx); } + + void placeForGPU(VulkanContext* ctx) { + /* create gpu image */ + VkImageCreateInfo texCreateInfo = {}; + texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + texCreateInfo.imageType = VK_IMAGE_TYPE_2D; + texCreateInfo.format = m_vkFmt; + texCreateInfo.mipLevels = m_mips; + texCreateInfo.arrayLayers = 1; + texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.extent = {uint32_t(m_width), uint32_t(m_height), 1}; + texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + m_gpuTex.create(m_ctx, &texCreateInfo); + + _setClampMode(m_clampMode); + m_descInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + /* create image view */ + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.pNext = nullptr; + viewInfo.image = m_gpuTex.m_image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = m_vkFmt; + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = m_mips; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView)); + m_descInfo.imageView = m_gpuView; + + /* Since we're going to blit to the texture image, set its layout to + * DESTINATION_OPTIMAL */ + SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_mips, 1); + + VkBufferImageCopy copyRegions[16] = {}; + size_t width = m_width; + size_t height = m_height; + size_t regionCount = std::min(size_t(16), m_mips); + size_t offset = 0; + for (int i = 0; i < regionCount; ++i) { + size_t regionPitch = width * height * m_pixelPitchNum / m_pixelPitchDenom; + + copyRegions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegions[i].imageSubresource.mipLevel = i; + copyRegions[i].imageSubresource.baseArrayLayer = 0; + copyRegions[i].imageSubresource.layerCount = 1; + copyRegions[i].imageExtent.width = width; + copyRegions[i].imageExtent.height = height; + copyRegions[i].imageExtent.depth = 1; + copyRegions[i].bufferOffset = offset; + + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + offset += regionPitch; + } + + /* Put the copy command into the command buffer */ + vk::CmdCopyBufferToImage(ctx->m_loadCmdBuf, m_cpuBuf.m_buffer, m_gpuTex.m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount, copyRegions); + + /* Set the layout for the texture image from DESTINATION_OPTIMAL to + * SHADER_READ_ONLY */ + SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mips, 1); + } + + TextureFormat format() const { return m_fmt; } +}; + +class VulkanTextureSA : public GraphicsDataNode { + friend class VulkanDataFactory; + VulkanContext* m_ctx; + TextureFormat m_fmt; + size_t m_sz; + size_t m_width, m_height, m_layers, m_mips; + TextureClampMode m_clampMode = TextureClampMode::Invalid; + VkFormat m_vkFmt; + int m_pixelPitchNum = 1; + int m_pixelPitchDenom = 1; + + VulkanTextureSA(const boo::ObjToken& parent, VulkanContext* ctx, size_t width, size_t height, + size_t layers, size_t mips, TextureFormat fmt, TextureClampMode clampMode, const void* data, + size_t sz) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_fmt(fmt) + , m_sz(sz) + , m_width(width) + , m_height(height) + , m_layers(layers) + , m_mips(mips) + , m_clampMode(clampMode) { + VkFormat pfmt; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = VK_FORMAT_R8G8B8A8_UNORM; + m_pixelPitchNum = 4; + break; + case TextureFormat::I8: + pfmt = VK_FORMAT_R8_UNORM; + break; + case TextureFormat::I16: + pfmt = VK_FORMAT_R16_UNORM; + m_pixelPitchNum = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); + } + m_vkFmt = pfmt; + + /* create cpu image buffer */ + VkBufferCreateInfo bufCreateInfo = {}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = sz; + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + void* mappedData = m_cpuBuf.createCPU(ctx, &bufCreateInfo); + memmove(mappedData, data, sz); + } + +public: + AllocatedBuffer m_cpuBuf; + AllocatedImage m_gpuTex; + VkImageView m_gpuView = VK_NULL_HANDLE; + VkSampler m_sampler = VK_NULL_HANDLE; + VkDescriptorImageInfo m_descInfo; + ~VulkanTextureSA() { + vk::DestroyImageView(m_ctx->m_dev, m_gpuView, nullptr); + m_gpuTex.destroy(m_ctx); + m_cpuBuf.destroy(m_ctx); + } + + void _setClampMode(TextureClampMode mode) { + MakeSampler(m_ctx, m_sampler, mode, m_mips); + m_descInfo.sampler = m_sampler; + } + + void setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + _setClampMode(mode); + } + + void deleteUploadObjects() { m_cpuBuf.destroy(m_ctx); } + + void placeForGPU(VulkanContext* ctx) { + /* create gpu image */ + VkImageCreateInfo texCreateInfo = {}; + texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + texCreateInfo.imageType = VK_IMAGE_TYPE_2D; + texCreateInfo.format = m_vkFmt; + texCreateInfo.mipLevels = m_mips; + texCreateInfo.arrayLayers = m_layers; + texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.extent = {uint32_t(m_width), uint32_t(m_height), 1}; + texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + m_gpuTex.create(m_ctx, &texCreateInfo); + + _setClampMode(m_clampMode); + m_descInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + /* create image view */ + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.pNext = nullptr; + viewInfo.image = m_gpuTex.m_image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + viewInfo.format = m_vkFmt; + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = m_mips; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = m_layers; + + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView)); + m_descInfo.imageView = m_gpuView; + + /* Since we're going to blit to the texture image, set its layout to + * DESTINATION_OPTIMAL */ + SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_mips, m_layers); + + VkBufferImageCopy copyRegions[16] = {}; + size_t width = m_width; + size_t height = m_height; + size_t regionCount = std::min(size_t(16), m_mips); + size_t offset = 0; + for (int i = 0; i < regionCount; ++i) { + size_t regionPitch = width * height * m_layers * m_pixelPitchNum / m_pixelPitchDenom; + + copyRegions[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegions[i].imageSubresource.mipLevel = i; + copyRegions[i].imageSubresource.baseArrayLayer = 0; + copyRegions[i].imageSubresource.layerCount = m_layers; + copyRegions[i].imageExtent.width = width; + copyRegions[i].imageExtent.height = height; + copyRegions[i].imageExtent.depth = 1; + copyRegions[i].bufferOffset = offset; + + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + offset += regionPitch; + } + + /* Put the copy command into the command buffer */ + vk::CmdCopyBufferToImage(ctx->m_loadCmdBuf, m_cpuBuf.m_buffer, m_gpuTex.m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount, copyRegions); + + /* Set the layout for the texture image from DESTINATION_OPTIMAL to + * SHADER_READ_ONLY */ + SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mips, m_layers); + } + + TextureFormat format() const { return m_fmt; } + size_t layers() const { return m_layers; } +}; + +class VulkanTextureD : public GraphicsDataNode { + friend class VulkanDataFactory; + friend struct VulkanCommandQueue; + size_t m_width; + size_t m_height; + TextureFormat m_fmt; + TextureClampMode m_clampMode; + VulkanCommandQueue* m_q; + std::unique_ptr m_stagingBuf; + size_t m_cpuSz; + VkDeviceSize m_cpuOffsets[2]; + VkFormat m_vkFmt; + int m_validSlots = 0; + VulkanTextureD(const boo::ObjToken& parent, VulkanCommandQueue* q, size_t width, size_t height, + TextureFormat fmt, TextureClampMode clampMode) + : GraphicsDataNode(parent), m_width(width), m_height(height), m_fmt(fmt), m_clampMode(clampMode), m_q(q) { + VkFormat pfmt; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = VK_FORMAT_R8G8B8A8_UNORM; + m_cpuSz = width * height * 4; + break; + case TextureFormat::I8: + pfmt = VK_FORMAT_R8_UNORM; + m_cpuSz = width * height; + break; + case TextureFormat::I16: + pfmt = VK_FORMAT_R16_UNORM; + m_cpuSz = width * height * 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); + } + m_vkFmt = pfmt; + m_stagingBuf.reset(new uint8_t[m_cpuSz]); + } + void update(int b); + +public: + VkBuffer m_cpuBuf = VK_NULL_HANDLE; /* Owned externally */ + uint8_t* m_cpuBufPtrs[2] = {}; + AllocatedImage m_gpuTex[2]; + VkImageView m_gpuView[2]; + VkSampler m_sampler = VK_NULL_HANDLE; + VkDescriptorImageInfo m_descInfo[2]; + ~VulkanTextureD(); + + void _setClampMode(TextureClampMode mode); + void setClampMode(TextureClampMode mode); + void load(const void* data, size_t sz); + void* map(size_t sz); + void unmap(); + + VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) { + for (int i = 0; i < 2; ++i) { + m_cpuOffsets[i] = offset; + offset += m_cpuSz; + } + + return offset; + } + + void placeForGPU(VulkanContext* ctx, VkBuffer bufObj, uint8_t* buf) { + m_cpuBuf = bufObj; + m_cpuBufPtrs[0] = buf + m_cpuOffsets[0]; + m_cpuBufPtrs[1] = buf + m_cpuOffsets[1]; + + /* Create images */ + VkImageCreateInfo texCreateInfo = {}; + texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + texCreateInfo.pNext = nullptr; + texCreateInfo.imageType = VK_IMAGE_TYPE_2D; + texCreateInfo.format = m_vkFmt; + texCreateInfo.extent.width = m_width; + texCreateInfo.extent.height = m_height; + texCreateInfo.extent.depth = 1; + texCreateInfo.mipLevels = 1; + texCreateInfo.arrayLayers = 1; + texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + texCreateInfo.queueFamilyIndexCount = 0; + texCreateInfo.pQueueFamilyIndices = nullptr; + texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + texCreateInfo.flags = 0; + + _setClampMode(m_clampMode); + for (int i = 0; i < 2; ++i) { + /* create gpu image */ + m_gpuTex[i].create(ctx, &texCreateInfo); + m_descInfo[i].sampler = m_sampler; + m_descInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.pNext = nullptr; + viewInfo.image = nullptr; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = m_vkFmt; + viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + for (int i = 0; i < 2; ++i) { + /* create image view */ + viewInfo.image = m_gpuTex[i].m_image; + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView[i])); + + m_descInfo[i].imageView = m_gpuView[i]; + } + } + + TextureFormat format() const { return m_fmt; } +}; + +#define MAX_BIND_TEXS 4 + +class VulkanTextureR : public GraphicsDataNode { + friend class VulkanDataFactory; + friend struct VulkanCommandQueue; + size_t m_width = 0; + size_t m_height = 0; + VkSampleCountFlags m_samplesColor, m_samplesDepth; + + size_t m_colorBindCount; + size_t m_depthBindCount; + + void Setup(VulkanContext* ctx) { + /* no-ops on first call */ + doDestroy(); + m_layout = VK_IMAGE_LAYOUT_UNDEFINED; + + /* color target */ + VkImageCreateInfo texCreateInfo = {}; + texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + texCreateInfo.pNext = nullptr; + texCreateInfo.imageType = VK_IMAGE_TYPE_2D; + texCreateInfo.format = ctx->m_internalFormat; + texCreateInfo.extent.width = m_width; + texCreateInfo.extent.height = m_height; + texCreateInfo.extent.depth = 1; + texCreateInfo.mipLevels = 1; + texCreateInfo.arrayLayers = 1; + texCreateInfo.samples = VkSampleCountFlagBits(m_samplesColor); + texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + texCreateInfo.queueFamilyIndexCount = 0; + texCreateInfo.pQueueFamilyIndices = nullptr; + texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + texCreateInfo.flags = 0; + m_colorTex.createFB(ctx, &texCreateInfo); + + /* depth target */ + texCreateInfo.samples = VkSampleCountFlagBits(m_samplesDepth); + texCreateInfo.format = VK_FORMAT_D32_SFLOAT; + texCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + m_depthTex.createFB(ctx, &texCreateInfo); + + texCreateInfo.samples = VkSampleCountFlagBits(1); + + for (size_t i = 0; i < m_colorBindCount; ++i) { + m_colorBindLayout[i] = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.format = ctx->m_internalFormat; + texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + m_colorBindTex[i].createFB(ctx, &texCreateInfo); + + m_colorBindDescInfo[i].sampler = m_sampler; + m_colorBindDescInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + for (size_t i = 0; i < m_depthBindCount; ++i) { + m_depthBindLayout[i] = VK_IMAGE_LAYOUT_UNDEFINED; + texCreateInfo.format = VK_FORMAT_D32_SFLOAT; + texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + m_depthBindTex[i].createFB(ctx, &texCreateInfo); + + m_depthBindDescInfo[i].sampler = m_sampler; + m_depthBindDescInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } /* Create resource views */ VkImageViewCreateInfo viewCreateInfo = {}; viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewCreateInfo.pNext = nullptr; - viewCreateInfo.image = m_image; + viewCreateInfo.image = m_colorTex.m_image; viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCreateInfo.format = ctx->m_displayFormat; + viewCreateInfo.format = ctx->m_internalFormat; viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; viewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; viewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; @@ -766,2834 +1805,1417 @@ void VulkanContext::Window::SwapChain::Buffer::setImage viewCreateInfo.subresourceRange.layerCount = 1; ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_colorView)); + viewCreateInfo.image = m_depthTex.m_image; + viewCreateInfo.format = VK_FORMAT_D32_SFLOAT; + viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_depthView)); + + for (size_t i = 0; i < m_colorBindCount; ++i) { + viewCreateInfo.image = m_colorBindTex[i].m_image; + viewCreateInfo.format = ctx->m_internalFormat; + viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_colorBindView[i])); + m_colorBindDescInfo[i].imageView = m_colorBindView[i]; + } + + for (size_t i = 0; i < m_depthBindCount; ++i) { + viewCreateInfo.image = m_depthBindTex[i].m_image; + viewCreateInfo.format = VK_FORMAT_D32_SFLOAT; + viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_depthBindView[i])); + m_depthBindDescInfo[i].imageView = m_depthBindView[i]; + } + /* framebuffer */ VkFramebufferCreateInfo fbCreateInfo = {}; fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbCreateInfo.pNext = nullptr; - fbCreateInfo.renderPass = ctx->m_passColorOnly; - fbCreateInfo.attachmentCount = 1; - fbCreateInfo.width = width; - fbCreateInfo.height = height; + fbCreateInfo.renderPass = ctx->m_pass; + fbCreateInfo.attachmentCount = 2; + fbCreateInfo.width = m_width; + fbCreateInfo.height = m_height; fbCreateInfo.layers = 1; - fbCreateInfo.pAttachments = &m_colorView; + VkImageView attachments[2] = {m_colorView, m_depthView}; + fbCreateInfo.pAttachments = attachments; ThrowIfFailed(vk::CreateFramebuffer(ctx->m_dev, &fbCreateInfo, nullptr, &m_framebuffer)); m_passBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; m_passBeginInfo.pNext = nullptr; - m_passBeginInfo.renderPass = ctx->m_passColorOnly; + m_passBeginInfo.renderPass = ctx->m_pass; m_passBeginInfo.framebuffer = m_framebuffer; m_passBeginInfo.renderArea.offset.x = 0; m_passBeginInfo.renderArea.offset.y = 0; - m_passBeginInfo.renderArea.extent.width = width; - m_passBeginInfo.renderArea.extent.height = height; + m_passBeginInfo.renderArea.extent.width = m_width; + m_passBeginInfo.renderArea.extent.height = m_height; m_passBeginInfo.clearValueCount = 0; m_passBeginInfo.pClearValues = nullptr; -} + } -void VulkanContext::Window::SwapChain::Buffer::destroy(VkDevice dev) -{ - if (m_colorView) - vk::DestroyImageView(dev, m_colorView, nullptr); - if (m_framebuffer) - vk::DestroyFramebuffer(dev, m_framebuffer, nullptr); -} - -void VulkanContext::initSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface, - VkFormat format, VkColorSpaceKHR colorspace) -{ - m_internalFormat = m_displayFormat = format; - if (m_deepColor) - m_internalFormat = VK_FORMAT_R16G16B16A16_UNORM; - - /* bootstrap render passes if needed */ - if (!m_pass) - { - VkAttachmentDescription attachments[2] = {}; - - /* color attachment */ - attachments[0].format = m_internalFormat; - attachments[0].samples = VkSampleCountFlagBits(m_sampleCountColor); - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference colorAttachmentRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - /* depth attachment */ - attachments[1].format = VK_FORMAT_D32_SFLOAT; - attachments[1].samples = VkSampleCountFlagBits(m_sampleCountDepth); - attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - VkAttachmentReference depthAttachmentRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - /* render subpass */ - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - subpass.pDepthStencilAttachment = &depthAttachmentRef; - - /* render pass */ - VkRenderPassCreateInfo renderPass = {}; - renderPass.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPass.attachmentCount = 2; - renderPass.pAttachments = attachments; - renderPass.subpassCount = 1; - renderPass.pSubpasses = &subpass; - ThrowIfFailed(vk::CreateRenderPass(m_dev, &renderPass, nullptr, &m_pass)); - - /* render pass color only */ - attachments[0].format = m_displayFormat; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - renderPass.attachmentCount = 1; - subpass.pDepthStencilAttachment = nullptr; - ThrowIfFailed(vk::CreateRenderPass(m_dev, &renderPass, nullptr, &m_passColorOnly)); - } - - VkSurfaceCapabilitiesKHR surfCapabilities; - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], surface, &surfCapabilities)); - - uint32_t presentModeCount; - ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, nullptr)); - std::unique_ptr presentModes(new VkPresentModeKHR[presentModeCount]); - - ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, presentModes.get())); - - VkExtent2D swapChainExtent; - // width and height are either both -1, or both not -1. - if (surfCapabilities.currentExtent.width == (uint32_t)-1) - { - // If the surface size is undefined, the size is set to - // the size of the images requested. - swapChainExtent.width = 50; - swapChainExtent.height = 50; - } - else - { - // If the surface size is defined, the swap chain size must match - swapChainExtent = surfCapabilities.currentExtent; - } - - // If mailbox mode is available, use it, as is the lowest-latency non- - // tearing mode. If not, try IMMEDIATE which will usually be available, - // and is fastest (though it tears). If not, fall back to FIFO which is - // always available. - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - for (size_t i=0 ; i 0) && - (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) - { - // Application must settle for fewer images than desired: - desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; - } - - VkSurfaceTransformFlagBitsKHR preTransform; - if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) - preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - else - preTransform = surfCapabilities.currentTransform; - - VkSwapchainCreateInfoKHR swapChainInfo = {}; - swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapChainInfo.pNext = nullptr; - swapChainInfo.surface = surface; - swapChainInfo.minImageCount = desiredNumberOfSwapChainImages; - swapChainInfo.imageFormat = format; - swapChainInfo.imageExtent.width = swapChainExtent.width; - swapChainInfo.imageExtent.height = swapChainExtent.height; - swapChainInfo.preTransform = preTransform; - swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapChainInfo.imageArrayLayers = 1; - swapChainInfo.presentMode = swapchainPresentMode; - swapChainInfo.oldSwapchain = nullptr; - swapChainInfo.clipped = true; - swapChainInfo.imageColorSpace = colorspace; - swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapChainInfo.queueFamilyIndexCount = 0; - swapChainInfo.pQueueFamilyIndices = nullptr; - - Window::SwapChain& sc = windowCtx.m_swapChains[windowCtx.m_activeSwapChain]; - ThrowIfFailed(vk::CreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &sc.m_swapChain)); - sc.m_format = format; - - uint32_t swapchainImageCount; - ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, nullptr)); - - std::unique_ptr swapchainImages(new VkImage[swapchainImageCount]); - ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, swapchainImages.get())); - - /* images */ - sc.m_bufs.resize(swapchainImageCount); - for (uint32_t i=0 ; i lk(m_resizeLock); - m_deferredResizes.emplace(windowCtx, surface, format, colorspace, rect); -} - -bool VulkanContext::_resizeSwapChains() -{ - std::unique_lock lk(m_resizeLock); - if (m_deferredResizes.empty()) - return false; - - while (m_deferredResizes.size()) - { - SwapChainResize& resize = m_deferredResizes.front(); - - VkSurfaceCapabilitiesKHR surfCapabilities; - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], resize.m_surface, &surfCapabilities)); - - uint32_t presentModeCount; - ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, nullptr)); - std::unique_ptr presentModes(new VkPresentModeKHR[presentModeCount]); - - ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, presentModes.get())); - - VkExtent2D swapChainExtent; - // width and height are either both -1, or both not -1. - if (surfCapabilities.currentExtent.width == (uint32_t)-1) - { - // If the surface size is undefined, the size is set to - // the size of the images requested. - swapChainExtent.width = 50; - swapChainExtent.height = 50; - } - else - { - // If the surface size is defined, the swap chain size must match - swapChainExtent = surfCapabilities.currentExtent; - } - - // If mailbox mode is available, use it, as is the lowest-latency non- - // tearing mode. If not, try IMMEDIATE which will usually be available, - // and is fastest (though it tears). If not, fall back to FIFO which is - // always available. - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - for (size_t i=0 ; i 0) && - (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) - { - // Application must settle for fewer images than desired: - desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; - } - - VkSurfaceTransformFlagBitsKHR preTransform; - if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) - preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - else - preTransform = surfCapabilities.currentTransform; - - Window::SwapChain& oldSc = resize.m_windowCtx.m_swapChains[resize.m_windowCtx.m_activeSwapChain]; - - VkSwapchainCreateInfoKHR swapChainInfo = {}; - swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapChainInfo.pNext = nullptr; - swapChainInfo.surface = resize.m_surface; - swapChainInfo.minImageCount = desiredNumberOfSwapChainImages; - swapChainInfo.imageFormat = resize.m_format; - swapChainInfo.imageExtent.width = swapChainExtent.width; - swapChainInfo.imageExtent.height = swapChainExtent.height; - swapChainInfo.preTransform = preTransform; - swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapChainInfo.imageArrayLayers = 1; - swapChainInfo.presentMode = swapchainPresentMode; - swapChainInfo.oldSwapchain = oldSc.m_swapChain; - swapChainInfo.clipped = true; - swapChainInfo.imageColorSpace = resize.m_colorspace; - swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapChainInfo.queueFamilyIndexCount = 0; - swapChainInfo.pQueueFamilyIndices = nullptr; - - resize.m_windowCtx.m_activeSwapChain ^= 1; - Window::SwapChain& sc = resize.m_windowCtx.m_swapChains[resize.m_windowCtx.m_activeSwapChain]; - sc.destroy(m_dev); - ThrowIfFailed(vk::CreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &sc.m_swapChain)); - sc.m_format = resize.m_format; - - uint32_t swapchainImageCount; - ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, nullptr)); - - std::unique_ptr swapchainImages(new VkImage[swapchainImageCount]); - ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, swapchainImages.get())); - - /* images */ - sc.m_bufs.resize(swapchainImageCount); - for (uint32_t i=0 ; i -{ - VkDescriptorPool m_descPool; - int m_allocatedSets = 0; - - VulkanDescriptorPool(VulkanDataFactoryImpl* factory) - : ListNode(factory) - { - VkDescriptorPoolSize poolSizes[2] = {}; - VkDescriptorPoolCreateInfo descriptorPoolInfo = {}; - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = nullptr; - descriptorPoolInfo.maxSets = BOO_VK_MAX_DESCRIPTOR_SETS; - descriptorPoolInfo.poolSizeCount = 2; - descriptorPoolInfo.pPoolSizes = poolSizes; - - poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSizes[0].descriptorCount = BOO_GLSL_MAX_UNIFORM_COUNT * BOO_VK_MAX_DESCRIPTOR_SETS; - - poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSizes[1].descriptorCount = BOO_GLSL_MAX_TEXTURE_COUNT * BOO_VK_MAX_DESCRIPTOR_SETS; - - ThrowIfFailed(vk::CreateDescriptorPool(factory->m_ctx->m_dev, &descriptorPoolInfo, nullptr, &m_descPool)); - } - - ~VulkanDescriptorPool() - { - vk::DestroyDescriptorPool(m_head->m_ctx->m_dev, m_descPool, nullptr); - } - - std::unique_lock destructorLock() override - { return std::unique_lock{m_head->m_dataMutex}; } - static std::unique_lock _getHeadLock(VulkanDataFactoryImpl* factory) - { return std::unique_lock{factory->m_dataMutex}; } - static VulkanDescriptorPool*& _getHeadPtr(VulkanDataFactoryImpl* factory) - { return factory->m_descPoolHead; } -}; - -boo::ObjToken VulkanDataFactoryImpl::allocateDescriptorSets(VkDescriptorSet* out) -{ - std::lock_guard lk(m_dataMutex); - boo::ObjToken pool; - if (!m_descPoolHead || m_descPoolHead->m_allocatedSets == BOO_VK_MAX_DESCRIPTOR_SETS) - pool = new VulkanDescriptorPool(this); - else - pool = m_descPoolHead; - - VkDescriptorSetLayout layouts[] = {m_ctx->m_descSetLayout, m_ctx->m_descSetLayout}; - VkDescriptorSetAllocateInfo descAllocInfo; - descAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descAllocInfo.pNext = nullptr; - descAllocInfo.descriptorPool = pool->m_descPool; - descAllocInfo.descriptorSetCount = 2; - descAllocInfo.pSetLayouts = layouts; - ThrowIfFailed(vk::AllocateDescriptorSets(m_ctx->m_dev, &descAllocInfo, out)); - pool->m_allocatedSets += 2; - - return pool; -} - -struct AllocatedBuffer -{ - VkBuffer m_buffer = VK_NULL_HANDLE; - VmaAllocation m_allocation; - - void* _create(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo, VmaMemoryUsage usage) - { - assert(m_buffer == VK_NULL_HANDLE && "create may only be called once"); - VmaAllocationCreateInfo bufAllocInfo = {}; - bufAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - bufAllocInfo.usage = usage; - - VmaAllocationInfo allocInfo; - ThrowIfFailed(vmaCreateBuffer(ctx->m_allocator, pBufferCreateInfo, &bufAllocInfo, - &m_buffer, &m_allocation, &allocInfo)); - return allocInfo.pMappedData; - } - - void* createCPU(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo) - { - return _create(ctx, pBufferCreateInfo, VMA_MEMORY_USAGE_CPU_ONLY); - } - - void* createCPUtoGPU(VulkanContext* ctx, const VkBufferCreateInfo* pBufferCreateInfo) - { - return _create(ctx, pBufferCreateInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - } - - void destroy(VulkanContext* ctx) - { - if (m_buffer) - { - vmaDestroyBuffer(ctx->m_allocator, m_buffer, m_allocation); - m_buffer = VK_NULL_HANDLE; - } - } -}; - -struct AllocatedImage -{ - VkImage m_image = VK_NULL_HANDLE; - VmaAllocation m_allocation; - - void _create(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInfo, VmaAllocationCreateFlags flags) - { - assert(m_image == VK_NULL_HANDLE && "create may only be called once"); - VmaAllocationCreateInfo bufAllocInfo = {}; - bufAllocInfo.flags = flags; - bufAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - ThrowIfFailed(vmaCreateImage(ctx->m_allocator, pImageCreateInfo, &bufAllocInfo, - &m_image, &m_allocation, nullptr)); - } - - void create(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInf) - { - _create(ctx, pImageCreateInf, 0); - } - - void createFB(VulkanContext* ctx, const VkImageCreateInfo* pImageCreateInf) - { - _create(ctx, pImageCreateInf, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT); - } - - void destroy(VulkanContext* ctx) - { - if (m_image) - { - vmaDestroyImage(ctx->m_allocator, m_image, m_allocation); - m_image = VK_NULL_HANDLE; - } - } -}; - -struct VulkanData : BaseGraphicsData -{ - VulkanContext* m_ctx; - - /* Vertex, Index, Uniform */ - AllocatedBuffer m_constantBuffers[3]; - AllocatedBuffer m_texStagingBuffer; - - explicit VulkanData(VulkanDataFactoryImpl& head __BooTraceArgs) - : BaseGraphicsData(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} - ~VulkanData() - { - for (int i=0 ; i<3 ; ++i) - m_constantBuffers[i].destroy(m_ctx); - m_texStagingBuffer.destroy(m_ctx); - } -}; - -struct VulkanPool : BaseGraphicsPool -{ - VulkanContext* m_ctx; - AllocatedBuffer m_constantBuffer; - - explicit VulkanPool(VulkanDataFactoryImpl& head __BooTraceArgs) - : BaseGraphicsPool(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} - ~VulkanPool() - { - m_constantBuffer.destroy(m_ctx); - } -}; - -static const VkBufferUsageFlagBits USE_TABLE[] = -{ - VkBufferUsageFlagBits(0), - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT -}; - -class VulkanGraphicsBufferS : public GraphicsDataNode -{ - friend class VulkanDataFactory; - friend struct VulkanCommandQueue; - VulkanContext* m_ctx; - size_t m_sz; - std::unique_ptr m_stagingBuf; - VulkanGraphicsBufferS(const boo::ObjToken& parent, BufferUse use, - VulkanContext* ctx, const void* data, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_ctx(ctx), m_sz(stride * count), - m_stagingBuf(new uint8_t[m_sz]), m_use(use) - { - memmove(m_stagingBuf.get(), data, m_sz); - m_bufferInfo.range = m_sz; - } -public: - size_t size() const {return m_sz;} - VkDescriptorBufferInfo m_bufferInfo; - BufferUse m_use; - - VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) - { - m_bufferInfo.offset = offset; - offset += m_sz; - - if (m_use == BufferUse::Uniform) - { - size_t minOffset = std::max(VkDeviceSize(256), - ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); - offset = (offset + minOffset - 1) & ~(minOffset - 1); - } - - return offset; - } - - void placeForGPU(VkBuffer bufObj, uint8_t* buf) - { - m_bufferInfo.buffer = bufObj; - memmove(buf + m_bufferInfo.offset, m_stagingBuf.get(), m_sz); - m_stagingBuf.reset(); - } -}; - -template -class VulkanGraphicsBufferD : public GraphicsDataNode -{ - friend class VulkanDataFactory; - friend class VulkanDataFactoryImpl; - friend struct VulkanCommandQueue; - VulkanContext* m_ctx; - size_t m_cpuSz; - std::unique_ptr m_cpuBuf; - int m_validSlots = 0; - VulkanGraphicsBufferD(const boo::ObjToken& parent, BufferUse use, - VulkanContext* ctx, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_ctx(ctx), m_cpuSz(stride * count), m_cpuBuf(new uint8_t[m_cpuSz]), m_use(use) - { - m_bufferInfo[0].range = m_cpuSz; - m_bufferInfo[1].range = m_cpuSz; - } - void update(int b); + VulkanCommandQueue* m_q; + VulkanTextureR(const boo::ObjToken& parent, VulkanCommandQueue* q, size_t width, size_t height, + TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount); public: - VkDescriptorBufferInfo m_bufferInfo[2]; - uint8_t* m_bufferPtrs[2] = {}; - BufferUse m_use; - void load(const void* data, size_t sz); - void* map(size_t sz); - void unmap(); + AllocatedImage m_colorTex; + VkImageView m_colorView = VK_NULL_HANDLE; - VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) - { - for (int i=0 ; i<2 ; ++i) - { - m_bufferInfo[i].offset = offset; - offset += m_cpuSz; + AllocatedImage m_depthTex; + VkImageView m_depthView = VK_NULL_HANDLE; - if (m_use == BufferUse::Uniform) - { - size_t minOffset = std::max(VkDeviceSize(256), - ctx->m_gpuProps.limits.minUniformBufferOffsetAlignment); - offset = (offset + minOffset - 1) & ~(minOffset - 1); - } - } + AllocatedImage m_colorBindTex[MAX_BIND_TEXS] = {}; + VkImageView m_colorBindView[MAX_BIND_TEXS] = {}; + VkDescriptorImageInfo m_colorBindDescInfo[MAX_BIND_TEXS] = {}; - return offset; + AllocatedImage m_depthBindTex[MAX_BIND_TEXS] = {}; + VkImageView m_depthBindView[MAX_BIND_TEXS] = {}; + VkDescriptorImageInfo m_depthBindDescInfo[MAX_BIND_TEXS] = {}; + + VkFramebuffer m_framebuffer = VK_NULL_HANDLE; + VkRenderPassBeginInfo m_passBeginInfo = {}; + + VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageLayout m_colorBindLayout[MAX_BIND_TEXS] = {}; + VkImageLayout m_depthBindLayout[MAX_BIND_TEXS] = {}; + + VkSampler m_sampler = VK_NULL_HANDLE; + + void setClampMode(TextureClampMode mode); + void doDestroy(); + ~VulkanTextureR(); + + void resize(VulkanContext* ctx, size_t width, size_t height) { + if (width < 1) + width = 1; + if (height < 1) + height = 1; + m_width = width; + m_height = height; + Setup(ctx); + } + + void initializeBindLayouts(VulkanContext* ctx) { + for (size_t i = 0; i < m_colorBindCount; ++i) { + SetImageLayout(ctx->m_loadCmdBuf, m_colorBindTex[i].m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + m_colorBindLayout[i] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } - void placeForGPU(VkBuffer bufObj, uint8_t* buf) - { - m_bufferInfo[0].buffer = bufObj; - m_bufferInfo[1].buffer = bufObj; - m_bufferPtrs[0] = buf + m_bufferInfo[0].offset; - m_bufferPtrs[1] = buf + m_bufferInfo[1].offset; + for (size_t i = 0; i < m_depthBindCount; ++i) { + SetImageLayout(ctx->m_loadCmdBuf, m_depthBindTex[i].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + m_depthBindLayout[i] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } + } }; -static void MakeSampler(VulkanContext* ctx, VkSampler& sampOut, TextureClampMode mode, int mips) -{ - uint32_t key = (uint32_t(mode) << 16) | mips; - auto search = ctx->m_samplers.find(key); - if (search != ctx->m_samplers.end()) - { - sampOut = search->second; - return; +static const size_t SEMANTIC_SIZE_TABLE[] = {0, 12, 16, 12, 16, 16, 4, 8, 16, 16, 16}; + +static const VkFormat SEMANTIC_TYPE_TABLE[] = { + VK_FORMAT_UNDEFINED, VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT}; + +struct VulkanVertexFormat { + VkVertexInputBindingDescription m_bindings[2]; + std::unique_ptr m_attributes; + VkPipelineVertexInputStateCreateInfo m_info; + size_t m_stride = 0; + size_t m_instStride = 0; + + VulkanVertexFormat(const VertexFormatInfo& info) + : m_attributes(new VkVertexInputAttributeDescription[info.elementCount]) { + m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + m_info.pNext = nullptr; + m_info.flags = 0; + m_info.vertexBindingDescriptionCount = 0; + m_info.pVertexBindingDescriptions = m_bindings; + m_info.vertexAttributeDescriptionCount = info.elementCount; + m_info.pVertexAttributeDescriptions = m_attributes.get(); + + for (size_t i = 0; i < info.elementCount; ++i) { + const VertexElementDescriptor* elemin = &info.elements[i]; + VkVertexInputAttributeDescription& attribute = m_attributes[i]; + int semantic = int(elemin->semantic & boo::VertexSemantic::SemanticMask); + attribute.location = i; + attribute.format = SEMANTIC_TYPE_TABLE[semantic]; + if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) { + attribute.binding = 1; + attribute.offset = m_instStride; + m_instStride += SEMANTIC_SIZE_TABLE[semantic]; + } else { + attribute.binding = 0; + attribute.offset = m_stride; + m_stride += SEMANTIC_SIZE_TABLE[semantic]; + } } - /* Create linear sampler */ - VkSamplerCreateInfo samplerInfo = {}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.pNext = nullptr; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.anisotropyEnable = ctx->m_features.samplerAnisotropy; - samplerInfo.maxAnisotropy = ctx->m_anisotropy; - samplerInfo.maxLod = mips - 1; - switch (mode) - { - case TextureClampMode::Repeat: - default: - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - case TextureClampMode::ClampToWhite: - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - break; - case TextureClampMode::ClampToBlack: - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - break; - case TextureClampMode::ClampToEdge: - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - case TextureClampMode::ClampToEdgeNearest: - samplerInfo.magFilter = VK_FILTER_NEAREST; - samplerInfo.minFilter = VK_FILTER_NEAREST; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - samplerInfo.anisotropyEnable = VK_FALSE; - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; + if (m_stride) { + m_bindings[0].binding = 0; + m_bindings[0].stride = m_stride; + m_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + ++m_info.vertexBindingDescriptionCount; } - ThrowIfFailed(vk::CreateSampler(ctx->m_dev, &samplerInfo, nullptr, &sampOut)); - ctx->m_samplers[key] = sampOut; -} - -class VulkanTextureS : public GraphicsDataNode -{ - friend class VulkanDataFactory; - VulkanContext* m_ctx; - TextureFormat m_fmt; - size_t m_sz; - size_t m_width, m_height, m_mips; - TextureClampMode m_clampMode; - VkFormat m_vkFmt; - int m_pixelPitchNum = 1; - int m_pixelPitchDenom = 1; - - VulkanTextureS(const boo::ObjToken& parent, VulkanContext* ctx, - size_t width, size_t height, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) - : GraphicsDataNode(parent), m_ctx(ctx), m_fmt(fmt), m_sz(sz), - m_width(width), m_height(height), m_mips(mips), m_clampMode(clampMode) - { - VkFormat pfmt; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = VK_FORMAT_R8G8B8A8_UNORM; - m_pixelPitchNum = 4; - break; - case TextureFormat::I8: - pfmt = VK_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pfmt = VK_FORMAT_R16_UNORM; - m_pixelPitchNum = 2; - break; - case TextureFormat::DXT1: - pfmt = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; - m_pixelPitchNum = 1; - m_pixelPitchDenom = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_vkFmt = pfmt; - - /* create cpu image buffer */ - VkBufferCreateInfo bufCreateInfo = {}; - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = sz; - bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - void* mappedData = m_cpuBuf.createCPU(ctx, &bufCreateInfo); - memmove(mappedData, data, sz); + if (m_instStride) { + m_bindings[m_info.vertexBindingDescriptionCount].binding = 1; + m_bindings[m_info.vertexBindingDescriptionCount].stride = m_instStride; + m_bindings[m_info.vertexBindingDescriptionCount].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + ++m_info.vertexBindingDescriptionCount; } + } +}; + +static const VkPrimitiveTopology PRIMITIVE_TABLE[] = { + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST}; + +static const VkBlendFactor BLEND_FACTOR_TABLE[] = {VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VK_BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR}; + +class VulkanShaderStage : public GraphicsDataNode { + friend class VulkanDataFactory; + VulkanContext* m_ctx; + VkShaderModule m_module; + VulkanShaderStage(const boo::ObjToken& parent, VulkanContext* ctx, const uint8_t* data, size_t size, + PipelineStage stage) + : GraphicsDataNode(parent), m_ctx(ctx) { + VkShaderModuleCreateInfo smCreateInfo = {}; + smCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + smCreateInfo.pNext = nullptr; + smCreateInfo.flags = 0; + + smCreateInfo.codeSize = size; + smCreateInfo.pCode = (uint32_t*)data; + ThrowIfFailed(vk::CreateShaderModule(m_ctx->m_dev, &smCreateInfo, nullptr, &m_module)); + } + public: - AllocatedBuffer m_cpuBuf; - AllocatedImage m_gpuTex; - VkImageView m_gpuView = VK_NULL_HANDLE; - VkSampler m_sampler = VK_NULL_HANDLE; - VkDescriptorImageInfo m_descInfo; - ~VulkanTextureS() - { - vk::DestroyImageView(m_ctx->m_dev, m_gpuView, nullptr); - m_gpuTex.destroy(m_ctx); - m_cpuBuf.destroy(m_ctx); - } - - void _setClampMode(TextureClampMode mode) - { - MakeSampler(m_ctx, m_sampler, mode, m_mips); - m_descInfo.sampler = m_sampler; - } - - void setClampMode(TextureClampMode mode) - { - if (m_clampMode == mode) - return; - m_clampMode = mode; - _setClampMode(mode); - } - - void deleteUploadObjects() - { - m_cpuBuf.destroy(m_ctx); - } - - void placeForGPU(VulkanContext* ctx) - { - /* create gpu image */ - VkImageCreateInfo texCreateInfo = {}; - texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - texCreateInfo.imageType = VK_IMAGE_TYPE_2D; - texCreateInfo.format = m_vkFmt; - texCreateInfo.mipLevels = m_mips; - texCreateInfo.arrayLayers = 1; - texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - texCreateInfo.extent = { uint32_t(m_width), uint32_t(m_height), 1 }; - texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - m_gpuTex.create(m_ctx, &texCreateInfo); - - _setClampMode(m_clampMode); - m_descInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - /* create image view */ - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.pNext = nullptr; - viewInfo.image = m_gpuTex.m_image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = m_vkFmt; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = m_mips; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView)); - m_descInfo.imageView = m_gpuView; - - /* Since we're going to blit to the texture image, set its layout to - * DESTINATION_OPTIMAL */ - SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_mips, 1); - - VkBufferImageCopy copyRegions[16] = {}; - size_t width = m_width; - size_t height = m_height; - size_t regionCount = std::min(size_t(16), m_mips); - size_t offset = 0; - for (int i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - offset += regionPitch; - } - - /* Put the copy command into the command buffer */ - vk::CmdCopyBufferToImage(ctx->m_loadCmdBuf, - m_cpuBuf.m_buffer, - m_gpuTex.m_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - regionCount, - copyRegions); - - /* Set the layout for the texture image from DESTINATION_OPTIMAL to - * SHADER_READ_ONLY */ - SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mips, 1); - } - - TextureFormat format() const {return m_fmt;} + ~VulkanShaderStage() { vk::DestroyShaderModule(m_ctx->m_dev, m_module, nullptr); } + VkShaderModule shader() const { return m_module; } }; -class VulkanTextureSA : public GraphicsDataNode -{ - friend class VulkanDataFactory; - VulkanContext* m_ctx; - TextureFormat m_fmt; - size_t m_sz; - size_t m_width, m_height, m_layers, m_mips; - TextureClampMode m_clampMode = TextureClampMode::Invalid; - VkFormat m_vkFmt; - int m_pixelPitchNum = 1; - int m_pixelPitchDenom = 1; - - VulkanTextureSA(const boo::ObjToken& parent, VulkanContext* ctx, - size_t width, size_t height, size_t layers, - size_t mips, TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) - : GraphicsDataNode(parent), - m_ctx(ctx), m_fmt(fmt), m_sz(sz), m_width(width), m_height(height), - m_layers(layers), m_mips(mips), m_clampMode(clampMode) - { - VkFormat pfmt; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = VK_FORMAT_R8G8B8A8_UNORM; - m_pixelPitchNum = 4; - break; - case TextureFormat::I8: - pfmt = VK_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pfmt = VK_FORMAT_R16_UNORM; - m_pixelPitchNum = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_vkFmt = pfmt; - - /* create cpu image buffer */ - VkBufferCreateInfo bufCreateInfo = {}; - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = sz; - bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - void* mappedData = m_cpuBuf.createCPU(ctx, &bufCreateInfo); - memmove(mappedData, data, sz); - } -public: - AllocatedBuffer m_cpuBuf; - AllocatedImage m_gpuTex; - VkImageView m_gpuView = VK_NULL_HANDLE; - VkSampler m_sampler = VK_NULL_HANDLE; - VkDescriptorImageInfo m_descInfo; - ~VulkanTextureSA() - { - vk::DestroyImageView(m_ctx->m_dev, m_gpuView, nullptr); - m_gpuTex.destroy(m_ctx); - m_cpuBuf.destroy(m_ctx); - } - - void _setClampMode(TextureClampMode mode) - { - MakeSampler(m_ctx, m_sampler, mode, m_mips); - m_descInfo.sampler = m_sampler; - } - - void setClampMode(TextureClampMode mode) - { - if (m_clampMode == mode) - return; - m_clampMode = mode; - _setClampMode(mode); - } - - void deleteUploadObjects() - { - m_cpuBuf.destroy(m_ctx); - } - - void placeForGPU(VulkanContext* ctx) - { - /* create gpu image */ - VkImageCreateInfo texCreateInfo = {}; - texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - texCreateInfo.imageType = VK_IMAGE_TYPE_2D; - texCreateInfo.format = m_vkFmt; - texCreateInfo.mipLevels = m_mips; - texCreateInfo.arrayLayers = m_layers; - texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - texCreateInfo.extent = { uint32_t(m_width), uint32_t(m_height), 1 }; - texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - m_gpuTex.create(m_ctx, &texCreateInfo); - - _setClampMode(m_clampMode); - m_descInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - /* create image view */ - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.pNext = nullptr; - viewInfo.image = m_gpuTex.m_image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - viewInfo.format = m_vkFmt; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = m_mips; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = m_layers; - - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView)); - m_descInfo.imageView = m_gpuView; - - /* Since we're going to blit to the texture image, set its layout to - * DESTINATION_OPTIMAL */ - SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_mips, m_layers); - - VkBufferImageCopy copyRegions[16] = {}; - size_t width = m_width; - size_t height = m_height; - size_t regionCount = std::min(size_t(16), m_mips); - size_t offset = 0; - for (int i=0 ; i 1) - width /= 2; - if (height > 1) - height /= 2; - offset += regionPitch; - } - - /* Put the copy command into the command buffer */ - vk::CmdCopyBufferToImage(ctx->m_loadCmdBuf, - m_cpuBuf.m_buffer, - m_gpuTex.m_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - regionCount, - copyRegions); - - /* Set the layout for the texture image from DESTINATION_OPTIMAL to - * SHADER_READ_ONLY */ - SetImageLayout(ctx->m_loadCmdBuf, m_gpuTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, m_mips, m_layers); - } - - TextureFormat format() const {return m_fmt;} - size_t layers() const {return m_layers;} -}; - -class VulkanTextureD : public GraphicsDataNode -{ - friend class VulkanDataFactory; - friend struct VulkanCommandQueue; - size_t m_width; - size_t m_height; - TextureFormat m_fmt; - TextureClampMode m_clampMode; - VulkanCommandQueue* m_q; - std::unique_ptr m_stagingBuf; - size_t m_cpuSz; - VkDeviceSize m_cpuOffsets[2]; - VkFormat m_vkFmt; - int m_validSlots = 0; - VulkanTextureD(const boo::ObjToken& parent, VulkanCommandQueue* q, - size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode) - : GraphicsDataNode(parent), m_width(width), m_height(height), m_fmt(fmt), m_clampMode(clampMode), m_q(q) - { - VkFormat pfmt; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = VK_FORMAT_R8G8B8A8_UNORM; - m_cpuSz = width * height * 4; - break; - case TextureFormat::I8: - pfmt = VK_FORMAT_R8_UNORM; - m_cpuSz = width * height; - break; - case TextureFormat::I16: - pfmt = VK_FORMAT_R16_UNORM; - m_cpuSz = width * height * 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_vkFmt = pfmt; - m_stagingBuf.reset(new uint8_t[m_cpuSz]); - } - void update(int b); -public: - VkBuffer m_cpuBuf = VK_NULL_HANDLE; /* Owned externally */ - uint8_t* m_cpuBufPtrs[2] = {}; - AllocatedImage m_gpuTex[2]; - VkImageView m_gpuView[2]; - VkSampler m_sampler = VK_NULL_HANDLE; - VkDescriptorImageInfo m_descInfo[2]; - ~VulkanTextureD(); - - void _setClampMode(TextureClampMode mode); - void setClampMode(TextureClampMode mode); - void load(const void* data, size_t sz); - void* map(size_t sz); - void unmap(); - - VkDeviceSize sizeForGPU(VulkanContext* ctx, VkDeviceSize offset) - { - for (int i=0 ; i<2 ; ++i) - { - m_cpuOffsets[i] = offset; - offset += m_cpuSz; - } - - return offset; - } - - void placeForGPU(VulkanContext* ctx, VkBuffer bufObj, uint8_t* buf) - { - m_cpuBuf = bufObj; - m_cpuBufPtrs[0] = buf + m_cpuOffsets[0]; - m_cpuBufPtrs[1] = buf + m_cpuOffsets[1]; - - /* Create images */ - VkImageCreateInfo texCreateInfo = {}; - texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - texCreateInfo.pNext = nullptr; - texCreateInfo.imageType = VK_IMAGE_TYPE_2D; - texCreateInfo.format = m_vkFmt; - texCreateInfo.extent.width = m_width; - texCreateInfo.extent.height = m_height; - texCreateInfo.extent.depth = 1; - texCreateInfo.mipLevels = 1; - texCreateInfo.arrayLayers = 1; - texCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - texCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - texCreateInfo.queueFamilyIndexCount = 0; - texCreateInfo.pQueueFamilyIndices = nullptr; - texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - texCreateInfo.flags = 0; - - _setClampMode(m_clampMode); - for (int i=0 ; i<2 ; ++i) - { - /* create gpu image */ - m_gpuTex[i].create(ctx, &texCreateInfo); - m_descInfo[i].sampler = m_sampler; - m_descInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.pNext = nullptr; - viewInfo.image = nullptr; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = m_vkFmt; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_R; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_G; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_B; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - for (int i=0 ; i<2 ; ++i) - { - /* create image view */ - viewInfo.image = m_gpuTex[i].m_image; - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewInfo, nullptr, &m_gpuView[i])); - - m_descInfo[i].imageView = m_gpuView[i]; - } - } - - TextureFormat format() const {return m_fmt;} -}; - -#define MAX_BIND_TEXS 4 - -class VulkanTextureR : public GraphicsDataNode -{ - friend class VulkanDataFactory; - friend struct VulkanCommandQueue; - size_t m_width = 0; - size_t m_height = 0; - VkSampleCountFlags m_samplesColor, m_samplesDepth; - - size_t m_colorBindCount; - size_t m_depthBindCount; - - void Setup(VulkanContext* ctx) - { - /* no-ops on first call */ - doDestroy(); - m_layout = VK_IMAGE_LAYOUT_UNDEFINED; - - /* color target */ - VkImageCreateInfo texCreateInfo = {}; - texCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - texCreateInfo.pNext = nullptr; - texCreateInfo.imageType = VK_IMAGE_TYPE_2D; - texCreateInfo.format = ctx->m_internalFormat; - texCreateInfo.extent.width = m_width; - texCreateInfo.extent.height = m_height; - texCreateInfo.extent.depth = 1; - texCreateInfo.mipLevels = 1; - texCreateInfo.arrayLayers = 1; - texCreateInfo.samples = VkSampleCountFlagBits(m_samplesColor); - texCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - texCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - texCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - texCreateInfo.queueFamilyIndexCount = 0; - texCreateInfo.pQueueFamilyIndices = nullptr; - texCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - texCreateInfo.flags = 0; - m_colorTex.createFB(ctx, &texCreateInfo); - - /* depth target */ - texCreateInfo.samples = VkSampleCountFlagBits(m_samplesDepth); - texCreateInfo.format = VK_FORMAT_D32_SFLOAT; - texCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - m_depthTex.createFB(ctx, &texCreateInfo); - - texCreateInfo.samples = VkSampleCountFlagBits(1); - - for (size_t i=0 ; im_internalFormat; - texCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - m_colorBindTex[i].createFB(ctx, &texCreateInfo); - - m_colorBindDescInfo[i].sampler = m_sampler; - m_colorBindDescInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - for (size_t i=0 ; im_internalFormat; - viewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; - viewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; - viewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; - viewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; - viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewCreateInfo.subresourceRange.baseMipLevel = 0; - viewCreateInfo.subresourceRange.levelCount = 1; - viewCreateInfo.subresourceRange.baseArrayLayer = 0; - viewCreateInfo.subresourceRange.layerCount = 1; - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_colorView)); - - viewCreateInfo.image = m_depthTex.m_image; - viewCreateInfo.format = VK_FORMAT_D32_SFLOAT; - viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_depthView)); - - for (size_t i=0 ; im_internalFormat; - viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - ThrowIfFailed(vk::CreateImageView(ctx->m_dev, &viewCreateInfo, nullptr, &m_colorBindView[i])); - m_colorBindDescInfo[i].imageView = m_colorBindView[i]; - } - - for (size_t i=0 ; im_dev, &viewCreateInfo, nullptr, &m_depthBindView[i])); - m_depthBindDescInfo[i].imageView = m_depthBindView[i]; - } - - /* framebuffer */ - VkFramebufferCreateInfo fbCreateInfo = {}; - fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.pNext = nullptr; - fbCreateInfo.renderPass = ctx->m_pass; - fbCreateInfo.attachmentCount = 2; - fbCreateInfo.width = m_width; - fbCreateInfo.height = m_height; - fbCreateInfo.layers = 1; - VkImageView attachments[2] = {m_colorView, m_depthView}; - fbCreateInfo.pAttachments = attachments; - ThrowIfFailed(vk::CreateFramebuffer(ctx->m_dev, &fbCreateInfo, nullptr, &m_framebuffer)); - - m_passBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - m_passBeginInfo.pNext = nullptr; - m_passBeginInfo.renderPass = ctx->m_pass; - m_passBeginInfo.framebuffer = m_framebuffer; - m_passBeginInfo.renderArea.offset.x = 0; - m_passBeginInfo.renderArea.offset.y = 0; - m_passBeginInfo.renderArea.extent.width = m_width; - m_passBeginInfo.renderArea.extent.height = m_height; - m_passBeginInfo.clearValueCount = 0; - m_passBeginInfo.pClearValues = nullptr; - } - - VulkanCommandQueue* m_q; - VulkanTextureR(const boo::ObjToken& parent, VulkanCommandQueue* q, - size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount); -public: - AllocatedImage m_colorTex; - VkImageView m_colorView = VK_NULL_HANDLE; - - AllocatedImage m_depthTex; - VkImageView m_depthView = VK_NULL_HANDLE; - - AllocatedImage m_colorBindTex[MAX_BIND_TEXS] = {}; - VkImageView m_colorBindView[MAX_BIND_TEXS] = {}; - VkDescriptorImageInfo m_colorBindDescInfo[MAX_BIND_TEXS] = {}; - - AllocatedImage m_depthBindTex[MAX_BIND_TEXS] = {}; - VkImageView m_depthBindView[MAX_BIND_TEXS] = {}; - VkDescriptorImageInfo m_depthBindDescInfo[MAX_BIND_TEXS] = {}; - - VkFramebuffer m_framebuffer = VK_NULL_HANDLE; - VkRenderPassBeginInfo m_passBeginInfo = {}; - - VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkImageLayout m_colorBindLayout[MAX_BIND_TEXS] = {}; - VkImageLayout m_depthBindLayout[MAX_BIND_TEXS] = {}; - - VkSampler m_sampler = VK_NULL_HANDLE; - - void setClampMode(TextureClampMode mode); - void doDestroy(); - ~VulkanTextureR(); - - void resize(VulkanContext* ctx, size_t width, size_t height) - { - if (width < 1) - width = 1; - if (height < 1) - height = 1; - m_width = width; - m_height = height; - Setup(ctx); - } - - void initializeBindLayouts(VulkanContext* ctx) - { - for (size_t i=0 ; im_loadCmdBuf, m_colorBindTex[i].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - m_colorBindLayout[i] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - - for (size_t i=0 ; im_loadCmdBuf, m_depthBindTex[i].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - m_depthBindLayout[i] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - } -}; - -static const size_t SEMANTIC_SIZE_TABLE[] = -{ - 0, - 12, - 16, - 12, - 16, - 16, - 4, - 8, - 16, - 16, - 16 -}; - -static const VkFormat SEMANTIC_TYPE_TABLE[] = -{ - VK_FORMAT_UNDEFINED, - VK_FORMAT_R32G32B32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R32G32B32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R8G8B8A8_UNORM, - VK_FORMAT_R32G32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT, - VK_FORMAT_R32G32B32A32_SFLOAT -}; - -struct VulkanVertexFormat -{ - VkVertexInputBindingDescription m_bindings[2]; - std::unique_ptr m_attributes; - VkPipelineVertexInputStateCreateInfo m_info; - size_t m_stride = 0; - size_t m_instStride = 0; - - VulkanVertexFormat(const VertexFormatInfo& info) - : m_attributes(new VkVertexInputAttributeDescription[info.elementCount]) - { - m_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - m_info.pNext = nullptr; - m_info.flags = 0; - m_info.vertexBindingDescriptionCount = 0; - m_info.pVertexBindingDescriptions = m_bindings; - m_info.vertexAttributeDescriptionCount = info.elementCount; - m_info.pVertexAttributeDescriptions = m_attributes.get(); - - for (size_t i=0 ; isemantic & boo::VertexSemantic::SemanticMask); - attribute.location = i; - attribute.format = SEMANTIC_TYPE_TABLE[semantic]; - if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) - { - attribute.binding = 1; - attribute.offset = m_instStride; - m_instStride += SEMANTIC_SIZE_TABLE[semantic]; - } - else - { - attribute.binding = 0; - attribute.offset = m_stride; - m_stride += SEMANTIC_SIZE_TABLE[semantic]; - } - } - - if (m_stride) - { - m_bindings[0].binding = 0; - m_bindings[0].stride = m_stride; - m_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - ++m_info.vertexBindingDescriptionCount; - } - if (m_instStride) - { - m_bindings[m_info.vertexBindingDescriptionCount].binding = 1; - m_bindings[m_info.vertexBindingDescriptionCount].stride = m_instStride; - m_bindings[m_info.vertexBindingDescriptionCount].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - ++m_info.vertexBindingDescriptionCount; - } - } -}; - -static const VkPrimitiveTopology PRIMITIVE_TABLE[] = -{ - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST -}; - -static const VkBlendFactor BLEND_FACTOR_TABLE[] = -{ - VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_SRC_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - VK_BLEND_FACTOR_DST_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_FACTOR_DST_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, - VK_BLEND_FACTOR_SRC1_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR -}; - -class VulkanShaderStage : public GraphicsDataNode -{ - friend class VulkanDataFactory; - VulkanContext* m_ctx; - VkShaderModule m_module; - VulkanShaderStage(const boo::ObjToken& parent, VulkanContext* ctx, - const uint8_t* data, size_t size, PipelineStage stage) - : GraphicsDataNode(parent), m_ctx(ctx) - { - VkShaderModuleCreateInfo smCreateInfo = {}; - smCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - smCreateInfo.pNext = nullptr; - smCreateInfo.flags = 0; - - smCreateInfo.codeSize = size; - smCreateInfo.pCode = (uint32_t*)data; - ThrowIfFailed(vk::CreateShaderModule(m_ctx->m_dev, &smCreateInfo, nullptr, &m_module)); - } -public: - ~VulkanShaderStage() - { - vk::DestroyShaderModule(m_ctx->m_dev, m_module, nullptr); - } - VkShaderModule shader() const { return m_module; } -}; - -class VulkanShaderPipeline : public GraphicsDataNode -{ +class VulkanShaderPipeline : public GraphicsDataNode { protected: - friend class VulkanDataFactory; - friend struct VulkanShaderDataBinding; - VulkanContext* m_ctx; - VkPipelineCache m_pipelineCache; - mutable VulkanVertexFormat m_vtxFmt; - mutable ObjToken m_vertex; - mutable ObjToken m_fragment; - mutable ObjToken m_geometry; - mutable ObjToken m_control; - mutable ObjToken m_evaluation; - BlendFactor m_srcFac; - BlendFactor m_dstFac; - Primitive m_prim; - ZTest m_depthTest; - bool m_depthWrite; - bool m_colorWrite; - bool m_alphaWrite; - bool m_overwriteAlpha; - CullMode m_culling; - uint32_t m_patchSize; - mutable VkPipeline m_pipeline = VK_NULL_HANDLE; + friend class VulkanDataFactory; + friend struct VulkanShaderDataBinding; + VulkanContext* m_ctx; + VkPipelineCache m_pipelineCache; + mutable VulkanVertexFormat m_vtxFmt; + mutable ObjToken m_vertex; + mutable ObjToken m_fragment; + mutable ObjToken m_geometry; + mutable ObjToken m_control; + mutable ObjToken m_evaluation; + BlendFactor m_srcFac; + BlendFactor m_dstFac; + Primitive m_prim; + ZTest m_depthTest; + bool m_depthWrite; + bool m_colorWrite; + bool m_alphaWrite; + bool m_overwriteAlpha; + CullMode m_culling; + uint32_t m_patchSize; + mutable VkPipeline m_pipeline = VK_NULL_HANDLE; + + VulkanShaderPipeline(const boo::ObjToken& parent, VulkanContext* ctx, ObjToken vertex, + ObjToken fragment, ObjToken geometry, ObjToken control, + ObjToken evaluation, VkPipelineCache pipelineCache, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_pipelineCache(pipelineCache) + , m_vtxFmt(vtxFmt) + , m_vertex(vertex) + , m_fragment(fragment) + , m_geometry(geometry) + , m_control(control) + , m_evaluation(evaluation) + , m_srcFac(info.srcFac) + , m_dstFac(info.dstFac) + , m_prim(info.prim) + , m_depthTest(info.depthTest) + , m_depthWrite(info.depthWrite) + , m_colorWrite(info.colorWrite) + , m_alphaWrite(info.alphaWrite) + , m_overwriteAlpha(info.overwriteAlpha) + , m_culling(info.culling) + , m_patchSize(info.patchSize) { + if (control && evaluation) + m_prim = Primitive::Patches; + } - VulkanShaderPipeline(const boo::ObjToken& parent, - VulkanContext* ctx, - ObjToken vertex, - ObjToken fragment, - ObjToken geometry, - ObjToken control, - ObjToken evaluation, - VkPipelineCache pipelineCache, - const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& info) - : GraphicsDataNode(parent), - m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt), - m_vertex(vertex), m_fragment(fragment), m_geometry(geometry), m_control(control), m_evaluation(evaluation), - m_srcFac(info.srcFac), m_dstFac(info.dstFac), m_prim(info.prim), - m_depthTest(info.depthTest), m_depthWrite(info.depthWrite), - m_colorWrite(info.colorWrite), m_alphaWrite(info.alphaWrite), - m_overwriteAlpha(info.overwriteAlpha), m_culling(info.culling), - m_patchSize(info.patchSize) - { - if (control && evaluation) - m_prim = Primitive::Patches; - } public: - ~VulkanShaderPipeline() - { - if (m_pipeline) - vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr); - if (m_pipelineCache) - vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr); - } - VulkanShaderPipeline& operator=(const VulkanShaderPipeline&) = delete; - VulkanShaderPipeline(const VulkanShaderPipeline&) = delete; - VkPipeline bind(VkRenderPass rPass = 0) const - { - if (!m_pipeline) - { - if (!rPass) - rPass = m_ctx->m_pass; + ~VulkanShaderPipeline() { + if (m_pipeline) + vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr); + if (m_pipelineCache) + vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr); + } + VulkanShaderPipeline& operator=(const VulkanShaderPipeline&) = delete; + VulkanShaderPipeline(const VulkanShaderPipeline&) = delete; + VkPipeline bind(VkRenderPass rPass = 0) const { + if (!m_pipeline) { + if (!rPass) + rPass = m_ctx->m_pass; - VkCullModeFlagBits cullMode; - switch (m_culling) - { - case CullMode::None: - default: - cullMode = VK_CULL_MODE_NONE; - break; - case CullMode::Backface: - cullMode = VK_CULL_MODE_BACK_BIT; - break; - case CullMode::Frontface: - cullMode = VK_CULL_MODE_FRONT_BIT; - break; - } + VkCullModeFlagBits cullMode; + switch (m_culling) { + case CullMode::None: + default: + cullMode = VK_CULL_MODE_NONE; + break; + case CullMode::Backface: + cullMode = VK_CULL_MODE_BACK_BIT; + break; + case CullMode::Frontface: + cullMode = VK_CULL_MODE_FRONT_BIT; + break; + } - VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {}; - VkPipelineDynamicStateCreateInfo dynamicState = {}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicState.pNext = nullptr; - dynamicState.pDynamicStates = dynamicStateEnables; - dynamicState.dynamicStateCount = 0; + VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {}; + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.pNext = nullptr; + dynamicState.pDynamicStates = dynamicStateEnables; + dynamicState.dynamicStateCount = 0; - VkPipelineShaderStageCreateInfo stages[5] = {}; - uint32_t numStages = 0; + VkPipelineShaderStageCreateInfo stages[5] = {}; + uint32_t numStages = 0; - if (m_vertex) - { - stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[numStages].pNext = nullptr; - stages[numStages].flags = 0; - stages[numStages].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[numStages].module = m_vertex.cast()->shader(); - stages[numStages].pName = "main"; - stages[numStages++].pSpecializationInfo = nullptr; - } + if (m_vertex) { + stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[numStages].pNext = nullptr; + stages[numStages].flags = 0; + stages[numStages].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[numStages].module = m_vertex.cast()->shader(); + stages[numStages].pName = "main"; + stages[numStages++].pSpecializationInfo = nullptr; + } - if (m_fragment) - { - stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[numStages].pNext = nullptr; - stages[numStages].flags = 0; - stages[numStages].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stages[numStages].module = m_fragment.cast()->shader(); - stages[numStages].pName = "main"; - stages[numStages++].pSpecializationInfo = nullptr; - } + if (m_fragment) { + stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[numStages].pNext = nullptr; + stages[numStages].flags = 0; + stages[numStages].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[numStages].module = m_fragment.cast()->shader(); + stages[numStages].pName = "main"; + stages[numStages++].pSpecializationInfo = nullptr; + } - if (m_geometry) - { - stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[numStages].pNext = nullptr; - stages[numStages].flags = 0; - stages[numStages].stage = VK_SHADER_STAGE_GEOMETRY_BIT; - stages[numStages].module = m_geometry.cast()->shader(); - stages[numStages].pName = "main"; - stages[numStages++].pSpecializationInfo = nullptr; - } + if (m_geometry) { + stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[numStages].pNext = nullptr; + stages[numStages].flags = 0; + stages[numStages].stage = VK_SHADER_STAGE_GEOMETRY_BIT; + stages[numStages].module = m_geometry.cast()->shader(); + stages[numStages].pName = "main"; + stages[numStages++].pSpecializationInfo = nullptr; + } - if (m_control) - { - stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[numStages].pNext = nullptr; - stages[numStages].flags = 0; - stages[numStages].stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - stages[numStages].module = m_control.cast()->shader(); - stages[numStages].pName = "main"; - stages[numStages++].pSpecializationInfo = nullptr; - } + if (m_control) { + stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[numStages].pNext = nullptr; + stages[numStages].flags = 0; + stages[numStages].stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + stages[numStages].module = m_control.cast()->shader(); + stages[numStages].pName = "main"; + stages[numStages++].pSpecializationInfo = nullptr; + } - if (m_evaluation) - { - stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stages[numStages].pNext = nullptr; - stages[numStages].flags = 0; - stages[numStages].stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - stages[numStages].module = m_evaluation.cast()->shader(); - stages[numStages].pName = "main"; - stages[numStages++].pSpecializationInfo = nullptr; - } + if (m_evaluation) { + stages[numStages].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[numStages].pNext = nullptr; + stages[numStages].flags = 0; + stages[numStages].stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + stages[numStages].module = m_evaluation.cast()->shader(); + stages[numStages].pName = "main"; + stages[numStages++].pSpecializationInfo = nullptr; + } - VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {}; - assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - assemblyInfo.pNext = nullptr; - assemblyInfo.flags = 0; - assemblyInfo.topology = PRIMITIVE_TABLE[int(m_prim)]; - assemblyInfo.primitiveRestartEnable = VK_TRUE; + VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {}; + assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + assemblyInfo.pNext = nullptr; + assemblyInfo.flags = 0; + assemblyInfo.topology = PRIMITIVE_TABLE[int(m_prim)]; + assemblyInfo.primitiveRestartEnable = VK_TRUE; - VkPipelineTessellationStateCreateInfo tessInfo = {}; - tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - tessInfo.pNext = nullptr; - tessInfo.flags = 0; - tessInfo.patchControlPoints = m_patchSize; + VkPipelineTessellationStateCreateInfo tessInfo = {}; + tessInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tessInfo.pNext = nullptr; + tessInfo.flags = 0; + tessInfo.patchControlPoints = m_patchSize; - VkPipelineViewportStateCreateInfo viewportInfo = {}; - viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportInfo.pNext = nullptr; - viewportInfo.flags = 0; - viewportInfo.viewportCount = 1; - viewportInfo.pViewports = nullptr; - viewportInfo.scissorCount = 1; - viewportInfo.pScissors = nullptr; - dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; - dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; + VkPipelineViewportStateCreateInfo viewportInfo = {}; + viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportInfo.pNext = nullptr; + viewportInfo.flags = 0; + viewportInfo.viewportCount = 1; + viewportInfo.pViewports = nullptr; + viewportInfo.scissorCount = 1; + viewportInfo.pScissors = nullptr; + dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; + dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; #if AMD_PAL_HACK - dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; + dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; #endif - VkPipelineRasterizationStateCreateInfo rasterizationInfo = {}; - rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationInfo.pNext = nullptr; - rasterizationInfo.flags = 0; - rasterizationInfo.depthClampEnable = VK_FALSE; - rasterizationInfo.rasterizerDiscardEnable = VK_FALSE; - rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL; - rasterizationInfo.cullMode = cullMode; - rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizationInfo.depthBiasEnable = VK_FALSE; - rasterizationInfo.lineWidth = 1.f; + VkPipelineRasterizationStateCreateInfo rasterizationInfo = {}; + rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationInfo.pNext = nullptr; + rasterizationInfo.flags = 0; + rasterizationInfo.depthClampEnable = VK_FALSE; + rasterizationInfo.rasterizerDiscardEnable = VK_FALSE; + rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL; + rasterizationInfo.cullMode = cullMode; + rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizationInfo.depthBiasEnable = VK_FALSE; + rasterizationInfo.lineWidth = 1.f; - VkPipelineMultisampleStateCreateInfo multisampleInfo = {}; - multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleInfo.pNext = nullptr; - multisampleInfo.flags = 0; - multisampleInfo.rasterizationSamples = VkSampleCountFlagBits(m_ctx->m_sampleCountColor); + VkPipelineMultisampleStateCreateInfo multisampleInfo = {}; + multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleInfo.pNext = nullptr; + multisampleInfo.flags = 0; + multisampleInfo.rasterizationSamples = VkSampleCountFlagBits(m_ctx->m_sampleCountColor); - VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {}; - depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilInfo.pNext = nullptr; - depthStencilInfo.flags = 0; - depthStencilInfo.depthTestEnable = m_depthTest != ZTest::None; - depthStencilInfo.depthWriteEnable = m_depthWrite; - depthStencilInfo.front.compareOp = VK_COMPARE_OP_ALWAYS; - depthStencilInfo.back.compareOp = VK_COMPARE_OP_ALWAYS; + VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {}; + depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilInfo.pNext = nullptr; + depthStencilInfo.flags = 0; + depthStencilInfo.depthTestEnable = m_depthTest != ZTest::None; + depthStencilInfo.depthWriteEnable = m_depthWrite; + depthStencilInfo.front.compareOp = VK_COMPARE_OP_ALWAYS; + depthStencilInfo.back.compareOp = VK_COMPARE_OP_ALWAYS; - switch (m_depthTest) - { - case ZTest::None: - default: - depthStencilInfo.depthCompareOp = VK_COMPARE_OP_ALWAYS; - break; - case ZTest::LEqual: - depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - break; - case ZTest::Greater: - depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER; - break; - case ZTest::Equal: - depthStencilInfo.depthCompareOp = VK_COMPARE_OP_EQUAL; - break; - case ZTest::GEqual: - depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; - break; - } + switch (m_depthTest) { + case ZTest::None: + default: + depthStencilInfo.depthCompareOp = VK_COMPARE_OP_ALWAYS; + break; + case ZTest::LEqual: + depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + break; + case ZTest::Greater: + depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER; + break; + case ZTest::Equal: + depthStencilInfo.depthCompareOp = VK_COMPARE_OP_EQUAL; + break; + case ZTest::GEqual: + depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; + break; + } - VkPipelineColorBlendAttachmentState colorAttachment = {}; - colorAttachment.blendEnable = m_dstFac != BlendFactor::Zero; - if (m_srcFac == BlendFactor::Subtract || m_dstFac == BlendFactor::Subtract) - { - colorAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorAttachment.colorBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; - if (m_overwriteAlpha) - { - colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - } - else - { - colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorAttachment.alphaBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; - } - } - else - { - colorAttachment.srcColorBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; - colorAttachment.dstColorBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; - colorAttachment.colorBlendOp = VK_BLEND_OP_ADD; - if (m_overwriteAlpha) - { - colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - } - else - { - colorAttachment.srcAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; - colorAttachment.dstAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; - } - colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - } - colorAttachment.colorWriteMask = - (m_colorWrite ? (VK_COLOR_COMPONENT_R_BIT | - VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT) : 0) | - (m_alphaWrite ? VK_COLOR_COMPONENT_A_BIT : 0); - - VkPipelineColorBlendStateCreateInfo colorBlendInfo = {}; - colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendInfo.pNext = nullptr; - colorBlendInfo.flags = 0; - colorBlendInfo.logicOpEnable = VK_FALSE; - colorBlendInfo.attachmentCount = 1; - colorBlendInfo.pAttachments = &colorAttachment; - - VkGraphicsPipelineCreateInfo pipelineCreateInfo = {}; - pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCreateInfo.pNext = nullptr; - pipelineCreateInfo.flags = 0; - pipelineCreateInfo.stageCount = numStages; - pipelineCreateInfo.pStages = stages; - pipelineCreateInfo.pVertexInputState = &m_vtxFmt.m_info; - pipelineCreateInfo.pInputAssemblyState = &assemblyInfo; - pipelineCreateInfo.pTessellationState = &tessInfo; - pipelineCreateInfo.pViewportState = &viewportInfo; - pipelineCreateInfo.pRasterizationState = &rasterizationInfo; - pipelineCreateInfo.pMultisampleState = &multisampleInfo; - pipelineCreateInfo.pDepthStencilState = &depthStencilInfo; - pipelineCreateInfo.pColorBlendState = &colorBlendInfo; - pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.layout = m_ctx->m_pipelinelayout; - pipelineCreateInfo.renderPass = rPass; - - ThrowIfFailed(vk::CreateGraphicsPipelines(m_ctx->m_dev, m_pipelineCache, 1, &pipelineCreateInfo, - nullptr, &m_pipeline)); - - m_vertex.reset(); - m_fragment.reset(); - m_geometry.reset(); - m_control.reset(); - m_evaluation.reset(); + VkPipelineColorBlendAttachmentState colorAttachment = {}; + colorAttachment.blendEnable = m_dstFac != BlendFactor::Zero; + if (m_srcFac == BlendFactor::Subtract || m_dstFac == BlendFactor::Subtract) { + colorAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.colorBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; + if (m_overwriteAlpha) { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + } else { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.alphaBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; } - return m_pipeline; + } else { + colorAttachment.srcColorBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; + colorAttachment.dstColorBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; + colorAttachment.colorBlendOp = VK_BLEND_OP_ADD; + if (m_overwriteAlpha) { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + } else { + colorAttachment.srcAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; + colorAttachment.dstAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; + } + colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + } + colorAttachment.colorWriteMask = + (m_colorWrite ? (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT) : 0) | + (m_alphaWrite ? VK_COLOR_COMPONENT_A_BIT : 0); + + VkPipelineColorBlendStateCreateInfo colorBlendInfo = {}; + colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendInfo.pNext = nullptr; + colorBlendInfo.flags = 0; + colorBlendInfo.logicOpEnable = VK_FALSE; + colorBlendInfo.attachmentCount = 1; + colorBlendInfo.pAttachments = &colorAttachment; + + VkGraphicsPipelineCreateInfo pipelineCreateInfo = {}; + pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineCreateInfo.pNext = nullptr; + pipelineCreateInfo.flags = 0; + pipelineCreateInfo.stageCount = numStages; + pipelineCreateInfo.pStages = stages; + pipelineCreateInfo.pVertexInputState = &m_vtxFmt.m_info; + pipelineCreateInfo.pInputAssemblyState = &assemblyInfo; + pipelineCreateInfo.pTessellationState = &tessInfo; + pipelineCreateInfo.pViewportState = &viewportInfo; + pipelineCreateInfo.pRasterizationState = &rasterizationInfo; + pipelineCreateInfo.pMultisampleState = &multisampleInfo; + pipelineCreateInfo.pDepthStencilState = &depthStencilInfo; + pipelineCreateInfo.pColorBlendState = &colorBlendInfo; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.layout = m_ctx->m_pipelinelayout; + pipelineCreateInfo.renderPass = rPass; + + ThrowIfFailed( + vk::CreateGraphicsPipelines(m_ctx->m_dev, m_pipelineCache, 1, &pipelineCreateInfo, nullptr, &m_pipeline)); + + m_vertex.reset(); + m_fragment.reset(); + m_geometry.reset(); + m_control.reset(); + m_evaluation.reset(); } + return m_pipeline; + } }; -static const VkDescriptorBufferInfo* GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) -{ - if (buf->dynamic()) - { - const VulkanGraphicsBufferD* cbuf = - static_cast*>(buf); - return &cbuf->m_bufferInfo[idx]; - } - else - { - const VulkanGraphicsBufferS* cbuf = static_cast(buf); - return &cbuf->m_bufferInfo; - } +static const VkDescriptorBufferInfo* GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) { + if (buf->dynamic()) { + const VulkanGraphicsBufferD* cbuf = + static_cast*>(buf); + return &cbuf->m_bufferInfo[idx]; + } else { + const VulkanGraphicsBufferS* cbuf = static_cast(buf); + return &cbuf->m_bufferInfo; + } } -static const VkDescriptorImageInfo* GetTextureGPUResource(const ITexture* tex, int idx, int bindIdx, bool depth) -{ - switch (tex->type()) - { - case TextureType::Dynamic: - { - const VulkanTextureD* ctex = static_cast(tex); - return &ctex->m_descInfo[idx]; - } - case TextureType::Static: - { - const VulkanTextureS* ctex = static_cast(tex); - return &ctex->m_descInfo; - } - case TextureType::StaticArray: - { - const VulkanTextureSA* ctex = static_cast(tex); - return &ctex->m_descInfo; - } - case TextureType::Render: - { - const VulkanTextureR* ctex = static_cast(tex); - return depth ? &ctex->m_depthBindDescInfo[bindIdx] : &ctex->m_colorBindDescInfo[bindIdx]; - } - default: break; - } - return nullptr; +static const VkDescriptorImageInfo* GetTextureGPUResource(const ITexture* tex, int idx, int bindIdx, bool depth) { + switch (tex->type()) { + case TextureType::Dynamic: { + const VulkanTextureD* ctex = static_cast(tex); + return &ctex->m_descInfo[idx]; + } + case TextureType::Static: { + const VulkanTextureS* ctex = static_cast(tex); + return &ctex->m_descInfo; + } + case TextureType::StaticArray: { + const VulkanTextureSA* ctex = static_cast(tex); + return &ctex->m_descInfo; + } + case TextureType::Render: { + const VulkanTextureR* ctex = static_cast(tex); + return depth ? &ctex->m_depthBindDescInfo[bindIdx] : &ctex->m_colorBindDescInfo[bindIdx]; + } + default: + break; + } + return nullptr; } -struct VulkanShaderDataBinding : GraphicsDataNode -{ - VulkanContext* m_ctx; - boo::ObjToken m_pipeline; - boo::ObjToken m_vbuf; - boo::ObjToken m_instVbuf; - boo::ObjToken m_ibuf; - std::vector> m_ubufs; - std::vector> m_ubufOffs; - VkImageView m_knownViewHandles[2][BOO_GLSL_MAX_TEXTURE_COUNT] = {}; - struct BindTex - { - boo::ObjToken tex; - int idx; - bool depth; - }; - std::vector m_texs; +struct VulkanShaderDataBinding : GraphicsDataNode { + VulkanContext* m_ctx; + boo::ObjToken m_pipeline; + boo::ObjToken m_vbuf; + boo::ObjToken m_instVbuf; + boo::ObjToken m_ibuf; + std::vector> m_ubufs; + std::vector> m_ubufOffs; + VkImageView m_knownViewHandles[2][BOO_GLSL_MAX_TEXTURE_COUNT] = {}; + struct BindTex { + boo::ObjToken tex; + int idx; + bool depth; + }; + std::vector m_texs; - VkBuffer m_vboBufs[2][2] = {{},{}}; - VkDeviceSize m_vboOffs[2][2] = {{},{}}; - VkBuffer m_iboBufs[2] = {}; - VkDeviceSize m_iboOffs[2] = {}; - boo::ObjToken m_descPool; - VkDescriptorSet m_descSets[2] = {}; + VkBuffer m_vboBufs[2][2] = {{}, {}}; + VkDeviceSize m_vboOffs[2][2] = {{}, {}}; + VkBuffer m_iboBufs[2] = {}; + VkDeviceSize m_iboOffs[2] = {}; + boo::ObjToken m_descPool; + VkDescriptorSet m_descSets[2] = {}; - size_t m_vertOffset; - size_t m_instOffset; + size_t m_vertOffset; + size_t m_instOffset; #ifndef NDEBUG - /* Debugging aids */ - bool m_committed = false; + /* Debugging aids */ + bool m_committed = false; #endif - VulkanShaderDataBinding(const boo::ObjToken& d, - VulkanDataFactoryImpl& factory, - const boo::ObjToken& pipeline, - const boo::ObjToken& vbuf, - const boo::ObjToken& instVbuf, - const boo::ObjToken& ibuf, - size_t ubufCount, const boo::ObjToken* ubufs, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* depthBinds, - size_t baseVert, size_t baseInst) - : GraphicsDataNode(d), - m_ctx(factory.m_ctx), - m_pipeline(pipeline), - m_vbuf(vbuf), - m_instVbuf(instVbuf), - m_ibuf(ibuf) - { - VulkanShaderPipeline* cpipeline = m_pipeline.cast(); - VulkanVertexFormat& vtxFmt = cpipeline->m_vtxFmt; - m_vertOffset = baseVert * vtxFmt.m_stride; - m_instOffset = baseInst * vtxFmt.m_instStride; + VulkanShaderDataBinding(const boo::ObjToken& d, VulkanDataFactoryImpl& factory, + const boo::ObjToken& pipeline, const boo::ObjToken& vbuf, + const boo::ObjToken& instVbuf, const boo::ObjToken& ibuf, + size_t ubufCount, const boo::ObjToken* ubufs, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, + const int* bindIdxs, const bool* depthBinds, size_t baseVert, size_t baseInst) + : GraphicsDataNode(d) + , m_ctx(factory.m_ctx) + , m_pipeline(pipeline) + , m_vbuf(vbuf) + , m_instVbuf(instVbuf) + , m_ibuf(ibuf) { + VulkanShaderPipeline* cpipeline = m_pipeline.cast(); + VulkanVertexFormat& vtxFmt = cpipeline->m_vtxFmt; + m_vertOffset = baseVert * vtxFmt.m_stride; + m_instOffset = baseInst * vtxFmt.m_instStride; - if (ubufOffs && ubufSizes) - { - m_ubufOffs.reserve(ubufCount); - for (size_t i=0 ; i fillArr; - fillArr.fill({VK_NULL_HANDLE, ubufOffs[i], (ubufSizes[i] + 255) & ~255}); - m_ubufOffs.push_back(fillArr); - } - } - m_ubufs.reserve(ubufCount); - for (size_t i=0 ; i fillArr; + fillArr.fill({VK_NULL_HANDLE, ubufOffs[i], (ubufSizes[i] + 255) & ~255}); + m_ubufOffs.push_back(fillArr); + } + } + m_ubufs.reserve(ubufCount); + for (size_t i = 0; i < ubufCount; ++i) { #ifndef NDEBUG - if (!ubufs[i]) - Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i)); + if (!ubufs[i]) + Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i)); #endif - m_ubufs.push_back(ubufs[i]); - } - m_texs.reserve(texCount); - for (size_t i=0 ; i 0) - m_descPool = factory.allocateDescriptorSets(m_descSets); + m_ubufs.push_back(ubufs[i]); + } + m_texs.reserve(texCount); + for (size_t i = 0; i < texCount; ++i) { + m_texs.push_back({texs[i], bindIdxs ? bindIdxs[i] : 0, depthBinds ? depthBinds[i] : false}); } - void commit(VulkanContext* ctx) - { - VkWriteDescriptorSet writes[(BOO_GLSL_MAX_UNIFORM_COUNT + BOO_GLSL_MAX_TEXTURE_COUNT) * 2] = {}; - size_t totalWrites = 0; - for (int b=0 ; b<2 ; ++b) - { - if (m_vbuf) - { - const VkDescriptorBufferInfo* vbufInfo = GetBufferGPUResource(m_vbuf.get(), b); - m_vboBufs[b][0] = vbufInfo->buffer; - m_vboOffs[b][0] = vbufInfo->offset + m_vertOffset; - } - if (m_instVbuf) - { - const VkDescriptorBufferInfo* vbufInfo = GetBufferGPUResource(m_instVbuf.get(), b); - m_vboBufs[b][1] = vbufInfo->buffer; - m_vboOffs[b][1] = vbufInfo->offset + m_instOffset; - } - if (m_ibuf) - { - const VkDescriptorBufferInfo* ibufInfo = GetBufferGPUResource(m_ibuf.get(), b); - m_iboBufs[b] = ibufInfo->buffer; - m_iboOffs[b] = ibufInfo->offset; - } + size_t totalDescs = ubufCount + texCount; + if (totalDescs > 0) + m_descPool = factory.allocateDescriptorSets(m_descSets); + } - size_t binding = 0; - if (m_ubufOffs.size()) - { - for (size_t i=0 ; ibuffer; - modInfo.offset += origInfo->offset; - writes[totalWrites].pBufferInfo = &modInfo; - writes[totalWrites].dstArrayElement = 0; - writes[totalWrites].dstBinding = binding; - ++totalWrites; - } - } - ++binding; - } - } - else - { - for (size_t i=0 ; ibuffer; + m_vboOffs[b][0] = vbufInfo->offset + m_vertOffset; + } + if (m_instVbuf) { + const VkDescriptorBufferInfo* vbufInfo = GetBufferGPUResource(m_instVbuf.get(), b); + m_vboBufs[b][1] = vbufInfo->buffer; + m_vboOffs[b][1] = vbufInfo->offset + m_instOffset; + } + if (m_ibuf) { + const VkDescriptorBufferInfo* ibufInfo = GetBufferGPUResource(m_ibuf.get(), b); + m_iboBufs[b] = ibufInfo->buffer; + m_iboOffs[b] = ibufInfo->offset; + } - for (size_t i=0 ; iimageView; - ++totalWrites; - } - ++binding; + size_t binding = 0; + if (m_ubufOffs.size()) { + for (size_t i = 0; i < BOO_GLSL_MAX_UNIFORM_COUNT; ++i) { + if (i < m_ubufs.size()) { + VkDescriptorBufferInfo& modInfo = m_ubufOffs[i][b]; + if (modInfo.range) { + writes[totalWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[totalWrites].pNext = nullptr; + writes[totalWrites].dstSet = m_descSets[b]; + writes[totalWrites].descriptorCount = 1; + writes[totalWrites].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + const VkDescriptorBufferInfo* origInfo = GetBufferGPUResource(m_ubufs[i].get(), b); + modInfo.buffer = origInfo->buffer; + modInfo.offset += origInfo->offset; + writes[totalWrites].pBufferInfo = &modInfo; + writes[totalWrites].dstArrayElement = 0; + writes[totalWrites].dstBinding = binding; + ++totalWrites; } + } + ++binding; } - if (totalWrites) - vk::UpdateDescriptorSets(ctx->m_dev, totalWrites, writes, 0, nullptr); + } else { + for (size_t i = 0; i < BOO_GLSL_MAX_UNIFORM_COUNT; ++i) { + if (i < m_ubufs.size()) { + writes[totalWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[totalWrites].pNext = nullptr; + writes[totalWrites].dstSet = m_descSets[b]; + writes[totalWrites].descriptorCount = 1; + writes[totalWrites].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + writes[totalWrites].pBufferInfo = GetBufferGPUResource(m_ubufs[i].get(), b); + writes[totalWrites].dstArrayElement = 0; + writes[totalWrites].dstBinding = binding; + ++totalWrites; + } + ++binding; + } + } -#ifndef NDEBUG - m_committed = true; -#endif + for (size_t i = 0; i < BOO_GLSL_MAX_TEXTURE_COUNT; ++i) { + if (i < m_texs.size() && m_texs[i].tex) { + writes[totalWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[totalWrites].pNext = nullptr; + writes[totalWrites].dstSet = m_descSets[b]; + writes[totalWrites].descriptorCount = 1; + writes[totalWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writes[totalWrites].pImageInfo = + GetTextureGPUResource(m_texs[i].tex.get(), b, m_texs[i].idx, m_texs[i].depth); + writes[totalWrites].dstArrayElement = 0; + writes[totalWrites].dstBinding = binding; + m_knownViewHandles[b][i] = writes[totalWrites].pImageInfo->imageView; + ++totalWrites; + } + ++binding; + } } + if (totalWrites) + vk::UpdateDescriptorSets(ctx->m_dev, totalWrites, writes, 0, nullptr); - void bind(VkCommandBuffer cmdBuf, int b, VkRenderPass rPass = 0) - { #ifndef NDEBUG - if (!m_committed) - Log.report(logvisor::Fatal, - "attempted to use uncommitted VulkanShaderDataBinding"); + m_committed = true; +#endif + } + + void bind(VkCommandBuffer cmdBuf, int b, VkRenderPass rPass = 0) { +#ifndef NDEBUG + if (!m_committed) + Log.report(logvisor::Fatal, "attempted to use uncommitted VulkanShaderDataBinding"); #endif - /* Ensure resized texture bindings are re-bound */ - size_t binding = BOO_GLSL_MAX_UNIFORM_COUNT; - VkWriteDescriptorSet writes[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; - size_t totalWrites = 0; - for (size_t i=0 ; iimageView != m_knownViewHandles[b][i]) - { - writes[totalWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes[totalWrites].pNext = nullptr; - writes[totalWrites].dstSet = m_descSets[b]; - writes[totalWrites].descriptorCount = 1; - writes[totalWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writes[totalWrites].pImageInfo = resComp; - writes[totalWrites].dstArrayElement = 0; - writes[totalWrites].dstBinding = binding; - ++totalWrites; - m_knownViewHandles[b][i] = resComp->imageView; - } - } - ++binding; + /* Ensure resized texture bindings are re-bound */ + size_t binding = BOO_GLSL_MAX_UNIFORM_COUNT; + VkWriteDescriptorSet writes[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; + size_t totalWrites = 0; + for (size_t i = 0; i < BOO_GLSL_MAX_TEXTURE_COUNT; ++i) { + if (i < m_texs.size() && m_texs[i].tex) { + const VkDescriptorImageInfo* resComp = + GetTextureGPUResource(m_texs[i].tex.get(), b, m_texs[i].idx, m_texs[i].depth); + if (resComp->imageView != m_knownViewHandles[b][i]) { + writes[totalWrites].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writes[totalWrites].pNext = nullptr; + writes[totalWrites].dstSet = m_descSets[b]; + writes[totalWrites].descriptorCount = 1; + writes[totalWrites].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writes[totalWrites].pImageInfo = resComp; + writes[totalWrites].dstArrayElement = 0; + writes[totalWrites].dstBinding = binding; + ++totalWrites; + m_knownViewHandles[b][i] = resComp->imageView; } - if (totalWrites) - vk::UpdateDescriptorSets(m_ctx->m_dev, totalWrites, writes, 0, nullptr); + } + ++binding; + } + if (totalWrites) + vk::UpdateDescriptorSets(m_ctx->m_dev, totalWrites, writes, 0, nullptr); - vk::CmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline.cast()->bind(rPass)); - if (m_descSets[b]) - vk::CmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_ctx->m_pipelinelayout, - 0, 1, &m_descSets[b], 0, nullptr); + vk::CmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline.cast()->bind(rPass)); + if (m_descSets[b]) + vk::CmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_ctx->m_pipelinelayout, 0, 1, &m_descSets[b], + 0, nullptr); - if (m_vbuf && m_instVbuf) - vk::CmdBindVertexBuffers(cmdBuf, 0, 2, m_vboBufs[b], m_vboOffs[b]); - else if (m_vbuf) - vk::CmdBindVertexBuffers(cmdBuf, 0, 1, m_vboBufs[b], m_vboOffs[b]); - else if (m_instVbuf) - vk::CmdBindVertexBuffers(cmdBuf, 1, 1, &m_vboBufs[b][1], &m_vboOffs[b][1]); + if (m_vbuf && m_instVbuf) + vk::CmdBindVertexBuffers(cmdBuf, 0, 2, m_vboBufs[b], m_vboOffs[b]); + else if (m_vbuf) + vk::CmdBindVertexBuffers(cmdBuf, 0, 1, m_vboBufs[b], m_vboOffs[b]); + else if (m_instVbuf) + vk::CmdBindVertexBuffers(cmdBuf, 1, 1, &m_vboBufs[b][1], &m_vboOffs[b][1]); - if (m_ibuf) - vk::CmdBindIndexBuffer(cmdBuf, m_iboBufs[b], m_iboOffs[b], VK_INDEX_TYPE_UINT32); + if (m_ibuf) + vk::CmdBindIndexBuffer(cmdBuf, m_iboBufs[b], m_iboOffs[b], VK_INDEX_TYPE_UINT32); #if AMD_PAL_HACK - /* AMD GCN architecture is prone to hanging after binding a new pipeline without also refreshing the - * device context registers (i.e. viewport, scissor, line width, blend constants). Blend Constants - * are the simplest register to set within the PAL codebase. */ - float dummy[4] = {}; - vk::CmdSetBlendConstants(cmdBuf, dummy); + /* AMD GCN architecture is prone to hanging after binding a new pipeline without also refreshing the + * device context registers (i.e. viewport, scissor, line width, blend constants). Blend Constants + * are the simplest register to set within the PAL codebase. */ + float dummy[4] = {}; + vk::CmdSetBlendConstants(cmdBuf, dummy); #endif - } + } }; -struct VulkanCommandQueue : IGraphicsCommandQueue -{ - Platform platform() const {return IGraphicsDataFactory::Platform::Vulkan;} - const SystemChar* platformName() const {return _SYS_STR("Vulkan");} - VulkanContext* m_ctx; - VulkanContext::Window* m_windowCtx; - IGraphicsContext* m_parent; +struct VulkanCommandQueue : IGraphicsCommandQueue { + Platform platform() const { return IGraphicsDataFactory::Platform::Vulkan; } + const SystemChar* platformName() const { return _SYS_STR("Vulkan"); } + VulkanContext* m_ctx; + VulkanContext::Window* m_windowCtx; + IGraphicsContext* m_parent; - VkCommandPool m_cmdPool; - VkCommandBuffer m_cmdBufs[2]; - VkSemaphore m_swapChainReadySem = VK_NULL_HANDLE; - VkSemaphore m_drawCompleteSem = VK_NULL_HANDLE; - VkFence m_drawCompleteFence; + VkCommandPool m_cmdPool; + VkCommandBuffer m_cmdBufs[2]; + VkSemaphore m_swapChainReadySem = VK_NULL_HANDLE; + VkSemaphore m_drawCompleteSem = VK_NULL_HANDLE; + VkFence m_drawCompleteFence; - VkCommandPool m_dynamicCmdPool; - VkCommandBuffer m_dynamicCmdBufs[2]; - VkFence m_dynamicBufFence; + VkCommandPool m_dynamicCmdPool; + VkCommandBuffer m_dynamicCmdBufs[2]; + VkFence m_dynamicBufFence; - bool m_running = true; - bool m_dynamicNeedsReset = false; - bool m_submitted = false; + bool m_running = true; + bool m_dynamicNeedsReset = false; + bool m_submitted = false; - int m_fillBuf = 0; - int m_drawBuf = 0; + int m_fillBuf = 0; + int m_drawBuf = 0; - std::vector> m_drawResTokens[2]; + std::vector> m_drawResTokens[2]; - void resetCommandBuffer() - { - ThrowIfFailed(vk::ResetCommandBuffer(m_cmdBufs[m_fillBuf], 0)); - VkCommandBufferBeginInfo cmdBufBeginInfo = {}; - cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - ThrowIfFailed(vk::BeginCommandBuffer(m_cmdBufs[m_fillBuf], &cmdBufBeginInfo)); + void resetCommandBuffer() { + ThrowIfFailed(vk::ResetCommandBuffer(m_cmdBufs[m_fillBuf], 0)); + VkCommandBufferBeginInfo cmdBufBeginInfo = {}; + cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + ThrowIfFailed(vk::BeginCommandBuffer(m_cmdBufs[m_fillBuf], &cmdBufBeginInfo)); + } + + void resetDynamicCommandBuffer() { + ThrowIfFailed(vk::ResetCommandBuffer(m_dynamicCmdBufs[m_fillBuf], 0)); + VkCommandBufferBeginInfo cmdBufBeginInfo = {}; + cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + ThrowIfFailed(vk::BeginCommandBuffer(m_dynamicCmdBufs[m_fillBuf], &cmdBufBeginInfo)); + m_dynamicNeedsReset = false; + } + + void stallDynamicUpload() { + if (m_dynamicNeedsReset) { + ThrowIfFailed(vk::WaitForFences(m_ctx->m_dev, 1, &m_dynamicBufFence, VK_FALSE, -1)); + resetDynamicCommandBuffer(); } - - void resetDynamicCommandBuffer() - { - ThrowIfFailed(vk::ResetCommandBuffer(m_dynamicCmdBufs[m_fillBuf], 0)); - VkCommandBufferBeginInfo cmdBufBeginInfo = {}; - cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - ThrowIfFailed(vk::BeginCommandBuffer(m_dynamicCmdBufs[m_fillBuf], &cmdBufBeginInfo)); - m_dynamicNeedsReset = false; - } - - void stallDynamicUpload() - { - if (m_dynamicNeedsReset) - { - ThrowIfFailed(vk::WaitForFences(m_ctx->m_dev, 1, &m_dynamicBufFence, VK_FALSE, -1)); - resetDynamicCommandBuffer(); - } - } - - VulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent) - : m_ctx(ctx), m_windowCtx(windowCtx), m_parent(parent) - { - VkCommandPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - poolInfo.queueFamilyIndex = m_ctx->m_graphicsQueueFamilyIndex; - ThrowIfFailed(vk::CreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_cmdPool)); - ThrowIfFailed(vk::CreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_dynamicCmdPool)); - - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = m_cmdPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = 2; - - VkCommandBufferBeginInfo cmdBufBeginInfo = {}; - cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - ThrowIfFailed(vk::AllocateCommandBuffers(m_ctx->m_dev, &allocInfo, m_cmdBufs)); - ThrowIfFailed(vk::BeginCommandBuffer(m_cmdBufs[0], &cmdBufBeginInfo)); - - allocInfo.commandPool = m_dynamicCmdPool; - ThrowIfFailed(vk::AllocateCommandBuffers(m_ctx->m_dev, &allocInfo, m_dynamicCmdBufs)); - ThrowIfFailed(vk::BeginCommandBuffer(m_dynamicCmdBufs[0], &cmdBufBeginInfo)); - - VkSemaphoreCreateInfo semInfo = {}; - semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - ThrowIfFailed(vk::CreateSemaphore(ctx->m_dev, &semInfo, nullptr, &m_swapChainReadySem)); - ThrowIfFailed(vk::CreateSemaphore(ctx->m_dev, &semInfo, nullptr, &m_drawCompleteSem)); - - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - ThrowIfFailed(vk::CreateFence(m_ctx->m_dev, &fenceInfo, nullptr, &m_drawCompleteFence)); - ThrowIfFailed(vk::CreateFence(m_ctx->m_dev, &fenceInfo, nullptr, &m_dynamicBufFence)); - } - - void startRenderer() - { - static_cast(m_parent->getDataFactory())->SetupGammaResources(); - } - - void stopRenderer() - { - m_running = false; - if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY) - vk::WaitForFences(m_ctx->m_dev, 1, &m_drawCompleteFence, VK_FALSE, -1); - stallDynamicUpload(); - static_cast(m_parent->getDataFactory())->DestroyGammaResources(); - m_drawResTokens[0].clear(); - m_drawResTokens[1].clear(); - m_boundTarget.reset(); - m_resolveDispSource.reset(); - } - - ~VulkanCommandQueue() - { - if (m_running) - stopRenderer(); - - vk::DestroyFence(m_ctx->m_dev, m_dynamicBufFence, nullptr); - vk::DestroyFence(m_ctx->m_dev, m_drawCompleteFence, nullptr); - vk::DestroySemaphore(m_ctx->m_dev, m_drawCompleteSem, nullptr); - vk::DestroySemaphore(m_ctx->m_dev, m_swapChainReadySem, nullptr); - vk::DestroyCommandPool(m_ctx->m_dev, m_dynamicCmdPool, nullptr); - vk::DestroyCommandPool(m_ctx->m_dev, m_cmdPool, nullptr); - } - - void setShaderDataBinding(const boo::ObjToken& binding) - { - VulkanShaderDataBinding* cbind = binding.cast(); - cbind->bind(m_cmdBufs[m_fillBuf], m_fillBuf); - m_drawResTokens[m_fillBuf].push_back(binding.get()); - } - - boo::ObjToken m_boundTarget; - void setRenderTarget(const boo::ObjToken& target) - { - VulkanTextureR* ctarget = target.cast(); - VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf]; - - if (m_boundTarget.get() != ctarget) - { - if (m_boundTarget) - { - vk::CmdEndRenderPass(cmdBuf); - VulkanTextureR* btarget = m_boundTarget.cast(); - SetImageLayout(cmdBuf, btarget->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - SetImageLayout(cmdBuf, btarget->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - } - - SetImageLayout(cmdBuf, ctarget->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - ctarget->m_layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); - SetImageLayout(cmdBuf, ctarget->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - ctarget->m_layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); - ctarget->m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - - m_boundTarget = target; - m_drawResTokens[m_fillBuf].push_back(target.get()); - } - - vk::CmdBeginRenderPass(cmdBuf, &ctarget->m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - } - - void setViewport(const SWindowRect& rect, float znear, float zfar) - { - if (m_boundTarget) - { - VulkanTextureR* ctarget = m_boundTarget.cast(); - VkViewport vp = {float(rect.location[0]), - float(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])), - float(rect.size[0]), float(rect.size[1]), znear, zfar}; - vk::CmdSetViewport(m_cmdBufs[m_fillBuf], 0, 1, &vp); - } - } - - void setScissor(const SWindowRect& rect) - { - if (m_boundTarget) - { - VulkanTextureR* ctarget = m_boundTarget.cast(); - VkRect2D vkrect = - { - {int32_t(rect.location[0]), - int32_t(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1]))}, - {uint32_t(rect.size[0]), uint32_t(rect.size[1])} - }; - vk::CmdSetScissor(m_cmdBufs[m_fillBuf], 0, 1, &vkrect); - } - } - - std::unordered_map> m_texResizes; - void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) - { - VulkanTextureR* ctex = tex.cast(); - m_texResizes[ctex] = std::make_pair(width, height); - m_drawResTokens[m_fillBuf].push_back(tex.get()); - } - - void schedulePostFrameHandler(std::function&& func) - { - func(); - } - - float m_clearColor[4] = {0.0,0.0,0.0,0.0}; - void setClearColor(const float rgba[4]) - { - m_clearColor[0] = rgba[0]; - m_clearColor[1] = rgba[1]; - m_clearColor[2] = rgba[2]; - m_clearColor[3] = rgba[3]; - } - - void clearTarget(bool render=true, bool depth=true) - { - if (!m_boundTarget) - return; - VulkanTextureR* ctarget = m_boundTarget.cast(); - VkClearAttachment clr[2] = {}; - VkClearRect rect = {}; - rect.layerCount = 1; - rect.rect.extent.width = ctarget->m_width; - rect.rect.extent.height = ctarget->m_height; - - if (render && depth) - { - clr[0].clearValue.color.float32[0] = m_clearColor[0]; - clr[0].clearValue.color.float32[1] = m_clearColor[1]; - clr[0].clearValue.color.float32[2] = m_clearColor[2]; - clr[0].clearValue.color.float32[3] = m_clearColor[3]; - clr[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - clr[1].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - clr[1].clearValue.depthStencil.depth = 1.f; - vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 2, clr, 1, &rect); - } - else if (render) - { - clr[0].clearValue.color.float32[0] = m_clearColor[0]; - clr[0].clearValue.color.float32[1] = m_clearColor[1]; - clr[0].clearValue.color.float32[2] = m_clearColor[2]; - clr[0].clearValue.color.float32[3] = m_clearColor[3]; - clr[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 1, clr, 1, &rect); - } - else if (depth) - { - clr[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - clr[0].clearValue.depthStencil.depth = 1.f; - vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 1, clr, 1, &rect); - } - } - - void draw(size_t start, size_t count) - { - vk::CmdDraw(m_cmdBufs[m_fillBuf], count, 1, start, 0); - } - - void drawIndexed(size_t start, size_t count) - { - vk::CmdDrawIndexed(m_cmdBufs[m_fillBuf], count, 1, start, 0, 0); - } - - void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) - { - vk::CmdDraw(m_cmdBufs[m_fillBuf], count, instCount, start, startInst); - } - - void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) - { - vk::CmdDrawIndexed(m_cmdBufs[m_fillBuf], count, instCount, start, 0, startInst); - } - - boo::ObjToken m_resolveDispSource; - void resolveDisplay(const boo::ObjToken& source) - { - m_resolveDispSource = source; - } - - bool _resolveDisplay() - { - if (!m_resolveDispSource) - return false; - VulkanContext::Window::SwapChain& sc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain]; - if (!sc.m_swapChain) - return false; - - VkCommandBuffer cmdBuf = m_cmdBufs[m_drawBuf]; - VulkanTextureR* csource = m_resolveDispSource.cast(); -#ifndef NDEBUG - if (!csource->m_colorBindCount) - Log.report(logvisor::Fatal, - "texture provided to resolveDisplay() must have at least 1 color binding"); -#endif - - ThrowIfFailed(vk::AcquireNextImageKHR(m_ctx->m_dev, sc.m_swapChain, UINT64_MAX, - m_swapChainReadySem, nullptr, &sc.m_backBuf)); - VulkanContext::Window::SwapChain::Buffer& dest = sc.m_bufs[sc.m_backBuf]; - - VulkanDataFactoryImpl* dataFactory = static_cast(m_parent->getDataFactory()); - if (dataFactory->m_gamma != 1.f || m_ctx->m_internalFormat != m_ctx->m_displayFormat) - { - SWindowRect rect(0, 0, csource->m_width, csource->m_height); - _resolveBindTexture(cmdBuf, csource, rect, true, 0, true, false); - VulkanShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); - - SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); - - vk::CmdBeginRenderPass(cmdBuf, &dest.m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - gammaBinding->m_texs[0].tex = m_resolveDispSource.get(); - gammaBinding->bind(cmdBuf, m_drawBuf, m_ctx->m_passColorOnly); - vk::CmdDraw(cmdBuf, 4, 1, 0, 0); - gammaBinding->m_texs[0].tex.reset(); - - vk::CmdEndRenderPass(cmdBuf); - - SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 1, 1); - } - else - { - SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - if (m_resolveDispSource == m_boundTarget) - SetImageLayout(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - - if (csource->m_samplesColor > 1) - { - VkImageResolve resolveInfo = {}; - resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolveInfo.srcSubresource.mipLevel = 0; - resolveInfo.srcSubresource.baseArrayLayer = 0; - resolveInfo.srcSubresource.layerCount = 1; - resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolveInfo.dstSubresource.mipLevel = 0; - resolveInfo.dstSubresource.baseArrayLayer = 0; - resolveInfo.dstSubresource.layerCount = 1; - resolveInfo.extent.width = csource->m_width; - resolveInfo.extent.height = csource->m_height; - resolveInfo.extent.depth = 1; - vk::CmdResolveImage(cmdBuf, - csource->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dest.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &resolveInfo); - } - else - { - VkImageCopy copyInfo = {}; - copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyInfo.srcSubresource.mipLevel = 0; - copyInfo.srcSubresource.baseArrayLayer = 0; - copyInfo.srcSubresource.layerCount = 1; - copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyInfo.dstSubresource.mipLevel = 0; - copyInfo.dstSubresource.baseArrayLayer = 0; - copyInfo.dstSubresource.layerCount = 1; - copyInfo.extent.width = csource->m_width; - copyInfo.extent.height = csource->m_height; - copyInfo.extent.depth = 1; - vk::CmdCopyImage(cmdBuf, - csource->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dest.m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ©Info); - } - - SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 1, 1); - - if (m_resolveDispSource == m_boundTarget) - SetImageLayout(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); - } - - m_resolveDispSource.reset(); - return true; - } - - void _resolveBindTexture(VkCommandBuffer cmdBuf, VulkanTextureR* ctexture, - const SWindowRect& rect, bool tlOrigin, - int bindIdx, bool color, bool depth) - { - if (color && ctexture->m_colorBindCount) - { - if (ctexture->m_samplesColor <= 1) - { - VkImageCopy copyInfo = {}; - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); - copyInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); - copyInfo.srcOffset.x = intersectRect.location[0]; - copyInfo.dstOffset = copyInfo.srcOffset; - copyInfo.extent.width = intersectRect.size[0]; - copyInfo.extent.height = intersectRect.size[1]; - copyInfo.extent.depth = 1; - copyInfo.dstSubresource.mipLevel = 0; - copyInfo.dstSubresource.baseArrayLayer = 0; - copyInfo.dstSubresource.layerCount = 1; - copyInfo.srcSubresource.mipLevel = 0; - copyInfo.srcSubresource.baseArrayLayer = 0; - copyInfo.srcSubresource.layerCount = 1; - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - ctexture->m_colorBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - vk::CmdCopyImage(cmdBuf, - ctexture->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ©Info); - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - ctexture->m_colorBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - else - { - VkImageResolve resolveInfo = {}; - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); - resolveInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); - resolveInfo.srcOffset.x = intersectRect.location[0]; - resolveInfo.dstOffset = resolveInfo.srcOffset; - resolveInfo.extent.width = intersectRect.size[0]; - resolveInfo.extent.height = intersectRect.size[1]; - resolveInfo.extent.depth = 1; - resolveInfo.dstSubresource.mipLevel = 0; - resolveInfo.dstSubresource.baseArrayLayer = 0; - resolveInfo.dstSubresource.layerCount = 1; - resolveInfo.srcSubresource.mipLevel = 0; - resolveInfo.srcSubresource.baseArrayLayer = 0; - resolveInfo.srcSubresource.layerCount = 1; - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - ctexture->m_colorBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - vk::CmdResolveImage(cmdBuf, - ctexture->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &resolveInfo); - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - ctexture->m_colorBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - } - - if (depth && ctexture->m_depthBindCount) - { - if (ctexture->m_samplesDepth <= 1) - { - VkImageCopy copyInfo = {}; - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); - copyInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); - copyInfo.srcOffset.x = intersectRect.location[0]; - copyInfo.dstOffset = copyInfo.srcOffset; - copyInfo.extent.width = intersectRect.size[0]; - copyInfo.extent.height = intersectRect.size[1]; - copyInfo.extent.depth = 1; - copyInfo.dstSubresource.mipLevel = 0; - copyInfo.dstSubresource.baseArrayLayer = 0; - copyInfo.dstSubresource.layerCount = 1; - copyInfo.srcSubresource.mipLevel = 0; - copyInfo.srcSubresource.baseArrayLayer = 0; - copyInfo.srcSubresource.layerCount = 1; - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - ctexture->m_depthBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - vk::CmdCopyImage(cmdBuf, - ctexture->m_depthTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ©Info); - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - ctexture->m_depthBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - else - { - VkImageResolve resolveInfo = {}; - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); - resolveInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); - resolveInfo.srcOffset.x = intersectRect.location[0]; - resolveInfo.dstOffset = resolveInfo.srcOffset; - resolveInfo.extent.width = intersectRect.size[0]; - resolveInfo.extent.height = intersectRect.size[1]; - resolveInfo.extent.depth = 1; - resolveInfo.dstSubresource.mipLevel = 0; - resolveInfo.dstSubresource.baseArrayLayer = 0; - resolveInfo.dstSubresource.layerCount = 1; - resolveInfo.srcSubresource.mipLevel = 0; - resolveInfo.srcSubresource.baseArrayLayer = 0; - resolveInfo.srcSubresource.layerCount = 1; - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - ctexture->m_depthBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - vk::CmdResolveImage(cmdBuf, - ctexture->m_depthTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &resolveInfo); - - if (ctexture == m_boundTarget.get()) - SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); - - SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - ctexture->m_depthBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } - } - } - - void resolveBindTexture(const boo::ObjToken& texture, - const SWindowRect& rect, bool tlOrigin, - int bindIdx, bool color, bool depth, bool clearDepth) - { - VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf]; - VulkanTextureR* ctexture = texture.cast(); - + } + + VulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent) + : m_ctx(ctx), m_windowCtx(windowCtx), m_parent(parent) { + VkCommandPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + poolInfo.queueFamilyIndex = m_ctx->m_graphicsQueueFamilyIndex; + ThrowIfFailed(vk::CreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_cmdPool)); + ThrowIfFailed(vk::CreateCommandPool(ctx->m_dev, &poolInfo, nullptr, &m_dynamicCmdPool)); + + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_cmdPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 2; + + VkCommandBufferBeginInfo cmdBufBeginInfo = {}; + cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + ThrowIfFailed(vk::AllocateCommandBuffers(m_ctx->m_dev, &allocInfo, m_cmdBufs)); + ThrowIfFailed(vk::BeginCommandBuffer(m_cmdBufs[0], &cmdBufBeginInfo)); + + allocInfo.commandPool = m_dynamicCmdPool; + ThrowIfFailed(vk::AllocateCommandBuffers(m_ctx->m_dev, &allocInfo, m_dynamicCmdBufs)); + ThrowIfFailed(vk::BeginCommandBuffer(m_dynamicCmdBufs[0], &cmdBufBeginInfo)); + + VkSemaphoreCreateInfo semInfo = {}; + semInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + ThrowIfFailed(vk::CreateSemaphore(ctx->m_dev, &semInfo, nullptr, &m_swapChainReadySem)); + ThrowIfFailed(vk::CreateSemaphore(ctx->m_dev, &semInfo, nullptr, &m_drawCompleteSem)); + + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + ThrowIfFailed(vk::CreateFence(m_ctx->m_dev, &fenceInfo, nullptr, &m_drawCompleteFence)); + ThrowIfFailed(vk::CreateFence(m_ctx->m_dev, &fenceInfo, nullptr, &m_dynamicBufFence)); + } + + void startRenderer() { static_cast(m_parent->getDataFactory())->SetupGammaResources(); } + + void stopRenderer() { + m_running = false; + if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY) + vk::WaitForFences(m_ctx->m_dev, 1, &m_drawCompleteFence, VK_FALSE, -1); + stallDynamicUpload(); + static_cast(m_parent->getDataFactory())->DestroyGammaResources(); + m_drawResTokens[0].clear(); + m_drawResTokens[1].clear(); + m_boundTarget.reset(); + m_resolveDispSource.reset(); + } + + ~VulkanCommandQueue() { + if (m_running) + stopRenderer(); + + vk::DestroyFence(m_ctx->m_dev, m_dynamicBufFence, nullptr); + vk::DestroyFence(m_ctx->m_dev, m_drawCompleteFence, nullptr); + vk::DestroySemaphore(m_ctx->m_dev, m_drawCompleteSem, nullptr); + vk::DestroySemaphore(m_ctx->m_dev, m_swapChainReadySem, nullptr); + vk::DestroyCommandPool(m_ctx->m_dev, m_dynamicCmdPool, nullptr); + vk::DestroyCommandPool(m_ctx->m_dev, m_cmdPool, nullptr); + } + + void setShaderDataBinding(const boo::ObjToken& binding) { + VulkanShaderDataBinding* cbind = binding.cast(); + cbind->bind(m_cmdBufs[m_fillBuf], m_fillBuf); + m_drawResTokens[m_fillBuf].push_back(binding.get()); + } + + boo::ObjToken m_boundTarget; + void setRenderTarget(const boo::ObjToken& target) { + VulkanTextureR* ctarget = target.cast(); + VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf]; + + if (m_boundTarget.get() != ctarget) { + if (m_boundTarget) { vk::CmdEndRenderPass(cmdBuf); - _resolveBindTexture(cmdBuf, ctexture, rect, tlOrigin, bindIdx, color, depth); - vk::CmdBeginRenderPass(cmdBuf, &m_boundTarget.cast()->m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + VulkanTextureR* btarget = m_boundTarget.cast(); + SetImageLayout(cmdBuf, btarget->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + SetImageLayout(cmdBuf, btarget->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + } - if (clearDepth) - { - VkClearAttachment clr = {}; - VkClearRect rect = {}; - rect.layerCount = 1; - rect.rect.extent.width = ctexture->m_width; - rect.rect.extent.height = ctexture->m_height; + SetImageLayout(cmdBuf, ctarget->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, ctarget->m_layout, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); + SetImageLayout(cmdBuf, ctarget->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, ctarget->m_layout, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); + ctarget->m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - clr.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - clr.clearValue.depthStencil.depth = 1.f; - vk::CmdClearAttachments(cmdBuf, 1, &clr, 1, &rect); - } + m_boundTarget = target; + m_drawResTokens[m_fillBuf].push_back(target.get()); } - void execute(); + vk::CmdBeginRenderPass(cmdBuf, &ctarget->m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + } + + void setViewport(const SWindowRect& rect, float znear, float zfar) { + if (m_boundTarget) { + VulkanTextureR* ctarget = m_boundTarget.cast(); + VkViewport vp = {float(rect.location[0]), + float(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])), + float(rect.size[0]), + float(rect.size[1]), + znear, + zfar}; + vk::CmdSetViewport(m_cmdBufs[m_fillBuf], 0, 1, &vp); + } + } + + void setScissor(const SWindowRect& rect) { + if (m_boundTarget) { + VulkanTextureR* ctarget = m_boundTarget.cast(); + VkRect2D vkrect = { + {int32_t(rect.location[0]), int32_t(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1]))}, + {uint32_t(rect.size[0]), uint32_t(rect.size[1])}}; + vk::CmdSetScissor(m_cmdBufs[m_fillBuf], 0, 1, &vkrect); + } + } + + std::unordered_map> m_texResizes; + void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) { + VulkanTextureR* ctex = tex.cast(); + m_texResizes[ctex] = std::make_pair(width, height); + m_drawResTokens[m_fillBuf].push_back(tex.get()); + } + + void schedulePostFrameHandler(std::function&& func) { func(); } + + float m_clearColor[4] = {0.0, 0.0, 0.0, 0.0}; + void setClearColor(const float rgba[4]) { + m_clearColor[0] = rgba[0]; + m_clearColor[1] = rgba[1]; + m_clearColor[2] = rgba[2]; + m_clearColor[3] = rgba[3]; + } + + void clearTarget(bool render = true, bool depth = true) { + if (!m_boundTarget) + return; + VulkanTextureR* ctarget = m_boundTarget.cast(); + VkClearAttachment clr[2] = {}; + VkClearRect rect = {}; + rect.layerCount = 1; + rect.rect.extent.width = ctarget->m_width; + rect.rect.extent.height = ctarget->m_height; + + if (render && depth) { + clr[0].clearValue.color.float32[0] = m_clearColor[0]; + clr[0].clearValue.color.float32[1] = m_clearColor[1]; + clr[0].clearValue.color.float32[2] = m_clearColor[2]; + clr[0].clearValue.color.float32[3] = m_clearColor[3]; + clr[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clr[1].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clr[1].clearValue.depthStencil.depth = 1.f; + vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 2, clr, 1, &rect); + } else if (render) { + clr[0].clearValue.color.float32[0] = m_clearColor[0]; + clr[0].clearValue.color.float32[1] = m_clearColor[1]; + clr[0].clearValue.color.float32[2] = m_clearColor[2]; + clr[0].clearValue.color.float32[3] = m_clearColor[3]; + clr[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 1, clr, 1, &rect); + } else if (depth) { + clr[0].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clr[0].clearValue.depthStencil.depth = 1.f; + vk::CmdClearAttachments(m_cmdBufs[m_fillBuf], 1, clr, 1, &rect); + } + } + + void draw(size_t start, size_t count) { vk::CmdDraw(m_cmdBufs[m_fillBuf], count, 1, start, 0); } + + void drawIndexed(size_t start, size_t count) { vk::CmdDrawIndexed(m_cmdBufs[m_fillBuf], count, 1, start, 0, 0); } + + void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst) { + vk::CmdDraw(m_cmdBufs[m_fillBuf], count, instCount, start, startInst); + } + + void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst) { + vk::CmdDrawIndexed(m_cmdBufs[m_fillBuf], count, instCount, start, 0, startInst); + } + + boo::ObjToken m_resolveDispSource; + void resolveDisplay(const boo::ObjToken& source) { m_resolveDispSource = source; } + + bool _resolveDisplay() { + if (!m_resolveDispSource) + return false; + VulkanContext::Window::SwapChain& sc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain]; + if (!sc.m_swapChain) + return false; + + VkCommandBuffer cmdBuf = m_cmdBufs[m_drawBuf]; + VulkanTextureR* csource = m_resolveDispSource.cast(); +#ifndef NDEBUG + if (!csource->m_colorBindCount) + Log.report(logvisor::Fatal, "texture provided to resolveDisplay() must have at least 1 color binding"); +#endif + + ThrowIfFailed( + vk::AcquireNextImageKHR(m_ctx->m_dev, sc.m_swapChain, UINT64_MAX, m_swapChainReadySem, nullptr, &sc.m_backBuf)); + VulkanContext::Window::SwapChain::Buffer& dest = sc.m_bufs[sc.m_backBuf]; + + VulkanDataFactoryImpl* dataFactory = static_cast(m_parent->getDataFactory()); + if (dataFactory->m_gamma != 1.f || m_ctx->m_internalFormat != m_ctx->m_displayFormat) { + SWindowRect rect(0, 0, csource->m_width, csource->m_height); + _resolveBindTexture(cmdBuf, csource, rect, true, 0, true, false); + VulkanShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); + + SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); + + vk::CmdBeginRenderPass(cmdBuf, &dest.m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + gammaBinding->m_texs[0].tex = m_resolveDispSource.get(); + gammaBinding->bind(cmdBuf, m_drawBuf, m_ctx->m_passColorOnly); + vk::CmdDraw(cmdBuf, 4, 1, 0, 0); + gammaBinding->m_texs[0].tex.reset(); + + vk::CmdEndRenderPass(cmdBuf); + + SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 1, 1); + } else { + SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + if (m_resolveDispSource == m_boundTarget) + SetImageLayout(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + + if (csource->m_samplesColor > 1) { + VkImageResolve resolveInfo = {}; + resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolveInfo.srcSubresource.mipLevel = 0; + resolveInfo.srcSubresource.baseArrayLayer = 0; + resolveInfo.srcSubresource.layerCount = 1; + resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolveInfo.dstSubresource.mipLevel = 0; + resolveInfo.dstSubresource.baseArrayLayer = 0; + resolveInfo.dstSubresource.layerCount = 1; + resolveInfo.extent.width = csource->m_width; + resolveInfo.extent.height = csource->m_height; + resolveInfo.extent.depth = 1; + vk::CmdResolveImage(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest.m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolveInfo); + } else { + VkImageCopy copyInfo = {}; + copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyInfo.srcSubresource.mipLevel = 0; + copyInfo.srcSubresource.baseArrayLayer = 0; + copyInfo.srcSubresource.layerCount = 1; + copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyInfo.dstSubresource.mipLevel = 0; + copyInfo.dstSubresource.baseArrayLayer = 0; + copyInfo.dstSubresource.layerCount = 1; + copyInfo.extent.width = csource->m_width; + copyInfo.extent.height = csource->m_height; + copyInfo.extent.depth = 1; + vk::CmdCopyImage(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest.m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info); + } + + SetImageLayout(cmdBuf, dest.m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 1, 1); + + if (m_resolveDispSource == m_boundTarget) + SetImageLayout(cmdBuf, csource->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); + } + + m_resolveDispSource.reset(); + return true; + } + + void _resolveBindTexture(VkCommandBuffer cmdBuf, VulkanTextureR* ctexture, const SWindowRect& rect, bool tlOrigin, + int bindIdx, bool color, bool depth) { + if (color && ctexture->m_colorBindCount) { + if (ctexture->m_samplesColor <= 1) { + VkImageCopy copyInfo = {}; + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); + copyInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); + copyInfo.srcOffset.x = intersectRect.location[0]; + copyInfo.dstOffset = copyInfo.srcOffset; + copyInfo.extent.width = intersectRect.size[0]; + copyInfo.extent.height = intersectRect.size[1]; + copyInfo.extent.depth = 1; + copyInfo.dstSubresource.mipLevel = 0; + copyInfo.dstSubresource.baseArrayLayer = 0; + copyInfo.dstSubresource.layerCount = 1; + copyInfo.srcSubresource.mipLevel = 0; + copyInfo.srcSubresource.baseArrayLayer = 0; + copyInfo.srcSubresource.layerCount = 1; + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, + ctexture->m_colorBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + vk::CmdCopyImage(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info); + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + ctexture->m_colorBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else { + VkImageResolve resolveInfo = {}; + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); + resolveInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); + resolveInfo.srcOffset.x = intersectRect.location[0]; + resolveInfo.dstOffset = resolveInfo.srcOffset; + resolveInfo.extent.width = intersectRect.size[0]; + resolveInfo.extent.height = intersectRect.size[1]; + resolveInfo.extent.depth = 1; + resolveInfo.dstSubresource.mipLevel = 0; + resolveInfo.dstSubresource.baseArrayLayer = 0; + resolveInfo.dstSubresource.layerCount = 1; + resolveInfo.srcSubresource.mipLevel = 0; + resolveInfo.srcSubresource.baseArrayLayer = 0; + resolveInfo.srcSubresource.layerCount = 1; + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, + ctexture->m_colorBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + vk::CmdResolveImage(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &resolveInfo); + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_colorTex.m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_colorBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + ctexture->m_colorBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + } + + if (depth && ctexture->m_depthBindCount) { + if (ctexture->m_samplesDepth <= 1) { + VkImageCopy copyInfo = {}; + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); + copyInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); + copyInfo.srcOffset.x = intersectRect.location[0]; + copyInfo.dstOffset = copyInfo.srcOffset; + copyInfo.extent.width = intersectRect.size[0]; + copyInfo.extent.height = intersectRect.size[1]; + copyInfo.extent.depth = 1; + copyInfo.dstSubresource.mipLevel = 0; + copyInfo.dstSubresource.baseArrayLayer = 0; + copyInfo.dstSubresource.layerCount = 1; + copyInfo.srcSubresource.mipLevel = 0; + copyInfo.srcSubresource.baseArrayLayer = 0; + copyInfo.srcSubresource.layerCount = 1; + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + ctexture->m_depthBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + copyInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + vk::CmdCopyImage(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info); + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + ctexture->m_depthBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else { + VkImageResolve resolveInfo = {}; + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); + resolveInfo.srcOffset.y = tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]); + resolveInfo.srcOffset.x = intersectRect.location[0]; + resolveInfo.dstOffset = resolveInfo.srcOffset; + resolveInfo.extent.width = intersectRect.size[0]; + resolveInfo.extent.height = intersectRect.size[1]; + resolveInfo.extent.depth = 1; + resolveInfo.dstSubresource.mipLevel = 0; + resolveInfo.dstSubresource.baseArrayLayer = 0; + resolveInfo.dstSubresource.layerCount = 1; + resolveInfo.srcSubresource.mipLevel = 0; + resolveInfo.srcSubresource.baseArrayLayer = 0; + resolveInfo.srcSubresource.layerCount = 1; + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + ctexture->m_depthBindLayout[bindIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + resolveInfo.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + resolveInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + vk::CmdResolveImage(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &resolveInfo); + + if (ctexture == m_boundTarget.get()) + SetImageLayout(cmdBuf, ctexture->m_depthTex.m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1, 1); + + SetImageLayout(cmdBuf, ctexture->m_depthBindTex[bindIdx].m_image, VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + ctexture->m_depthBindLayout[bindIdx] = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + } + } + + void resolveBindTexture(const boo::ObjToken& texture, const SWindowRect& rect, bool tlOrigin, int bindIdx, + bool color, bool depth, bool clearDepth) { + VkCommandBuffer cmdBuf = m_cmdBufs[m_fillBuf]; + VulkanTextureR* ctexture = texture.cast(); + + vk::CmdEndRenderPass(cmdBuf); + _resolveBindTexture(cmdBuf, ctexture, rect, tlOrigin, bindIdx, color, depth); + vk::CmdBeginRenderPass(cmdBuf, &m_boundTarget.cast()->m_passBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + if (clearDepth) { + VkClearAttachment clr = {}; + VkClearRect rect = {}; + rect.layerCount = 1; + rect.rect.extent.width = ctexture->m_width; + rect.rect.extent.height = ctexture->m_height; + + clr.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clr.clearValue.depthStencil.depth = 1.f; + vk::CmdClearAttachments(cmdBuf, 1, &clr, 1, &rect); + } + } + + void execute(); }; -void VulkanTextureR::doDestroy() -{ - if (m_framebuffer) - { - vk::DestroyFramebuffer(m_q->m_ctx->m_dev, m_framebuffer, nullptr); - m_framebuffer = VK_NULL_HANDLE; - } - if (m_colorView) - { - vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView, nullptr); - m_colorView = VK_NULL_HANDLE; - } - m_colorTex.destroy(m_q->m_ctx); - if (m_depthView) - { - vk::DestroyImageView(m_q->m_ctx->m_dev, m_depthView, nullptr); - m_depthView = VK_NULL_HANDLE; - } - m_depthTex.destroy(m_q->m_ctx); - for (size_t i=0 ; im_ctx->m_dev, m_colorBindView[i], nullptr); - m_colorBindView[i] = VK_NULL_HANDLE; - } - for (size_t i=0 ; im_ctx); - for (size_t i=0 ; im_ctx->m_dev, m_depthBindView[i], nullptr); - m_depthBindView[i] = VK_NULL_HANDLE; - } - for (size_t i=0 ; im_ctx); -} - -VulkanTextureR::VulkanTextureR(const boo::ObjToken& parent, VulkanCommandQueue* q, - size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount) -: GraphicsDataNode(parent), m_q(q), - m_width(width), m_height(height), - m_samplesColor(q->m_ctx->m_sampleCountColor), - m_samplesDepth(q->m_ctx->m_sampleCountDepth), - m_colorBindCount(colorBindCount), - m_depthBindCount(depthBindCount) -{ - if (colorBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many color bindings for render texture"); - if (depthBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many depth bindings for render texture"); - - if (m_samplesColor == 0) m_samplesColor = 1; - if (m_samplesDepth == 0) m_samplesDepth = 1; - setClampMode(clampMode); - Setup(q->m_ctx); -} - -VulkanTextureR::~VulkanTextureR() -{ +void VulkanTextureR::doDestroy() { + if (m_framebuffer) { vk::DestroyFramebuffer(m_q->m_ctx->m_dev, m_framebuffer, nullptr); + m_framebuffer = VK_NULL_HANDLE; + } + if (m_colorView) { vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView, nullptr); - m_colorTex.destroy(m_q->m_ctx); + m_colorView = VK_NULL_HANDLE; + } + m_colorTex.destroy(m_q->m_ctx); + if (m_depthView) { vk::DestroyImageView(m_q->m_ctx->m_dev, m_depthView, nullptr); - m_depthTex.destroy(m_q->m_ctx); - for (size_t i=0 ; im_ctx->m_dev, m_colorBindView[i], nullptr); - for (size_t i=0 ; im_ctx); - for (size_t i=0 ; im_ctx->m_dev, m_depthBindView[i], nullptr); - for (size_t i=0 ; im_ctx); -} - -void VulkanTextureR::setClampMode(TextureClampMode mode) -{ - MakeSampler(m_q->m_ctx, m_sampler, mode, 1); - for (size_t i=0 ; i -void VulkanGraphicsBufferD::update(int b) -{ - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - memmove(m_bufferPtrs[b], m_cpuBuf.get(), m_cpuSz); - m_validSlots |= slot; + m_depthView = VK_NULL_HANDLE; + } + m_depthTex.destroy(m_q->m_ctx); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + if (m_colorBindView[i]) { + vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView[i], nullptr); + m_colorBindView[i] = VK_NULL_HANDLE; } -} - -template -void VulkanGraphicsBufferD::load(const void* data, size_t sz) -{ - size_t bufSz = std::min(sz, m_cpuSz); - memmove(m_cpuBuf.get(), data, bufSz); - m_validSlots = 0; -} -template -void* VulkanGraphicsBufferD::map(size_t sz) -{ - if (sz > m_cpuSz) - return nullptr; - return m_cpuBuf.get(); -} -template -void VulkanGraphicsBufferD::unmap() -{ - m_validSlots = 0; -} - -VulkanTextureD::~VulkanTextureD() -{ - vk::DestroyImageView(m_q->m_ctx->m_dev, m_gpuView[0], nullptr); - vk::DestroyImageView(m_q->m_ctx->m_dev, m_gpuView[1], nullptr); - m_gpuTex[0].destroy(m_q->m_ctx); - m_gpuTex[1].destroy(m_q->m_ctx); -} - -void VulkanTextureD::update(int b) -{ - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - m_q->stallDynamicUpload(); - VkCommandBuffer cmdBuf = m_q->m_dynamicCmdBufs[b]; - - /* copy staging data */ - memmove(m_cpuBufPtrs[b], m_stagingBuf.get(), m_cpuSz); - - SetImageLayout(cmdBuf, m_gpuTex[b].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); - - /* Put the copy command into the command buffer */ - VkBufferImageCopy copyRegion = {}; - copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.imageSubresource.mipLevel = 0; - copyRegion.imageSubresource.baseArrayLayer = 0; - copyRegion.imageSubresource.layerCount = 1; - copyRegion.imageExtent.width = m_width; - copyRegion.imageExtent.height = m_height; - copyRegion.imageExtent.depth = 1; - copyRegion.bufferOffset = m_cpuOffsets[b]; - - vk::CmdCopyBufferToImage(cmdBuf, - m_cpuBuf, - m_gpuTex[b].m_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); - - /* Set the layout for the texture image from DESTINATION_OPTIMAL to - * SHADER_READ_ONLY */ - SetImageLayout(cmdBuf, m_gpuTex[b].m_image, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); - - m_validSlots |= slot; + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + m_colorBindTex[i].destroy(m_q->m_ctx); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + if (m_depthBindView[i]) { + vk::DestroyImageView(m_q->m_ctx->m_dev, m_depthBindView[i], nullptr); + m_depthBindView[i] = VK_NULL_HANDLE; } + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + m_depthBindTex[i].destroy(m_q->m_ctx); } -void VulkanTextureD::_setClampMode(TextureClampMode mode) -{ - MakeSampler(m_q->m_ctx, m_sampler, mode, 1); - for (int i=0 ; i<2 ; ++i) - m_descInfo[i].sampler = m_sampler; + +VulkanTextureR::VulkanTextureR(const boo::ObjToken& parent, VulkanCommandQueue* q, size_t width, + size_t height, TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount) +: GraphicsDataNode(parent) +, m_q(q) +, m_width(width) +, m_height(height) +, m_samplesColor(q->m_ctx->m_sampleCountColor) +, m_samplesDepth(q->m_ctx->m_sampleCountDepth) +, m_colorBindCount(colorBindCount) +, m_depthBindCount(depthBindCount) { + if (colorBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many color bindings for render texture"); + if (depthBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many depth bindings for render texture"); + + if (m_samplesColor == 0) + m_samplesColor = 1; + if (m_samplesDepth == 0) + m_samplesDepth = 1; + setClampMode(clampMode); + Setup(q->m_ctx); } -void VulkanTextureD::setClampMode(TextureClampMode mode) -{ - if (m_clampMode == mode) - return; - m_clampMode = mode; - _setClampMode(mode); + +VulkanTextureR::~VulkanTextureR() { + vk::DestroyFramebuffer(m_q->m_ctx->m_dev, m_framebuffer, nullptr); + vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorView, nullptr); + m_colorTex.destroy(m_q->m_ctx); + vk::DestroyImageView(m_q->m_ctx->m_dev, m_depthView, nullptr); + m_depthTex.destroy(m_q->m_ctx); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + if (m_colorBindView[i]) + vk::DestroyImageView(m_q->m_ctx->m_dev, m_colorBindView[i], nullptr); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + m_colorBindTex[i].destroy(m_q->m_ctx); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + if (m_depthBindView[i]) + vk::DestroyImageView(m_q->m_ctx->m_dev, m_depthBindView[i], nullptr); + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) + m_depthBindTex[i].destroy(m_q->m_ctx); } -void VulkanTextureD::load(const void* data, size_t sz) -{ - size_t bufSz = std::min(sz, m_cpuSz); - memmove(m_stagingBuf.get(), data, bufSz); - m_validSlots = 0; + +void VulkanTextureR::setClampMode(TextureClampMode mode) { + MakeSampler(m_q->m_ctx, m_sampler, mode, 1); + for (size_t i = 0; i < m_colorBindCount; ++i) + m_colorBindDescInfo[i].sampler = m_sampler; + for (size_t i = 0; i < m_depthBindCount; ++i) + m_depthBindDescInfo[i].sampler = m_sampler; } -void* VulkanTextureD::map(size_t sz) -{ - if (sz > m_cpuSz) - return nullptr; - return m_stagingBuf.get(); + +template +void VulkanGraphicsBufferD::update(int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + memmove(m_bufferPtrs[b], m_cpuBuf.get(), m_cpuSz); + m_validSlots |= slot; + } } -void VulkanTextureD::unmap() -{ - m_validSlots = 0; + +template +void VulkanGraphicsBufferD::load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memmove(m_cpuBuf.get(), data, bufSz); + m_validSlots = 0; } +template +void* VulkanGraphicsBufferD::map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_cpuBuf.get(); +} +template +void VulkanGraphicsBufferD::unmap() { + m_validSlots = 0; +} + +VulkanTextureD::~VulkanTextureD() { + vk::DestroyImageView(m_q->m_ctx->m_dev, m_gpuView[0], nullptr); + vk::DestroyImageView(m_q->m_ctx->m_dev, m_gpuView[1], nullptr); + m_gpuTex[0].destroy(m_q->m_ctx); + m_gpuTex[1].destroy(m_q->m_ctx); +} + +void VulkanTextureD::update(int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + m_q->stallDynamicUpload(); + VkCommandBuffer cmdBuf = m_q->m_dynamicCmdBufs[b]; + + /* copy staging data */ + memmove(m_cpuBufPtrs[b], m_stagingBuf.get(), m_cpuSz); + + SetImageLayout(cmdBuf, m_gpuTex[b].m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, 1); + + /* Put the copy command into the command buffer */ + VkBufferImageCopy copyRegion = {}; + copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.imageSubresource.mipLevel = 0; + copyRegion.imageSubresource.baseArrayLayer = 0; + copyRegion.imageSubresource.layerCount = 1; + copyRegion.imageExtent.width = m_width; + copyRegion.imageExtent.height = m_height; + copyRegion.imageExtent.depth = 1; + copyRegion.bufferOffset = m_cpuOffsets[b]; + + vk::CmdCopyBufferToImage(cmdBuf, m_cpuBuf, m_gpuTex[b].m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + ©Region); + + /* Set the layout for the texture image from DESTINATION_OPTIMAL to + * SHADER_READ_ONLY */ + SetImageLayout(cmdBuf, m_gpuTex[b].m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1, 1); + + m_validSlots |= slot; + } +} +void VulkanTextureD::_setClampMode(TextureClampMode mode) { + MakeSampler(m_q->m_ctx, m_sampler, mode, 1); + for (int i = 0; i < 2; ++i) + m_descInfo[i].sampler = m_sampler; +} +void VulkanTextureD::setClampMode(TextureClampMode mode) { + if (m_clampMode == mode) + return; + m_clampMode = mode; + _setClampMode(mode); +} +void VulkanTextureD::load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memmove(m_stagingBuf.get(), data, bufSz); + m_validSlots = 0; +} +void* VulkanTextureD::map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_stagingBuf.get(); +} +void VulkanTextureD::unmap() { m_validSlots = 0; } VulkanDataFactoryImpl::VulkanDataFactoryImpl(IGraphicsContext* parent, VulkanContext* ctx) : m_parent(parent), m_ctx(ctx) {} @@ -3602,463 +3224,409 @@ VulkanDataFactory::Context::Context(VulkanDataFactory& parent __BooTraceArgs) : m_parent(parent), m_data(new VulkanData(static_cast(parent) __BooTraceArgsUse)) {} VulkanDataFactory::Context::~Context() {} -boo::ObjToken -VulkanDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - return {new VulkanGraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; +boo::ObjToken VulkanDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, + size_t stride, size_t count) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + return {new VulkanGraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; } -boo::ObjToken -VulkanDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - return {new VulkanGraphicsBufferD(m_data, use, factory.m_ctx, stride, count)}; +boo::ObjToken VulkanDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, + size_t count) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + return {new VulkanGraphicsBufferD(m_data, use, factory.m_ctx, stride, count)}; } -boo::ObjToken -VulkanDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - return {new VulkanTextureS(m_data, factory.m_ctx, width, height, mips, fmt, clampMode, data, sz)}; +boo::ObjToken VulkanDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, + const void* data, size_t sz) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + return {new VulkanTextureS(m_data, factory.m_ctx, width, height, mips, fmt, clampMode, data, sz)}; } -boo::ObjToken -VulkanDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - return {new VulkanTextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, clampMode, data, sz)}; +boo::ObjToken VulkanDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, + size_t mips, TextureFormat fmt, + TextureClampMode clampMode, + const void* data, size_t sz) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + return {new VulkanTextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, clampMode, data, sz)}; } -boo::ObjToken -VulkanDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, - TextureClampMode clampMode) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - return {new VulkanTextureD(m_data, q, width, height, fmt, clampMode)}; +boo::ObjToken VulkanDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + return {new VulkanTextureD(m_data, q, width, height, fmt, clampMode)}; } -boo::ObjToken -VulkanDataFactory::Context::newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - return {new VulkanTextureR(m_data, q, width, height, clampMode, colorBindCount, depthBindCount)}; +boo::ObjToken VulkanDataFactory::Context::newRenderTexture(size_t width, size_t height, + TextureClampMode clampMode, size_t colorBindCount, + size_t depthBindCount) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + VulkanCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + return {new VulkanTextureR(m_data, q, width, height, clampMode, colorBindCount, depthBindCount)}; } -ObjToken -VulkanDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); +ObjToken VulkanDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, + PipelineStage stage) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); - if (stage == PipelineStage::Control || stage == PipelineStage::Evaluation) - { - if (!factory.m_ctx->m_features.tessellationShader) - Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); + if (stage == PipelineStage::Control || stage == PipelineStage::Evaluation) { + if (!factory.m_ctx->m_features.tessellationShader) + Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); + } + + return {new VulkanShaderStage(m_data, factory.m_ctx, data, size, stage)}; +} + +ObjToken VulkanDataFactory::Context::newShaderPipeline( + ObjToken vertex, ObjToken fragment, ObjToken geometry, + ObjToken control, ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& additionalInfo) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + + if (control || evaluation) { + if (!factory.m_ctx->m_features.tessellationShader) + Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); + if (additionalInfo.patchSize > factory.m_ctx->m_gpuProps.limits.maxTessellationPatchSize) + Log.report(logvisor::Fatal, "Device supports %d patch vertices, %d requested", + int(factory.m_ctx->m_gpuProps.limits.maxTessellationPatchSize), int(additionalInfo.patchSize)); + } + + return {new VulkanShaderPipeline(m_data, factory.m_ctx, vertex, fragment, geometry, control, evaluation, + VK_NULL_HANDLE, vtxFmt, additionalInfo)}; +} + +boo::ObjToken VulkanDataFactory::Context::newShaderDataBinding( + const boo::ObjToken& pipeline, const boo::ObjToken& vbuf, + const boo::ObjToken& instVbuf, const boo::ObjToken& ibuf, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* /*ubufStages*/, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* bindIdxs, + const bool* bindDepth, size_t baseVert, size_t baseInst) { + VulkanDataFactoryImpl& factory = static_cast(m_parent); + return {new VulkanShaderDataBinding(m_data, factory, pipeline, vbuf, instVbuf, ibuf, ubufCount, ubufs, ubufOffs, + ubufSizes, texCount, texs, bindIdxs, bindDepth, baseVert, baseInst)}; +} + +void VulkanDataFactoryImpl::commitTransaction( + const std::function& trans __BooTraceArgs) { + Context ctx(*this __BooTraceArgsUse); + if (!trans(ctx)) + return; + + VulkanData* data = ctx.m_data.cast(); + + /* size up resources */ + VkDeviceSize constantMemSizes[3] = {}; + VkDeviceSize texMemSize = 0; + + if (data->m_SBufs) + for (IGraphicsBufferS& buf : *data->m_SBufs) { + auto& cbuf = static_cast(buf); + if (cbuf.m_use == BufferUse::Null) + continue; + VkDeviceSize& sz = constantMemSizes[int(cbuf.m_use) - 1]; + sz = cbuf.sizeForGPU(m_ctx, sz); } - return {new VulkanShaderStage(m_data, factory.m_ctx, data, size, stage)}; -} - -ObjToken -VulkanDataFactory::Context::newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& additionalInfo) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - - if (control || evaluation) - { - if (!factory.m_ctx->m_features.tessellationShader) - Log.report(logvisor::Fatal, "Device does not support tessellation shaders"); - if (additionalInfo.patchSize > factory.m_ctx->m_gpuProps.limits.maxTessellationPatchSize) - Log.report(logvisor::Fatal, "Device supports %d patch vertices, %d requested", - int(factory.m_ctx->m_gpuProps.limits.maxTessellationPatchSize), int(additionalInfo.patchSize)); + if (data->m_DBufs) + for (IGraphicsBufferD& buf : *data->m_DBufs) { + auto& cbuf = static_cast&>(buf); + if (cbuf.m_use == BufferUse::Null) + continue; + VkDeviceSize& sz = constantMemSizes[int(cbuf.m_use) - 1]; + sz = cbuf.sizeForGPU(m_ctx, sz); } - return {new VulkanShaderPipeline(m_data, factory.m_ctx, vertex, fragment, geometry, - control, evaluation, VK_NULL_HANDLE, vtxFmt, additionalInfo)}; -} + if (data->m_DTexs) + for (ITextureD& tex : *data->m_DTexs) { + auto& ctex = static_cast(tex); + texMemSize = ctex.sizeForGPU(m_ctx, texMemSize); + } -boo::ObjToken -VulkanDataFactory::Context::newShaderDataBinding( - const boo::ObjToken& pipeline, - const boo::ObjToken& vbuf, - const boo::ObjToken& instVbuf, - const boo::ObjToken& ibuf, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* /*ubufStages*/, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* bindDepth, - size_t baseVert, size_t baseInst) -{ - VulkanDataFactoryImpl& factory = static_cast(m_parent); - return {new VulkanShaderDataBinding(m_data, factory, pipeline, vbuf, instVbuf, ibuf, - ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs, - bindIdxs, bindDepth, baseVert, baseInst)}; -} + std::unique_lock qlk(m_ctx->m_queueLock); -void VulkanDataFactoryImpl::commitTransaction - (const std::function& trans __BooTraceArgs) -{ - Context ctx(*this __BooTraceArgsUse); - if (!trans(ctx)) - return; + /* allocate memory and place buffers */ + for (int i = 0; i < 3; ++i) { + if (constantMemSizes[i]) { + AllocatedBuffer& poolBuf = data->m_constantBuffers[i]; - VulkanData* data = ctx.m_data.cast(); + VkBufferCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = constantMemSizes[i]; + createInfo.usage = USE_TABLE[i + 1]; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); - /* size up resources */ - VkDeviceSize constantMemSizes[3] = {}; - VkDeviceSize texMemSize = 0; - - if (data->m_SBufs) - for (IGraphicsBufferS& buf : *data->m_SBufs) - { - auto& cbuf = static_cast(buf); - if (cbuf.m_use == BufferUse::Null) - continue; - VkDeviceSize& sz = constantMemSizes[int(cbuf.m_use) - 1]; - sz = cbuf.sizeForGPU(m_ctx, sz); + if (data->m_SBufs) + for (IGraphicsBufferS& buf : *data->m_SBufs) { + auto& cbuf = static_cast(buf); + if (int(cbuf.m_use) - 1 != i) + continue; + cbuf.placeForGPU(poolBuf.m_buffer, mappedData); } - if (data->m_DBufs) - for (IGraphicsBufferD& buf : *data->m_DBufs) - { - auto& cbuf = static_cast&>(buf); - if (cbuf.m_use == BufferUse::Null) - continue; - VkDeviceSize& sz = constantMemSizes[int(cbuf.m_use) - 1]; - sz = cbuf.sizeForGPU(m_ctx, sz); + if (data->m_DBufs) + for (IGraphicsBufferD& buf : *data->m_DBufs) { + auto& cbuf = static_cast&>(buf); + if (int(cbuf.m_use) - 1 != i) + continue; + cbuf.placeForGPU(poolBuf.m_buffer, mappedData); } + } + } + + /* place static textures */ + if (data->m_STexs) + for (ITextureS& tex : *data->m_STexs) + static_cast(tex).placeForGPU(m_ctx); + + if (data->m_SATexs) + for (ITextureSA& tex : *data->m_SATexs) + static_cast(tex).placeForGPU(m_ctx); + + /* allocate memory and place dynamic textures */ + if (texMemSize) { + AllocatedBuffer& poolBuf = data->m_texStagingBuffer; + + VkBufferCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = texMemSize; + createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); if (data->m_DTexs) - for (ITextureD& tex : *data->m_DTexs) - { - auto& ctex = static_cast(tex); - texMemSize = ctex.sizeForGPU(m_ctx, texMemSize); - } + for (ITextureD& tex : *data->m_DTexs) + static_cast(tex).placeForGPU(m_ctx, poolBuf.m_buffer, mappedData); + } - std::unique_lock qlk(m_ctx->m_queueLock); + /* initialize bind texture layout */ + if (data->m_RTexs) + for (ITextureR& tex : *data->m_RTexs) + static_cast(tex).initializeBindLayouts(m_ctx); - /* allocate memory and place buffers */ - for (int i=0 ; i<3 ; ++i) - { - if (constantMemSizes[i]) - { - AllocatedBuffer& poolBuf = data->m_constantBuffers[i]; + /* Execute static uploads */ + ThrowIfFailed(vk::EndCommandBuffer(m_ctx->m_loadCmdBuf)); + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &m_ctx->m_loadCmdBuf; - VkBufferCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - createInfo.size = constantMemSizes[i]; - createInfo.usage = USE_TABLE[i+1]; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); + /* Take exclusive lock here and submit queue */ + ThrowIfFailed(vk::QueueWaitIdle(m_ctx->m_queue)); + ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, VK_NULL_HANDLE)); - if (data->m_SBufs) - for (IGraphicsBufferS& buf : *data->m_SBufs) - { - auto& cbuf = static_cast(buf); - if (int(cbuf.m_use) - 1 != i) - continue; - cbuf.placeForGPU(poolBuf.m_buffer, mappedData); - } + /* Commit data bindings (create descriptor sets) */ + if (data->m_SBinds) + for (IShaderDataBinding& bind : *data->m_SBinds) + static_cast(bind).commit(m_ctx); - if (data->m_DBufs) - for (IGraphicsBufferD& buf : *data->m_DBufs) - { - auto& cbuf = static_cast&>(buf); - if (int(cbuf.m_use) - 1 != i) - continue; - cbuf.placeForGPU(poolBuf.m_buffer, mappedData); - } - } - } + /* Wait for uploads to complete */ + ThrowIfFailed(vk::QueueWaitIdle(m_ctx->m_queue)); + qlk.unlock(); - /* place static textures */ - if (data->m_STexs) - for (ITextureS& tex : *data->m_STexs) - static_cast(tex).placeForGPU(m_ctx); + /* Reset command buffer */ + ThrowIfFailed(vk::ResetCommandBuffer(m_ctx->m_loadCmdBuf, 0)); + VkCommandBufferBeginInfo cmdBufBeginInfo = {}; + cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + ThrowIfFailed(vk::BeginCommandBuffer(m_ctx->m_loadCmdBuf, &cmdBufBeginInfo)); - if (data->m_SATexs) - for (ITextureSA& tex : *data->m_SATexs) - static_cast(tex).placeForGPU(m_ctx); + /* Delete upload objects */ + if (data->m_STexs) + for (ITextureS& tex : *data->m_STexs) + static_cast(tex).deleteUploadObjects(); - /* allocate memory and place dynamic textures */ - if (texMemSize) - { - AllocatedBuffer& poolBuf = data->m_texStagingBuffer; - - VkBufferCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - createInfo.size = texMemSize; - createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); - - if (data->m_DTexs) - for (ITextureD& tex : *data->m_DTexs) - static_cast(tex).placeForGPU(m_ctx, poolBuf.m_buffer, mappedData); - } - - /* initialize bind texture layout */ - if (data->m_RTexs) - for (ITextureR& tex : *data->m_RTexs) - static_cast(tex).initializeBindLayouts(m_ctx); - - /* Execute static uploads */ - ThrowIfFailed(vk::EndCommandBuffer(m_ctx->m_loadCmdBuf)); - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &m_ctx->m_loadCmdBuf; - - /* Take exclusive lock here and submit queue */ - ThrowIfFailed(vk::QueueWaitIdle(m_ctx->m_queue)); - ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, VK_NULL_HANDLE)); - - /* Commit data bindings (create descriptor sets) */ - if (data->m_SBinds) - for (IShaderDataBinding& bind : *data->m_SBinds) - static_cast(bind).commit(m_ctx); - - /* Wait for uploads to complete */ - ThrowIfFailed(vk::QueueWaitIdle(m_ctx->m_queue)); - qlk.unlock(); - - /* Reset command buffer */ - ThrowIfFailed(vk::ResetCommandBuffer(m_ctx->m_loadCmdBuf, 0)); - VkCommandBufferBeginInfo cmdBufBeginInfo = {}; - cmdBufBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - ThrowIfFailed(vk::BeginCommandBuffer(m_ctx->m_loadCmdBuf, &cmdBufBeginInfo)); - - /* Delete upload objects */ - if (data->m_STexs) - for (ITextureS& tex : *data->m_STexs) - static_cast(tex).deleteUploadObjects(); - - if (data->m_SATexs) - for (ITextureSA& tex : *data->m_SATexs) - static_cast(tex).deleteUploadObjects(); + if (data->m_SATexs) + for (ITextureSA& tex : *data->m_SATexs) + static_cast(tex).deleteUploadObjects(); } -boo::ObjToken -VulkanDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) -{ - boo::ObjToken pool(new VulkanPool(*this __BooTraceArgsUse)); - VulkanPool* cpool = pool.cast(); - VulkanGraphicsBufferD* retval = - new VulkanGraphicsBufferD(pool, use, m_ctx, stride, count); +boo::ObjToken VulkanDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, + size_t count __BooTraceArgs) { + boo::ObjToken pool(new VulkanPool(*this __BooTraceArgsUse)); + VulkanPool* cpool = pool.cast(); + VulkanGraphicsBufferD* retval = + new VulkanGraphicsBufferD(pool, use, m_ctx, stride, count); - VkDeviceSize size = retval->sizeForGPU(m_ctx, 0); + VkDeviceSize size = retval->sizeForGPU(m_ctx, 0); - /* allocate memory */ - if (size) - { - AllocatedBuffer& poolBuf = cpool->m_constantBuffer; - VkBufferCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - createInfo.size = size; - createInfo.usage = USE_TABLE[int(use)]; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); - retval->placeForGPU(poolBuf.m_buffer, mappedData); - } + /* allocate memory */ + if (size) { + AllocatedBuffer& poolBuf = cpool->m_constantBuffer; + VkBufferCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.size = size; + createInfo.usage = USE_TABLE[int(use)]; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + uint8_t* mappedData = reinterpret_cast(poolBuf.createCPUtoGPU(m_ctx, &createInfo)); + retval->placeForGPU(poolBuf.m_buffer, mappedData); + } - return {retval}; + return {retval}; } -void VulkanCommandQueue::execute() -{ - if (!m_running) - return; +void VulkanCommandQueue::execute() { + if (!m_running) + return; - /* Stage dynamic uploads */ - VulkanDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); - std::unique_lock datalk(gfxF->m_dataMutex); - if (gfxF->m_dataHead) - { - for (BaseGraphicsData& d : *gfxF->m_dataHead) - { - if (d.m_DBufs) - for (IGraphicsBufferD& b : *d.m_DBufs) - static_cast&>(b).update(m_fillBuf); - if (d.m_DTexs) - for (ITextureD& t : *d.m_DTexs) - static_cast(t).update(m_fillBuf); - } + /* Stage dynamic uploads */ + VulkanDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); + std::unique_lock datalk(gfxF->m_dataMutex); + if (gfxF->m_dataHead) { + for (BaseGraphicsData& d : *gfxF->m_dataHead) { + if (d.m_DBufs) + for (IGraphicsBufferD& b : *d.m_DBufs) + static_cast&>(b).update(m_fillBuf); + if (d.m_DTexs) + for (ITextureD& t : *d.m_DTexs) + static_cast(t).update(m_fillBuf); } - if (gfxF->m_poolHead) - { - for (BaseGraphicsPool& p : *gfxF->m_poolHead) - { - if (p.m_DBufs) - for (IGraphicsBufferD& b : *p.m_DBufs) - static_cast&>(b).update(m_fillBuf); - } + } + if (gfxF->m_poolHead) { + for (BaseGraphicsPool& p : *gfxF->m_poolHead) { + if (p.m_DBufs) + for (IGraphicsBufferD& b : *p.m_DBufs) + static_cast&>(b).update(m_fillBuf); } - datalk.unlock(); + } + datalk.unlock(); - /* Perform dynamic uploads */ - std::unique_lock lk(m_ctx->m_queueLock); - if (!m_dynamicNeedsReset) - { - vk::EndCommandBuffer(m_dynamicCmdBufs[m_fillBuf]); + /* Perform dynamic uploads */ + std::unique_lock lk(m_ctx->m_queueLock); + if (!m_dynamicNeedsReset) { + vk::EndCommandBuffer(m_dynamicCmdBufs[m_fillBuf]); - vk::WaitForFences(m_ctx->m_dev, 1, &m_dynamicBufFence, VK_FALSE, -1); - vk::ResetFences(m_ctx->m_dev, 1, &m_dynamicBufFence); + vk::WaitForFences(m_ctx->m_dev, 1, &m_dynamicBufFence, VK_FALSE, -1); + vk::ResetFences(m_ctx->m_dev, 1, &m_dynamicBufFence); - VkSubmitInfo submitInfo = {}; - submitInfo.pNext = nullptr; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.waitSemaphoreCount = 0; - submitInfo.pWaitSemaphores = nullptr; - submitInfo.pWaitDstStageMask = nullptr; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &m_dynamicCmdBufs[m_fillBuf]; - submitInfo.signalSemaphoreCount = 0; - submitInfo.pSignalSemaphores = nullptr; - ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_dynamicBufFence)); - } - - vk::CmdEndRenderPass(m_cmdBufs[m_fillBuf]); - - /* Check on fence */ - if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY) - { - /* Abandon this list (renderer too slow) */ - resetCommandBuffer(); - m_dynamicNeedsReset = true; - m_resolveDispSource = nullptr; - - /* Clear dead data */ - m_drawResTokens[m_fillBuf].clear(); - return; - } - m_submitted = false; - - vk::ResetFences(m_ctx->m_dev, 1, &m_drawCompleteFence); - - /* Perform texture and swap-chain resizes */ - if (m_ctx->_resizeSwapChains() || m_texResizes.size()) - { - for (const auto& resize : m_texResizes) - { - if (m_boundTarget.get() == resize.first) - m_boundTarget.reset(); - resize.first->resize(m_ctx, resize.second.first, resize.second.second); - } - m_texResizes.clear(); - resetCommandBuffer(); - m_dynamicNeedsReset = true; - m_resolveDispSource = nullptr; - return; - } - - /* Clear dead data */ - m_drawResTokens[m_drawBuf].clear(); - - m_drawBuf = m_fillBuf; - m_fillBuf ^= 1; - - /* Queue the command buffer for execution */ - VkPipelineStageFlags pipeStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = {}; submitInfo.pNext = nullptr; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.waitSemaphoreCount = 0; submitInfo.pWaitSemaphores = nullptr; - submitInfo.pWaitDstStageMask = &pipeStageFlags; + submitInfo.pWaitDstStageMask = nullptr; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &m_cmdBufs[m_drawBuf]; + submitInfo.pCommandBuffers = &m_dynamicCmdBufs[m_fillBuf]; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = nullptr; - if (_resolveDisplay()) - { - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &m_swapChainReadySem; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &m_drawCompleteSem; - } - ThrowIfFailed(vk::EndCommandBuffer(m_cmdBufs[m_drawBuf])); - ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_drawCompleteFence)); - m_submitted = true; + ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_dynamicBufFence)); + } - if (submitInfo.signalSemaphoreCount) - { - VulkanContext::Window::SwapChain& thisSc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain]; - - VkPresentInfoKHR present; - present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present.pNext = nullptr; - present.swapchainCount = 1; - present.pSwapchains = &thisSc.m_swapChain; - present.pImageIndices = &thisSc.m_backBuf; - present.waitSemaphoreCount = 1; - present.pWaitSemaphores = &m_drawCompleteSem; - present.pResults = nullptr; - - ThrowIfFailed(vk::QueuePresentKHR(m_ctx->m_queue, &present)); - } + vk::CmdEndRenderPass(m_cmdBufs[m_fillBuf]); + /* Check on fence */ + if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY) { + /* Abandon this list (renderer too slow) */ resetCommandBuffer(); - resetDynamicCommandBuffer(); + m_dynamicNeedsReset = true; + m_resolveDispSource = nullptr; + + /* Clear dead data */ + m_drawResTokens[m_fillBuf].clear(); + return; + } + m_submitted = false; + + vk::ResetFences(m_ctx->m_dev, 1, &m_drawCompleteFence); + + /* Perform texture and swap-chain resizes */ + if (m_ctx->_resizeSwapChains() || m_texResizes.size()) { + for (const auto& resize : m_texResizes) { + if (m_boundTarget.get() == resize.first) + m_boundTarget.reset(); + resize.first->resize(m_ctx, resize.second.first, resize.second.second); + } + m_texResizes.clear(); + resetCommandBuffer(); + m_dynamicNeedsReset = true; + m_resolveDispSource = nullptr; + return; + } + + /* Clear dead data */ + m_drawResTokens[m_drawBuf].clear(); + + m_drawBuf = m_fillBuf; + m_fillBuf ^= 1; + + /* Queue the command buffer for execution */ + VkPipelineStageFlags pipeStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submitInfo = {}; + submitInfo.pNext = nullptr; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 0; + submitInfo.pWaitSemaphores = nullptr; + submitInfo.pWaitDstStageMask = &pipeStageFlags; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &m_cmdBufs[m_drawBuf]; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + if (_resolveDisplay()) { + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &m_swapChainReadySem; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &m_drawCompleteSem; + } + ThrowIfFailed(vk::EndCommandBuffer(m_cmdBufs[m_drawBuf])); + ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_drawCompleteFence)); + m_submitted = true; + + if (submitInfo.signalSemaphoreCount) { + VulkanContext::Window::SwapChain& thisSc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain]; + + VkPresentInfoKHR present; + present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present.pNext = nullptr; + present.swapchainCount = 1; + present.pSwapchains = &thisSc.m_swapChain; + present.pImageIndices = &thisSc.m_backBuf; + present.waitSemaphoreCount = 1; + present.pWaitSemaphores = &m_drawCompleteSem; + present.pResults = nullptr; + + ThrowIfFailed(vk::QueuePresentKHR(m_ctx->m_queue, &present)); + } + + resetCommandBuffer(); + resetDynamicCommandBuffer(); } std::unique_ptr _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, - IGraphicsContext* parent) -{ - return std::make_unique(ctx, windowCtx, parent); + IGraphicsContext* parent) { + return std::make_unique(ctx, windowCtx, parent); } -std::unique_ptr _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx) -{ - return std::make_unique(parent, ctx); +std::unique_ptr _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx) { + return std::make_unique(parent, ctx); } -static const EShLanguage ShaderTypes[] = -{ - EShLangVertex, - EShLangVertex, - EShLangFragment, - EShLangGeometry, - EShLangTessControl, - EShLangTessEvaluation -}; +static const EShLanguage ShaderTypes[] = {EShLangVertex, EShLangVertex, EShLangFragment, + EShLangGeometry, EShLangTessControl, EShLangTessEvaluation}; -std::vector VulkanDataFactory::CompileGLSL(const char* source, PipelineStage stage) -{ - EShLanguage lang = ShaderTypes[int(stage)]; - const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); - glslang::TShader shader(lang); - shader.setStrings(&source, 1); - if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) - { - printf("%s\n", source); - Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog()); - } +std::vector VulkanDataFactory::CompileGLSL(const char* source, PipelineStage stage) { + EShLanguage lang = ShaderTypes[int(stage)]; + const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules); + glslang::TShader shader(lang); + shader.setStrings(&source, 1); + if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) { + printf("%s\n", source); + Log.report(logvisor::Fatal, "unable to compile shader\n%s", shader.getInfoLog()); + } - glslang::TProgram prog; - prog.addShader(&shader); - if (!prog.link(messages)) - { - Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); - } + glslang::TProgram prog; + prog.addShader(&shader); + if (!prog.link(messages)) { + Log.report(logvisor::Fatal, "unable to link shader program\n%s", prog.getInfoLog()); + } - std::vector out; - glslang::GlslangToSpv(*prog.getIntermediate(lang), out); - //spv::Disassemble(std::cerr, out); + std::vector out; + glslang::GlslangToSpv(*prog.getIntermediate(lang), out); + // spv::Disassemble(std::cerr, out); - std::vector ret(out.size() * 4); - memcpy(ret.data(), out.data(), ret.size()); - return ret; + std::vector ret(out.size() * 4); + memcpy(ret.data(), out.data(), ret.size()); + return ret; } -} +} // namespace boo diff --git a/lib/graphicsdev/VulkanDispatchTable.cpp b/lib/graphicsdev/VulkanDispatchTable.cpp index 727f3cb..5bef1c0 100644 --- a/lib/graphicsdev/VulkanDispatchTable.cpp +++ b/lib/graphicsdev/VulkanDispatchTable.cpp @@ -184,342 +184,458 @@ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; PFN_vkDebugReportMessageEXT DebugReportMessageEXT; -void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) -{ - GetInstanceProcAddr = get_instance_proc_addr; +void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) { + GetInstanceProcAddr = get_instance_proc_addr; - CreateInstance = reinterpret_cast(GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); - EnumerateInstanceExtensionProperties = reinterpret_cast(GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties")); - EnumerateInstanceLayerProperties = reinterpret_cast(GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); + CreateInstance = reinterpret_cast(GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); + EnumerateInstanceExtensionProperties = reinterpret_cast( + GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties")); + EnumerateInstanceLayerProperties = reinterpret_cast( + GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); } -void init_dispatch_table_middle(VkInstance instance, bool include_bottom) -{ - GetInstanceProcAddr = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetInstanceProcAddr")); +void init_dispatch_table_middle(VkInstance instance, bool include_bottom) { + GetInstanceProcAddr = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetInstanceProcAddr")); - DestroyInstance = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyInstance")); - EnumeratePhysicalDevices = reinterpret_cast(GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices")); - GetPhysicalDeviceFeatures = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures")); - GetPhysicalDeviceFormatProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties")); - GetPhysicalDeviceImageFormatProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties")); - GetPhysicalDeviceProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties")); - GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties")); - GetPhysicalDeviceMemoryProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties")); - CreateDevice = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDevice")); - EnumerateDeviceExtensionProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties")); - GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties")); - DestroySurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySurfaceKHR")); - GetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR")); - GetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); - GetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR")); - GetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR")); - GetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR")); - GetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR")); - GetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")); - GetDisplayModePropertiesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR")); - CreateDisplayModeKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR")); - GetDisplayPlaneCapabilitiesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")); - CreateDisplayPlaneSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR")); + DestroyInstance = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyInstance")); + EnumeratePhysicalDevices = + reinterpret_cast(GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices")); + GetPhysicalDeviceFeatures = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures")); + GetPhysicalDeviceFormatProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties")); + GetPhysicalDeviceImageFormatProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties")); + GetPhysicalDeviceProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties")); + GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties")); + GetPhysicalDeviceMemoryProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties")); + CreateDevice = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDevice")); + EnumerateDeviceExtensionProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties")); + GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties")); + DestroySurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySurfaceKHR")); + GetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR")); + GetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); + GetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR")); + GetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR")); + GetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR")); + GetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR")); + GetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")); + GetDisplayModePropertiesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR")); + CreateDisplayModeKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR")); + GetDisplayPlaneCapabilitiesKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")); + CreateDisplayPlaneSurfaceKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR")); #ifdef VK_USE_PLATFORM_XLIB_KHR - CreateXlibSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR")); + CreateXlibSurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_XLIB_KHR - GetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR")); + GetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR")); #endif #ifdef VK_USE_PLATFORM_XCB_KHR - CreateXcbSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR")); + CreateXcbSurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_XCB_KHR - GetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR")); + GetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR")); #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR - CreateWaylandSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")); + CreateWaylandSurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_WAYLAND_KHR - GetPhysicalDeviceWaylandPresentationSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); + GetPhysicalDeviceWaylandPresentationSupportKHR = + reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); #endif #ifdef VK_USE_PLATFORM_MIR_KHR - CreateMirSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR")); + CreateMirSurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_MIR_KHR - GetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR")); + GetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR")); #endif #ifdef VK_USE_PLATFORM_ANDROID_KHR - CreateAndroidSurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR")); + CreateAndroidSurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_WIN32_KHR - CreateWin32SurfaceKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")); + CreateWin32SurfaceKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")); #endif #ifdef VK_USE_PLATFORM_WIN32_KHR - GetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); + GetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); #endif - CreateDebugReportCallbackEXT = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); - DestroyDebugReportCallbackEXT = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); - DebugReportMessageEXT = reinterpret_cast(GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")); + CreateDebugReportCallbackEXT = reinterpret_cast( + GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); + DestroyDebugReportCallbackEXT = reinterpret_cast( + GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); + DebugReportMessageEXT = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")); - if (!include_bottom) - return; + if (!include_bottom) + return; - GetDeviceProcAddr = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); - DestroyDevice = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDevice")); - GetDeviceQueue = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceQueue")); - QueueSubmit = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueSubmit")); - QueueWaitIdle = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueWaitIdle")); - DeviceWaitIdle = reinterpret_cast(GetInstanceProcAddr(instance, "vkDeviceWaitIdle")); - AllocateMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateMemory")); - FreeMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeMemory")); - MapMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkMapMemory")); - UnmapMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkUnmapMemory")); - FlushMappedMemoryRanges = reinterpret_cast(GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges")); - InvalidateMappedMemoryRanges = reinterpret_cast(GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges")); - GetDeviceMemoryCommitment = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment")); - BindBufferMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkBindBufferMemory")); - BindImageMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkBindImageMemory")); - GetBufferMemoryRequirements = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements")); - GetImageMemoryRequirements = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements")); - GetImageSparseMemoryRequirements = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements")); - QueueBindSparse = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueBindSparse")); - CreateFence = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateFence")); - DestroyFence = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyFence")); - ResetFences = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetFences")); - GetFenceStatus = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetFenceStatus")); - WaitForFences = reinterpret_cast(GetInstanceProcAddr(instance, "vkWaitForFences")); - CreateSemaphore = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSemaphore")); - DestroySemaphore = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySemaphore")); - CreateEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateEvent")); - DestroyEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyEvent")); - GetEventStatus = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetEventStatus")); - SetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkSetEvent")); - ResetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetEvent")); - CreateQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateQueryPool")); - DestroyQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyQueryPool")); - GetQueryPoolResults = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetQueryPoolResults")); - CreateBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateBuffer")); - DestroyBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyBuffer")); - CreateBufferView = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateBufferView")); - DestroyBufferView = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyBufferView")); - CreateImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateImage")); - DestroyImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyImage")); - GetImageSubresourceLayout = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout")); - CreateImageView = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateImageView")); - DestroyImageView = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyImageView")); - CreateShaderModule = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateShaderModule")); - DestroyShaderModule = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyShaderModule")); - CreatePipelineCache = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreatePipelineCache")); - DestroyPipelineCache = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipelineCache")); - GetPipelineCacheData = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPipelineCacheData")); - MergePipelineCaches = reinterpret_cast(GetInstanceProcAddr(instance, "vkMergePipelineCaches")); - CreateGraphicsPipelines = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines")); - CreateComputePipelines = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateComputePipelines")); - DestroyPipeline = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipeline")); - CreatePipelineLayout = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreatePipelineLayout")); - DestroyPipelineLayout = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipelineLayout")); - CreateSampler = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSampler")); - DestroySampler = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySampler")); - CreateDescriptorSetLayout = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout")); - DestroyDescriptorSetLayout = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout")); - CreateDescriptorPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDescriptorPool")); - DestroyDescriptorPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDescriptorPool")); - ResetDescriptorPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetDescriptorPool")); - AllocateDescriptorSets = reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateDescriptorSets")); - FreeDescriptorSets = reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeDescriptorSets")); - UpdateDescriptorSets = reinterpret_cast(GetInstanceProcAddr(instance, "vkUpdateDescriptorSets")); - CreateFramebuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateFramebuffer")); - DestroyFramebuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyFramebuffer")); - CreateRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateRenderPass")); - DestroyRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyRenderPass")); - GetRenderAreaGranularity = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity")); - CreateCommandPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateCommandPool")); - DestroyCommandPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyCommandPool")); - ResetCommandPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetCommandPool")); - AllocateCommandBuffers = reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateCommandBuffers")); - FreeCommandBuffers = reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeCommandBuffers")); - BeginCommandBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkBeginCommandBuffer")); - EndCommandBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkEndCommandBuffer")); - ResetCommandBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetCommandBuffer")); - CmdBindPipeline = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindPipeline")); - CmdSetViewport = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetViewport")); - CmdSetScissor = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetScissor")); - CmdSetLineWidth = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetLineWidth")); - CmdSetDepthBias = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetDepthBias")); - CmdSetBlendConstants = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetBlendConstants")); - CmdSetDepthBounds = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetDepthBounds")); - CmdSetStencilCompareMask = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask")); - CmdSetStencilWriteMask = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask")); - CmdSetStencilReference = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilReference")); - CmdBindDescriptorSets = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets")); - CmdBindIndexBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer")); - CmdBindVertexBuffers = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers")); - CmdDraw = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDraw")); - CmdDrawIndexed = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndexed")); - CmdDrawIndirect = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndirect")); - CmdDrawIndexedIndirect = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect")); - CmdDispatch = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDispatch")); - CmdDispatchIndirect = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDispatchIndirect")); - CmdCopyBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyBuffer")); - CmdCopyImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyImage")); - CmdBlitImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBlitImage")); - CmdCopyBufferToImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage")); - CmdCopyImageToBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer")); - CmdUpdateBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdUpdateBuffer")); - CmdFillBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdFillBuffer")); - CmdClearColorImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearColorImage")); - CmdClearDepthStencilImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage")); - CmdClearAttachments = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearAttachments")); - CmdResolveImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResolveImage")); - CmdSetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetEvent")); - CmdResetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResetEvent")); - CmdWaitEvents = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdWaitEvents")); - CmdPipelineBarrier = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdPipelineBarrier")); - CmdBeginQuery = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBeginQuery")); - CmdEndQuery = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdEndQuery")); - CmdResetQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResetQueryPool")); - CmdWriteTimestamp = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdWriteTimestamp")); - CmdCopyQueryPoolResults = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults")); - CmdPushConstants = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdPushConstants")); - CmdBeginRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBeginRenderPass")); - CmdNextSubpass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdNextSubpass")); - CmdEndRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdEndRenderPass")); - CmdExecuteCommands = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdExecuteCommands")); - CreateSwapchainKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSwapchainKHR")); - DestroySwapchainKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySwapchainKHR")); - GetSwapchainImagesKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR")); - AcquireNextImageKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkAcquireNextImageKHR")); - QueuePresentKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueuePresentKHR")); - CreateSharedSwapchainsKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR")); + GetDeviceProcAddr = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); + DestroyDevice = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDevice")); + GetDeviceQueue = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceQueue")); + QueueSubmit = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueSubmit")); + QueueWaitIdle = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueWaitIdle")); + DeviceWaitIdle = reinterpret_cast(GetInstanceProcAddr(instance, "vkDeviceWaitIdle")); + AllocateMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateMemory")); + FreeMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeMemory")); + MapMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkMapMemory")); + UnmapMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkUnmapMemory")); + FlushMappedMemoryRanges = + reinterpret_cast(GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges")); + InvalidateMappedMemoryRanges = reinterpret_cast( + GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges")); + GetDeviceMemoryCommitment = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment")); + BindBufferMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkBindBufferMemory")); + BindImageMemory = reinterpret_cast(GetInstanceProcAddr(instance, "vkBindImageMemory")); + GetBufferMemoryRequirements = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements")); + GetImageMemoryRequirements = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements")); + GetImageSparseMemoryRequirements = reinterpret_cast( + GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements")); + QueueBindSparse = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueueBindSparse")); + CreateFence = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateFence")); + DestroyFence = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyFence")); + ResetFences = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetFences")); + GetFenceStatus = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetFenceStatus")); + WaitForFences = reinterpret_cast(GetInstanceProcAddr(instance, "vkWaitForFences")); + CreateSemaphore = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSemaphore")); + DestroySemaphore = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySemaphore")); + CreateEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateEvent")); + DestroyEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyEvent")); + GetEventStatus = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetEventStatus")); + SetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkSetEvent")); + ResetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetEvent")); + CreateQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateQueryPool")); + DestroyQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyQueryPool")); + GetQueryPoolResults = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetQueryPoolResults")); + CreateBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateBuffer")); + DestroyBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyBuffer")); + CreateBufferView = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateBufferView")); + DestroyBufferView = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyBufferView")); + CreateImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateImage")); + DestroyImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyImage")); + GetImageSubresourceLayout = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout")); + CreateImageView = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateImageView")); + DestroyImageView = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyImageView")); + CreateShaderModule = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateShaderModule")); + DestroyShaderModule = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyShaderModule")); + CreatePipelineCache = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreatePipelineCache")); + DestroyPipelineCache = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipelineCache")); + GetPipelineCacheData = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetPipelineCacheData")); + MergePipelineCaches = + reinterpret_cast(GetInstanceProcAddr(instance, "vkMergePipelineCaches")); + CreateGraphicsPipelines = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines")); + CreateComputePipelines = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateComputePipelines")); + DestroyPipeline = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipeline")); + CreatePipelineLayout = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreatePipelineLayout")); + DestroyPipelineLayout = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyPipelineLayout")); + CreateSampler = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSampler")); + DestroySampler = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySampler")); + CreateDescriptorSetLayout = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout")); + DestroyDescriptorSetLayout = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout")); + CreateDescriptorPool = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateDescriptorPool")); + DestroyDescriptorPool = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyDescriptorPool")); + ResetDescriptorPool = + reinterpret_cast(GetInstanceProcAddr(instance, "vkResetDescriptorPool")); + AllocateDescriptorSets = + reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateDescriptorSets")); + FreeDescriptorSets = + reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeDescriptorSets")); + UpdateDescriptorSets = + reinterpret_cast(GetInstanceProcAddr(instance, "vkUpdateDescriptorSets")); + CreateFramebuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateFramebuffer")); + DestroyFramebuffer = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyFramebuffer")); + CreateRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateRenderPass")); + DestroyRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyRenderPass")); + GetRenderAreaGranularity = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity")); + CreateCommandPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateCommandPool")); + DestroyCommandPool = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroyCommandPool")); + ResetCommandPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkResetCommandPool")); + AllocateCommandBuffers = + reinterpret_cast(GetInstanceProcAddr(instance, "vkAllocateCommandBuffers")); + FreeCommandBuffers = + reinterpret_cast(GetInstanceProcAddr(instance, "vkFreeCommandBuffers")); + BeginCommandBuffer = + reinterpret_cast(GetInstanceProcAddr(instance, "vkBeginCommandBuffer")); + EndCommandBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkEndCommandBuffer")); + ResetCommandBuffer = + reinterpret_cast(GetInstanceProcAddr(instance, "vkResetCommandBuffer")); + CmdBindPipeline = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindPipeline")); + CmdSetViewport = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetViewport")); + CmdSetScissor = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetScissor")); + CmdSetLineWidth = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetLineWidth")); + CmdSetDepthBias = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetDepthBias")); + CmdSetBlendConstants = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetBlendConstants")); + CmdSetDepthBounds = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetDepthBounds")); + CmdSetStencilCompareMask = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask")); + CmdSetStencilWriteMask = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask")); + CmdSetStencilReference = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetStencilReference")); + CmdBindDescriptorSets = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets")); + CmdBindIndexBuffer = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer")); + CmdBindVertexBuffers = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers")); + CmdDraw = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDraw")); + CmdDrawIndexed = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndexed")); + CmdDrawIndirect = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndirect")); + CmdDrawIndexedIndirect = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect")); + CmdDispatch = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDispatch")); + CmdDispatchIndirect = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdDispatchIndirect")); + CmdCopyBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyBuffer")); + CmdCopyImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyImage")); + CmdBlitImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBlitImage")); + CmdCopyBufferToImage = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage")); + CmdCopyImageToBuffer = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer")); + CmdUpdateBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdUpdateBuffer")); + CmdFillBuffer = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdFillBuffer")); + CmdClearColorImage = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearColorImage")); + CmdClearDepthStencilImage = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage")); + CmdClearAttachments = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdClearAttachments")); + CmdResolveImage = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResolveImage")); + CmdSetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdSetEvent")); + CmdResetEvent = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResetEvent")); + CmdWaitEvents = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdWaitEvents")); + CmdPipelineBarrier = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdPipelineBarrier")); + CmdBeginQuery = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBeginQuery")); + CmdEndQuery = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdEndQuery")); + CmdResetQueryPool = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdResetQueryPool")); + CmdWriteTimestamp = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdWriteTimestamp")); + CmdCopyQueryPoolResults = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults")); + CmdPushConstants = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdPushConstants")); + CmdBeginRenderPass = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdBeginRenderPass")); + CmdNextSubpass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdNextSubpass")); + CmdEndRenderPass = reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdEndRenderPass")); + CmdExecuteCommands = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCmdExecuteCommands")); + CreateSwapchainKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSwapchainKHR")); + DestroySwapchainKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkDestroySwapchainKHR")); + GetSwapchainImagesKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR")); + AcquireNextImageKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkAcquireNextImageKHR")); + QueuePresentKHR = reinterpret_cast(GetInstanceProcAddr(instance, "vkQueuePresentKHR")); + CreateSharedSwapchainsKHR = + reinterpret_cast(GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR")); } -void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) -{ - GetDeviceProcAddr = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); - GetDeviceProcAddr = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceProcAddr")); +void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) { + GetDeviceProcAddr = reinterpret_cast(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); + GetDeviceProcAddr = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceProcAddr")); - DestroyDevice = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDevice")); - GetDeviceQueue = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceQueue")); - QueueSubmit = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueSubmit")); - QueueWaitIdle = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueWaitIdle")); - DeviceWaitIdle = reinterpret_cast(GetDeviceProcAddr(dev, "vkDeviceWaitIdle")); - AllocateMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateMemory")); - FreeMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeMemory")); - MapMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkMapMemory")); - UnmapMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkUnmapMemory")); - FlushMappedMemoryRanges = reinterpret_cast(GetDeviceProcAddr(dev, "vkFlushMappedMemoryRanges")); - InvalidateMappedMemoryRanges = reinterpret_cast(GetDeviceProcAddr(dev, "vkInvalidateMappedMemoryRanges")); - GetDeviceMemoryCommitment = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceMemoryCommitment")); - BindBufferMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkBindBufferMemory")); - BindImageMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkBindImageMemory")); - GetBufferMemoryRequirements = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetBufferMemoryRequirements")); - GetImageMemoryRequirements = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetImageMemoryRequirements")); - GetImageSparseMemoryRequirements = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetImageSparseMemoryRequirements")); - QueueBindSparse = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueBindSparse")); - CreateFence = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateFence")); - DestroyFence = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyFence")); - ResetFences = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetFences")); - GetFenceStatus = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetFenceStatus")); - WaitForFences = reinterpret_cast(GetDeviceProcAddr(dev, "vkWaitForFences")); - CreateSemaphore = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSemaphore")); - DestroySemaphore = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySemaphore")); - CreateEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateEvent")); - DestroyEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyEvent")); - GetEventStatus = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetEventStatus")); - SetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkSetEvent")); - ResetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetEvent")); - CreateQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateQueryPool")); - DestroyQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyQueryPool")); - GetQueryPoolResults = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetQueryPoolResults")); - CreateBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateBuffer")); - DestroyBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyBuffer")); - CreateBufferView = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateBufferView")); - DestroyBufferView = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyBufferView")); - CreateImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateImage")); - DestroyImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyImage")); - GetImageSubresourceLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetImageSubresourceLayout")); - CreateImageView = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateImageView")); - DestroyImageView = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyImageView")); - CreateShaderModule = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateShaderModule")); - DestroyShaderModule = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyShaderModule")); - CreatePipelineCache = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreatePipelineCache")); - DestroyPipelineCache = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipelineCache")); - GetPipelineCacheData = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetPipelineCacheData")); - MergePipelineCaches = reinterpret_cast(GetDeviceProcAddr(dev, "vkMergePipelineCaches")); - CreateGraphicsPipelines = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateGraphicsPipelines")); - CreateComputePipelines = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateComputePipelines")); - DestroyPipeline = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipeline")); - CreatePipelineLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreatePipelineLayout")); - DestroyPipelineLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipelineLayout")); - CreateSampler = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSampler")); - DestroySampler = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySampler")); - CreateDescriptorSetLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateDescriptorSetLayout")); - DestroyDescriptorSetLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDescriptorSetLayout")); - CreateDescriptorPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateDescriptorPool")); - DestroyDescriptorPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDescriptorPool")); - ResetDescriptorPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetDescriptorPool")); - AllocateDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateDescriptorSets")); - FreeDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeDescriptorSets")); - UpdateDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkUpdateDescriptorSets")); - CreateFramebuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateFramebuffer")); - DestroyFramebuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyFramebuffer")); - CreateRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateRenderPass")); - DestroyRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyRenderPass")); - GetRenderAreaGranularity = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetRenderAreaGranularity")); - CreateCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateCommandPool")); - DestroyCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyCommandPool")); - ResetCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetCommandPool")); - AllocateCommandBuffers = reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateCommandBuffers")); - FreeCommandBuffers = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeCommandBuffers")); - BeginCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkBeginCommandBuffer")); - EndCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkEndCommandBuffer")); - ResetCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetCommandBuffer")); - CmdBindPipeline = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindPipeline")); - CmdSetViewport = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetViewport")); - CmdSetScissor = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetScissor")); - CmdSetLineWidth = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetLineWidth")); - CmdSetDepthBias = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetDepthBias")); - CmdSetBlendConstants = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetBlendConstants")); - CmdSetDepthBounds = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetDepthBounds")); - CmdSetStencilCompareMask = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilCompareMask")); - CmdSetStencilWriteMask = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilWriteMask")); - CmdSetStencilReference = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilReference")); - CmdBindDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindDescriptorSets")); - CmdBindIndexBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindIndexBuffer")); - CmdBindVertexBuffers = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindVertexBuffers")); - CmdDraw = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDraw")); - CmdDrawIndexed = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndexed")); - CmdDrawIndirect = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndirect")); - CmdDrawIndexedIndirect = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndexedIndirect")); - CmdDispatch = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDispatch")); - CmdDispatchIndirect = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDispatchIndirect")); - CmdCopyBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyBuffer")); - CmdCopyImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyImage")); - CmdBlitImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBlitImage")); - CmdCopyBufferToImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyBufferToImage")); - CmdCopyImageToBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyImageToBuffer")); - CmdUpdateBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdUpdateBuffer")); - CmdFillBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdFillBuffer")); - CmdClearColorImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearColorImage")); - CmdClearDepthStencilImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearDepthStencilImage")); - CmdClearAttachments = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearAttachments")); - CmdResolveImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResolveImage")); - CmdSetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetEvent")); - CmdResetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResetEvent")); - CmdWaitEvents = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdWaitEvents")); - CmdPipelineBarrier = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdPipelineBarrier")); - CmdBeginQuery = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBeginQuery")); - CmdEndQuery = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdEndQuery")); - CmdResetQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResetQueryPool")); - CmdWriteTimestamp = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdWriteTimestamp")); - CmdCopyQueryPoolResults = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyQueryPoolResults")); - CmdPushConstants = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdPushConstants")); - CmdBeginRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBeginRenderPass")); - CmdNextSubpass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdNextSubpass")); - CmdEndRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdEndRenderPass")); - CmdExecuteCommands = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdExecuteCommands")); - CreateSwapchainKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSwapchainKHR")); - DestroySwapchainKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySwapchainKHR")); - GetSwapchainImagesKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetSwapchainImagesKHR")); - AcquireNextImageKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkAcquireNextImageKHR")); - QueuePresentKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueuePresentKHR")); - CreateSharedSwapchainsKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR")); + DestroyDevice = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDevice")); + GetDeviceQueue = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceQueue")); + QueueSubmit = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueSubmit")); + QueueWaitIdle = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueWaitIdle")); + DeviceWaitIdle = reinterpret_cast(GetDeviceProcAddr(dev, "vkDeviceWaitIdle")); + AllocateMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateMemory")); + FreeMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeMemory")); + MapMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkMapMemory")); + UnmapMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkUnmapMemory")); + FlushMappedMemoryRanges = + reinterpret_cast(GetDeviceProcAddr(dev, "vkFlushMappedMemoryRanges")); + InvalidateMappedMemoryRanges = + reinterpret_cast(GetDeviceProcAddr(dev, "vkInvalidateMappedMemoryRanges")); + GetDeviceMemoryCommitment = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetDeviceMemoryCommitment")); + BindBufferMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkBindBufferMemory")); + BindImageMemory = reinterpret_cast(GetDeviceProcAddr(dev, "vkBindImageMemory")); + GetBufferMemoryRequirements = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetBufferMemoryRequirements")); + GetImageMemoryRequirements = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetImageMemoryRequirements")); + GetImageSparseMemoryRequirements = reinterpret_cast( + GetDeviceProcAddr(dev, "vkGetImageSparseMemoryRequirements")); + QueueBindSparse = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueueBindSparse")); + CreateFence = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateFence")); + DestroyFence = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyFence")); + ResetFences = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetFences")); + GetFenceStatus = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetFenceStatus")); + WaitForFences = reinterpret_cast(GetDeviceProcAddr(dev, "vkWaitForFences")); + CreateSemaphore = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSemaphore")); + DestroySemaphore = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySemaphore")); + CreateEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateEvent")); + DestroyEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyEvent")); + GetEventStatus = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetEventStatus")); + SetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkSetEvent")); + ResetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetEvent")); + CreateQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateQueryPool")); + DestroyQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyQueryPool")); + GetQueryPoolResults = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetQueryPoolResults")); + CreateBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateBuffer")); + DestroyBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyBuffer")); + CreateBufferView = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateBufferView")); + DestroyBufferView = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyBufferView")); + CreateImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateImage")); + DestroyImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyImage")); + GetImageSubresourceLayout = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetImageSubresourceLayout")); + CreateImageView = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateImageView")); + DestroyImageView = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyImageView")); + CreateShaderModule = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateShaderModule")); + DestroyShaderModule = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyShaderModule")); + CreatePipelineCache = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreatePipelineCache")); + DestroyPipelineCache = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipelineCache")); + GetPipelineCacheData = reinterpret_cast(GetDeviceProcAddr(dev, "vkGetPipelineCacheData")); + MergePipelineCaches = reinterpret_cast(GetDeviceProcAddr(dev, "vkMergePipelineCaches")); + CreateGraphicsPipelines = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateGraphicsPipelines")); + CreateComputePipelines = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateComputePipelines")); + DestroyPipeline = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipeline")); + CreatePipelineLayout = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreatePipelineLayout")); + DestroyPipelineLayout = + reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyPipelineLayout")); + CreateSampler = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSampler")); + DestroySampler = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySampler")); + CreateDescriptorSetLayout = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateDescriptorSetLayout")); + DestroyDescriptorSetLayout = + reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDescriptorSetLayout")); + CreateDescriptorPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateDescriptorPool")); + DestroyDescriptorPool = + reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyDescriptorPool")); + ResetDescriptorPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetDescriptorPool")); + AllocateDescriptorSets = + reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateDescriptorSets")); + FreeDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeDescriptorSets")); + UpdateDescriptorSets = reinterpret_cast(GetDeviceProcAddr(dev, "vkUpdateDescriptorSets")); + CreateFramebuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateFramebuffer")); + DestroyFramebuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyFramebuffer")); + CreateRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateRenderPass")); + DestroyRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyRenderPass")); + GetRenderAreaGranularity = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetRenderAreaGranularity")); + CreateCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateCommandPool")); + DestroyCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroyCommandPool")); + ResetCommandPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetCommandPool")); + AllocateCommandBuffers = + reinterpret_cast(GetDeviceProcAddr(dev, "vkAllocateCommandBuffers")); + FreeCommandBuffers = reinterpret_cast(GetDeviceProcAddr(dev, "vkFreeCommandBuffers")); + BeginCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkBeginCommandBuffer")); + EndCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkEndCommandBuffer")); + ResetCommandBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkResetCommandBuffer")); + CmdBindPipeline = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindPipeline")); + CmdSetViewport = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetViewport")); + CmdSetScissor = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetScissor")); + CmdSetLineWidth = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetLineWidth")); + CmdSetDepthBias = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetDepthBias")); + CmdSetBlendConstants = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetBlendConstants")); + CmdSetDepthBounds = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetDepthBounds")); + CmdSetStencilCompareMask = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilCompareMask")); + CmdSetStencilWriteMask = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilWriteMask")); + CmdSetStencilReference = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetStencilReference")); + CmdBindDescriptorSets = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindDescriptorSets")); + CmdBindIndexBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindIndexBuffer")); + CmdBindVertexBuffers = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBindVertexBuffers")); + CmdDraw = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDraw")); + CmdDrawIndexed = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndexed")); + CmdDrawIndirect = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndirect")); + CmdDrawIndexedIndirect = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDrawIndexedIndirect")); + CmdDispatch = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDispatch")); + CmdDispatchIndirect = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdDispatchIndirect")); + CmdCopyBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyBuffer")); + CmdCopyImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyImage")); + CmdBlitImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBlitImage")); + CmdCopyBufferToImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyBufferToImage")); + CmdCopyImageToBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyImageToBuffer")); + CmdUpdateBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdUpdateBuffer")); + CmdFillBuffer = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdFillBuffer")); + CmdClearColorImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearColorImage")); + CmdClearDepthStencilImage = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearDepthStencilImage")); + CmdClearAttachments = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdClearAttachments")); + CmdResolveImage = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResolveImage")); + CmdSetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdSetEvent")); + CmdResetEvent = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResetEvent")); + CmdWaitEvents = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdWaitEvents")); + CmdPipelineBarrier = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdPipelineBarrier")); + CmdBeginQuery = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBeginQuery")); + CmdEndQuery = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdEndQuery")); + CmdResetQueryPool = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdResetQueryPool")); + CmdWriteTimestamp = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdWriteTimestamp")); + CmdCopyQueryPoolResults = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdCopyQueryPoolResults")); + CmdPushConstants = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdPushConstants")); + CmdBeginRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdBeginRenderPass")); + CmdNextSubpass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdNextSubpass")); + CmdEndRenderPass = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdEndRenderPass")); + CmdExecuteCommands = reinterpret_cast(GetDeviceProcAddr(dev, "vkCmdExecuteCommands")); + CreateSwapchainKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSwapchainKHR")); + DestroySwapchainKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkDestroySwapchainKHR")); + GetSwapchainImagesKHR = + reinterpret_cast(GetDeviceProcAddr(dev, "vkGetSwapchainImagesKHR")); + AcquireNextImageKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkAcquireNextImageKHR")); + QueuePresentKHR = reinterpret_cast(GetDeviceProcAddr(dev, "vkQueuePresentKHR")); + CreateSharedSwapchainsKHR = + reinterpret_cast(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR")); } } // namespace vk diff --git a/lib/graphicsdev/nx/NX.cpp b/lib/graphicsdev/nx/NX.cpp index aef5e00..a7f16ad 100644 --- a/lib/graphicsdev/nx/NX.cpp +++ b/lib/graphicsdev/nx/NX.cpp @@ -21,1760 +21,300 @@ extern "C" { #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::NX"); struct NXCommandQueue; -class NXDataFactoryImpl : public NXDataFactory, public GraphicsDataFactoryHead -{ +class NXDataFactoryImpl : public NXDataFactory, public GraphicsDataFactoryHead { public: - float m_gamma = 1.f; - ObjToken m_gammaBinding; - IGraphicsContext* m_parent; - NXContext* m_ctx; + float m_gamma = 1.f; + ObjToken m_gammaBinding; + IGraphicsContext* m_parent; + NXContext* m_ctx; - NXDataFactoryImpl(IGraphicsContext* parent, NXContext* ctx) : m_parent(parent), m_ctx(ctx) {} + NXDataFactoryImpl(IGraphicsContext* parent, NXContext* ctx) : m_parent(parent), m_ctx(ctx) {} - Platform platform() const {return Platform::NX;} - const SystemChar* platformName() const {return _SYS_STR("NX");} + Platform platform() const { return Platform::NX; } + const SystemChar* platformName() const { return _SYS_STR("NX"); } - void SetupGammaResources() - { + void SetupGammaResources() {} - } + void DestroyGammaResources() {} - void DestroyGammaResources() - { + void commitTransaction(const FactoryCommitFunc& __BooTraceArgs); - } + boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); - void commitTransaction(const FactoryCommitFunc& __BooTraceArgs); + void setDisplayGamma(float gamma) { + m_gamma = gamma; + // if (gamma != 1.f) + // UpdateGammaLUT(m_gammaLUT.get(), gamma); + } - boo::ObjToken newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs); - - void setDisplayGamma(float gamma) - { - m_gamma = gamma; - //if (gamma != 1.f) - // UpdateGammaLUT(m_gammaLUT.get(), gamma); - } - - bool isTessellationSupported(uint32_t& maxPatchSizeOut) - { - maxPatchSizeOut = 0; - if (!m_ctx->m_st->ctx->Extensions.ARB_tessellation_shader) - return false; - maxPatchSizeOut = m_ctx->m_st->ctx->Const.MaxPatchVertices; - return true; - } + bool isTessellationSupported(uint32_t& maxPatchSizeOut) { + maxPatchSizeOut = 0; + if (!m_ctx->m_st->ctx->Extensions.ARB_tessellation_shader) + return false; + maxPatchSizeOut = m_ctx->m_st->ctx->Const.MaxPatchVertices; + return true; + } }; -struct NXData : BaseGraphicsData -{ - NXContext* m_ctx; +struct NXData : BaseGraphicsData { + NXContext* m_ctx; - /* Vertex, Index, Uniform */ - struct pipe_resource* m_constantBuffers[3] = {}; + /* Vertex, Index, Uniform */ + struct pipe_resource* m_constantBuffers[3] = {}; - explicit NXData(NXDataFactoryImpl& head __BooTraceArgs) - : BaseGraphicsData(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} - ~NXData() - { - for (int i=0 ; i<3 ; ++i) - pipe_resource_reference(&m_constantBuffers[i], nullptr); - } + explicit NXData(NXDataFactoryImpl& head __BooTraceArgs) + : BaseGraphicsData(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} + ~NXData() { + for (int i = 0; i < 3; ++i) + pipe_resource_reference(&m_constantBuffers[i], nullptr); + } }; -struct NXPool : BaseGraphicsPool -{ - NXContext* m_ctx; - struct pipe_resource* m_constantBuffer; +struct NXPool : BaseGraphicsPool { + NXContext* m_ctx; + struct pipe_resource* m_constantBuffer; - explicit NXPool(NXDataFactoryImpl& head __BooTraceArgs) - : BaseGraphicsPool(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} - ~NXPool() - { - pipe_resource_reference(&m_constantBuffer, nullptr); - } + explicit NXPool(NXDataFactoryImpl& head __BooTraceArgs) + : BaseGraphicsPool(head __BooTraceArgsUse), m_ctx(head.m_ctx) {} + ~NXPool() { pipe_resource_reference(&m_constantBuffer, nullptr); } }; -static const unsigned USE_TABLE[] = -{ - 0, - PIPE_BIND_VERTEX_BUFFER, - PIPE_BIND_INDEX_BUFFER, - PIPE_BIND_CONSTANT_BUFFER +static const unsigned USE_TABLE[] = {0, PIPE_BIND_VERTEX_BUFFER, PIPE_BIND_INDEX_BUFFER, PIPE_BIND_CONSTANT_BUFFER}; + +union nx_buffer_info { + pipe_vertex_buffer v; + pipe_constant_buffer c; }; -union nx_buffer_info -{ - pipe_vertex_buffer v; - pipe_constant_buffer c; -}; +class NXGraphicsBufferS : public GraphicsDataNode { + friend class NXDataFactory; + friend struct NXCommandQueue; + NXContext* m_ctx; + size_t m_sz; + std::unique_ptr m_stagingBuf; + NXGraphicsBufferS(const boo::ObjToken& parent, BufferUse use, NXContext* ctx, const void* data, + size_t stride, size_t count) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_sz(stride * count) + , m_stagingBuf(new uint8_t[m_sz]) + , m_use(use) { + memmove(m_stagingBuf.get(), data, m_sz); + if (m_use == BufferUse::Vertex) + m_bufferInfo.v.stride = uint16_t(stride); + } -class NXGraphicsBufferS : public GraphicsDataNode -{ - friend class NXDataFactory; - friend struct NXCommandQueue; - NXContext* m_ctx; - size_t m_sz; - std::unique_ptr m_stagingBuf; - NXGraphicsBufferS(const boo::ObjToken& parent, BufferUse use, - NXContext* ctx, const void* data, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_ctx(ctx), m_sz(stride * count), - m_stagingBuf(new uint8_t[m_sz]), m_use(use) - { - memmove(m_stagingBuf.get(), data, m_sz); - if (m_use == BufferUse::Vertex) - m_bufferInfo.v.stride = uint16_t(stride); - } public: - size_t size() const {return m_sz;} - nx_buffer_info m_bufferInfo; - BufferUse m_use; + size_t size() const { return m_sz; } + nx_buffer_info m_bufferInfo; + BufferUse m_use; - unsigned sizeForGPU(NXContext* ctx, unsigned offset) - { - if (m_use == BufferUse::Uniform) - { - unsigned minOffset = std::max(256u, - ctx->m_st->ctx->Const.UniformBufferOffsetAlignment); - offset = (offset + minOffset - 1) & ~(minOffset - 1); - m_bufferInfo.c.buffer_offset = offset; - m_bufferInfo.c.buffer_size = m_sz; - } - else - { - m_bufferInfo.v.buffer_offset = offset; - } - offset += m_sz; - - return offset; + unsigned sizeForGPU(NXContext* ctx, unsigned offset) { + if (m_use == BufferUse::Uniform) { + unsigned minOffset = std::max(256u, ctx->m_st->ctx->Const.UniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); + m_bufferInfo.c.buffer_offset = offset; + m_bufferInfo.c.buffer_size = m_sz; + } else { + m_bufferInfo.v.buffer_offset = offset; } + offset += m_sz; - void placeForGPU(struct pipe_resource* bufObj, uint8_t* buf) - { - if (m_use == BufferUse::Uniform) - m_bufferInfo.c.buffer = bufObj; - else - m_bufferInfo.v.buffer.resource = bufObj; - memmove(buf + m_bufferInfo.v.buffer_offset, m_stagingBuf.get(), m_sz); - m_stagingBuf.reset(); - } + return offset; + } + + void placeForGPU(struct pipe_resource* bufObj, uint8_t* buf) { + if (m_use == BufferUse::Uniform) + m_bufferInfo.c.buffer = bufObj; + else + m_bufferInfo.v.buffer.resource = bufObj; + memmove(buf + m_bufferInfo.v.buffer_offset, m_stagingBuf.get(), m_sz); + m_stagingBuf.reset(); + } }; template -class NXGraphicsBufferD : public GraphicsDataNode -{ - friend class NXDataFactory; - friend class NXDataFactoryImpl; - friend struct NXCommandQueue; - NXContext* m_ctx; - size_t m_cpuSz; - std::unique_ptr m_cpuBuf; - int m_validSlots = 0; - NXGraphicsBufferD(const boo::ObjToken& parent, BufferUse use, - NXContext* ctx, size_t stride, size_t count) - : GraphicsDataNode(parent), - m_ctx(ctx), m_cpuSz(stride * count), m_cpuBuf(new uint8_t[m_cpuSz]), m_use(use) - { - if (m_use == BufferUse::Vertex) - { - m_bufferInfo[0].v.stride = stride; - m_bufferInfo[1].v.stride = stride; - } +class NXGraphicsBufferD : public GraphicsDataNode { + friend class NXDataFactory; + friend class NXDataFactoryImpl; + friend struct NXCommandQueue; + NXContext* m_ctx; + size_t m_cpuSz; + std::unique_ptr m_cpuBuf; + int m_validSlots = 0; + NXGraphicsBufferD(const boo::ObjToken& parent, BufferUse use, NXContext* ctx, size_t stride, size_t count) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_cpuSz(stride * count) + , m_cpuBuf(new uint8_t[m_cpuSz]) + , m_use(use) { + if (m_use == BufferUse::Vertex) { + m_bufferInfo[0].v.stride = stride; + m_bufferInfo[1].v.stride = stride; } - void update(int b) - { - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - memcpy(m_bufferPtrs[b], m_cpuBuf.get(), m_cpuSz); - m_validSlots |= slot; - } + } + void update(int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + memcpy(m_bufferPtrs[b], m_cpuBuf.get(), m_cpuSz); + m_validSlots |= slot; } + } public: - nx_buffer_info m_bufferInfo[2]; - uint8_t* m_bufferPtrs[2] = {}; - BufferUse m_use; - void load(const void* data, size_t sz) - { - size_t bufSz = std::min(sz, m_cpuSz); - memmove(m_cpuBuf.get(), data, bufSz); - m_validSlots = 0; - } - void* map(size_t sz) - { - if (sz > m_cpuSz) - return nullptr; - return m_cpuBuf.get(); - } - void unmap() - { - m_validSlots = 0; + nx_buffer_info m_bufferInfo[2]; + uint8_t* m_bufferPtrs[2] = {}; + BufferUse m_use; + void load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memmove(m_cpuBuf.get(), data, bufSz); + m_validSlots = 0; + } + void* map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_cpuBuf.get(); + } + void unmap() { m_validSlots = 0; } + + unsigned sizeForGPU(NXContext* ctx, unsigned offset) { + for (int i = 0; i < 2; ++i) { + if (m_use == BufferUse::Uniform) { + size_t minOffset = std::max(256u, ctx->m_st->ctx->Const.UniformBufferOffsetAlignment); + offset = (offset + minOffset - 1) & ~(minOffset - 1); + m_bufferInfo[i].c.buffer_offset = offset; + m_bufferInfo[i].c.buffer_size = m_cpuSz; + } else { + m_bufferInfo[i].v.buffer_offset = offset; + } + offset += m_cpuSz; } - unsigned sizeForGPU(NXContext* ctx, unsigned offset) - { - for (int i=0 ; i<2 ; ++i) - { - if (m_use == BufferUse::Uniform) - { - size_t minOffset = std::max(256u, - ctx->m_st->ctx->Const.UniformBufferOffsetAlignment); - offset = (offset + minOffset - 1) & ~(minOffset - 1); - m_bufferInfo[i].c.buffer_offset = offset; - m_bufferInfo[i].c.buffer_size = m_cpuSz; - } - else - { - m_bufferInfo[i].v.buffer_offset = offset; - } - offset += m_cpuSz; - } + return offset; + } - return offset; - } - - void placeForGPU(struct pipe_resource* bufObj, uint8_t* buf) - { - if (m_use == BufferUse::Uniform) - { - m_bufferInfo[0].c.buffer = bufObj; - m_bufferInfo[1].c.buffer = bufObj; - m_bufferPtrs[0] = buf + m_bufferInfo[0].c.buffer_offset; - m_bufferPtrs[1] = buf + m_bufferInfo[1].c.buffer_offset; - } - else - { - m_bufferInfo[0].v.buffer.resource = bufObj; - m_bufferInfo[1].v.buffer.resource = bufObj; - m_bufferPtrs[0] = buf + m_bufferInfo[0].v.buffer_offset; - m_bufferPtrs[1] = buf + m_bufferInfo[1].v.buffer_offset; - } + void placeForGPU(struct pipe_resource* bufObj, uint8_t* buf) { + if (m_use == BufferUse::Uniform) { + m_bufferInfo[0].c.buffer = bufObj; + m_bufferInfo[1].c.buffer = bufObj; + m_bufferPtrs[0] = buf + m_bufferInfo[0].c.buffer_offset; + m_bufferPtrs[1] = buf + m_bufferInfo[1].c.buffer_offset; + } else { + m_bufferInfo[0].v.buffer.resource = bufObj; + m_bufferInfo[1].v.buffer.resource = bufObj; + m_bufferPtrs[0] = buf + m_bufferInfo[0].v.buffer_offset; + m_bufferPtrs[1] = buf + m_bufferInfo[1].v.buffer_offset; } + } }; -static void MakeSampler(NXContext* ctx, void*& sampOut, TextureClampMode mode, int mips) -{ - uint32_t key = (uint32_t(mode) << 16) | mips; - auto search = ctx->m_samplers.find(key); - if (search != ctx->m_samplers.end()) - { - sampOut = search->second; - return; - } +static void MakeSampler(NXContext* ctx, void*& sampOut, TextureClampMode mode, int mips) { + uint32_t key = (uint32_t(mode) << 16) | mips; + auto search = ctx->m_samplers.find(key); + if (search != ctx->m_samplers.end()) { + sampOut = search->second; + return; + } - /* Create linear sampler */ - pipe_sampler_state samplerInfo = {}; - samplerInfo.min_img_filter = PIPE_TEX_FILTER_LINEAR; - samplerInfo.min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR; - samplerInfo.mag_img_filter = PIPE_TEX_FILTER_LINEAR; - samplerInfo.compare_mode = PIPE_TEX_COMPARE_NONE; - samplerInfo.compare_func = PIPE_FUNC_ALWAYS; - samplerInfo.normalized_coords = 1; - samplerInfo.max_anisotropy = 16; - samplerInfo.seamless_cube_map = 0; - samplerInfo.lod_bias = 0; - samplerInfo.min_lod = 0; - samplerInfo.max_lod = mips - 1; - switch (mode) - { - case TextureClampMode::Repeat: - default: - samplerInfo.wrap_s = PIPE_TEX_WRAP_REPEAT; - samplerInfo.wrap_t = PIPE_TEX_WRAP_REPEAT; - samplerInfo.wrap_r = PIPE_TEX_WRAP_REPEAT; - break; - case TextureClampMode::ClampToWhite: - samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - for (int i = 0; i < 4; ++i) - samplerInfo.border_color.f[i] = 1.f; - break; - case TextureClampMode::ClampToBlack: - samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; - samplerInfo.border_color.f[3] = 1.f; - break; - case TextureClampMode::ClampToEdge: - samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - break; - case TextureClampMode::ClampToEdgeNearest: - samplerInfo.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - samplerInfo.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; - samplerInfo.min_img_filter = PIPE_TEX_FILTER_NEAREST; - samplerInfo.max_anisotropy = 0; - samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; - break; - } - sampOut = ctx->m_pctx->create_sampler_state(ctx->m_pctx, &samplerInfo); - ctx->m_samplers[key] = sampOut; + /* Create linear sampler */ + pipe_sampler_state samplerInfo = {}; + samplerInfo.min_img_filter = PIPE_TEX_FILTER_LINEAR; + samplerInfo.min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR; + samplerInfo.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + samplerInfo.compare_mode = PIPE_TEX_COMPARE_NONE; + samplerInfo.compare_func = PIPE_FUNC_ALWAYS; + samplerInfo.normalized_coords = 1; + samplerInfo.max_anisotropy = 16; + samplerInfo.seamless_cube_map = 0; + samplerInfo.lod_bias = 0; + samplerInfo.min_lod = 0; + samplerInfo.max_lod = mips - 1; + switch (mode) { + case TextureClampMode::Repeat: + default: + samplerInfo.wrap_s = PIPE_TEX_WRAP_REPEAT; + samplerInfo.wrap_t = PIPE_TEX_WRAP_REPEAT; + samplerInfo.wrap_r = PIPE_TEX_WRAP_REPEAT; + break; + case TextureClampMode::ClampToWhite: + samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + for (int i = 0; i < 4; ++i) + samplerInfo.border_color.f[i] = 1.f; + break; + case TextureClampMode::ClampToBlack: + samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; + samplerInfo.border_color.f[3] = 1.f; + break; + case TextureClampMode::ClampToEdge: + samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + break; + case TextureClampMode::ClampToEdgeNearest: + samplerInfo.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + samplerInfo.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + samplerInfo.min_img_filter = PIPE_TEX_FILTER_NEAREST; + samplerInfo.max_anisotropy = 0; + samplerInfo.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + samplerInfo.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + samplerInfo.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + break; + } + sampOut = ctx->m_pctx->create_sampler_state(ctx->m_pctx, &samplerInfo); + ctx->m_samplers[key] = sampOut; } -class NXTextureS : public GraphicsDataNode -{ - friend class NXDataFactory; - NXContext* m_ctx; - TextureFormat m_fmt; - size_t m_sz; - size_t m_width, m_height, m_mips; - TextureClampMode m_clampMode; - pipe_format m_nxFmt; - int m_pixelPitchNum = 1; - int m_pixelPitchDenom = 1; - - NXTextureS(const boo::ObjToken& parent, NXContext* ctx, - size_t width, size_t height, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) - : GraphicsDataNode(parent), m_ctx(ctx), m_fmt(fmt), m_sz(sz), - m_width(width), m_height(height), m_mips(mips), m_clampMode(clampMode) - { - pipe_format pfmt; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; - m_pixelPitchNum = 4; - break; - case TextureFormat::I8: - pfmt = PIPE_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pfmt = PIPE_FORMAT_R16_UNORM; - m_pixelPitchNum = 2; - break; - case TextureFormat::DXT1: - pfmt = PIPE_FORMAT_DXT1_RGBA; - m_pixelPitchNum = 1; - m_pixelPitchDenom = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_nxFmt = pfmt; - - struct pipe_resource texTempl = {}; - texTempl.target = PIPE_TEXTURE_2D; - texTempl.format = m_nxFmt; - texTempl.width0 = width; - texTempl.height0 = height; - texTempl.depth0 = 1; - texTempl.last_level = mips - 1; - texTempl.array_size = 1; - texTempl.bind = PIPE_BIND_SAMPLER_VIEW; - m_gpuTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_gpuTex) { - Log.report(logvisor::Fatal, "Failed to create texture"); - return; - } - - uint blockSize = util_format_get_blocksize(m_nxFmt); - uint8_t* ptr = (uint8_t*)data; - for (int i=0 ; im_pctx->texture_subdata(ctx->m_pctx, m_gpuTex, i, PIPE_TRANSFER_WRITE, - &box, ptr, rowStride, imageBytes); - - if (width > 1) - width /= 2; - if (height > 1) - height /= 2; - ptr += regionPitch; - } - - struct pipe_sampler_view svTempl = {}; - svTempl.format = m_nxFmt; - svTempl.texture = m_gpuTex; - svTempl.u.tex.last_level = mips - 1; - svTempl.swizzle_r = PIPE_SWIZZLE_X; - svTempl.swizzle_g = PIPE_SWIZZLE_Y; - svTempl.swizzle_b = PIPE_SWIZZLE_Z; - svTempl.swizzle_a = PIPE_SWIZZLE_W; - m_gpuView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex, &svTempl); - } -public: - struct pipe_resource* m_gpuTex; - struct pipe_sampler_view* m_gpuView = nullptr; - void* m_sampler = nullptr; - ~NXTextureS() - { - pipe_resource_reference(&m_gpuTex, nullptr); - pipe_sampler_view_reference(&m_gpuView, nullptr); - } - - void setClampMode(TextureClampMode mode) - { - m_clampMode = mode; - MakeSampler(m_ctx, m_sampler, mode, m_mips); - } - - TextureFormat format() const {return m_fmt;} -}; - -class NXTextureSA : public GraphicsDataNode -{ - friend class NXDataFactory; - NXContext* m_ctx; - TextureFormat m_fmt; - size_t m_sz; - size_t m_width, m_height, m_layers, m_mips; - TextureClampMode m_clampMode; - pipe_format m_nxFmt; - int m_pixelPitchNum = 1; - int m_pixelPitchDenom = 1; - - NXTextureSA(const boo::ObjToken& parent, NXContext* ctx, - size_t width, size_t height, size_t layers, - size_t mips, TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) - : GraphicsDataNode(parent), - m_ctx(ctx), m_fmt(fmt), m_sz(sz), m_width(width), m_height(height), - m_layers(layers), m_mips(mips), m_clampMode(clampMode) - { - pipe_format pfmt; - switch (fmt) - { - case TextureFormat::RGBA8: - pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; - m_pixelPitchNum = 4; - break; - case TextureFormat::I8: - pfmt = PIPE_FORMAT_R8_UNORM; - break; - case TextureFormat::I16: - pfmt = PIPE_FORMAT_R16_UNORM; - m_pixelPitchNum = 2; - break; - default: - Log.report(logvisor::Fatal, "unsupported tex format"); - } - m_nxFmt = pfmt; - - struct pipe_resource texTempl = {}; - texTempl.target = PIPE_TEXTURE_2D; - texTempl.format = m_nxFmt; - texTempl.width0 = width; - texTempl.height0 = height; - texTempl.depth0 = 1; - texTempl.last_level = mips - 1; - texTempl.array_size = layers; - texTempl.bind = PIPE_BIND_SAMPLER_VIEW; - m_gpuTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_gpuTex) { - Log.report(logvisor::Fatal, "Failed to create texture"); - return; - } - - uint blockSize = util_format_get_blocksize(m_nxFmt); - uint8_t* ptr = (uint8_t*)data; - for (int i=0 ; im_pctx->texture_subdata(ctx->m_pctx, m_gpuTex, i, PIPE_TRANSFER_WRITE, - &box, ptr, rowStride, imageBytes); - - if (width > 1) - width /= 2; - if (height > 1) - height /= 2; - ptr += regionPitch; - } - - struct pipe_sampler_view svTempl = {}; - svTempl.format = m_nxFmt; - svTempl.texture = m_gpuTex; - svTempl.u.tex.last_layer = layers - 1; - svTempl.u.tex.last_level = mips - 1; - svTempl.swizzle_r = PIPE_SWIZZLE_X; - svTempl.swizzle_g = PIPE_SWIZZLE_Y; - svTempl.swizzle_b = PIPE_SWIZZLE_Z; - svTempl.swizzle_a = PIPE_SWIZZLE_W; - m_gpuView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex, &svTempl); - } -public: - struct pipe_resource* m_gpuTex; - struct pipe_sampler_view* m_gpuView = nullptr; - void* m_sampler = nullptr; - ~NXTextureSA() - { - pipe_resource_reference(&m_gpuTex, nullptr); - pipe_sampler_view_reference(&m_gpuView, nullptr); - } - - void setClampMode(TextureClampMode mode) - { - m_clampMode = mode; - MakeSampler(m_ctx, m_sampler, mode, m_mips); - } - - TextureFormat format() const {return m_fmt;} - size_t layers() const {return m_layers;} -}; - -class NXTextureD : public GraphicsDataNode -{ - friend class NXDataFactory; - friend class NXCommandQueue; - NXCommandQueue* m_q; - size_t m_width; - size_t m_height; - TextureFormat m_fmt; - TextureClampMode m_clampMode; - std::unique_ptr m_stagingBuf; - size_t m_cpuSz; - pipe_format m_nxFmt; - int m_validSlots = 0; - NXTextureD(const boo::ObjToken& parent, NXCommandQueue* q, - size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); - - void update(int b); - -public: - struct pipe_resource* m_gpuTex[2]; - struct pipe_sampler_view* m_gpuView[2]; - void* m_sampler = nullptr; - ~NXTextureD() - { - for (int i = 0; i < 2; ++i) - { - pipe_resource_reference(&m_gpuTex[i], nullptr); - pipe_sampler_view_reference(&m_gpuView[i], nullptr); - } - } - - void setClampMode(TextureClampMode mode); - - void load(const void* data, size_t sz); - void* map(size_t sz); - void unmap(); - - TextureFormat format() const {return m_fmt;} -}; - -#define MAX_BIND_TEXS 4 - -static constexpr pipe_format ColorFormat = PIPE_FORMAT_R8G8B8A8_UNORM; -static constexpr pipe_format DepthFormat = PIPE_FORMAT_Z32_FLOAT; - -class NXTextureR : public GraphicsDataNode -{ - NXContext* m_ctx; - - friend class NXDataFactory; - friend struct NXCommandQueue; - size_t m_width = 0; - size_t m_height = 0; - unsigned m_samplesColor, m_samplesDepth; - - size_t m_colorBindCount; - size_t m_depthBindCount; - - void Setup(NXContext* ctx) - { - /* no-ops on first call */ - doDestroy(); - - /* color target */ - struct pipe_resource texTempl = {}; - texTempl.target = PIPE_TEXTURE_2D; - texTempl.format = ColorFormat; - texTempl.width0 = m_width; - texTempl.height0 = m_height; - texTempl.depth0 = 1; - texTempl.array_size = 1; - texTempl.nr_samples = texTempl.nr_storage_samples = m_samplesColor; - texTempl.bind = PIPE_BIND_RENDER_TARGET; - m_colorTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_colorTex) { - Log.report(logvisor::Fatal, "Failed to create color target texture"); - return; - } - - /* depth target */ - texTempl.format = DepthFormat; - texTempl.nr_samples = texTempl.nr_storage_samples = m_samplesDepth; - texTempl.bind = PIPE_BIND_DEPTH_STENCIL; - m_depthTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_depthTex) { - Log.report(logvisor::Fatal, "Failed to create depth target texture"); - return; - } - - texTempl.nr_samples = texTempl.nr_storage_samples = 1; - - for (size_t i=0 ; im_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_colorBindTex[i]) { - Log.report(logvisor::Fatal, "Failed to create color bind texture"); - return; - } - } - - for (size_t i=0 ; im_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_depthBindTex[i]) { - Log.report(logvisor::Fatal, "Failed to create depth bind texture"); - return; - } - } - - /* Create resource views */ - struct pipe_sampler_view svTempl = {}; - svTempl.format = ColorFormat; - svTempl.swizzle_r = PIPE_SWIZZLE_X; - svTempl.swizzle_g = PIPE_SWIZZLE_Y; - svTempl.swizzle_b = PIPE_SWIZZLE_Z; - svTempl.swizzle_a = PIPE_SWIZZLE_W; - svTempl.texture = m_colorTex; - m_colorView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_colorTex, &svTempl); - if (!m_colorView) { - Log.report(logvisor::Fatal, "Failed to create color sampler view"); - return; - } - - svTempl.format = DepthFormat; - svTempl.texture = m_depthTex; - m_depthView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_depthTex, &svTempl); - if (!m_depthView) { - Log.report(logvisor::Fatal, "Failed to create depth sampler view"); - return; - } - - svTempl.format = ColorFormat; - for (size_t i=0 ; im_pctx->create_sampler_view(ctx->m_pctx, m_colorBindTex[i], &svTempl); - if (!m_colorBindView[i]) { - Log.report(logvisor::Fatal, "Failed to create color bind sampler view"); - return; - } - } - - svTempl.format = DepthFormat; - for (size_t i=0 ; im_pctx->create_sampler_view(ctx->m_pctx, m_depthBindTex[i], &svTempl); - if (!m_depthBindView[i]) { - Log.report(logvisor::Fatal, "Failed to create depth bind sampler view"); - return; - } - } - - /* surfaces */ - struct pipe_surface surfTempl = {}; - surfTempl.format = ColorFormat; - m_colorSurface = ctx->m_pctx->create_surface(ctx->m_pctx, m_colorTex, &surfTempl); - if (!m_colorSurface) { - Log.report(logvisor::Fatal, "Failed to create color surface"); - return; - } - - surfTempl.format = DepthFormat; - m_depthSurface = ctx->m_pctx->create_surface(ctx->m_pctx, m_depthTex, &surfTempl); - if (!m_depthSurface) { - Log.report(logvisor::Fatal, "Failed to create depth surface"); - return; - } - - /* framebuffer */ - m_framebuffer.width = uint16_t(m_width); - m_framebuffer.height = uint16_t(m_height); - m_framebuffer.nr_cbufs = 1; - m_framebuffer.cbufs[0] = m_colorSurface; - m_framebuffer.zsbuf = m_depthSurface; - } - - NXTextureR(const boo::ObjToken& parent, NXContext* ctx, - size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount) - : GraphicsDataNode(parent), m_ctx(ctx) - { - if (colorBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many color bindings for render texture"); - if (depthBindCount > MAX_BIND_TEXS) - Log.report(logvisor::Fatal, "too many depth bindings for render texture"); - - if (m_samplesColor == 0) m_samplesColor = 1; - if (m_samplesDepth == 0) m_samplesDepth = 1; - setClampMode(clampMode); - Setup(ctx); - } -public: - struct pipe_resource* m_colorTex; - struct pipe_sampler_view* m_colorView = nullptr; - - struct pipe_resource* m_depthTex; - struct pipe_sampler_view* m_depthView = nullptr; - - struct pipe_resource* m_colorBindTex[MAX_BIND_TEXS] = {}; - struct pipe_sampler_view* m_colorBindView[MAX_BIND_TEXS] = {}; - - struct pipe_resource* m_depthBindTex[MAX_BIND_TEXS] = {}; - struct pipe_sampler_view* m_depthBindView[MAX_BIND_TEXS] = {}; - - struct pipe_surface* m_colorSurface = nullptr; - struct pipe_surface* m_depthSurface = nullptr; - - void* m_sampler = nullptr; - - struct pipe_framebuffer_state m_framebuffer = {}; - - void setClampMode(TextureClampMode mode) - { - MakeSampler(m_ctx, m_sampler, mode, 1); - } - - void doDestroy() - { - pipe_resource_reference(&m_colorTex, nullptr); - pipe_sampler_view_reference(&m_colorView, nullptr); - - pipe_resource_reference(&m_depthTex, nullptr); - pipe_sampler_view_reference(&m_depthView, nullptr); - - for (size_t i = 0; i < MAX_BIND_TEXS; ++i) - { - pipe_resource_reference(&m_colorBindTex[i], nullptr); - pipe_sampler_view_reference(&m_colorBindView[i], nullptr); - - pipe_resource_reference(&m_depthBindTex[i], nullptr); - pipe_sampler_view_reference(&m_depthBindView[i], nullptr); - } - - pipe_surface_reference(&m_colorSurface, nullptr); - pipe_surface_reference(&m_depthSurface, nullptr); - } - - ~NXTextureR() - { - doDestroy(); - } - - void resize(NXContext* ctx, size_t width, size_t height) - { - if (width < 1) - width = 1; - if (height < 1) - height = 1; - m_width = width; - m_height = height; - Setup(ctx); - } -}; - -static const size_t SEMANTIC_SIZE_TABLE[] = - { - 0, - 12, - 16, - 12, - 16, - 16, - 4, - 8, - 16, - 16, - 16 - }; - -static const pipe_format SEMANTIC_TYPE_TABLE[] = -{ - PIPE_FORMAT_NONE, - PIPE_FORMAT_R32G32B32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT, - PIPE_FORMAT_R32G32B32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT, - PIPE_FORMAT_R8G8B8A8_UNORM, - PIPE_FORMAT_R32G32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT, - PIPE_FORMAT_R32G32B32A32_FLOAT -}; - -struct NXVertexFormat -{ - void* m_vtxElem; - size_t m_stride = 0; - size_t m_instStride = 0; - - NXVertexFormat(NXContext* ctx, const VertexFormatInfo& info) - { - std::unique_ptr attributes(new pipe_vertex_element[info.elementCount]); - for (size_t i = 0; i < info.elementCount; ++i) - { - const VertexElementDescriptor* elemin = &info.elements[i]; - pipe_vertex_element& attribute = attributes[i]; - int semantic = int(elemin->semantic & boo::VertexSemantic::SemanticMask); - attribute.src_format = SEMANTIC_TYPE_TABLE[semantic]; - if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) - { - attribute.vertex_buffer_index = 1; - attribute.instance_divisor = 1; - attribute.src_offset = m_instStride; - m_instStride += SEMANTIC_SIZE_TABLE[semantic]; - } - else - { - attribute.vertex_buffer_index = 0; - attribute.instance_divisor = 0; - attribute.src_offset = m_stride; - m_stride += SEMANTIC_SIZE_TABLE[semantic]; - } - } - - uint64_t key = XXH64(attributes.get(), sizeof(pipe_vertex_element) * info.elementCount, 0); - auto search = ctx->m_vtxElemStates.find(key); - if (search != ctx->m_vtxElemStates.end()) - { - m_vtxElem = search->second; - return; - } - m_vtxElem = ctx->m_pctx->create_vertex_elements_state(ctx->m_pctx, info.elementCount, attributes.get()); - ctx->m_vtxElemStates[key] = m_vtxElem; - } -}; - -static const pipe_prim_type PRIMITIVE_TABLE[] = -{ - PIPE_PRIM_TRIANGLES, - PIPE_PRIM_TRIANGLE_STRIP, - PIPE_PRIM_PATCHES -}; - -static const nx_shader_stage SHADER_TYPE_TABLE[] = -{ - nx_shader_stage::NONE, - nx_shader_stage::VERTEX, - nx_shader_stage::FRAGMENT, - nx_shader_stage::GEOMETRY, - nx_shader_stage::TESS_CTRL, - nx_shader_stage::TESS_EVAL, -}; - -class NXShaderStage : public GraphicsDataNode -{ - friend class NXDataFactory; - nx_shader_stage_object m_obj; - NXShaderStage(const boo::ObjToken& parent, NXContext* ctx, - const uint8_t* data, size_t size, PipelineStage stage) - : GraphicsDataNode(parent), - m_obj(ctx->m_compiler.compile(SHADER_TYPE_TABLE[int(stage)], (char*)data)) - { - if (!m_obj) - Log.report(logvisor::Fatal, "Shader compile fail:\n%s\n", m_obj.info_log()); - } -public: - const nx_shader_stage_object* shader() const { return &m_obj; } -}; - -static const unsigned BLEND_FACTOR_TABLE[] = -{ - PIPE_BLENDFACTOR_ZERO, - PIPE_BLENDFACTOR_ONE, - PIPE_BLENDFACTOR_SRC_COLOR, - PIPE_BLENDFACTOR_INV_SRC_COLOR, - PIPE_BLENDFACTOR_DST_COLOR, - PIPE_BLENDFACTOR_INV_DST_COLOR, - PIPE_BLENDFACTOR_SRC_ALPHA, - PIPE_BLENDFACTOR_INV_SRC_ALPHA, - PIPE_BLENDFACTOR_DST_ALPHA, - PIPE_BLENDFACTOR_INV_DST_ALPHA, - PIPE_BLENDFACTOR_SRC1_COLOR, - PIPE_BLENDFACTOR_INV_SRC1_COLOR -}; - -static void MakeBlendState(NXContext* ctx, void*& bsOut, const AdditionalPipelineInfo& info) -{ - uint32_t key = (uint32_t(info.srcFac) << 16) | (uint32_t(info.dstFac) << 3) | - info.colorWrite << 2 | info.alphaWrite << 1 | info.overwriteAlpha; - auto search = ctx->m_blendStates.find(key); - if (search != ctx->m_blendStates.end()) - { - bsOut = search->second; - return; - } - - pipe_blend_state bs = {}; - bs.rt->blend_enable = info.srcFac != BlendFactor::One || info.dstFac != BlendFactor::Zero; - if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) - { - bs.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - bs.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; - bs.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT; - if (info.overwriteAlpha) - { - bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - bs.rt[0].alpha_func = PIPE_BLEND_ADD; - } - else - { - bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; - bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; - bs.rt[0].alpha_func = PIPE_BLEND_REVERSE_SUBTRACT; - } - } - else - { - bs.rt[0].rgb_src_factor = BLEND_FACTOR_TABLE[int(info.srcFac)]; - bs.rt[0].rgb_dst_factor = BLEND_FACTOR_TABLE[int(info.dstFac)]; - bs.rt[0].rgb_func = PIPE_BLEND_ADD; - if (info.overwriteAlpha) - { - bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; - bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; - } - else - { - bs.rt[0].alpha_src_factor = BLEND_FACTOR_TABLE[int(info.srcFac)]; - bs.rt[0].alpha_dst_factor = BLEND_FACTOR_TABLE[int(info.dstFac)]; - } - bs.rt[0].alpha_func = PIPE_BLEND_ADD; - } - - bs.rt[0].colormask = - (info.colorWrite ? (PIPE_MASK_R | - PIPE_MASK_G | - PIPE_MASK_B) : 0) | - (info.alphaWrite ? PIPE_MASK_A : 0); - - bsOut = ctx->m_pctx->create_blend_state(ctx->m_pctx, &bs); - ctx->m_blendStates[key] = bsOut; -} - -static void MakeRasterizerState(NXContext* ctx, void*& rasOut, const AdditionalPipelineInfo& info) -{ - uint32_t key = uint32_t(info.culling); - auto search = ctx->m_rasStates.find(key); - if (search != ctx->m_rasStates.end()) - { - rasOut = search->second; - return; - } - - pipe_rasterizer_state ras = {}; - ras.clamp_fragment_color = 1; - ras.front_ccw = 1; - switch (info.culling) - { - case CullMode::None: - default: - ras.cull_face = PIPE_FACE_NONE; - break; - case CullMode::Backface: - ras.cull_face = PIPE_FACE_BACK; - break; - case CullMode::Frontface: - ras.cull_face = PIPE_FACE_FRONT; - break; - } - ras.scissor = 1; - ras.multisample = unsigned(ctx->m_sampleCount > 1); - ras.half_pixel_center = 1; - ras.bottom_edge_rule = 1; - ras.depth_clip_near = 1; - ras.depth_clip_far = 1; - - rasOut = ctx->m_pctx->create_rasterizer_state(ctx->m_pctx, &ras); - ctx->m_rasStates[key] = rasOut; -} - -static void MakeDepthStencilState(NXContext* ctx, void*& dsOut, const AdditionalPipelineInfo& info) -{ - uint32_t key = (uint32_t(info.depthTest) << 16) | info.depthWrite; - auto search = ctx->m_dsStates.find(key); - if (search != ctx->m_dsStates.end()) - { - dsOut = search->second; - return; - } - - pipe_depth_stencil_alpha_state ds = {}; - ds.depth.enabled = info.depthTest != ZTest::None; - ds.depth.writemask = info.depthWrite; - switch (info.depthTest) - { - case ZTest::None: - default: - ds.depth.func = PIPE_FUNC_ALWAYS; - break; - case ZTest::LEqual: - ds.depth.func = PIPE_FUNC_LEQUAL; - break; - case ZTest::Greater: - ds.depth.func = PIPE_FUNC_GREATER; - break; - case ZTest::Equal: - ds.depth.func = PIPE_FUNC_EQUAL; - break; - case ZTest::GEqual: - ds.depth.func = PIPE_FUNC_GEQUAL; - break; - } - - dsOut = ctx->m_pctx->create_depth_stencil_alpha_state(ctx->m_pctx, &ds); - ctx->m_dsStates[key] = dsOut; -} - -class NXShaderPipeline : public GraphicsDataNode -{ -protected: - friend class NXDataFactory; - friend struct NXShaderDataBinding; - NXVertexFormat m_vtxFmt; - nx_linked_shader m_shader; - Primitive m_prim; - pipe_prim_type m_nxPrim; - uint32_t m_patchSize; - - void* m_blendState; - void* m_rasState; - void* m_dsState; - - NXShaderPipeline(const boo::ObjToken& parent, - NXContext* ctx, - ObjToken vertex, - ObjToken fragment, - ObjToken geometry, - ObjToken control, - ObjToken evaluation, - const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& info) - : GraphicsDataNode(parent), - m_vtxFmt(ctx, vtxFmt), m_prim(info.prim), m_patchSize(info.patchSize) - { - m_nxPrim = PRIMITIVE_TABLE[int(m_prim)]; - MakeBlendState(ctx, m_blendState, info); - MakeRasterizerState(ctx, m_rasState, info); - MakeDepthStencilState(ctx, m_dsState, info); - - const nx_shader_stage_object* stages[5]; - unsigned numStages = 0; - if (vertex) - stages[numStages++] = vertex.cast()->shader(); - if (control) - stages[numStages++] = control.cast()->shader(); - if (evaluation) - stages[numStages++] = evaluation.cast()->shader(); - if (geometry) - stages[numStages++] = geometry.cast()->shader(); - if (fragment) - stages[numStages++] = fragment.cast()->shader(); - std::string infoLog; - m_shader = ctx->m_compiler.link(numStages, stages, &infoLog); - if (!m_shader) - Log.report(logvisor::Fatal, "Unable to link shader:\n%s\n", infoLog.c_str()); - } -public: - NXShaderPipeline& operator=(const NXShaderPipeline&) = delete; - NXShaderPipeline(const NXShaderPipeline&) = delete; - void bind(struct pipe_context* pctx) const - { - const struct gl_shader_program* prog = m_shader.program(); - if (gl_linked_shader* fs = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]) - { - struct st_fragment_program* p = (struct st_fragment_program*)fs->Program; - pctx->bind_fs_state(pctx, p->variants->driver_shader); - } - if (gl_linked_shader* gs = prog->_LinkedShaders[MESA_SHADER_GEOMETRY]) - { - struct st_common_program* p = (struct st_common_program*)gs->Program; - pctx->bind_gs_state(pctx, p->variants->driver_shader); - } - if (gl_linked_shader* tes = prog->_LinkedShaders[MESA_SHADER_TESS_EVAL]) - { - struct st_common_program* p = (struct st_common_program*)tes->Program; - pctx->bind_tes_state(pctx, p->variants->driver_shader); - } - if (gl_linked_shader* tcs = prog->_LinkedShaders[MESA_SHADER_TESS_CTRL]) - { - struct st_common_program* p = (struct st_common_program*)tcs->Program; - pctx->bind_tcs_state(pctx, p->variants->driver_shader); - } - if (gl_linked_shader* vs = prog->_LinkedShaders[MESA_SHADER_VERTEX]) - { - struct st_vertex_program* p = (struct st_vertex_program*)vs->Program; - pctx->bind_vs_state(pctx, p->variants->driver_shader); - } - - pctx->bind_blend_state(pctx, m_blendState); - pctx->bind_rasterizer_state(pctx, m_rasState); - pctx->bind_depth_stencil_alpha_state(pctx, m_dsState); - } -}; - -static const nx_buffer_info* GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) -{ - if (buf->dynamic()) - { - const NXGraphicsBufferD* cbuf = - static_cast*>(buf); - return &cbuf->m_bufferInfo[idx]; - } - else - { - const NXGraphicsBufferS* cbuf = static_cast(buf); - return &cbuf->m_bufferInfo; - } -} - -static const struct pipe_sampler_view* GetTextureGPUResource( - const ITexture* tex, int idx, int bindIdx, bool depth, void*& samplerOut) -{ - switch (tex->type()) - { - case TextureType::Dynamic: - { - const NXTextureD* ctex = static_cast(tex); - samplerOut = ctex->m_sampler; - return ctex->m_gpuView[idx]; - } - case TextureType::Static: - { - const NXTextureS* ctex = static_cast(tex); - samplerOut = ctex->m_sampler; - return ctex->m_gpuView; - } - case TextureType::StaticArray: - { - const NXTextureSA* ctex = static_cast(tex); - samplerOut = ctex->m_sampler; - return ctex->m_gpuView; - } - case TextureType::Render: - { - const NXTextureR* ctex = static_cast(tex); - samplerOut = ctex->m_sampler; - return depth ? ctex->m_depthBindView[bindIdx] : ctex->m_colorBindView[bindIdx]; - } - default: break; - } - return nullptr; -} - -struct NXShaderDataBinding : GraphicsDataNode -{ - NXContext* m_ctx; - boo::ObjToken m_pipeline; - boo::ObjToken m_vbuf; - boo::ObjToken m_instVbuf; - boo::ObjToken m_ibuf; - std::vector> m_ubufs; - std::vector> m_ubufOffs; - struct BindTex - { - boo::ObjToken tex; - int idx; - bool depth; - }; - std::vector m_texs; - - struct pipe_vertex_buffer m_vboBufs[2][2] = {{},{}}; - std::vector> m_ubufBinds[MESA_SHADER_STAGES]; - - size_t m_vertOffset; - size_t m_instOffset; - -#ifndef NDEBUG - /* Debugging aids */ - bool m_committed = false; -#endif - - NXShaderDataBinding(const boo::ObjToken& d, - NXDataFactoryImpl& factory, - const boo::ObjToken& pipeline, - const boo::ObjToken& vbuf, - const boo::ObjToken& instVbuf, - const boo::ObjToken& ibuf, - size_t ubufCount, const boo::ObjToken* ubufs, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* depthBinds, - size_t baseVert, size_t baseInst) - : GraphicsDataNode(d), - m_ctx(factory.m_ctx), - m_pipeline(pipeline), - m_vbuf(vbuf), - m_instVbuf(instVbuf), - m_ibuf(ibuf) - { - NXShaderPipeline* cpipeline = m_pipeline.cast(); - NXVertexFormat& vtxFmt = cpipeline->m_vtxFmt; - m_vertOffset = baseVert * vtxFmt.m_stride; - m_instOffset = baseInst * vtxFmt.m_instStride; - - m_ubufs.reserve(ubufCount); - if (ubufOffs && ubufSizes) - m_ubufOffs.reserve(ubufCount); - for (size_t i=0 ; im_pctx; - - for (int i = 0; i < 2; ++i) - { - if (m_vbuf) - { - m_vboBufs[i][0] = GetBufferGPUResource(m_vbuf.get(), i)->v; - m_vboBufs[i][0].buffer_offset += m_vertOffset; - } - if (m_instVbuf) - { - m_vboBufs[i][1] = GetBufferGPUResource(m_instVbuf.get(), i)->v; - m_vboBufs[i][1].buffer_offset += m_instOffset; - } - } - - NXShaderPipeline* cpipeline = m_pipeline.cast(); - const struct gl_shader_program* program = cpipeline->m_shader.program(); - for (uint i = 0; i < MESA_SHADER_STAGES; ++i) - { - if (const struct gl_linked_shader* lsh = program->_LinkedShaders[i]) - { - std::vector>& bindings = m_ubufBinds[i]; - const struct gl_shader_program_data* data = lsh->Program->sh.data; - bindings.reserve(data->NumUniformBlocks); - for (uint j = 0; j < data->NumUniformBlocks; ++j) - { - const struct gl_uniform_block* block = &data->UniformBlocks[j]; - assert(block->Binding < m_ubufs.size() && "Uniform binding oob"); - bindings.emplace_back(); - for (int k = 0; k < 2; ++k) - { - struct pipe_constant_buffer& bufBind = bindings.back()[k]; - const nx_buffer_info* buf = GetBufferGPUResource(m_ubufs[block->Binding].get(), k); - bufBind = buf->c; - if (!m_ubufOffs.empty()) - { - bufBind.buffer_offset += m_ubufOffs[block->Binding][0]; - bufBind.buffer_size = unsigned(m_ubufOffs[block->Binding][1]); - } - } - } - } - } - -#ifndef NDEBUG - m_committed = true; -#endif - } - - void bind(int b) - { -#ifndef NDEBUG - if (!m_committed) - Log.report(logvisor::Fatal, - "attempted to use uncommitted NXShaderDataBinding"); -#endif - struct pipe_context* pctx = m_ctx->m_pctx; - - NXShaderPipeline* pipeline = m_pipeline.cast(); - pipeline->bind(pctx); - const struct gl_shader_program* program = pipeline->m_shader.program(); - for (uint i = 0; i < MESA_SHADER_STAGES; ++i) - { - uint j = 0; - for (const auto& bind : m_ubufBinds[i]) - pctx->set_constant_buffer(pctx, pipe_shader_type(i), j++, &bind[b]); - - if (const struct gl_linked_shader* lsh = program->_LinkedShaders[i]) - { - void* samplers[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; - struct pipe_sampler_view* samplerViews[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; - unsigned numSamplers = 0; - const struct gl_program* stprogram = lsh->Program; - for (int t = 0; t < BOO_GLSL_MAX_TEXTURE_COUNT; ++t) - { - if (stprogram->SamplersUsed & (1 << t)) - { - GLubyte unit = GLubyte(stprogram->SamplerUnits[t] - BOO_GLSL_MAX_UNIFORM_COUNT); - assert(unit < m_texs.size() && "Texture binding oob"); - const BindTex& tex = m_texs[unit]; - samplerViews[numSamplers] = (pipe_sampler_view*) - GetTextureGPUResource(tex.tex.get(), t, tex.idx, tex.depth, samplers[numSamplers]); - ++numSamplers; - } - } - pctx->bind_sampler_states(pctx, pipe_shader_type(i), 0, numSamplers, samplers); - pctx->set_sampler_views(pctx, pipe_shader_type(i), 0, numSamplers, samplerViews); - } - } - - if (m_vbuf && m_instVbuf) - pctx->set_vertex_buffers(pctx, 0, 2, m_vboBufs[b]); - else if (m_vbuf) - pctx->set_vertex_buffers(pctx, 0, 1, m_vboBufs[b]); - else if (m_instVbuf) - pctx->set_vertex_buffers(pctx, 1, 1, &m_vboBufs[b][1]); - } - - pipe_prim_type getPrimitive() const { return m_pipeline.cast()->m_nxPrim; } - uint32_t getPatchVerts() const { return m_pipeline.cast()->m_patchSize; } - struct pipe_resource* getIndexBuf(int b) const { return GetBufferGPUResource(m_ibuf.get(), b)->v.buffer.resource; } -}; - -struct NXCommandQueue : IGraphicsCommandQueue -{ - Platform platform() const {return IGraphicsDataFactory::Platform::Vulkan;} - const SystemChar* platformName() const {return _SYS_STR("NX");} - NXContext* m_ctx; - IGraphicsContext* m_parent; - - bool m_running = true; - - int m_fillBuf = 0; - int m_drawBuf = 0; - - std::vector> m_drawResTokens[2]; - - NXCommandQueue(NXContext* ctx, IGraphicsContext* parent) - : m_ctx(ctx), m_parent(parent) - { - } - - void startRenderer() - { - static_cast(m_parent->getDataFactory())->SetupGammaResources(); - } - - void stopRenderer() - { - m_running = false; - static_cast(m_parent->getDataFactory())->DestroyGammaResources(); - m_drawResTokens[0].clear(); - m_drawResTokens[1].clear(); - m_boundTarget.reset(); - m_resolveDispSource.reset(); - } - - ~NXCommandQueue() - { - if (m_running) - stopRenderer(); - } - - boo::ObjToken m_curSDBinding; - void setShaderDataBinding(const boo::ObjToken& binding) - { - m_curSDBinding = binding; - NXShaderDataBinding* cbind = binding.cast(); - cbind->bind(m_fillBuf); - m_drawResTokens[m_fillBuf].push_back(binding.get()); - } - - boo::ObjToken m_boundTarget; - void setRenderTarget(const boo::ObjToken& target) - { - NXTextureR* ctarget = target.cast(); - - if (m_boundTarget.get() != ctarget) - { - m_boundTarget = target; - m_drawResTokens[m_fillBuf].push_back(target.get()); - } - - m_ctx->m_pctx->set_framebuffer_state(m_ctx->m_pctx, &ctarget->m_framebuffer); - } - - void setViewport(const SWindowRect& rect, float znear, float zfar) - { - if (m_boundTarget) - { - NXTextureR* ctarget = m_boundTarget.cast(); - - struct gl_context* ctx = m_ctx->m_st->ctx; - ctx->ViewportArray[0].X = float(rect.location[0]); - ctx->ViewportArray[0].Y = float(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])); - ctx->ViewportArray[0].Width = float(rect.size[0]); - ctx->ViewportArray[0].Height = float(rect.size[1]); - ctx->ViewportArray[0].Near = znear; - ctx->ViewportArray[0].Far = zfar; - - pipe_viewport_state vp = {}; - _mesa_get_viewport_xform(ctx, 0, vp.scale, vp.translate); - m_ctx->m_pctx->set_viewport_states(m_ctx->m_pctx, 0, 1, &vp); - } - } - - void setScissor(const SWindowRect& rect) - { - if (m_boundTarget) - { - NXTextureR* ctarget = m_boundTarget.cast(); - - pipe_scissor_state scissor = {}; - scissor.minx = unsigned(rect.location[0]); - scissor.miny = unsigned(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])); - scissor.maxx = scissor.minx + unsigned(rect.size[0]); - scissor.maxy = scissor.miny + unsigned(rect.size[1]); - - m_ctx->m_pctx->set_scissor_states(m_ctx->m_pctx, 0, 1, &scissor); - } - } - - std::unordered_map> m_texResizes; - void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) - { - NXTextureR* ctex = tex.cast(); - m_texResizes[ctex] = std::make_pair(width, height); - m_drawResTokens[m_fillBuf].push_back(tex.get()); - } - - void schedulePostFrameHandler(std::function&& func) - { - func(); - } - - float m_clearColor[4] = {0.0,0.0,0.0,0.0}; - void setClearColor(const float rgba[4]) - { - m_clearColor[0] = rgba[0]; - m_clearColor[1] = rgba[1]; - m_clearColor[2] = rgba[2]; - m_clearColor[3] = rgba[3]; - } - - void clearTarget(bool render=true, bool depth=true) - { - if (!m_boundTarget) - return; - unsigned buffers = 0; - if (render) - buffers |= PIPE_CLEAR_COLOR0; - if (depth) - buffers |= PIPE_CLEAR_DEPTH; - pipe_color_union cunion; - for (int i = 0; i < 4; ++i) - cunion.f[i] = m_clearColor[i]; - m_ctx->m_pctx->clear(m_ctx->m_pctx, buffers, &cunion, 1.f, 0); - } - - void draw(size_t start, size_t count) - { - pipe_draw_info info = {}; - NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); - info.mode = sdBinding->getPrimitive(); - info.vertices_per_patch = sdBinding->getPatchVerts(); - info.start = start; - info.count = count; - m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); - } - - void drawIndexed(size_t start, size_t count) - { - pipe_draw_info info = {}; - NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); - info.index_size = 4; - info.mode = sdBinding->getPrimitive(); - info.primitive_restart = 1; - info.vertices_per_patch = sdBinding->getPatchVerts(); - info.start = start; - info.count = count; - info.restart_index = 0xffffffff; - info.index.resource = sdBinding->getIndexBuf(m_fillBuf); - m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); - } - - void drawInstances(size_t start, size_t count, size_t instCount) - { - pipe_draw_info info = {}; - NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); - info.mode = sdBinding->getPrimitive(); - info.vertices_per_patch = sdBinding->getPatchVerts(); - info.start = start; - info.count = count; - info.instance_count = instCount; - m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); - } - - void drawInstancesIndexed(size_t start, size_t count, size_t instCount) - { - pipe_draw_info info = {}; - NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); - info.index_size = 4; - info.mode = sdBinding->getPrimitive(); - info.primitive_restart = 1; - info.vertices_per_patch = sdBinding->getPatchVerts(); - info.start = start; - info.count = count; - info.instance_count = instCount; - info.restart_index = 0xffffffff; - info.index.resource = sdBinding->getIndexBuf(m_fillBuf); - m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); - } - - boo::ObjToken m_resolveDispSource; - void resolveDisplay(const boo::ObjToken& source) - { - m_resolveDispSource = source; - } - - bool _resolveDisplay() - { - if (!m_resolveDispSource) - return false; - - NXTextureR* csource = m_resolveDispSource.cast(); -#ifndef NDEBUG - if (!csource->m_colorBindCount) - Log.report(logvisor::Fatal, - "texture provided to resolveDisplay() must have at least 1 color binding"); -#endif - - struct pipe_surface* backBuf = m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT]; - - NXDataFactoryImpl* dataFactory = static_cast(m_parent->getDataFactory()); - if (dataFactory->m_gamma != 1.f) - { - SWindowRect rect(0, 0, csource->m_width, csource->m_height); - _resolveBindTexture(csource, rect, true, 0, true, false); - NXShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); - - pipe_framebuffer_state fstate = {}; - fstate.width = backBuf->texture->width0; - fstate.height = backBuf->texture->height0; - fstate.nr_cbufs = 1; - fstate.cbufs[0] = backBuf; - m_ctx->m_pctx->set_framebuffer_state(m_ctx->m_pctx, &fstate); - - gammaBinding->m_texs[0].tex = m_resolveDispSource.get(); - gammaBinding->bind(m_drawBuf); - pipe_draw_info info = {}; - info.mode = PIPE_PRIM_TRIANGLE_STRIP; - info.start = 0; - info.count = 4; - info.instance_count = 1; - m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); - gammaBinding->m_texs[0].tex.reset(); - } - else - { - pipe_blit_info binfo = {}; - binfo.src.resource = csource->m_colorTex; - binfo.dst.resource = backBuf->texture; - u_box_2d(0, 0, csource->m_width, csource->m_height, &binfo.src.box); - binfo.dst.box = binfo.src.box; - binfo.src.format = binfo.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM; - binfo.mask = PIPE_MASK_RGBA; - binfo.filter = PIPE_TEX_FILTER_NEAREST; - m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); - } - - m_resolveDispSource.reset(); - return true; - } - - void _resolveBindTexture(NXTextureR* ctexture, - const SWindowRect& rect, bool tlOrigin, - int bindIdx, bool color, bool depth) - { - SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); - - if (color && ctexture->m_colorBindCount) - { - pipe_blit_info binfo = {}; - binfo.src.resource = ctexture->m_colorTex; - binfo.dst.resource = ctexture->m_colorBindTex[bindIdx]; - u_box_2d(intersectRect.location[0], - tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]), - intersectRect.size[0], intersectRect.size[1], &binfo.src.box); - binfo.dst.box = binfo.src.box; - binfo.src.format = binfo.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM; - binfo.mask = PIPE_MASK_RGBA; - binfo.filter = PIPE_TEX_FILTER_NEAREST; - m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); - } - - if (depth && ctexture->m_depthBindCount) - { - pipe_blit_info binfo = {}; - binfo.src.resource = ctexture->m_depthTex; - binfo.dst.resource = ctexture->m_depthBindTex[bindIdx]; - u_box_2d(intersectRect.location[0], - tlOrigin ? intersectRect.location[1] : - (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]), - intersectRect.size[0], intersectRect.size[1], &binfo.src.box); - binfo.dst.box = binfo.src.box; - binfo.src.format = binfo.dst.format = PIPE_FORMAT_Z32_FLOAT; - binfo.mask = PIPE_MASK_Z; - binfo.filter = PIPE_TEX_FILTER_NEAREST; - m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); - } - } - - void resolveBindTexture(const boo::ObjToken& texture, - const SWindowRect& rect, bool tlOrigin, - int bindIdx, bool color, bool depth, bool clearDepth) - { - NXTextureR* ctexture = texture.cast(); - _resolveBindTexture(ctexture, rect, tlOrigin, bindIdx, color, depth); - if (clearDepth) - m_ctx->m_pctx->clear(m_ctx->m_pctx, PIPE_CLEAR_DEPTH, nullptr, 1.f, 0); - } - - void execute(); -}; - -NXDataFactory::Context::Context(NXDataFactory& parent __BooTraceArgs) -: m_parent(parent), m_data(new NXData(static_cast(parent) __BooTraceArgsUse)) {} -NXDataFactory::Context::~Context() {} - -boo::ObjToken -NXDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXGraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; -} - -boo::ObjToken -NXDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXGraphicsBufferD(m_data, use, factory.m_ctx, stride, count)}; -} - -boo::ObjToken -NXDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, - TextureClampMode clampMode, const void* data, size_t sz) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXTextureS(m_data, factory.m_ctx, width, height, mips, fmt, clampMode, data, sz)}; -} - -boo::ObjToken -NXDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, - TextureFormat fmt, TextureClampMode clampMode, - const void* data, size_t sz) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXTextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, clampMode, data, sz)}; -} - -boo::ObjToken -NXDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - NXCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); - return {new NXTextureD(m_data, q, width, height, fmt, clampMode)}; -} - -boo::ObjToken -NXDataFactory::Context::newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, - size_t colorBindCount, size_t depthBindCount) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXTextureR(m_data, factory.m_ctx, width, height, clampMode, colorBindCount, depthBindCount)}; -} - -ObjToken -NXDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXShaderStage(m_data, factory.m_ctx, data, size, stage)}; -} - -ObjToken -NXDataFactory::Context::newShaderPipeline(ObjToken vertex, ObjToken fragment, - ObjToken geometry, ObjToken control, - ObjToken evaluation, const VertexFormatInfo& vtxFmt, - const AdditionalPipelineInfo& info) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXShaderPipeline(m_data, factory.m_ctx, vertex, fragment, geometry, control, evaluation, vtxFmt, info)}; -} - -boo::ObjToken -NXDataFactory::Context::newShaderDataBinding(const boo::ObjToken& pipeline, - const boo::ObjToken& vbo, - const boo::ObjToken& instVbo, - const boo::ObjToken& ibo, - size_t ubufCount, const boo::ObjToken* ubufs, const PipelineStage* ubufStages, - const size_t* ubufOffs, const size_t* ubufSizes, - size_t texCount, const boo::ObjToken* texs, - const int* bindIdxs, const bool* bindDepth, - size_t baseVert, size_t baseInst) -{ - NXDataFactoryImpl& factory = static_cast(m_parent); - return {new NXShaderDataBinding(m_data, factory, pipeline, vbo, instVbo, ibo, ubufCount, ubufs, ubufOffs, - ubufSizes, texCount, texs, bindIdxs, bindDepth, baseVert, baseInst)}; -} - -NXTextureD::NXTextureD(const boo::ObjToken& parent, NXCommandQueue* q, - size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode) -: GraphicsDataNode(parent), m_q(q), m_width(width), m_height(height), - m_fmt(fmt), m_clampMode(clampMode) -{ - NXContext* ctx = m_q->m_ctx; +class NXTextureS : public GraphicsDataNode { + friend class NXDataFactory; + NXContext* m_ctx; + TextureFormat m_fmt; + size_t m_sz; + size_t m_width, m_height, m_mips; + TextureClampMode m_clampMode; + pipe_format m_nxFmt; + int m_pixelPitchNum = 1; + int m_pixelPitchDenom = 1; + + NXTextureS(const boo::ObjToken& parent, NXContext* ctx, size_t width, size_t height, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_fmt(fmt) + , m_sz(sz) + , m_width(width) + , m_height(height) + , m_mips(mips) + , m_clampMode(clampMode) { pipe_format pfmt; - switch (fmt) - { + switch (fmt) { case TextureFormat::RGBA8: - pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; - m_cpuSz = width * height * 4; - break; + pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; + m_pixelPitchNum = 4; + break; case TextureFormat::I8: - pfmt = PIPE_FORMAT_R8_UNORM; - m_cpuSz = width * height; - break; + pfmt = PIPE_FORMAT_R8_UNORM; + break; case TextureFormat::I16: - pfmt = PIPE_FORMAT_R16_UNORM; - m_cpuSz = width * height * 2; - break; + pfmt = PIPE_FORMAT_R16_UNORM; + m_pixelPitchNum = 2; + break; + case TextureFormat::DXT1: + pfmt = PIPE_FORMAT_DXT1_RGBA; + m_pixelPitchNum = 1; + m_pixelPitchDenom = 2; + break; default: - Log.report(logvisor::Fatal, "unsupported tex format"); + Log.report(logvisor::Fatal, "unsupported tex format"); } m_nxFmt = pfmt; - m_stagingBuf.reset(new uint8_t[m_cpuSz]); struct pipe_resource texTempl = {}; texTempl.target = PIPE_TEXTURE_2D; @@ -1782,392 +322,1569 @@ NXTextureD::NXTextureD(const boo::ObjToken& parent, NXCommandQ texTempl.width0 = width; texTempl.height0 = height; texTempl.depth0 = 1; + texTempl.last_level = mips - 1; texTempl.array_size = 1; texTempl.bind = PIPE_BIND_SAMPLER_VIEW; - for (int i = 0; i < 2; ++i) - { - m_gpuTex[i] = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); - if (!m_gpuTex[i]) { - Log.report(logvisor::Fatal, "Failed to create texture"); - return; - } + m_gpuTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_gpuTex) { + Log.report(logvisor::Fatal, "Failed to create texture"); + return; + } + + uint blockSize = util_format_get_blocksize(m_nxFmt); + uint8_t* ptr = (uint8_t*)data; + for (int i = 0; i < mips; ++i) { + size_t regionPitch = width * height * m_pixelPitchNum / m_pixelPitchDenom; + size_t rowStride = width * blockSize; + size_t imageBytes = rowStride * height; + + struct pipe_box box; + u_box_2d(0, 0, width, height, &box); + + ctx->m_pctx->texture_subdata(ctx->m_pctx, m_gpuTex, i, PIPE_TRANSFER_WRITE, &box, ptr, rowStride, imageBytes); + + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + ptr += regionPitch; } struct pipe_sampler_view svTempl = {}; svTempl.format = m_nxFmt; + svTempl.texture = m_gpuTex; + svTempl.u.tex.last_level = mips - 1; svTempl.swizzle_r = PIPE_SWIZZLE_X; svTempl.swizzle_g = PIPE_SWIZZLE_Y; svTempl.swizzle_b = PIPE_SWIZZLE_Z; svTempl.swizzle_a = PIPE_SWIZZLE_W; - for (int i = 0; i < 2; ++i) - { - svTempl.texture = m_gpuTex[i]; - m_gpuView[i] = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex[i], &svTempl); - } -} + m_gpuView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex, &svTempl); + } -void NXTextureD::update(int b) -{ - int slot = 1 << b; - if ((slot & m_validSlots) == 0) - { - NXContext* ctx = m_q->m_ctx; - uint blockSize = util_format_get_blocksize(m_nxFmt); - uint8_t* ptr = m_stagingBuf.get(); - size_t rowStride = m_width * blockSize; - size_t imageBytes = rowStride * m_height; +public: + struct pipe_resource* m_gpuTex; + struct pipe_sampler_view* m_gpuView = nullptr; + void* m_sampler = nullptr; + ~NXTextureS() { + pipe_resource_reference(&m_gpuTex, nullptr); + pipe_sampler_view_reference(&m_gpuView, nullptr); + } - struct pipe_box box; - u_box_2d(0, 0, m_width, m_height, &box); - - ctx->m_pctx->texture_subdata(ctx->m_pctx, m_gpuTex[m_q->m_fillBuf], 0, PIPE_TRANSFER_WRITE, - &box, ptr, rowStride, imageBytes); - - m_validSlots |= slot; - } -} - -void NXTextureD::setClampMode(TextureClampMode mode) -{ + void setClampMode(TextureClampMode mode) { m_clampMode = mode; - MakeSampler(m_q->m_ctx, m_sampler, mode, 1); -} + MakeSampler(m_ctx, m_sampler, mode, m_mips); + } -void NXTextureD::load(const void* data, size_t sz) -{ - size_t bufSz = std::min(sz, m_cpuSz); - memmove(m_stagingBuf.get(), data, bufSz); - m_validSlots = 0; -} + TextureFormat format() const { return m_fmt; } +}; -void* NXTextureD::map(size_t sz) -{ - if (sz > m_cpuSz) - return nullptr; - return m_stagingBuf.get(); -} +class NXTextureSA : public GraphicsDataNode { + friend class NXDataFactory; + NXContext* m_ctx; + TextureFormat m_fmt; + size_t m_sz; + size_t m_width, m_height, m_layers, m_mips; + TextureClampMode m_clampMode; + pipe_format m_nxFmt; + int m_pixelPitchNum = 1; + int m_pixelPitchDenom = 1; -void NXTextureD::unmap() -{ - m_validSlots = 0; -} + NXTextureSA(const boo::ObjToken& parent, NXContext* ctx, size_t width, size_t height, size_t layers, + size_t mips, TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz) + : GraphicsDataNode(parent) + , m_ctx(ctx) + , m_fmt(fmt) + , m_sz(sz) + , m_width(width) + , m_height(height) + , m_layers(layers) + , m_mips(mips) + , m_clampMode(clampMode) { + pipe_format pfmt; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; + m_pixelPitchNum = 4; + break; + case TextureFormat::I8: + pfmt = PIPE_FORMAT_R8_UNORM; + break; + case TextureFormat::I16: + pfmt = PIPE_FORMAT_R16_UNORM; + m_pixelPitchNum = 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); + } + m_nxFmt = pfmt; -static inline struct pipe_resource * -pipe_buffer_create_flags(struct pipe_screen *screen, - unsigned bind, - enum pipe_resource_usage usage, - unsigned flags, - unsigned size) -{ - struct pipe_resource buffer; - memset(&buffer, 0, sizeof buffer); - buffer.target = PIPE_BUFFER; - buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ - buffer.bind = bind; - buffer.usage = usage; - buffer.flags = flags; - buffer.width0 = size; - buffer.height0 = 1; - buffer.depth0 = 1; - buffer.array_size = 1; - return screen->resource_create(screen, &buffer); -} + struct pipe_resource texTempl = {}; + texTempl.target = PIPE_TEXTURE_2D; + texTempl.format = m_nxFmt; + texTempl.width0 = width; + texTempl.height0 = height; + texTempl.depth0 = 1; + texTempl.last_level = mips - 1; + texTempl.array_size = layers; + texTempl.bind = PIPE_BIND_SAMPLER_VIEW; + m_gpuTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_gpuTex) { + Log.report(logvisor::Fatal, "Failed to create texture"); + return; + } -void NXDataFactoryImpl::commitTransaction - (const std::function& trans __BooTraceArgs) -{ - Context ctx(*this __BooTraceArgsUse); - if (!trans(ctx)) + uint blockSize = util_format_get_blocksize(m_nxFmt); + uint8_t* ptr = (uint8_t*)data; + for (int i = 0; i < mips; ++i) { + size_t regionPitch = width * height * m_layers * m_pixelPitchNum / m_pixelPitchDenom; + size_t rowStride = width * blockSize; + size_t imageBytes = rowStride * height; + + struct pipe_box box; + u_box_2d(0, 0, width, height, &box); + + ctx->m_pctx->texture_subdata(ctx->m_pctx, m_gpuTex, i, PIPE_TRANSFER_WRITE, &box, ptr, rowStride, imageBytes); + + if (width > 1) + width /= 2; + if (height > 1) + height /= 2; + ptr += regionPitch; + } + + struct pipe_sampler_view svTempl = {}; + svTempl.format = m_nxFmt; + svTempl.texture = m_gpuTex; + svTempl.u.tex.last_layer = layers - 1; + svTempl.u.tex.last_level = mips - 1; + svTempl.swizzle_r = PIPE_SWIZZLE_X; + svTempl.swizzle_g = PIPE_SWIZZLE_Y; + svTempl.swizzle_b = PIPE_SWIZZLE_Z; + svTempl.swizzle_a = PIPE_SWIZZLE_W; + m_gpuView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex, &svTempl); + } + +public: + struct pipe_resource* m_gpuTex; + struct pipe_sampler_view* m_gpuView = nullptr; + void* m_sampler = nullptr; + ~NXTextureSA() { + pipe_resource_reference(&m_gpuTex, nullptr); + pipe_sampler_view_reference(&m_gpuView, nullptr); + } + + void setClampMode(TextureClampMode mode) { + m_clampMode = mode; + MakeSampler(m_ctx, m_sampler, mode, m_mips); + } + + TextureFormat format() const { return m_fmt; } + size_t layers() const { return m_layers; } +}; + +class NXTextureD : public GraphicsDataNode { + friend class NXDataFactory; + friend class NXCommandQueue; + NXCommandQueue* m_q; + size_t m_width; + size_t m_height; + TextureFormat m_fmt; + TextureClampMode m_clampMode; + std::unique_ptr m_stagingBuf; + size_t m_cpuSz; + pipe_format m_nxFmt; + int m_validSlots = 0; + NXTextureD(const boo::ObjToken& parent, NXCommandQueue* q, size_t width, size_t height, + TextureFormat fmt, TextureClampMode clampMode); + + void update(int b); + +public: + struct pipe_resource* m_gpuTex[2]; + struct pipe_sampler_view* m_gpuView[2]; + void* m_sampler = nullptr; + ~NXTextureD() { + for (int i = 0; i < 2; ++i) { + pipe_resource_reference(&m_gpuTex[i], nullptr); + pipe_sampler_view_reference(&m_gpuView[i], nullptr); + } + } + + void setClampMode(TextureClampMode mode); + + void load(const void* data, size_t sz); + void* map(size_t sz); + void unmap(); + + TextureFormat format() const { return m_fmt; } +}; + +#define MAX_BIND_TEXS 4 + +static constexpr pipe_format ColorFormat = PIPE_FORMAT_R8G8B8A8_UNORM; +static constexpr pipe_format DepthFormat = PIPE_FORMAT_Z32_FLOAT; + +class NXTextureR : public GraphicsDataNode { + NXContext* m_ctx; + + friend class NXDataFactory; + friend struct NXCommandQueue; + size_t m_width = 0; + size_t m_height = 0; + unsigned m_samplesColor, m_samplesDepth; + + size_t m_colorBindCount; + size_t m_depthBindCount; + + void Setup(NXContext* ctx) { + /* no-ops on first call */ + doDestroy(); + + /* color target */ + struct pipe_resource texTempl = {}; + texTempl.target = PIPE_TEXTURE_2D; + texTempl.format = ColorFormat; + texTempl.width0 = m_width; + texTempl.height0 = m_height; + texTempl.depth0 = 1; + texTempl.array_size = 1; + texTempl.nr_samples = texTempl.nr_storage_samples = m_samplesColor; + texTempl.bind = PIPE_BIND_RENDER_TARGET; + m_colorTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_colorTex) { + Log.report(logvisor::Fatal, "Failed to create color target texture"); + return; + } + + /* depth target */ + texTempl.format = DepthFormat; + texTempl.nr_samples = texTempl.nr_storage_samples = m_samplesDepth; + texTempl.bind = PIPE_BIND_DEPTH_STENCIL; + m_depthTex = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_depthTex) { + Log.report(logvisor::Fatal, "Failed to create depth target texture"); + return; + } + + texTempl.nr_samples = texTempl.nr_storage_samples = 1; + + for (size_t i = 0; i < m_colorBindCount; ++i) { + texTempl.format = ColorFormat; + texTempl.bind = PIPE_BIND_SAMPLER_VIEW; + m_colorBindTex[i] = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_colorBindTex[i]) { + Log.report(logvisor::Fatal, "Failed to create color bind texture"); return; - - NXData* data = ctx.m_data.cast(); - - /* size up resources */ - unsigned constantMemSizes[3] = {}; - - if (data->m_SBufs) - for (IGraphicsBufferS& buf : *data->m_SBufs) - { - auto& cbuf = static_cast(buf); - if (cbuf.m_use == BufferUse::Null) - continue; - unsigned& sz = constantMemSizes[int(cbuf.m_use) - 1]; - sz = cbuf.sizeForGPU(m_ctx, sz); - } - - if (data->m_DBufs) - for (IGraphicsBufferD& buf : *data->m_DBufs) - { - auto& cbuf = static_cast&>(buf); - if (cbuf.m_use == BufferUse::Null) - continue; - unsigned& sz = constantMemSizes[int(cbuf.m_use) - 1]; - sz = cbuf.sizeForGPU(m_ctx, sz); - } - - /* allocate memory and place buffers */ - for (int i=0 ; i<3 ; ++i) - { - if (constantMemSizes[i]) - { - struct pipe_resource* poolBuf = - pipe_buffer_create_flags(m_ctx->m_screen, USE_TABLE[i+1], PIPE_USAGE_DEFAULT, - PIPE_RESOURCE_FLAG_MAP_PERSISTENT | PIPE_RESOURCE_FLAG_MAP_COHERENT, - constantMemSizes[i]); - data->m_constantBuffers[i] = poolBuf; - pipe_transfer* xfer; - uint8_t* mappedData = (uint8_t*)pipe_buffer_map(m_ctx->m_pctx, poolBuf, - PIPE_TRANSFER_WRITE | PIPE_TRANSFER_MAP_DIRECTLY | - PIPE_TRANSFER_PERSISTENT | PIPE_TRANSFER_COHERENT, &xfer); - - if (data->m_SBufs) - for (IGraphicsBufferS& buf : *data->m_SBufs) - { - auto& cbuf = static_cast(buf); - if (int(cbuf.m_use) - 1 != i) - continue; - cbuf.placeForGPU(poolBuf, mappedData); - } - - if (data->m_DBufs) - for (IGraphicsBufferD& buf : *data->m_DBufs) - { - auto& cbuf = static_cast&>(buf); - if (int(cbuf.m_use) - 1 != i) - continue; - cbuf.placeForGPU(poolBuf, mappedData); - } - } + } } - /* Commit data bindings (create descriptor sets) */ - if (data->m_SBinds) - for (IShaderDataBinding& bind : *data->m_SBinds) - static_cast(bind).commit(); -} - -boo::ObjToken -NXDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) -{ - boo::ObjToken pool(new NXPool(*this __BooTraceArgsUse)); - NXPool* cpool = pool.cast(); - NXGraphicsBufferD* retval = - new NXGraphicsBufferD(pool, use, m_ctx, stride, count); - - unsigned size = retval->sizeForGPU(m_ctx, 0); - - /* allocate memory */ - if (size) - { - struct pipe_resource* poolBuf = - pipe_buffer_create_flags(m_ctx->m_screen, USE_TABLE[int(use)], PIPE_USAGE_DEFAULT, - PIPE_RESOURCE_FLAG_MAP_PERSISTENT | PIPE_RESOURCE_FLAG_MAP_COHERENT, size); - cpool->m_constantBuffer = poolBuf; - pipe_transfer* xfer; - uint8_t* mappedData = (uint8_t*)pipe_buffer_map(m_ctx->m_pctx, poolBuf, - PIPE_TRANSFER_WRITE | PIPE_TRANSFER_MAP_DIRECTLY | - PIPE_TRANSFER_PERSISTENT | PIPE_TRANSFER_COHERENT, &xfer); - retval->placeForGPU(poolBuf, mappedData); - } - - return {retval}; -} - -void NXCommandQueue::execute() -{ - if (!m_running) + for (size_t i = 0; i < m_depthBindCount; ++i) { + texTempl.format = DepthFormat; + texTempl.bind = PIPE_BIND_SAMPLER_VIEW; + m_depthBindTex[i] = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_depthBindTex[i]) { + Log.report(logvisor::Fatal, "Failed to create depth bind texture"); return; - - /* Stage dynamic uploads */ - NXDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); - std::unique_lock datalk(gfxF->m_dataMutex); - if (gfxF->m_dataHead) - { - for (BaseGraphicsData& d : *gfxF->m_dataHead) - { - if (d.m_DBufs) - for (IGraphicsBufferD& b : *d.m_DBufs) - static_cast&>(b).update(m_fillBuf); - if (d.m_DTexs) - for (ITextureD& t : *d.m_DTexs) - static_cast(t).update(m_fillBuf); - } + } } - if (gfxF->m_poolHead) - { - for (BaseGraphicsPool& p : *gfxF->m_poolHead) - { - if (p.m_DBufs) - for (IGraphicsBufferD& b : *p.m_DBufs) - static_cast&>(b).update(m_fillBuf); - } - } - datalk.unlock(); - /* Perform texture and swap-chain resizes */ - if (m_ctx->_resizeWindowSurfaces() || m_texResizes.size()) - { - for (const auto& resize : m_texResizes) - { - if (m_boundTarget.get() == resize.first) - m_boundTarget.reset(); - resize.first->resize(m_ctx, resize.second.first, resize.second.second); - } - m_texResizes.clear(); - m_resolveDispSource = nullptr; + /* Create resource views */ + struct pipe_sampler_view svTempl = {}; + svTempl.format = ColorFormat; + svTempl.swizzle_r = PIPE_SWIZZLE_X; + svTempl.swizzle_g = PIPE_SWIZZLE_Y; + svTempl.swizzle_b = PIPE_SWIZZLE_Z; + svTempl.swizzle_a = PIPE_SWIZZLE_W; + svTempl.texture = m_colorTex; + m_colorView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_colorTex, &svTempl); + if (!m_colorView) { + Log.report(logvisor::Fatal, "Failed to create color sampler view"); + return; + } + + svTempl.format = DepthFormat; + svTempl.texture = m_depthTex; + m_depthView = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_depthTex, &svTempl); + if (!m_depthView) { + Log.report(logvisor::Fatal, "Failed to create depth sampler view"); + return; + } + + svTempl.format = ColorFormat; + for (size_t i = 0; i < m_colorBindCount; ++i) { + svTempl.texture = m_colorBindTex[i]; + m_colorBindView[i] = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_colorBindTex[i], &svTempl); + if (!m_colorBindView[i]) { + Log.report(logvisor::Fatal, "Failed to create color bind sampler view"); return; + } } - /* Clear dead data */ - m_drawResTokens[m_drawBuf].clear(); - - /* Swap internal buffers */ - m_drawBuf = m_fillBuf; - m_fillBuf ^= 1; - - /* Flush the pipe */ - m_ctx->m_pctx->flush(m_ctx->m_pctx, nullptr, PIPE_FLUSH_END_OF_FRAME); - - /* Set framebuffer fence */ - NvFence fence; - struct pipe_surface* old_back = m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT]; - fence.id = nouveau_switch_resource_get_syncpoint(old_back->texture, &fence.value); - if ((int)fence.id >= 0) { - NvFence* surf_fence = &m_ctx->m_fences[m_ctx->m_fence_swap]; - if (surf_fence->id != fence.id || surf_fence->value != fence.value) { - *surf_fence = fence; - - NvMultiFence mf; - nvMultiFenceCreate(&mf, &fence); - gfxAppendFence(&mf); - } + svTempl.format = DepthFormat; + for (size_t i = 0; i < m_depthBindCount; ++i) { + svTempl.texture = m_depthBindTex[i]; + m_depthBindView[i] = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_depthBindTex[i], &svTempl); + if (!m_depthBindView[i]) { + Log.report(logvisor::Fatal, "Failed to create depth bind sampler view"); + return; + } } - gfxSwapBuffers(); + /* surfaces */ + struct pipe_surface surfTempl = {}; + surfTempl.format = ColorFormat; + m_colorSurface = ctx->m_pctx->create_surface(ctx->m_pctx, m_colorTex, &surfTempl); + if (!m_colorSurface) { + Log.report(logvisor::Fatal, "Failed to create color surface"); + return; + } - /* Swap buffer attachments and invalidate framebuffer */ - m_ctx->m_fence_swap = !m_ctx->m_fence_swap; - m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT] = m_ctx->m_windowSurfaces[ST_ATTACHMENT_FRONT_LEFT]; - m_ctx->m_windowSurfaces[ST_ATTACHMENT_FRONT_LEFT] = old_back; + surfTempl.format = DepthFormat; + m_depthSurface = ctx->m_pctx->create_surface(ctx->m_pctx, m_depthTex, &surfTempl); + if (!m_depthSurface) { + Log.report(logvisor::Fatal, "Failed to create depth surface"); + return; + } + + /* framebuffer */ + m_framebuffer.width = uint16_t(m_width); + m_framebuffer.height = uint16_t(m_height); + m_framebuffer.nr_cbufs = 1; + m_framebuffer.cbufs[0] = m_colorSurface; + m_framebuffer.zsbuf = m_depthSurface; + } + + NXTextureR(const boo::ObjToken& parent, NXContext* ctx, size_t width, size_t height, + TextureClampMode clampMode, size_t colorBindCount, size_t depthBindCount) + : GraphicsDataNode(parent), m_ctx(ctx) { + if (colorBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many color bindings for render texture"); + if (depthBindCount > MAX_BIND_TEXS) + Log.report(logvisor::Fatal, "too many depth bindings for render texture"); + + if (m_samplesColor == 0) + m_samplesColor = 1; + if (m_samplesDepth == 0) + m_samplesDepth = 1; + setClampMode(clampMode); + Setup(ctx); + } + +public: + struct pipe_resource* m_colorTex; + struct pipe_sampler_view* m_colorView = nullptr; + + struct pipe_resource* m_depthTex; + struct pipe_sampler_view* m_depthView = nullptr; + + struct pipe_resource* m_colorBindTex[MAX_BIND_TEXS] = {}; + struct pipe_sampler_view* m_colorBindView[MAX_BIND_TEXS] = {}; + + struct pipe_resource* m_depthBindTex[MAX_BIND_TEXS] = {}; + struct pipe_sampler_view* m_depthBindView[MAX_BIND_TEXS] = {}; + + struct pipe_surface* m_colorSurface = nullptr; + struct pipe_surface* m_depthSurface = nullptr; + + void* m_sampler = nullptr; + + struct pipe_framebuffer_state m_framebuffer = {}; + + void setClampMode(TextureClampMode mode) { MakeSampler(m_ctx, m_sampler, mode, 1); } + + void doDestroy() { + pipe_resource_reference(&m_colorTex, nullptr); + pipe_sampler_view_reference(&m_colorView, nullptr); + + pipe_resource_reference(&m_depthTex, nullptr); + pipe_sampler_view_reference(&m_depthView, nullptr); + + for (size_t i = 0; i < MAX_BIND_TEXS; ++i) { + pipe_resource_reference(&m_colorBindTex[i], nullptr); + pipe_sampler_view_reference(&m_colorBindView[i], nullptr); + + pipe_resource_reference(&m_depthBindTex[i], nullptr); + pipe_sampler_view_reference(&m_depthBindView[i], nullptr); + } + + pipe_surface_reference(&m_colorSurface, nullptr); + pipe_surface_reference(&m_depthSurface, nullptr); + } + + ~NXTextureR() { doDestroy(); } + + void resize(NXContext* ctx, size_t width, size_t height) { + if (width < 1) + width = 1; + if (height < 1) + height = 1; + m_width = width; + m_height = height; + Setup(ctx); + } +}; + +static const size_t SEMANTIC_SIZE_TABLE[] = {0, 12, 16, 12, 16, 16, 4, 8, 16, 16, 16}; + +static const pipe_format SEMANTIC_TYPE_TABLE[] = {PIPE_FORMAT_NONE, + PIPE_FORMAT_R32G32B32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R32G32B32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R8G8B8A8_UNORM, + PIPE_FORMAT_R32G32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT}; + +struct NXVertexFormat { + void* m_vtxElem; + size_t m_stride = 0; + size_t m_instStride = 0; + + NXVertexFormat(NXContext* ctx, const VertexFormatInfo& info) { + std::unique_ptr attributes(new pipe_vertex_element[info.elementCount]); + for (size_t i = 0; i < info.elementCount; ++i) { + const VertexElementDescriptor* elemin = &info.elements[i]; + pipe_vertex_element& attribute = attributes[i]; + int semantic = int(elemin->semantic & boo::VertexSemantic::SemanticMask); + attribute.src_format = SEMANTIC_TYPE_TABLE[semantic]; + if ((elemin->semantic & boo::VertexSemantic::Instanced) != boo::VertexSemantic::None) { + attribute.vertex_buffer_index = 1; + attribute.instance_divisor = 1; + attribute.src_offset = m_instStride; + m_instStride += SEMANTIC_SIZE_TABLE[semantic]; + } else { + attribute.vertex_buffer_index = 0; + attribute.instance_divisor = 0; + attribute.src_offset = m_stride; + m_stride += SEMANTIC_SIZE_TABLE[semantic]; + } + } + + uint64_t key = XXH64(attributes.get(), sizeof(pipe_vertex_element) * info.elementCount, 0); + auto search = ctx->m_vtxElemStates.find(key); + if (search != ctx->m_vtxElemStates.end()) { + m_vtxElem = search->second; + return; + } + m_vtxElem = ctx->m_pctx->create_vertex_elements_state(ctx->m_pctx, info.elementCount, attributes.get()); + ctx->m_vtxElemStates[key] = m_vtxElem; + } +}; + +static const pipe_prim_type PRIMITIVE_TABLE[] = {PIPE_PRIM_TRIANGLES, PIPE_PRIM_TRIANGLE_STRIP, PIPE_PRIM_PATCHES}; + +static const nx_shader_stage SHADER_TYPE_TABLE[] = { + nx_shader_stage::NONE, nx_shader_stage::VERTEX, nx_shader_stage::FRAGMENT, + nx_shader_stage::GEOMETRY, nx_shader_stage::TESS_CTRL, nx_shader_stage::TESS_EVAL, +}; + +class NXShaderStage : public GraphicsDataNode { + friend class NXDataFactory; + nx_shader_stage_object m_obj; + NXShaderStage(const boo::ObjToken& parent, NXContext* ctx, const uint8_t* data, size_t size, + PipelineStage stage) + : GraphicsDataNode(parent), m_obj(ctx->m_compiler.compile(SHADER_TYPE_TABLE[int(stage)], (char*)data)) { + if (!m_obj) + Log.report(logvisor::Fatal, "Shader compile fail:\n%s\n", m_obj.info_log()); + } + +public: + const nx_shader_stage_object* shader() const { return &m_obj; } +}; + +static const unsigned BLEND_FACTOR_TABLE[] = { + PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_SRC_COLOR, + PIPE_BLENDFACTOR_INV_SRC_COLOR, PIPE_BLENDFACTOR_DST_COLOR, PIPE_BLENDFACTOR_INV_DST_COLOR, + PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_DST_ALPHA, + PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC1_COLOR, PIPE_BLENDFACTOR_INV_SRC1_COLOR}; + +static void MakeBlendState(NXContext* ctx, void*& bsOut, const AdditionalPipelineInfo& info) { + uint32_t key = (uint32_t(info.srcFac) << 16) | (uint32_t(info.dstFac) << 3) | info.colorWrite << 2 | + info.alphaWrite << 1 | info.overwriteAlpha; + auto search = ctx->m_blendStates.find(key); + if (search != ctx->m_blendStates.end()) { + bsOut = search->second; + return; + } + + pipe_blend_state bs = {}; + bs.rt->blend_enable = info.srcFac != BlendFactor::One || info.dstFac != BlendFactor::Zero; + if (info.srcFac == BlendFactor::Subtract || info.dstFac == BlendFactor::Subtract) { + bs.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + bs.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + bs.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT; + if (info.overwriteAlpha) { + bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + bs.rt[0].alpha_func = PIPE_BLEND_ADD; + } else { + bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + bs.rt[0].alpha_func = PIPE_BLEND_REVERSE_SUBTRACT; + } + } else { + bs.rt[0].rgb_src_factor = BLEND_FACTOR_TABLE[int(info.srcFac)]; + bs.rt[0].rgb_dst_factor = BLEND_FACTOR_TABLE[int(info.dstFac)]; + bs.rt[0].rgb_func = PIPE_BLEND_ADD; + if (info.overwriteAlpha) { + bs.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + bs.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + } else { + bs.rt[0].alpha_src_factor = BLEND_FACTOR_TABLE[int(info.srcFac)]; + bs.rt[0].alpha_dst_factor = BLEND_FACTOR_TABLE[int(info.dstFac)]; + } + bs.rt[0].alpha_func = PIPE_BLEND_ADD; + } + + bs.rt[0].colormask = + (info.colorWrite ? (PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B) : 0) | (info.alphaWrite ? PIPE_MASK_A : 0); + + bsOut = ctx->m_pctx->create_blend_state(ctx->m_pctx, &bs); + ctx->m_blendStates[key] = bsOut; } -static void setMesaConfig() -{ - // Uncomment below to disable error checking and save CPU time (useful for production): - //setenv("MESA_NO_ERROR", "1", 1); +static void MakeRasterizerState(NXContext* ctx, void*& rasOut, const AdditionalPipelineInfo& info) { + uint32_t key = uint32_t(info.culling); + auto search = ctx->m_rasStates.find(key); + if (search != ctx->m_rasStates.end()) { + rasOut = search->second; + return; + } - // Uncomment below to enable Mesa logging: - setenv("EGL_LOG_LEVEL", "debug", 1); - setenv("MESA_VERBOSE", "all", 1); - setenv("NOUVEAU_MESA_DEBUG", "1", 1); + pipe_rasterizer_state ras = {}; + ras.clamp_fragment_color = 1; + ras.front_ccw = 1; + switch (info.culling) { + case CullMode::None: + default: + ras.cull_face = PIPE_FACE_NONE; + break; + case CullMode::Backface: + ras.cull_face = PIPE_FACE_BACK; + break; + case CullMode::Frontface: + ras.cull_face = PIPE_FACE_FRONT; + break; + } + ras.scissor = 1; + ras.multisample = unsigned(ctx->m_sampleCount > 1); + ras.half_pixel_center = 1; + ras.bottom_edge_rule = 1; + ras.depth_clip_near = 1; + ras.depth_clip_far = 1; - // Uncomment below to enable shader debugging in Nouveau: - setenv("NV50_PROG_OPTIMIZE", "0", 1); - setenv("NV50_PROG_DEBUG", "1", 1); - setenv("NV50_PROG_CHIPSET", "0x120", 1); + rasOut = ctx->m_pctx->create_rasterizer_state(ctx->m_pctx, &ras); + ctx->m_rasStates[key] = rasOut; } -bool NXContext::initialize() -{ - /* Set mesa configuration (useful for debugging) */ - setMesaConfig(); +static void MakeDepthStencilState(NXContext* ctx, void*& dsOut, const AdditionalPipelineInfo& info) { + uint32_t key = (uint32_t(info.depthTest) << 16) | info.depthWrite; + auto search = ctx->m_dsStates.find(key); + if (search != ctx->m_dsStates.end()) { + dsOut = search->second; + return; + } - gfxInitDefault(); - gfxSetMode(GfxMode_TiledDouble); - consoleInit(NULL); - printf("Activated console\n\n"); - m_screen = nouveau_switch_screen_create(); - if (!m_screen) - { - Log.report(logvisor::Fatal, "Failed to create nouveau screen"); - return false; - } - printf("nouveau_switch_screen_create done\n"); - fflush(stdout); + pipe_depth_stencil_alpha_state ds = {}; + ds.depth.enabled = info.depthTest != ZTest::None; + ds.depth.writemask = info.depthWrite; + switch (info.depthTest) { + case ZTest::None: + default: + ds.depth.func = PIPE_FUNC_ALWAYS; + break; + case ZTest::LEqual: + ds.depth.func = PIPE_FUNC_LEQUAL; + break; + case ZTest::Greater: + ds.depth.func = PIPE_FUNC_GREATER; + break; + case ZTest::Equal: + ds.depth.func = PIPE_FUNC_EQUAL; + break; + case ZTest::GEqual: + ds.depth.func = PIPE_FUNC_GEQUAL; + break; + } - m_pctx = m_screen->context_create(m_screen, nullptr, 0); - if (!m_pctx) - { - Log.report(logvisor::Fatal, "Failed to create pipe context"); - m_screen->destroy(m_screen); - return false; - } - printf("m_screen->context_create done\n"); - - st_config_options opts = {}; - m_st = st_create_context(API_OPENGL_CORE, m_pctx, nullptr, nullptr, &opts, false); - if (!m_st) - { - Log.report(logvisor::Fatal, "Failed to create st context"); - m_screen->destroy(m_screen); - return false; - } - - u32 width, height; - gfxGetFramebufferResolution(&width, &height); - - for (int i = 0; i < 2; ++i) - { - /* color target */ - struct pipe_resource texTempl = {}; - texTempl.target = PIPE_TEXTURE_RECT; - texTempl.format = ColorFormat; - texTempl.width0 = width; - texTempl.height0 = height; - texTempl.depth0 = 1; - texTempl.array_size = 1; - texTempl.usage = PIPE_USAGE_DEFAULT; - texTempl.nr_samples = texTempl.nr_storage_samples = 1; - texTempl.bind = PIPE_BIND_RENDER_TARGET; - u32 index = i == ST_ATTACHMENT_FRONT_LEFT ? 1 : 0; - struct winsys_handle whandle; - whandle.type = WINSYS_HANDLE_TYPE_SHARED; - whandle.handle = gfxGetFramebufferHandle(index, &whandle.offset); - whandle.stride = gfxGetFramebufferPitch(); - struct pipe_resource* tex = m_screen->resource_from_handle(m_screen, &texTempl, &whandle, 0); - if (!tex) { - Log.report(logvisor::Fatal, "Failed to create color target texture"); - return false; - } - - /* surface */ - struct pipe_surface surfTempl = {}; - surfTempl.format = ColorFormat; - m_windowSurfaces[i] = m_pctx->create_surface(m_pctx, tex, &surfTempl); - if (!m_windowSurfaces[i]) { - Log.report(logvisor::Fatal, "Failed to create color surface"); - return false; - } - - m_fences[i].id = UINT32_MAX; - } - - return m_compiler.initialize(m_screen, m_st); + dsOut = ctx->m_pctx->create_depth_stencil_alpha_state(ctx->m_pctx, &ds); + ctx->m_dsStates[key] = dsOut; } -bool NXContext::terminate() -{ - if (m_st) - st_destroy_context(m_st); - if (m_screen) - m_screen->destroy(m_screen); - gfxExit(); +class NXShaderPipeline : public GraphicsDataNode { +protected: + friend class NXDataFactory; + friend struct NXShaderDataBinding; + NXVertexFormat m_vtxFmt; + nx_linked_shader m_shader; + Primitive m_prim; + pipe_prim_type m_nxPrim; + uint32_t m_patchSize; + + void* m_blendState; + void* m_rasState; + void* m_dsState; + + NXShaderPipeline(const boo::ObjToken& parent, NXContext* ctx, ObjToken vertex, + ObjToken fragment, ObjToken geometry, ObjToken control, + ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) + : GraphicsDataNode(parent), m_vtxFmt(ctx, vtxFmt), m_prim(info.prim), m_patchSize(info.patchSize) { + m_nxPrim = PRIMITIVE_TABLE[int(m_prim)]; + MakeBlendState(ctx, m_blendState, info); + MakeRasterizerState(ctx, m_rasState, info); + MakeDepthStencilState(ctx, m_dsState, info); + + const nx_shader_stage_object* stages[5]; + unsigned numStages = 0; + if (vertex) + stages[numStages++] = vertex.cast()->shader(); + if (control) + stages[numStages++] = control.cast()->shader(); + if (evaluation) + stages[numStages++] = evaluation.cast()->shader(); + if (geometry) + stages[numStages++] = geometry.cast()->shader(); + if (fragment) + stages[numStages++] = fragment.cast()->shader(); + std::string infoLog; + m_shader = ctx->m_compiler.link(numStages, stages, &infoLog); + if (!m_shader) + Log.report(logvisor::Fatal, "Unable to link shader:\n%s\n", infoLog.c_str()); + } + +public: + NXShaderPipeline& operator=(const NXShaderPipeline&) = delete; + NXShaderPipeline(const NXShaderPipeline&) = delete; + void bind(struct pipe_context* pctx) const { + const struct gl_shader_program* prog = m_shader.program(); + if (gl_linked_shader* fs = prog->_LinkedShaders[MESA_SHADER_FRAGMENT]) { + struct st_fragment_program* p = (struct st_fragment_program*)fs->Program; + pctx->bind_fs_state(pctx, p->variants->driver_shader); + } + if (gl_linked_shader* gs = prog->_LinkedShaders[MESA_SHADER_GEOMETRY]) { + struct st_common_program* p = (struct st_common_program*)gs->Program; + pctx->bind_gs_state(pctx, p->variants->driver_shader); + } + if (gl_linked_shader* tes = prog->_LinkedShaders[MESA_SHADER_TESS_EVAL]) { + struct st_common_program* p = (struct st_common_program*)tes->Program; + pctx->bind_tes_state(pctx, p->variants->driver_shader); + } + if (gl_linked_shader* tcs = prog->_LinkedShaders[MESA_SHADER_TESS_CTRL]) { + struct st_common_program* p = (struct st_common_program*)tcs->Program; + pctx->bind_tcs_state(pctx, p->variants->driver_shader); + } + if (gl_linked_shader* vs = prog->_LinkedShaders[MESA_SHADER_VERTEX]) { + struct st_vertex_program* p = (struct st_vertex_program*)vs->Program; + pctx->bind_vs_state(pctx, p->variants->driver_shader); + } + + pctx->bind_blend_state(pctx, m_blendState); + pctx->bind_rasterizer_state(pctx, m_rasState); + pctx->bind_depth_stencil_alpha_state(pctx, m_dsState); + } +}; + +static const nx_buffer_info* GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) { + if (buf->dynamic()) { + const NXGraphicsBufferD* cbuf = static_cast*>(buf); + return &cbuf->m_bufferInfo[idx]; + } else { + const NXGraphicsBufferS* cbuf = static_cast(buf); + return &cbuf->m_bufferInfo; + } +} + +static const struct pipe_sampler_view* GetTextureGPUResource(const ITexture* tex, int idx, int bindIdx, bool depth, + void*& samplerOut) { + switch (tex->type()) { + case TextureType::Dynamic: { + const NXTextureD* ctex = static_cast(tex); + samplerOut = ctex->m_sampler; + return ctex->m_gpuView[idx]; + } + case TextureType::Static: { + const NXTextureS* ctex = static_cast(tex); + samplerOut = ctex->m_sampler; + return ctex->m_gpuView; + } + case TextureType::StaticArray: { + const NXTextureSA* ctex = static_cast(tex); + samplerOut = ctex->m_sampler; + return ctex->m_gpuView; + } + case TextureType::Render: { + const NXTextureR* ctex = static_cast(tex); + samplerOut = ctex->m_sampler; + return depth ? ctex->m_depthBindView[bindIdx] : ctex->m_colorBindView[bindIdx]; + } + default: + break; + } + return nullptr; +} + +struct NXShaderDataBinding : GraphicsDataNode { + NXContext* m_ctx; + boo::ObjToken m_pipeline; + boo::ObjToken m_vbuf; + boo::ObjToken m_instVbuf; + boo::ObjToken m_ibuf; + std::vector> m_ubufs; + std::vector> m_ubufOffs; + struct BindTex { + boo::ObjToken tex; + int idx; + bool depth; + }; + std::vector m_texs; + + struct pipe_vertex_buffer m_vboBufs[2][2] = {{}, {}}; + std::vector> m_ubufBinds[MESA_SHADER_STAGES]; + + size_t m_vertOffset; + size_t m_instOffset; + +#ifndef NDEBUG + /* Debugging aids */ + bool m_committed = false; +#endif + + NXShaderDataBinding(const boo::ObjToken& d, NXDataFactoryImpl& factory, + const boo::ObjToken& pipeline, const boo::ObjToken& vbuf, + const boo::ObjToken& instVbuf, const boo::ObjToken& ibuf, + size_t ubufCount, const boo::ObjToken* ubufs, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, + const int* bindIdxs, const bool* depthBinds, size_t baseVert, size_t baseInst) + : GraphicsDataNode(d) + , m_ctx(factory.m_ctx) + , m_pipeline(pipeline) + , m_vbuf(vbuf) + , m_instVbuf(instVbuf) + , m_ibuf(ibuf) { + NXShaderPipeline* cpipeline = m_pipeline.cast(); + NXVertexFormat& vtxFmt = cpipeline->m_vtxFmt; + m_vertOffset = baseVert * vtxFmt.m_stride; + m_instOffset = baseInst * vtxFmt.m_instStride; + + m_ubufs.reserve(ubufCount); + if (ubufOffs && ubufSizes) + m_ubufOffs.reserve(ubufCount); + for (size_t i = 0; i < ubufCount; ++i) { +#ifndef NDEBUG + if (!ubufs[i]) + Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i)); +#endif + m_ubufs.push_back(ubufs[i]); + if (ubufOffs && ubufSizes) + m_ubufOffs.push_back({ubufOffs[i], ubufSizes[i]}); + } + m_texs.reserve(texCount); + for (size_t i = 0; i < texCount; ++i) { + m_texs.push_back({texs[i], bindIdxs ? bindIdxs[i] : 0, depthBinds ? depthBinds[i] : false}); + } + } + + void commit() { + struct pipe_context* pctx = m_ctx->m_pctx; + + for (int i = 0; i < 2; ++i) { + if (m_vbuf) { + m_vboBufs[i][0] = GetBufferGPUResource(m_vbuf.get(), i)->v; + m_vboBufs[i][0].buffer_offset += m_vertOffset; + } + if (m_instVbuf) { + m_vboBufs[i][1] = GetBufferGPUResource(m_instVbuf.get(), i)->v; + m_vboBufs[i][1].buffer_offset += m_instOffset; + } + } + + NXShaderPipeline* cpipeline = m_pipeline.cast(); + const struct gl_shader_program* program = cpipeline->m_shader.program(); + for (uint i = 0; i < MESA_SHADER_STAGES; ++i) { + if (const struct gl_linked_shader* lsh = program->_LinkedShaders[i]) { + std::vector>& bindings = m_ubufBinds[i]; + const struct gl_shader_program_data* data = lsh->Program->sh.data; + bindings.reserve(data->NumUniformBlocks); + for (uint j = 0; j < data->NumUniformBlocks; ++j) { + const struct gl_uniform_block* block = &data->UniformBlocks[j]; + assert(block->Binding < m_ubufs.size() && "Uniform binding oob"); + bindings.emplace_back(); + for (int k = 0; k < 2; ++k) { + struct pipe_constant_buffer& bufBind = bindings.back()[k]; + const nx_buffer_info* buf = GetBufferGPUResource(m_ubufs[block->Binding].get(), k); + bufBind = buf->c; + if (!m_ubufOffs.empty()) { + bufBind.buffer_offset += m_ubufOffs[block->Binding][0]; + bufBind.buffer_size = unsigned(m_ubufOffs[block->Binding][1]); + } + } + } + } + } + +#ifndef NDEBUG + m_committed = true; +#endif + } + + void bind(int b) { +#ifndef NDEBUG + if (!m_committed) + Log.report(logvisor::Fatal, "attempted to use uncommitted NXShaderDataBinding"); +#endif + struct pipe_context* pctx = m_ctx->m_pctx; + + NXShaderPipeline* pipeline = m_pipeline.cast(); + pipeline->bind(pctx); + const struct gl_shader_program* program = pipeline->m_shader.program(); + for (uint i = 0; i < MESA_SHADER_STAGES; ++i) { + uint j = 0; + for (const auto& bind : m_ubufBinds[i]) + pctx->set_constant_buffer(pctx, pipe_shader_type(i), j++, &bind[b]); + + if (const struct gl_linked_shader* lsh = program->_LinkedShaders[i]) { + void* samplers[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; + struct pipe_sampler_view* samplerViews[BOO_GLSL_MAX_TEXTURE_COUNT] = {}; + unsigned numSamplers = 0; + const struct gl_program* stprogram = lsh->Program; + for (int t = 0; t < BOO_GLSL_MAX_TEXTURE_COUNT; ++t) { + if (stprogram->SamplersUsed & (1 << t)) { + GLubyte unit = GLubyte(stprogram->SamplerUnits[t] - BOO_GLSL_MAX_UNIFORM_COUNT); + assert(unit < m_texs.size() && "Texture binding oob"); + const BindTex& tex = m_texs[unit]; + samplerViews[numSamplers] = + (pipe_sampler_view*)GetTextureGPUResource(tex.tex.get(), t, tex.idx, tex.depth, samplers[numSamplers]); + ++numSamplers; + } + } + pctx->bind_sampler_states(pctx, pipe_shader_type(i), 0, numSamplers, samplers); + pctx->set_sampler_views(pctx, pipe_shader_type(i), 0, numSamplers, samplerViews); + } + } + + if (m_vbuf && m_instVbuf) + pctx->set_vertex_buffers(pctx, 0, 2, m_vboBufs[b]); + else if (m_vbuf) + pctx->set_vertex_buffers(pctx, 0, 1, m_vboBufs[b]); + else if (m_instVbuf) + pctx->set_vertex_buffers(pctx, 1, 1, &m_vboBufs[b][1]); + } + + pipe_prim_type getPrimitive() const { return m_pipeline.cast()->m_nxPrim; } + uint32_t getPatchVerts() const { return m_pipeline.cast()->m_patchSize; } + struct pipe_resource* getIndexBuf(int b) const { + return GetBufferGPUResource(m_ibuf.get(), b)->v.buffer.resource; + } +}; + +struct NXCommandQueue : IGraphicsCommandQueue { + Platform platform() const { return IGraphicsDataFactory::Platform::Vulkan; } + const SystemChar* platformName() const { return _SYS_STR("NX"); } + NXContext* m_ctx; + IGraphicsContext* m_parent; + + bool m_running = true; + + int m_fillBuf = 0; + int m_drawBuf = 0; + + std::vector> m_drawResTokens[2]; + + NXCommandQueue(NXContext* ctx, IGraphicsContext* parent) : m_ctx(ctx), m_parent(parent) {} + + void startRenderer() { static_cast(m_parent->getDataFactory())->SetupGammaResources(); } + + void stopRenderer() { + m_running = false; + static_cast(m_parent->getDataFactory())->DestroyGammaResources(); + m_drawResTokens[0].clear(); + m_drawResTokens[1].clear(); + m_boundTarget.reset(); + m_resolveDispSource.reset(); + } + + ~NXCommandQueue() { + if (m_running) + stopRenderer(); + } + + boo::ObjToken m_curSDBinding; + void setShaderDataBinding(const boo::ObjToken& binding) { + m_curSDBinding = binding; + NXShaderDataBinding* cbind = binding.cast(); + cbind->bind(m_fillBuf); + m_drawResTokens[m_fillBuf].push_back(binding.get()); + } + + boo::ObjToken m_boundTarget; + void setRenderTarget(const boo::ObjToken& target) { + NXTextureR* ctarget = target.cast(); + + if (m_boundTarget.get() != ctarget) { + m_boundTarget = target; + m_drawResTokens[m_fillBuf].push_back(target.get()); + } + + m_ctx->m_pctx->set_framebuffer_state(m_ctx->m_pctx, &ctarget->m_framebuffer); + } + + void setViewport(const SWindowRect& rect, float znear, float zfar) { + if (m_boundTarget) { + NXTextureR* ctarget = m_boundTarget.cast(); + + struct gl_context* ctx = m_ctx->m_st->ctx; + ctx->ViewportArray[0].X = float(rect.location[0]); + ctx->ViewportArray[0].Y = float(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])); + ctx->ViewportArray[0].Width = float(rect.size[0]); + ctx->ViewportArray[0].Height = float(rect.size[1]); + ctx->ViewportArray[0].Near = znear; + ctx->ViewportArray[0].Far = zfar; + + pipe_viewport_state vp = {}; + _mesa_get_viewport_xform(ctx, 0, vp.scale, vp.translate); + m_ctx->m_pctx->set_viewport_states(m_ctx->m_pctx, 0, 1, &vp); + } + } + + void setScissor(const SWindowRect& rect) { + if (m_boundTarget) { + NXTextureR* ctarget = m_boundTarget.cast(); + + pipe_scissor_state scissor = {}; + scissor.minx = unsigned(rect.location[0]); + scissor.miny = unsigned(std::max(0, int(ctarget->m_height) - rect.location[1] - rect.size[1])); + scissor.maxx = scissor.minx + unsigned(rect.size[0]); + scissor.maxy = scissor.miny + unsigned(rect.size[1]); + + m_ctx->m_pctx->set_scissor_states(m_ctx->m_pctx, 0, 1, &scissor); + } + } + + std::unordered_map> m_texResizes; + void resizeRenderTexture(const boo::ObjToken& tex, size_t width, size_t height) { + NXTextureR* ctex = tex.cast(); + m_texResizes[ctex] = std::make_pair(width, height); + m_drawResTokens[m_fillBuf].push_back(tex.get()); + } + + void schedulePostFrameHandler(std::function&& func) { func(); } + + float m_clearColor[4] = {0.0, 0.0, 0.0, 0.0}; + void setClearColor(const float rgba[4]) { + m_clearColor[0] = rgba[0]; + m_clearColor[1] = rgba[1]; + m_clearColor[2] = rgba[2]; + m_clearColor[3] = rgba[3]; + } + + void clearTarget(bool render = true, bool depth = true) { + if (!m_boundTarget) + return; + unsigned buffers = 0; + if (render) + buffers |= PIPE_CLEAR_COLOR0; + if (depth) + buffers |= PIPE_CLEAR_DEPTH; + pipe_color_union cunion; + for (int i = 0; i < 4; ++i) + cunion.f[i] = m_clearColor[i]; + m_ctx->m_pctx->clear(m_ctx->m_pctx, buffers, &cunion, 1.f, 0); + } + + void draw(size_t start, size_t count) { + pipe_draw_info info = {}; + NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); + info.mode = sdBinding->getPrimitive(); + info.vertices_per_patch = sdBinding->getPatchVerts(); + info.start = start; + info.count = count; + m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); + } + + void drawIndexed(size_t start, size_t count) { + pipe_draw_info info = {}; + NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); + info.index_size = 4; + info.mode = sdBinding->getPrimitive(); + info.primitive_restart = 1; + info.vertices_per_patch = sdBinding->getPatchVerts(); + info.start = start; + info.count = count; + info.restart_index = 0xffffffff; + info.index.resource = sdBinding->getIndexBuf(m_fillBuf); + m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); + } + + void drawInstances(size_t start, size_t count, size_t instCount) { + pipe_draw_info info = {}; + NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); + info.mode = sdBinding->getPrimitive(); + info.vertices_per_patch = sdBinding->getPatchVerts(); + info.start = start; + info.count = count; + info.instance_count = instCount; + m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); + } + + void drawInstancesIndexed(size_t start, size_t count, size_t instCount) { + pipe_draw_info info = {}; + NXShaderDataBinding* sdBinding = m_curSDBinding.cast(); + info.index_size = 4; + info.mode = sdBinding->getPrimitive(); + info.primitive_restart = 1; + info.vertices_per_patch = sdBinding->getPatchVerts(); + info.start = start; + info.count = count; + info.instance_count = instCount; + info.restart_index = 0xffffffff; + info.index.resource = sdBinding->getIndexBuf(m_fillBuf); + m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); + } + + boo::ObjToken m_resolveDispSource; + void resolveDisplay(const boo::ObjToken& source) { m_resolveDispSource = source; } + + bool _resolveDisplay() { + if (!m_resolveDispSource) + return false; + + NXTextureR* csource = m_resolveDispSource.cast(); +#ifndef NDEBUG + if (!csource->m_colorBindCount) + Log.report(logvisor::Fatal, "texture provided to resolveDisplay() must have at least 1 color binding"); +#endif + + struct pipe_surface* backBuf = m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT]; + + NXDataFactoryImpl* dataFactory = static_cast(m_parent->getDataFactory()); + if (dataFactory->m_gamma != 1.f) { + SWindowRect rect(0, 0, csource->m_width, csource->m_height); + _resolveBindTexture(csource, rect, true, 0, true, false); + NXShaderDataBinding* gammaBinding = dataFactory->m_gammaBinding.cast(); + + pipe_framebuffer_state fstate = {}; + fstate.width = backBuf->texture->width0; + fstate.height = backBuf->texture->height0; + fstate.nr_cbufs = 1; + fstate.cbufs[0] = backBuf; + m_ctx->m_pctx->set_framebuffer_state(m_ctx->m_pctx, &fstate); + + gammaBinding->m_texs[0].tex = m_resolveDispSource.get(); + gammaBinding->bind(m_drawBuf); + pipe_draw_info info = {}; + info.mode = PIPE_PRIM_TRIANGLE_STRIP; + info.start = 0; + info.count = 4; + info.instance_count = 1; + m_ctx->m_pctx->draw_vbo(m_ctx->m_pctx, &info); + gammaBinding->m_texs[0].tex.reset(); + } else { + pipe_blit_info binfo = {}; + binfo.src.resource = csource->m_colorTex; + binfo.dst.resource = backBuf->texture; + u_box_2d(0, 0, csource->m_width, csource->m_height, &binfo.src.box); + binfo.dst.box = binfo.src.box; + binfo.src.format = binfo.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM; + binfo.mask = PIPE_MASK_RGBA; + binfo.filter = PIPE_TEX_FILTER_NEAREST; + m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); + } + + m_resolveDispSource.reset(); return true; + } + + void _resolveBindTexture(NXTextureR* ctexture, const SWindowRect& rect, bool tlOrigin, int bindIdx, bool color, + bool depth) { + SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, ctexture->m_width, ctexture->m_height)); + + if (color && ctexture->m_colorBindCount) { + pipe_blit_info binfo = {}; + binfo.src.resource = ctexture->m_colorTex; + binfo.dst.resource = ctexture->m_colorBindTex[bindIdx]; + u_box_2d(intersectRect.location[0], + tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]), + intersectRect.size[0], intersectRect.size[1], &binfo.src.box); + binfo.dst.box = binfo.src.box; + binfo.src.format = binfo.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM; + binfo.mask = PIPE_MASK_RGBA; + binfo.filter = PIPE_TEX_FILTER_NEAREST; + m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); + } + + if (depth && ctexture->m_depthBindCount) { + pipe_blit_info binfo = {}; + binfo.src.resource = ctexture->m_depthTex; + binfo.dst.resource = ctexture->m_depthBindTex[bindIdx]; + u_box_2d(intersectRect.location[0], + tlOrigin ? intersectRect.location[1] + : (ctexture->m_height - intersectRect.size[1] - intersectRect.location[1]), + intersectRect.size[0], intersectRect.size[1], &binfo.src.box); + binfo.dst.box = binfo.src.box; + binfo.src.format = binfo.dst.format = PIPE_FORMAT_Z32_FLOAT; + binfo.mask = PIPE_MASK_Z; + binfo.filter = PIPE_TEX_FILTER_NEAREST; + m_ctx->m_pctx->blit(m_ctx->m_pctx, &binfo); + } + } + + void resolveBindTexture(const boo::ObjToken& texture, const SWindowRect& rect, bool tlOrigin, int bindIdx, + bool color, bool depth, bool clearDepth) { + NXTextureR* ctexture = texture.cast(); + _resolveBindTexture(ctexture, rect, tlOrigin, bindIdx, color, depth); + if (clearDepth) + m_ctx->m_pctx->clear(m_ctx->m_pctx, PIPE_CLEAR_DEPTH, nullptr, 1.f, 0); + } + + void execute(); +}; + +NXDataFactory::Context::Context(NXDataFactory& parent __BooTraceArgs) +: m_parent(parent), m_data(new NXData(static_cast(parent) __BooTraceArgsUse)) {} +NXDataFactory::Context::~Context() {} + +boo::ObjToken NXDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, + size_t count) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXGraphicsBufferS(m_data, use, factory.m_ctx, data, stride, count)}; } -bool NXContext::_resizeWindowSurfaces() -{ +boo::ObjToken NXDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXGraphicsBufferD(m_data, use, factory.m_ctx, stride, count)}; +} + +boo::ObjToken NXDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, + TextureFormat fmt, TextureClampMode clampMode, + const void* data, size_t sz) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXTextureS(m_data, factory.m_ctx, width, height, mips, fmt, clampMode, data, sz)}; +} + +boo::ObjToken NXDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, + size_t mips, TextureFormat fmt, + TextureClampMode clampMode, const void* data, + size_t sz) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXTextureSA(m_data, factory.m_ctx, width, height, layers, mips, fmt, clampMode, data, sz)}; +} + +boo::ObjToken NXDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt, + TextureClampMode clampMode) { + NXDataFactoryImpl& factory = static_cast(m_parent); + NXCommandQueue* q = static_cast(factory.m_parent->getCommandQueue()); + return {new NXTextureD(m_data, q, width, height, fmt, clampMode)}; +} + +boo::ObjToken NXDataFactory::Context::newRenderTexture(size_t width, size_t height, + TextureClampMode clampMode, size_t colorBindCount, + size_t depthBindCount) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXTextureR(m_data, factory.m_ctx, width, height, clampMode, colorBindCount, depthBindCount)}; +} + +ObjToken NXDataFactory::Context::newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXShaderStage(m_data, factory.m_ctx, data, size, stage)}; +} + +ObjToken NXDataFactory::Context::newShaderPipeline( + ObjToken vertex, ObjToken fragment, ObjToken geometry, + ObjToken control, ObjToken evaluation, const VertexFormatInfo& vtxFmt, + const AdditionalPipelineInfo& info) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXShaderPipeline(m_data, factory.m_ctx, vertex, fragment, geometry, control, evaluation, vtxFmt, info)}; +} + +boo::ObjToken NXDataFactory::Context::newShaderDataBinding( + const boo::ObjToken& pipeline, const boo::ObjToken& vbo, + const boo::ObjToken& instVbo, const boo::ObjToken& ibo, size_t ubufCount, + const boo::ObjToken* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs, + const size_t* ubufSizes, size_t texCount, const boo::ObjToken* texs, const int* bindIdxs, + const bool* bindDepth, size_t baseVert, size_t baseInst) { + NXDataFactoryImpl& factory = static_cast(m_parent); + return {new NXShaderDataBinding(m_data, factory, pipeline, vbo, instVbo, ibo, ubufCount, ubufs, ubufOffs, ubufSizes, + texCount, texs, bindIdxs, bindDepth, baseVert, baseInst)}; +} + +NXTextureD::NXTextureD(const boo::ObjToken& parent, NXCommandQueue* q, size_t width, size_t height, + TextureFormat fmt, TextureClampMode clampMode) +: GraphicsDataNode(parent), m_q(q), m_width(width), m_height(height), m_fmt(fmt), m_clampMode(clampMode) { + NXContext* ctx = m_q->m_ctx; + pipe_format pfmt; + switch (fmt) { + case TextureFormat::RGBA8: + pfmt = PIPE_FORMAT_R8G8B8A8_UNORM; + m_cpuSz = width * height * 4; + break; + case TextureFormat::I8: + pfmt = PIPE_FORMAT_R8_UNORM; + m_cpuSz = width * height; + break; + case TextureFormat::I16: + pfmt = PIPE_FORMAT_R16_UNORM; + m_cpuSz = width * height * 2; + break; + default: + Log.report(logvisor::Fatal, "unsupported tex format"); + } + m_nxFmt = pfmt; + m_stagingBuf.reset(new uint8_t[m_cpuSz]); + + struct pipe_resource texTempl = {}; + texTempl.target = PIPE_TEXTURE_2D; + texTempl.format = m_nxFmt; + texTempl.width0 = width; + texTempl.height0 = height; + texTempl.depth0 = 1; + texTempl.array_size = 1; + texTempl.bind = PIPE_BIND_SAMPLER_VIEW; + for (int i = 0; i < 2; ++i) { + m_gpuTex[i] = ctx->m_screen->resource_create(ctx->m_screen, &texTempl); + if (!m_gpuTex[i]) { + Log.report(logvisor::Fatal, "Failed to create texture"); + return; + } + } + + struct pipe_sampler_view svTempl = {}; + svTempl.format = m_nxFmt; + svTempl.swizzle_r = PIPE_SWIZZLE_X; + svTempl.swizzle_g = PIPE_SWIZZLE_Y; + svTempl.swizzle_b = PIPE_SWIZZLE_Z; + svTempl.swizzle_a = PIPE_SWIZZLE_W; + for (int i = 0; i < 2; ++i) { + svTempl.texture = m_gpuTex[i]; + m_gpuView[i] = ctx->m_pctx->create_sampler_view(ctx->m_pctx, m_gpuTex[i], &svTempl); + } +} + +void NXTextureD::update(int b) { + int slot = 1 << b; + if ((slot & m_validSlots) == 0) { + NXContext* ctx = m_q->m_ctx; + uint blockSize = util_format_get_blocksize(m_nxFmt); + uint8_t* ptr = m_stagingBuf.get(); + size_t rowStride = m_width * blockSize; + size_t imageBytes = rowStride * m_height; + + struct pipe_box box; + u_box_2d(0, 0, m_width, m_height, &box); + + ctx->m_pctx->texture_subdata(ctx->m_pctx, m_gpuTex[m_q->m_fillBuf], 0, PIPE_TRANSFER_WRITE, &box, ptr, rowStride, + imageBytes); + + m_validSlots |= slot; + } +} + +void NXTextureD::setClampMode(TextureClampMode mode) { + m_clampMode = mode; + MakeSampler(m_q->m_ctx, m_sampler, mode, 1); +} + +void NXTextureD::load(const void* data, size_t sz) { + size_t bufSz = std::min(sz, m_cpuSz); + memmove(m_stagingBuf.get(), data, bufSz); + m_validSlots = 0; +} + +void* NXTextureD::map(size_t sz) { + if (sz > m_cpuSz) + return nullptr; + return m_stagingBuf.get(); +} + +void NXTextureD::unmap() { m_validSlots = 0; } + +static inline struct pipe_resource* pipe_buffer_create_flags(struct pipe_screen* screen, unsigned bind, + enum pipe_resource_usage usage, unsigned flags, + unsigned size) { + struct pipe_resource buffer; + memset(&buffer, 0, sizeof buffer); + buffer.target = PIPE_BUFFER; + buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */ + buffer.bind = bind; + buffer.usage = usage; + buffer.flags = flags; + buffer.width0 = size; + buffer.height0 = 1; + buffer.depth0 = 1; + buffer.array_size = 1; + return screen->resource_create(screen, &buffer); +} + +void NXDataFactoryImpl::commitTransaction( + const std::function& trans __BooTraceArgs) { + Context ctx(*this __BooTraceArgsUse); + if (!trans(ctx)) + return; + + NXData* data = ctx.m_data.cast(); + + /* size up resources */ + unsigned constantMemSizes[3] = {}; + + if (data->m_SBufs) + for (IGraphicsBufferS& buf : *data->m_SBufs) { + auto& cbuf = static_cast(buf); + if (cbuf.m_use == BufferUse::Null) + continue; + unsigned& sz = constantMemSizes[int(cbuf.m_use) - 1]; + sz = cbuf.sizeForGPU(m_ctx, sz); + } + + if (data->m_DBufs) + for (IGraphicsBufferD& buf : *data->m_DBufs) { + auto& cbuf = static_cast&>(buf); + if (cbuf.m_use == BufferUse::Null) + continue; + unsigned& sz = constantMemSizes[int(cbuf.m_use) - 1]; + sz = cbuf.sizeForGPU(m_ctx, sz); + } + + /* allocate memory and place buffers */ + for (int i = 0; i < 3; ++i) { + if (constantMemSizes[i]) { + struct pipe_resource* poolBuf = pipe_buffer_create_flags( + m_ctx->m_screen, USE_TABLE[i + 1], PIPE_USAGE_DEFAULT, + PIPE_RESOURCE_FLAG_MAP_PERSISTENT | PIPE_RESOURCE_FLAG_MAP_COHERENT, constantMemSizes[i]); + data->m_constantBuffers[i] = poolBuf; + pipe_transfer* xfer; + uint8_t* mappedData = (uint8_t*)pipe_buffer_map( + m_ctx->m_pctx, poolBuf, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_MAP_DIRECTLY | PIPE_TRANSFER_PERSISTENT | PIPE_TRANSFER_COHERENT, &xfer); + + if (data->m_SBufs) + for (IGraphicsBufferS& buf : *data->m_SBufs) { + auto& cbuf = static_cast(buf); + if (int(cbuf.m_use) - 1 != i) + continue; + cbuf.placeForGPU(poolBuf, mappedData); + } + + if (data->m_DBufs) + for (IGraphicsBufferD& buf : *data->m_DBufs) { + auto& cbuf = static_cast&>(buf); + if (int(cbuf.m_use) - 1 != i) + continue; + cbuf.placeForGPU(poolBuf, mappedData); + } + } + } + + /* Commit data bindings (create descriptor sets) */ + if (data->m_SBinds) + for (IShaderDataBinding& bind : *data->m_SBinds) + static_cast(bind).commit(); +} + +boo::ObjToken NXDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, + size_t count __BooTraceArgs) { + boo::ObjToken pool(new NXPool(*this __BooTraceArgsUse)); + NXPool* cpool = pool.cast(); + NXGraphicsBufferD* retval = + new NXGraphicsBufferD(pool, use, m_ctx, stride, count); + + unsigned size = retval->sizeForGPU(m_ctx, 0); + + /* allocate memory */ + if (size) { + struct pipe_resource* poolBuf = + pipe_buffer_create_flags(m_ctx->m_screen, USE_TABLE[int(use)], PIPE_USAGE_DEFAULT, + PIPE_RESOURCE_FLAG_MAP_PERSISTENT | PIPE_RESOURCE_FLAG_MAP_COHERENT, size); + cpool->m_constantBuffer = poolBuf; + pipe_transfer* xfer; + uint8_t* mappedData = (uint8_t*)pipe_buffer_map( + m_ctx->m_pctx, poolBuf, + PIPE_TRANSFER_WRITE | PIPE_TRANSFER_MAP_DIRECTLY | PIPE_TRANSFER_PERSISTENT | PIPE_TRANSFER_COHERENT, &xfer); + retval->placeForGPU(poolBuf, mappedData); + } + + return {retval}; +} + +void NXCommandQueue::execute() { + if (!m_running) + return; + + /* Stage dynamic uploads */ + NXDataFactoryImpl* gfxF = static_cast(m_parent->getDataFactory()); + std::unique_lock datalk(gfxF->m_dataMutex); + if (gfxF->m_dataHead) { + for (BaseGraphicsData& d : *gfxF->m_dataHead) { + if (d.m_DBufs) + for (IGraphicsBufferD& b : *d.m_DBufs) + static_cast&>(b).update(m_fillBuf); + if (d.m_DTexs) + for (ITextureD& t : *d.m_DTexs) + static_cast(t).update(m_fillBuf); + } + } + if (gfxF->m_poolHead) { + for (BaseGraphicsPool& p : *gfxF->m_poolHead) { + if (p.m_DBufs) + for (IGraphicsBufferD& b : *p.m_DBufs) + static_cast&>(b).update(m_fillBuf); + } + } + datalk.unlock(); + + /* Perform texture and swap-chain resizes */ + if (m_ctx->_resizeWindowSurfaces() || m_texResizes.size()) { + for (const auto& resize : m_texResizes) { + if (m_boundTarget.get() == resize.first) + m_boundTarget.reset(); + resize.first->resize(m_ctx, resize.second.first, resize.second.second); + } + m_texResizes.clear(); + m_resolveDispSource = nullptr; + return; + } + + /* Clear dead data */ + m_drawResTokens[m_drawBuf].clear(); + + /* Swap internal buffers */ + m_drawBuf = m_fillBuf; + m_fillBuf ^= 1; + + /* Flush the pipe */ + m_ctx->m_pctx->flush(m_ctx->m_pctx, nullptr, PIPE_FLUSH_END_OF_FRAME); + + /* Set framebuffer fence */ + NvFence fence; + struct pipe_surface* old_back = m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT]; + fence.id = nouveau_switch_resource_get_syncpoint(old_back->texture, &fence.value); + if ((int)fence.id >= 0) { + NvFence* surf_fence = &m_ctx->m_fences[m_ctx->m_fence_swap]; + if (surf_fence->id != fence.id || surf_fence->value != fence.value) { + *surf_fence = fence; + + NvMultiFence mf; + nvMultiFenceCreate(&mf, &fence); + gfxAppendFence(&mf); + } + } + + gfxSwapBuffers(); + + /* Swap buffer attachments and invalidate framebuffer */ + m_ctx->m_fence_swap = !m_ctx->m_fence_swap; + m_ctx->m_windowSurfaces[ST_ATTACHMENT_BACK_LEFT] = m_ctx->m_windowSurfaces[ST_ATTACHMENT_FRONT_LEFT]; + m_ctx->m_windowSurfaces[ST_ATTACHMENT_FRONT_LEFT] = old_back; +} + +static void setMesaConfig() { + // Uncomment below to disable error checking and save CPU time (useful for production): + // setenv("MESA_NO_ERROR", "1", 1); + + // Uncomment below to enable Mesa logging: + setenv("EGL_LOG_LEVEL", "debug", 1); + setenv("MESA_VERBOSE", "all", 1); + setenv("NOUVEAU_MESA_DEBUG", "1", 1); + + // Uncomment below to enable shader debugging in Nouveau: + setenv("NV50_PROG_OPTIMIZE", "0", 1); + setenv("NV50_PROG_DEBUG", "1", 1); + setenv("NV50_PROG_CHIPSET", "0x120", 1); +} + +bool NXContext::initialize() { + /* Set mesa configuration (useful for debugging) */ + setMesaConfig(); + + gfxInitDefault(); + gfxSetMode(GfxMode_TiledDouble); + consoleInit(NULL); + printf("Activated console\n\n"); + m_screen = nouveau_switch_screen_create(); + if (!m_screen) { + Log.report(logvisor::Fatal, "Failed to create nouveau screen"); return false; + } + printf("nouveau_switch_screen_create done\n"); + fflush(stdout); + + m_pctx = m_screen->context_create(m_screen, nullptr, 0); + if (!m_pctx) { + Log.report(logvisor::Fatal, "Failed to create pipe context"); + m_screen->destroy(m_screen); + return false; + } + printf("m_screen->context_create done\n"); + + st_config_options opts = {}; + m_st = st_create_context(API_OPENGL_CORE, m_pctx, nullptr, nullptr, &opts, false); + if (!m_st) { + Log.report(logvisor::Fatal, "Failed to create st context"); + m_screen->destroy(m_screen); + return false; + } + + u32 width, height; + gfxGetFramebufferResolution(&width, &height); + + for (int i = 0; i < 2; ++i) { + /* color target */ + struct pipe_resource texTempl = {}; + texTempl.target = PIPE_TEXTURE_RECT; + texTempl.format = ColorFormat; + texTempl.width0 = width; + texTempl.height0 = height; + texTempl.depth0 = 1; + texTempl.array_size = 1; + texTempl.usage = PIPE_USAGE_DEFAULT; + texTempl.nr_samples = texTempl.nr_storage_samples = 1; + texTempl.bind = PIPE_BIND_RENDER_TARGET; + u32 index = i == ST_ATTACHMENT_FRONT_LEFT ? 1 : 0; + struct winsys_handle whandle; + whandle.type = WINSYS_HANDLE_TYPE_SHARED; + whandle.handle = gfxGetFramebufferHandle(index, &whandle.offset); + whandle.stride = gfxGetFramebufferPitch(); + struct pipe_resource* tex = m_screen->resource_from_handle(m_screen, &texTempl, &whandle, 0); + if (!tex) { + Log.report(logvisor::Fatal, "Failed to create color target texture"); + return false; + } + + /* surface */ + struct pipe_surface surfTempl = {}; + surfTempl.format = ColorFormat; + m_windowSurfaces[i] = m_pctx->create_surface(m_pctx, tex, &surfTempl); + if (!m_windowSurfaces[i]) { + Log.report(logvisor::Fatal, "Failed to create color surface"); + return false; + } + + m_fences[i].id = UINT32_MAX; + } + + return m_compiler.initialize(m_screen, m_st); } -std::unique_ptr _NewNXCommandQueue(NXContext* ctx, IGraphicsContext* parent) -{ - return std::make_unique(ctx, parent); +bool NXContext::terminate() { + if (m_st) + st_destroy_context(m_st); + if (m_screen) + m_screen->destroy(m_screen); + gfxExit(); + return true; } -std::unique_ptr _NewNXDataFactory(IGraphicsContext* parent, NXContext* ctx) -{ - return std::make_unique(parent, ctx); +bool NXContext::_resizeWindowSurfaces() { return false; } + +std::unique_ptr _NewNXCommandQueue(NXContext* ctx, IGraphicsContext* parent) { + return std::make_unique(ctx, parent); } +std::unique_ptr _NewNXDataFactory(IGraphicsContext* parent, NXContext* ctx) { + return std::make_unique(parent, ctx); } + +} // namespace boo diff --git a/lib/graphicsdev/nx/nx_compiler.cpp b/lib/graphicsdev/nx/nx_compiler.cpp index 92ec834..b66b611 100644 --- a/lib/graphicsdev/nx/nx_compiler.cpp +++ b/lib/graphicsdev/nx/nx_compiler.cpp @@ -52,212 +52,165 @@ extern "C" { #include "nvc0/nvc0_program.h" } -_GLAPI_EXPORT __thread void * _glapi_tls_Context; -_GLAPI_EXPORT __thread struct _glapi_table * _glapi_tls_Dispatch; +_GLAPI_EXPORT __thread void* _glapi_tls_Context; +_GLAPI_EXPORT __thread struct _glapi_table* _glapi_tls_Dispatch; -int -_glapi_add_dispatch( const char * const * function_names, - const char * parameter_signature ) -{ - return 0; +int _glapi_add_dispatch(const char* const* function_names, const char* parameter_signature) { return 0; } + +void _glapi_destroy_multithread(void) {} + +void _glapi_check_multithread(void) {} + +void _glapi_set_context(void* context) { _glapi_tls_Context = context; } + +void* _glapi_get_context() { return _glapi_tls_Context; } + +void _glapi_set_dispatch(struct _glapi_table* dispatch) { _glapi_tls_Dispatch = dispatch; } + +struct _glapi_table* _glapi_get_dispatch() { + return _glapi_tls_Dispatch; } -void -_glapi_destroy_multithread(void) -{ -} - -void -_glapi_check_multithread(void) -{ -} - -void -_glapi_set_context(void *context) -{ - _glapi_tls_Context = context; -} - -void * -_glapi_get_context() -{ - return _glapi_tls_Context; -} - -void -_glapi_set_dispatch(struct _glapi_table *dispatch) -{ - _glapi_tls_Dispatch = dispatch; -} - -struct _glapi_table * -_glapi_get_dispatch() -{ - return _glapi_tls_Dispatch; -} - -GLuint -_glapi_get_dispatch_table_size(void) -{ - /* - * The dispatch table size (number of entries) is the size of the - * _glapi_table struct plus the number of dynamic entries we can add. - * The extra slots can be filled in by DRI drivers that register new - * extension functions. - */ - return 0; +GLuint _glapi_get_dispatch_table_size(void) { + /* + * The dispatch table size (number of entries) is the size of the + * _glapi_table struct plus the number of dynamic entries we can add. + * The extra slots can be filled in by DRI drivers that register new + * extension functions. + */ + return 0; } class dead_variable_visitor : public ir_hierarchical_visitor { public: - dead_variable_visitor() - { - variables = _mesa_set_create(NULL, - _mesa_hash_pointer, - _mesa_key_pointer_equal); - } - - virtual ~dead_variable_visitor() - { - _mesa_set_destroy(variables, NULL); - } - - virtual ir_visitor_status visit(ir_variable *ir) - { - /* If the variable is auto or temp, add it to the set of variables that - * are candidates for removal. - */ - if (ir->data.mode != ir_var_auto && ir->data.mode != ir_var_temporary) - return visit_continue; - - _mesa_set_add(variables, ir); - - return visit_continue; - } - - virtual ir_visitor_status visit(ir_dereference_variable *ir) - { - struct set_entry *entry = _mesa_set_search(variables, ir->var); - - /* If a variable is dereferenced at all, remove it from the set of - * variables that are candidates for removal. - */ - if (entry != NULL) - _mesa_set_remove(variables, entry); - - return visit_continue; - } - - void remove_dead_variables() - { - struct set_entry *entry; - - set_foreach(variables, entry) { - ir_variable *ir = (ir_variable *) entry->key; - - assert(ir->ir_type == ir_type_variable); - ir->remove(); - } + dead_variable_visitor() { variables = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); } + + virtual ~dead_variable_visitor() { _mesa_set_destroy(variables, NULL); } + + virtual ir_visitor_status visit(ir_variable* ir) { + /* If the variable is auto or temp, add it to the set of variables that + * are candidates for removal. + */ + if (ir->data.mode != ir_var_auto && ir->data.mode != ir_var_temporary) + return visit_continue; + + _mesa_set_add(variables, ir); + + return visit_continue; + } + + virtual ir_visitor_status visit(ir_dereference_variable* ir) { + struct set_entry* entry = _mesa_set_search(variables, ir->var); + + /* If a variable is dereferenced at all, remove it from the set of + * variables that are candidates for removal. + */ + if (entry != NULL) + _mesa_set_remove(variables, entry); + + return visit_continue; + } + + void remove_dead_variables() { + struct set_entry* entry; + + set_foreach(variables, entry) { + ir_variable* ir = (ir_variable*)entry->key; + + assert(ir->ir_type == ir_type_variable); + ir->remove(); } + } private: - set *variables; + set* variables; }; -void nx_compiler::compile_shader(struct gl_context *ctx, struct gl_shader *shader) -{ - struct _mesa_glsl_parse_state *state = - new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader); +void nx_compiler::compile_shader(struct gl_context* ctx, struct gl_shader* shader) { + struct _mesa_glsl_parse_state* state = new (shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader); - _mesa_glsl_compile_shader(ctx, shader, m_options.dump_ast, - m_options.dump_hir, true); + _mesa_glsl_compile_shader(ctx, shader, m_options.dump_ast, m_options.dump_hir, true); - /* Print out the resulting IR */ - if (!state->error && m_options.dump_lir) { - _mesa_print_ir(stdout, shader->ir, state); - } + /* Print out the resulting IR */ + if (!state->error && m_options.dump_lir) { + _mesa_print_ir(stdout, shader->ir, state); + } } -nx_compiler::nx_compiler() -{ - m_options.glsl_version = 330; - m_options.do_link = true; +nx_compiler::nx_compiler() { + m_options.glsl_version = 330; + m_options.do_link = true; } -nx_compiler::~nx_compiler() -{ - if (m_ownsCtx) - { - _mesa_glsl_release_types(); - _mesa_glsl_release_builtin_functions(); - if (m_st) - st_destroy_context(m_st); - if (m_screen) - m_screen->destroy(m_screen); - } +nx_compiler::~nx_compiler() { + if (m_ownsCtx) { + _mesa_glsl_release_types(); + _mesa_glsl_release_builtin_functions(); + if (m_st) + st_destroy_context(m_st); + if (m_screen) + m_screen->destroy(m_screen); + } } -bool nx_compiler::initialize(struct pipe_screen *screen, struct st_context *st, - const struct standalone_options *o) -{ - m_screen = screen; - m_st = st; - if (o) - memcpy(&m_options, o, sizeof(*o)); - return true; +bool nx_compiler::initialize(struct pipe_screen* screen, struct st_context* st, const struct standalone_options* o) { + m_screen = screen; + m_st = st; + if (o) + memcpy(&m_options, o, sizeof(*o)); + return true; } -bool nx_compiler::initialize(const struct standalone_options* o) -{ - m_ownsCtx = true; - bool glsl_es; +bool nx_compiler::initialize(const struct standalone_options* o) { + m_ownsCtx = true; + bool glsl_es; - if (o) - memcpy(&m_options, o, sizeof(*o)); + if (o) + memcpy(&m_options, o, sizeof(*o)); - switch (m_options.glsl_version) { - case 100: - case 300: - glsl_es = true; - break; - case 110: - case 120: - case 130: - case 140: - case 150: - case 330: - case 400: - case 410: - case 420: - case 430: - case 440: - case 450: - case 460: - glsl_es = false; - break; - default: - fprintf(stderr, "Unrecognized GLSL version `%d'\n", m_options.glsl_version); - return false; - } + switch (m_options.glsl_version) { + case 100: + case 300: + glsl_es = true; + break; + case 110: + case 120: + case 130: + case 140: + case 150: + case 330: + case 400: + case 410: + case 420: + case 430: + case 440: + case 450: + case 460: + glsl_es = false; + break; + default: + fprintf(stderr, "Unrecognized GLSL version `%d'\n", m_options.glsl_version); + return false; + } - gl_api use_api; - if (glsl_es) { - use_api = API_OPENGLES2; - } else { - use_api = m_options.glsl_version > 130 ? API_OPENGL_CORE : API_OPENGL_COMPAT; - } + gl_api use_api; + if (glsl_es) { + use_api = API_OPENGLES2; + } else { + use_api = m_options.glsl_version > 130 ? API_OPENGL_CORE : API_OPENGL_COMPAT; + } - struct nouveau_screen *(*init)(struct nouveau_device *); + struct nouveau_screen* (*init)(struct nouveau_device*); - struct nouveau_drm *fakedrm = (struct nouveau_drm *)malloc(sizeof(struct nouveau_drm)); - if (!fakedrm) - return false; - memset(fakedrm, 0, sizeof(*fakedrm)); - nouveau_device *ndev; - if (nouveau_device_new(&fakedrm->client, 0, nullptr, 0, &ndev)) - return false; + struct nouveau_drm* fakedrm = (struct nouveau_drm*)malloc(sizeof(struct nouveau_drm)); + if (!fakedrm) + return false; + memset(fakedrm, 0, sizeof(*fakedrm)); + nouveau_device* ndev; + if (nouveau_device_new(&fakedrm->client, 0, nullptr, 0, &ndev)) + return false; - switch (ndev->chipset & ~0xf) { + switch (ndev->chipset & ~0xf) { #if 0 case 0x30: case 0x40: @@ -271,401 +224,367 @@ bool nx_compiler::initialize(const struct standalone_options* o) init = nv50_screen_create; break; #endif - default: - case 0xc0: - case 0xd0: - case 0xe0: - case 0xf0: - case 0x100: - case 0x110: - case 0x120: - case 0x130: - init = nvc0_screen_create; - break; - } + default: + case 0xc0: + case 0xd0: + case 0xe0: + case 0xf0: + case 0x100: + case 0x110: + case 0x120: + case 0x130: + init = nvc0_screen_create; + break; + } - struct nouveau_screen *screen = init(ndev); - if (!screen) - return false; - screen->refcount = 1; - struct pipe_context *p_ctx = screen->base.context_create(&screen->base, nullptr, 0); - if (!p_ctx) - { - screen->base.destroy(&screen->base); - return false; - } + struct nouveau_screen* screen = init(ndev); + if (!screen) + return false; + screen->refcount = 1; + struct pipe_context* p_ctx = screen->base.context_create(&screen->base, nullptr, 0); + if (!p_ctx) { + screen->base.destroy(&screen->base); + return false; + } - st_config_options opts = {}; - struct st_context *st = st_create_context(use_api, p_ctx, nullptr, nullptr, &opts, false); - if (!st) - { - screen->base.destroy(&screen->base); - return false; - } + st_config_options opts = {}; + struct st_context* st = st_create_context(use_api, p_ctx, nullptr, nullptr, &opts, false); + if (!st) { + screen->base.destroy(&screen->base); + return false; + } - return initialize(&screen->base, st); + return initialize(&screen->base, st); } -nx_shader_stage_object::nx_shader_stage_object(const nx_shader_stage_object& other) -: m_parent(other.m_parent) -{ - if (!other.m_shader || !m_parent) - return; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader(ctx, &m_shader, other.m_shader); +nx_shader_stage_object::nx_shader_stage_object(const nx_shader_stage_object& other) : m_parent(other.m_parent) { + if (!other.m_shader || !m_parent) + return; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader(ctx, &m_shader, other.m_shader); } -nx_shader_stage_object& nx_shader_stage_object::operator=(const nx_shader_stage_object& other) -{ - m_parent = other.m_parent; - if (!other.m_shader || !m_parent) - return *this; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader(ctx, &m_shader, other.m_shader); +nx_shader_stage_object& nx_shader_stage_object::operator=(const nx_shader_stage_object& other) { + m_parent = other.m_parent; + if (!other.m_shader || !m_parent) return *this; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader(ctx, &m_shader, other.m_shader); + return *this; } -void nx_shader_stage_object::reset() -{ - if (!m_shader || !m_parent) - return; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader(ctx, &m_shader, nullptr); +void nx_shader_stage_object::reset() { + if (!m_shader || !m_parent) + return; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader(ctx, &m_shader, nullptr); } -nx_shader_stage_object::operator bool() const -{ - if (!m_shader) - return false; - return m_shader->CompileStatus; +nx_shader_stage_object::operator bool() const { + if (!m_shader) + return false; + return m_shader->CompileStatus; } -nx_shader_stage nx_shader_stage_object::stage() const -{ - return nx_shader_stage(m_shader->Stage); +nx_shader_stage nx_shader_stage_object::stage() const { return nx_shader_stage(m_shader->Stage); } + +const char* nx_shader_stage_object::info_log() const { + if (!m_shader) + return nullptr; + return m_shader->InfoLog; } -const char* nx_shader_stage_object::info_log() const -{ - if (!m_shader) - return nullptr; - return m_shader->InfoLog; +nx_linked_shader::nx_linked_shader(const nx_linked_shader& other) : m_parent(other.m_parent) { + if (!other.m_program || !m_parent) + return; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader_program(ctx, &m_program, other.m_program); } -nx_linked_shader::nx_linked_shader(const nx_linked_shader& other) -: m_parent(other.m_parent) -{ - if (!other.m_program || !m_parent) - return; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader_program(ctx, &m_program, other.m_program); -} - -nx_linked_shader& nx_linked_shader::operator=(const nx_linked_shader& other) -{ - m_parent = other.m_parent; - if (!other.m_program || !m_parent) - return *this; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader_program(ctx, &m_program, other.m_program); +nx_linked_shader& nx_linked_shader::operator=(const nx_linked_shader& other) { + m_parent = other.m_parent; + if (!other.m_program || !m_parent) return *this; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader_program(ctx, &m_program, other.m_program); + return *this; } -void nx_linked_shader::reset() -{ - if (!m_program || !m_parent) - return; - struct gl_context *ctx = m_parent->m_st->ctx; - _mesa_reference_shader_program(ctx, &m_program, nullptr); +void nx_linked_shader::reset() { + if (!m_program || !m_parent) + return; + struct gl_context* ctx = m_parent->m_st->ctx; + _mesa_reference_shader_program(ctx, &m_program, nullptr); } -nx_shader_stage_object nx_compiler::compile(nx_shader_stage type, const char *source) -{ - struct gl_context *ctx = m_st->ctx; +nx_shader_stage_object nx_compiler::compile(nx_shader_stage type, const char* source) { + struct gl_context* ctx = m_st->ctx; - nx_shader_stage_object ret(*this); - ret.m_shader = rzalloc(nullptr, gl_shader); - assert(ret.m_shader != NULL); - ret.m_shader->RefCount = 1; + nx_shader_stage_object ret(*this); + ret.m_shader = rzalloc(nullptr, gl_shader); + assert(ret.m_shader != NULL); + ret.m_shader->RefCount = 1; - ret.m_shader->Stage = gl_shader_stage(type); - ret.m_shader->Source = source; + ret.m_shader->Stage = gl_shader_stage(type); + ret.m_shader->Source = source; - compile_shader(ctx, ret.m_shader); + compile_shader(ctx, ret.m_shader); - /* Mesa doesn't actually own the source, so take it away here */ - ret.m_shader->Source = nullptr; + /* Mesa doesn't actually own the source, so take it away here */ + ret.m_shader->Source = nullptr; - return ret; + return ret; } -nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_object **stages, std::string* infoLog) -{ - nx_linked_shader ret(*this); - int status = EXIT_SUCCESS; - struct gl_context *ctx = m_st->ctx; +nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_object** stages, std::string* infoLog) { + nx_linked_shader ret(*this); + int status = EXIT_SUCCESS; + struct gl_context* ctx = m_st->ctx; - struct gl_shader_program *whole_program; + struct gl_shader_program* whole_program; - whole_program = rzalloc (NULL, struct gl_shader_program); - assert(whole_program != NULL); - whole_program->Type = GL_SHADER_PROGRAM_MESA; - whole_program->data = rzalloc(whole_program, struct gl_shader_program_data); - assert(whole_program->data != NULL); - whole_program->data->RefCount = 1; - whole_program->data->InfoLog = ralloc_strdup(whole_program->data, ""); - ret.m_program = whole_program; + whole_program = rzalloc(NULL, struct gl_shader_program); + assert(whole_program != NULL); + whole_program->Type = GL_SHADER_PROGRAM_MESA; + whole_program->data = rzalloc(whole_program, struct gl_shader_program_data); + assert(whole_program->data != NULL); + whole_program->data->RefCount = 1; + whole_program->data->InfoLog = ralloc_strdup(whole_program->data, ""); + ret.m_program = whole_program; - whole_program->Shaders = (struct gl_shader **)calloc(num_stages, sizeof(struct gl_shader *)); - assert(whole_program->Shaders != NULL); + whole_program->Shaders = (struct gl_shader**)calloc(num_stages, sizeof(struct gl_shader*)); + assert(whole_program->Shaders != NULL); - for (unsigned i = 0; i < num_stages; i++) { - whole_program->Shaders[whole_program->NumShaders] = stages[i]->m_shader; - stages[i]->m_shader->RefCount++; - whole_program->NumShaders++; + for (unsigned i = 0; i < num_stages; i++) { + whole_program->Shaders[whole_program->NumShaders] = stages[i]->m_shader; + stages[i]->m_shader->RefCount++; + whole_program->NumShaders++; - if (!stages[i]->m_shader->CompileStatus) { - status = EXIT_FAILURE; - break; - } + if (!stages[i]->m_shader->CompileStatus) { + status = EXIT_FAILURE; + break; } + } + + if (status == EXIT_SUCCESS) { + _mesa_clear_shader_program_data(ctx, whole_program); + + if (m_options.do_link) { + link_shaders(ctx, whole_program); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (whole_program->_LinkedShaders[i]) + whole_program->_LinkedShaders[i]->Program->Target = _mesa_shader_stage_to_program(i); + } + } else { + const gl_shader_stage stage = whole_program->Shaders[0]->Stage; + + whole_program->data->LinkStatus = LINKING_SUCCESS; + whole_program->_LinkedShaders[stage] = + link_intrastage_shaders(whole_program /* mem_ctx */, ctx, whole_program, whole_program->Shaders, 1, true); + whole_program->_LinkedShaders[stage]->Program->Target = _mesa_shader_stage_to_program(stage); + + /* Par-linking can fail, for example, if there are undefined external + * references. + */ + if (whole_program->_LinkedShaders[stage] != NULL) { + assert(whole_program->data->LinkStatus); + + struct gl_shader_compiler_options* const compiler_options = &ctx->Const.ShaderCompilerOptions[stage]; + + exec_list* const ir = whole_program->_LinkedShaders[stage]->ir; + + bool progress; + do { + progress = do_function_inlining(ir); + + progress = do_common_optimization(ir, false, false, compiler_options, true) && progress; + } while (progress); + } + } + + status = (whole_program->data->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; + + if (infoLog) + *infoLog = whole_program->data->InfoLog; if (status == EXIT_SUCCESS) { - _mesa_clear_shader_program_data(ctx, whole_program); + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader* shader = whole_program->_LinkedShaders[i]; - if (m_options.do_link) { - link_shaders(ctx, whole_program); - for (int i = 0; i < MESA_SHADER_STAGES; ++i) { - if (whole_program->_LinkedShaders[i]) - whole_program->_LinkedShaders[i]->Program->Target = _mesa_shader_stage_to_program(i); - } - } else { - const gl_shader_stage stage = whole_program->Shaders[0]->Stage; - - whole_program->data->LinkStatus = LINKING_SUCCESS; - whole_program->_LinkedShaders[stage] = - link_intrastage_shaders(whole_program /* mem_ctx */, - ctx, - whole_program, - whole_program->Shaders, - 1, - true); - whole_program->_LinkedShaders[stage]->Program->Target = _mesa_shader_stage_to_program(stage); - - /* Par-linking can fail, for example, if there are undefined external - * references. - */ - if (whole_program->_LinkedShaders[stage] != NULL) { - assert(whole_program->data->LinkStatus); - - struct gl_shader_compiler_options *const compiler_options = - &ctx->Const.ShaderCompilerOptions[stage]; - - exec_list *const ir = - whole_program->_LinkedShaders[stage]->ir; - - bool progress; - do { - progress = do_function_inlining(ir); - - progress = do_common_optimization(ir, - false, - false, - compiler_options, - true) - && progress; - } while(progress); - } - } - - status = (whole_program->data->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; - - if (infoLog) - *infoLog = whole_program->data->InfoLog; - - if (status == EXIT_SUCCESS) { - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *shader = whole_program->_LinkedShaders[i]; - - if (!shader) - continue; - - add_neg_to_sub_visitor v; - visit_list_elements(&v, shader->ir); - - dead_variable_visitor dv; - visit_list_elements(&dv, shader->ir); - dv.remove_dead_variables(); - } - - if (m_options.dump_builder) { - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *shader = whole_program->_LinkedShaders[i]; - - if (!shader) - continue; - - _mesa_print_builder_for_ir(stdout, shader->ir); - } - } - - ctx->_Shader = &ctx->Shader; - st_link_shader(ctx, whole_program); - ctx->_Shader = nullptr; - return ret; - } - } - - return nx_linked_shader(*this); -} - -static void -SizeProgramBuffer(const nvc0_program *prog, size_t &sz) -{ - sz += 140; - sz += prog->code_size; -} - -template static void -OutputField(T f, uint8_t *&ptr) -{ - memcpy(ptr, &f, sizeof(f)); - ptr += sizeof(f); -} - -static void -BuildProgramBuffer(const nvc0_program *prog, uint8_t *&ptr) -{ - OutputField(prog->type, ptr); - OutputField(prog->translated, ptr); - OutputField(prog->need_tls, ptr); - OutputField(prog->num_gprs, ptr); - OutputField(prog->code_base, ptr); - OutputField(prog->code_size, ptr); - OutputField(prog->parm_size, ptr); - for (const auto& h : prog->hdr) - OutputField(h, ptr); - for (const auto& h : prog->flags) - OutputField(h, ptr); - OutputField(prog->vp.clip_mode, ptr); - OutputField(prog->vp.clip_enable, ptr); - OutputField(prog->vp.cull_enable, ptr); - OutputField(prog->vp.num_ucps, ptr); - OutputField(prog->vp.edgeflag, ptr); - OutputField(prog->vp.need_vertex_id, ptr); - OutputField(prog->vp.need_draw_parameters, ptr); - OutputField(prog->fp.early_z, ptr); - OutputField(prog->fp.colors, ptr); - OutputField(prog->fp.color_interp[0], ptr); - OutputField(prog->fp.color_interp[1], ptr); - OutputField(prog->fp.sample_mask_in, ptr); - OutputField(prog->fp.force_persample_interp, ptr); - OutputField(prog->fp.flatshade, ptr); - OutputField(prog->fp.reads_framebuffer, ptr); - OutputField(prog->fp.post_depth_coverage, ptr); - OutputField(prog->tp.tess_mode, ptr); - OutputField(prog->tp.input_patch_size, ptr); - OutputField(prog->cp.lmem_size, ptr); - OutputField(prog->cp.smem_size, ptr); - OutputField(prog->num_barriers, ptr); - memcpy(ptr, prog->code, prog->code_size); - ptr += prog->code_size; -} - -std::pair, size_t> -nx_compiler::offline_link(unsigned num_stages, const nx_shader_stage_object **stages, std::string *infoLog) -{ - std::pair, size_t> ret = {}; - auto whole_program = link(num_stages, stages, infoLog); - if (!whole_program) - return ret; - - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *shader = whole_program.m_program->_LinkedShaders[i]; if (!shader) + continue; + + add_neg_to_sub_visitor v; + visit_list_elements(&v, shader->ir); + + dead_variable_visitor dv; + visit_list_elements(&dv, shader->ir); + dv.remove_dead_variables(); + } + + if (m_options.dump_builder) { + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader* shader = whole_program->_LinkedShaders[i]; + + if (!shader) continue; - struct gl_program *prog = shader->Program; - switch (prog->Target) { - case GL_VERTEX_PROGRAM_ARB: { - struct st_vertex_program *p = (struct st_vertex_program *)prog; - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - SizeProgramBuffer(dp, ret.second); - break; - } - case GL_TESS_CONTROL_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - SizeProgramBuffer(dp, ret.second); - break; - } - case GL_TESS_EVALUATION_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - SizeProgramBuffer(dp, ret.second); - break; - } - case GL_GEOMETRY_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - SizeProgramBuffer(dp, ret.second); - break; - } - case GL_FRAGMENT_PROGRAM_ARB: { - struct st_fragment_program *p = (struct st_fragment_program *)prog; - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - SizeProgramBuffer(dp, ret.second); - break; - } - default: - assert(0); + _mesa_print_builder_for_ir(stdout, shader->ir); } + } + + ctx->_Shader = &ctx->Shader; + st_link_shader(ctx, whole_program); + ctx->_Shader = nullptr; + return ret; } + } - ret.first.reset(new uint8_t[ret.second]); - uint8_t *pbuf = ret.first.get(); + return nx_linked_shader(*this); +} - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *shader = whole_program.m_program->_LinkedShaders[i]; - if (!shader) - continue; - struct gl_program *prog = shader->Program; +static void SizeProgramBuffer(const nvc0_program* prog, size_t& sz) { + sz += 140; + sz += prog->code_size; +} - switch (prog->Target) { - case GL_VERTEX_PROGRAM_ARB: { - struct st_vertex_program *p = (struct st_vertex_program *)prog; - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - BuildProgramBuffer(dp, pbuf); - break; - } - case GL_TESS_CONTROL_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - BuildProgramBuffer(dp, pbuf); - break; - } - case GL_TESS_EVALUATION_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - BuildProgramBuffer(dp, pbuf); - break; - } - case GL_GEOMETRY_PROGRAM_NV: { - struct st_common_program *p = st_common_program(prog); - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - BuildProgramBuffer(dp, pbuf); - break; - } - case GL_FRAGMENT_PROGRAM_ARB: { - struct st_fragment_program *p = (struct st_fragment_program *)prog; - nvc0_program *dp = (nvc0_program *)p->variants->driver_shader; - BuildProgramBuffer(dp, pbuf); - break; - } - default: - assert(0); - } - } +template +static void OutputField(T f, uint8_t*& ptr) { + memcpy(ptr, &f, sizeof(f)); + ptr += sizeof(f); +} +static void BuildProgramBuffer(const nvc0_program* prog, uint8_t*& ptr) { + OutputField(prog->type, ptr); + OutputField(prog->translated, ptr); + OutputField(prog->need_tls, ptr); + OutputField(prog->num_gprs, ptr); + OutputField(prog->code_base, ptr); + OutputField(prog->code_size, ptr); + OutputField(prog->parm_size, ptr); + for (const auto& h : prog->hdr) + OutputField(h, ptr); + for (const auto& h : prog->flags) + OutputField(h, ptr); + OutputField(prog->vp.clip_mode, ptr); + OutputField(prog->vp.clip_enable, ptr); + OutputField(prog->vp.cull_enable, ptr); + OutputField(prog->vp.num_ucps, ptr); + OutputField(prog->vp.edgeflag, ptr); + OutputField(prog->vp.need_vertex_id, ptr); + OutputField(prog->vp.need_draw_parameters, ptr); + OutputField(prog->fp.early_z, ptr); + OutputField(prog->fp.colors, ptr); + OutputField(prog->fp.color_interp[0], ptr); + OutputField(prog->fp.color_interp[1], ptr); + OutputField(prog->fp.sample_mask_in, ptr); + OutputField(prog->fp.force_persample_interp, ptr); + OutputField(prog->fp.flatshade, ptr); + OutputField(prog->fp.reads_framebuffer, ptr); + OutputField(prog->fp.post_depth_coverage, ptr); + OutputField(prog->tp.tess_mode, ptr); + OutputField(prog->tp.input_patch_size, ptr); + OutputField(prog->cp.lmem_size, ptr); + OutputField(prog->cp.smem_size, ptr); + OutputField(prog->num_barriers, ptr); + memcpy(ptr, prog->code, prog->code_size); + ptr += prog->code_size; +} + +std::pair, size_t> nx_compiler::offline_link(unsigned num_stages, + const nx_shader_stage_object** stages, + std::string* infoLog) { + std::pair, size_t> ret = {}; + auto whole_program = link(num_stages, stages, infoLog); + if (!whole_program) return ret; + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader* shader = whole_program.m_program->_LinkedShaders[i]; + if (!shader) + continue; + struct gl_program* prog = shader->Program; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: { + struct st_vertex_program* p = (struct st_vertex_program*)prog; + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + SizeProgramBuffer(dp, ret.second); + break; + } + case GL_TESS_CONTROL_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + SizeProgramBuffer(dp, ret.second); + break; + } + case GL_TESS_EVALUATION_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + SizeProgramBuffer(dp, ret.second); + break; + } + case GL_GEOMETRY_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + SizeProgramBuffer(dp, ret.second); + break; + } + case GL_FRAGMENT_PROGRAM_ARB: { + struct st_fragment_program* p = (struct st_fragment_program*)prog; + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + SizeProgramBuffer(dp, ret.second); + break; + } + default: + assert(0); + } + } + + ret.first.reset(new uint8_t[ret.second]); + uint8_t* pbuf = ret.first.get(); + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader* shader = whole_program.m_program->_LinkedShaders[i]; + if (!shader) + continue; + struct gl_program* prog = shader->Program; + + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: { + struct st_vertex_program* p = (struct st_vertex_program*)prog; + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + BuildProgramBuffer(dp, pbuf); + break; + } + case GL_TESS_CONTROL_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + BuildProgramBuffer(dp, pbuf); + break; + } + case GL_TESS_EVALUATION_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + BuildProgramBuffer(dp, pbuf); + break; + } + case GL_GEOMETRY_PROGRAM_NV: { + struct st_common_program* p = st_common_program(prog); + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + BuildProgramBuffer(dp, pbuf); + break; + } + case GL_FRAGMENT_PROGRAM_ARB: { + struct st_fragment_program* p = (struct st_fragment_program*)prog; + nvc0_program* dp = (nvc0_program*)p->variants->driver_shader; + BuildProgramBuffer(dp, pbuf); + break; + } + default: + assert(0); + } + } + + return ret; } diff --git a/lib/graphicsdev/nx/nx_compiler_driver.cpp b/lib/graphicsdev/nx/nx_compiler_driver.cpp index 46741b0..3ef02fc 100644 --- a/lib/graphicsdev/nx/nx_compiler_driver.cpp +++ b/lib/graphicsdev/nx/nx_compiler_driver.cpp @@ -1,40 +1,36 @@ #include "boo/graphicsdev/nx_compiler.hpp" -int main(int argc, char** argv) -{ - nx_compiler c; - c.initialize(); +int main(int argc, char** argv) { + nx_compiler c; + c.initialize(); - nx_shader_stage_object objs[] = - { - c.compile(nx_shader_stage::VERTEX, - "#version 330\n" - "#extension GL_ARB_separate_shader_objects: enable\n" - "#extension GL_ARB_shading_language_420pack: enable\n" - "layout(location=0) in vec3 in_pos;\n" - "layout(location=1) in vec3 in_norm;\n" - "layout(location=2) in vec2 in_uv;\n" - "layout(location=0) out vec2 out_uv;\n" - "void main()\n" - "{\n" - " gl_Position = vec4(in_pos, 1.0).zyxx;\n" - " out_uv = in_uv;\n" - "}"), - c.compile(nx_shader_stage::FRAGMENT, - "#version 330\n" - "#extension GL_ARB_separate_shader_objects: enable\n" - "#extension GL_ARB_shading_language_420pack: enable\n" - "layout(binding=8) uniform sampler2D texs[2];\n" - "layout(location=0) out vec4 out_frag;\n" - "layout(location=0) in vec2 out_uv;\n" - "void main()\n" - "{\n" - " out_frag = texture(texs[0], out_uv) + texture(texs[1], out_uv);\n" - "}") - }; + nx_shader_stage_object objs[] = {c.compile(nx_shader_stage::VERTEX, + "#version 330\n" + "#extension GL_ARB_separate_shader_objects: enable\n" + "#extension GL_ARB_shading_language_420pack: enable\n" + "layout(location=0) in vec3 in_pos;\n" + "layout(location=1) in vec3 in_norm;\n" + "layout(location=2) in vec2 in_uv;\n" + "layout(location=0) out vec2 out_uv;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(in_pos, 1.0).zyxx;\n" + " out_uv = in_uv;\n" + "}"), + c.compile(nx_shader_stage::FRAGMENT, + "#version 330\n" + "#extension GL_ARB_separate_shader_objects: enable\n" + "#extension GL_ARB_shading_language_420pack: enable\n" + "layout(binding=8) uniform sampler2D texs[2];\n" + "layout(location=0) out vec4 out_frag;\n" + "layout(location=0) in vec2 out_uv;\n" + "void main()\n" + "{\n" + " out_frag = texture(texs[0], out_uv) + texture(texs[1], out_uv);\n" + "}")}; - std::string log; - auto linkData = c.link(2, objs, &log); + std::string log; + auto linkData = c.link(2, objs, &log); - return 0; + return 0; } diff --git a/lib/inputdev/DeviceBase.cpp b/lib/inputdev/DeviceBase.cpp index 8af4704..379c184 100644 --- a/lib/inputdev/DeviceBase.cpp +++ b/lib/inputdev/DeviceBase.cpp @@ -3,111 +3,93 @@ #include "IHIDDevice.hpp" #include -namespace boo -{ +namespace boo { -DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token) -: m_typeHash(typeHash), m_token(token) -{ +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::_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::closeDevice() -{ - if (m_token) - m_token->_deviceClose(); +void DeviceBase::deviceError(const char* error, ...) { + va_list vl; + va_start(vl, error); + vfprintf(stderr, error, vl); + va_end(vl); } -void DeviceBase::deviceError(const char* error, ...) -{ - va_list vl; - va_start(vl, error); - vfprintf(stderr, error, vl); - va_end(vl); +bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) { + if (m_hidDev) + return m_hidDev->_sendUSBInterruptTransfer(data, length); + return false; } -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; } -size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) -{ - if (m_hidDev) - return m_hidDev->_receiveUSBInterruptTransfer(data, length); - return false; +unsigned DeviceBase::getVendorId() { + if (m_token) + return m_token->getVendorId(); + return -1; } -unsigned DeviceBase::getVendorId() -{ - if (m_token) - return m_token->getVendorId(); - return -1; +unsigned DeviceBase::getProductId() { + if (m_token) + return m_token->getProductId(); + return -1; } -unsigned DeviceBase::getProductId() -{ - if (m_token) - return m_token->getProductId(); - return -1; +std::string_view DeviceBase::getVendorName() { + if (m_token) + return m_token->getVendorName(); + return {}; } -std::string_view DeviceBase::getVendorName() -{ - if (m_token) - return m_token->getVendorName(); - return {}; -} - -std::string_view DeviceBase::getProductName() -{ - if (m_token) - return m_token->getProductName(); - return {}; +std::string_view DeviceBase::getProductName() { + if (m_token) + return m_token->getProductName(); + return {}; } #if _WIN32 #if !WINDOWS_STORE -const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() -{ - if (m_hidDev) - return m_hidDev->_getReportDescriptor(); - return {}; +const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() { + if (m_hidDev) + return m_hidDev->_getReportDescriptor(); + return {}; } #endif #else -std::vector DeviceBase::getReportDescriptor() -{ - if (m_hidDev) - return m_hidDev->_getReportDescriptor(); - return {}; +std::vector DeviceBase::getReportDescriptor() { + 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; +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; +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 diff --git a/lib/inputdev/DeviceFinder.cpp b/lib/inputdev/DeviceFinder.cpp index 25ddf8a..3d0889a 100644 --- a/lib/inputdev/DeviceFinder.cpp +++ b/lib/inputdev/DeviceFinder.cpp @@ -6,68 +6,59 @@ #include #endif -namespace boo -{ +namespace boo { DeviceFinder* DeviceFinder::skDevFinder = nullptr; #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 - } - } - } - +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 diff --git a/lib/inputdev/DeviceSignature.cpp b/lib/inputdev/DeviceSignature.cpp index 9a20577..f2474ef 100644 --- a/lib/inputdev/DeviceSignature.cpp +++ b/lib/inputdev/DeviceSignature.cpp @@ -3,87 +3,75 @@ #include "boo/inputdev/GenericPad.hpp" #include "IHIDDevice.hpp" -namespace boo -{ +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; +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; } - for (const DeviceSignature* sig : sigSet) - { - if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId()) - return true; - } - return false; + 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 IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp); -std::shared_ptr DeviceSignature::DeviceNew(DeviceToken& token) -{ - std::shared_ptr retval; +std::shared_ptr DeviceSignature::DeviceNew(DeviceToken& token) { + std::shared_ptr 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; + /* 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; } - if (!foundSig) - { - /* Try Generic HID devices */ - if (token.getDeviceType() == DeviceType::HID) - { - retval = std::make_shared(&token); - if (!retval) - return nullptr; - - retval->m_hidDev = IHIDDeviceNew(token, retval); - if (!retval->m_hidDev) - return nullptr; - retval->m_hidDev->_startThread(); - - return retval; - } - + ++sigIter; + } + if (!foundSig) { + /* Try Generic HID devices */ + if (token.getDeviceType() == DeviceType::HID) { + retval = std::make_shared(&token); + if (!retval) return nullptr; + + retval->m_hidDev = IHIDDeviceNew(token, retval); + if (!retval->m_hidDev) + return nullptr; + retval->m_hidDev->_startThread(); + + return retval; } - 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; + 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 diff --git a/lib/inputdev/DolphinSmashAdapter.cpp b/lib/inputdev/DolphinSmashAdapter.cpp index e6127ea..d954c9b 100644 --- a/lib/inputdev/DolphinSmashAdapter.cpp +++ b/lib/inputdev/DolphinSmashAdapter.cpp @@ -3,8 +3,7 @@ #include #include -namespace boo -{ +namespace boo { /* * Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c */ @@ -14,134 +13,118 @@ DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) DolphinSmashAdapter::~DolphinSmashAdapter() {} -static inline EDolphinControllerType parseType(unsigned char status) -{ - EDolphinControllerType type = - EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird); - switch (type) - { - case EDolphinControllerType::Normal: - case EDolphinControllerType::Wavebird: - return type; - default: - return EDolphinControllerType::None; - } -} - -static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) -{ - memset(stateOut, 0, sizeof(DolphinControllerState)); - unsigned char status = payload[0]; - EDolphinControllerType type = parseType(status); - - rumble = ((status & 0x04) != 0) ? true : false; - - stateOut->m_btns = (uint16_t)payload[1] << 8 | (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]; - +static inline EDolphinControllerType parseType(unsigned char status) { + EDolphinControllerType type = + EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird); + switch (type) { + case EDolphinControllerType::Normal: + case EDolphinControllerType::Wavebird: return type; + default: + return EDolphinControllerType::None; + } } -void DolphinSmashAdapter::initialCycle() -{ - uint8_t handshakePayload[] = {0x13}; - sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload)); +static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) { + memset(stateOut, 0, sizeof(DolphinControllerState)); + unsigned char status = payload[0]; + EDolphinControllerType type = parseType(status); + + rumble = ((status & 0x04) != 0) ? true : false; + + stateOut->m_btns = (uint16_t)payload[1] << 8 | (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::transferCycle() -{ - uint8_t payload[37]; - size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); - if (recvSz != 37 || payload[0] != 0x21) - return; +void DolphinSmashAdapter::initialCycle() { + uint8_t handshakePayload[] = {0x13}; + sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload)); +} - // printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); +void DolphinSmashAdapter::transferCycle() { + uint8_t payload[37]; + size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); + if (recvSz != 37 || payload[0] != 0x21) + return; - std::lock_guard lk(m_callbackLock); - if (!m_callback) - return; + // printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]); - /* Parse controller states */ - uint8_t* controller = &payload[1]; - uint8_t rumbleMask = 0; - for (uint32_t i = 0; i < 4; i++, controller += 9) - { - DolphinControllerState state; - bool rumble = false; - EDolphinControllerType type = parseState(&state, controller, rumble); - if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) - { - m_leftStickCal[0] = state.m_leftStick[0]; - m_leftStickCal[1] = state.m_leftStick[1]; - m_rightStickCal[0] = state.m_rightStick[0]; - m_rightStickCal[1] = state.m_rightStick[1]; - m_triggersCal[0] = state.m_analogTriggers[0]; - m_triggersCal[1] = state.m_analogTriggers[1]; - m_knownControllers |= 1 << i; - m_callback->controllerConnected(i, type); - } - else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i)) - { - m_knownControllers &= ~(1 << i); - m_callback->controllerDisconnected(i); - } - if (m_knownControllers & 1 << i) - { - 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 ? 1 << i : 0; + std::lock_guard lk(m_callbackLock); + if (!m_callback) + return; + + /* Parse controller states */ + uint8_t* controller = &payload[1]; + uint8_t rumbleMask = 0; + for (uint32_t i = 0; i < 4; i++, controller += 9) { + DolphinControllerState state; + bool rumble = false; + EDolphinControllerType type = parseState(&state, controller, rumble); + if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) { + m_leftStickCal[0] = state.m_leftStick[0]; + m_leftStickCal[1] = state.m_leftStick[1]; + m_rightStickCal[0] = state.m_rightStick[0]; + m_rightStickCal[1] = state.m_rightStick[1]; + m_triggersCal[0] = state.m_analogTriggers[0]; + m_triggersCal[1] = state.m_analogTriggers[1]; + m_knownControllers |= 1 << i; + m_callback->controllerConnected(i, type); + } else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i)) { + m_knownControllers &= ~(1 << i); + m_callback->controllerDisconnected(i); + } + if (m_knownControllers & 1 << i) { + 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 ? 1 << i : 0; + } + + /* Send rumble message (if needed) */ + uint8_t rumbleReq = m_rumbleRequest & rumbleMask; + if (rumbleReq != m_rumbleState) { + uint8_t rumbleMessage[5] = {0x11}; + for (int i = 0; i < 4; ++i) { + if (rumbleReq & 1 << i) + rumbleMessage[i + 1] = 1; + else if (m_hardStop[i]) + rumbleMessage[i + 1] = 2; + else + rumbleMessage[i + 1] = 0; } - /* Send rumble message (if needed) */ - uint8_t rumbleReq = m_rumbleRequest & rumbleMask; - if (rumbleReq != m_rumbleState) - { - uint8_t rumbleMessage[5] = {0x11}; - for (int i = 0; i < 4; ++i) - { - if (rumbleReq & 1 << i) - rumbleMessage[i + 1] = 1; - else if (m_hardStop[i]) - rumbleMessage[i + 1] = 2; - else - rumbleMessage[i + 1] = 0; - } - - sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); - m_rumbleState = rumbleReq; - } -} - -void DolphinSmashAdapter::finalCycle() -{ - uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); + m_rumbleState = rumbleReq; + } } -void DolphinSmashAdapter::deviceDisconnected() -{ - for (uint32_t i = 0; i < 4; i++) - { - if (m_knownControllers & 1 << i) - { - m_knownControllers &= ~(1 << i); - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerDisconnected(i); - } +void DolphinSmashAdapter::finalCycle() { + uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; + sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); +} + +void DolphinSmashAdapter::deviceDisconnected() { + for (uint32_t i = 0; i < 4; i++) { + if (m_knownControllers & 1 << i) { + m_knownControllers &= ~(1 << i); + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(i); } + } } /* The following code is derived from pad.c in libogc @@ -170,98 +153,79 @@ void DolphinSmashAdapter::deviceDisconnected() static int16_t pad_clampregion[8] = {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; - int signY; - int d; +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; + int signY; + int d; - if (x > 0) - { - signX = 1; - } - else - { - signX = -1; - x = -x; - } + if (x > 0) { + signX = 1; + } else { + signX = -1; + x = -x; + } - if (y > 0) - { - signY = 1; - } - else - { - signY = -1; - y = -y; - } + if (y > 0) { + signY = 1; + } else { + signY = -1; + y = -y; + } - if (x <= min) - x = 0; - else - x -= min; + if (x <= min) + x = 0; + else + x -= min; - if (y <= min) - { - y = 0; - } - else - { - y -= min; - } + if (y <= min) { + y = 0; + } else { + y -= min; + } - if (x == 0 && y == 0) - { - px = py = 0; - return; - } + if (x == 0 && y == 0) { + px = py = 0; + return; + } - if (xy * y <= xy * x) - { - d = xy * x + (max - xy) * y; - if (xy * max < d) - { - x = int16_t(xy * max * x / d); - y = int16_t(xy * max * y / d); - } + if (xy * y <= xy * x) { + 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 - { - d = xy * y + (max - xy) * x; - if (xy * max < d) - { - x = int16_t(xy * max * x / d); - y = int16_t(xy * max * y / d); - } + } else { + 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); + px = int16_t(signX * x); + py = int16_t(signY * y); } -static void pad_clamptrigger(int16_t& trigger) -{ - int16_t min, max; +static void pad_clamptrigger(int16_t& trigger) { + int16_t min, max; - min = pad_clampregion[0]; - max = pad_clampregion[1]; - if (min > trigger) - trigger = 0; - else - { - if (max < trigger) - trigger = max; - trigger -= min; - } + min = pad_clampregion[0]; + 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]); -} +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 diff --git a/lib/inputdev/DualshockPad.cpp b/lib/inputdev/DualshockPad.cpp index 6dce576..dc425f8 100644 --- a/lib/inputdev/DualshockPad.cpp +++ b/lib/inputdev/DualshockPad.cpp @@ -7,54 +7,40 @@ #include #ifdef _WIN32 -static inline uint16_t bswap16(uint16_t val) {return _byteswap_ushort(val);} +static inline uint16_t bswap16(uint16_t val) { return _byteswap_ushort(val); } #elif __GNUC__ && !defined(__FreeBSD__) -static inline uint16_t bswap16(uint16_t val) {return __builtin_bswap16(val); } +static inline uint16_t bswap16(uint16_t val) { return __builtin_bswap16(val); } #elif !defined(__FreeBSD__) -static inline uint16_t bswap16(uint16_t val) {return __builtin_byteswap(val);} +static inline 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) +#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 -}; +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(dev_typeid(DualshockPad), token), - m_rumbleRequest(EDualshockMotor::None), - m_rumbleState(EDualshockMotor::None) -{ - memcpy(m_report.buf, defaultReport, 49); +: TDeviceBase(dev_typeid(DualshockPad), token) +, m_rumbleRequest(EDualshockMotor::None) +, m_rumbleState(EDualshockMotor::None) { + memcpy(m_report.buf, defaultReport, 49); } -DualshockPad::~DualshockPad() -{ +DualshockPad::~DualshockPad() {} +void DualshockPad::deviceDisconnected() { + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(); } -void DualshockPad::deviceDisconnected() -{ - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerDisconnected(); -} - -void DualshockPad::initialCycle() -{ +void DualshockPad::initialCycle() { #if 0 uint8_t setupCommand[5] = {0xF4, 0x42, 0x0c, 0x00, 0x00}; //Tells controller to start sending changes on in pipe if (!sendHIDReport(setupCommand, 5, HIDReportType::Feature, 0xF4)) @@ -69,77 +55,64 @@ void DualshockPad::initialCycle() #endif } -void DualshockPad::transferCycle() -{ +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::finalCycle() -{ - m_report.rumble.leftDuration = 0; - m_report.rumble.leftForce = 0; - m_report.rumble.rightDuration = 0; - m_report.rumble.rightOn = false; +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(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 lk(m_callbackLock); + if (m_callback) + m_callback->controllerUpdate(*this, state); + } + + if (m_rumbleRequest != m_rumbleState) { + if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None) { + 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 ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None) { + 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; + } } -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(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 lk(m_callbackLock); - if (m_callback) - m_callback->controllerUpdate(*this, state); - } - - if (m_rumbleRequest != m_rumbleState) - { - if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None) - { - 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 ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None) - { - 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; - } -} - -} // boo +} // namespace boo diff --git a/lib/inputdev/GenericPad.cpp b/lib/inputdev/GenericPad.cpp index 45b4fc5..49b9250 100644 --- a/lib/inputdev/GenericPad.cpp +++ b/lib/inputdev/GenericPad.cpp @@ -1,57 +1,46 @@ #include "boo/inputdev/GenericPad.hpp" #include "boo/inputdev/DeviceToken.hpp" -namespace boo -{ +namespace boo { -GenericPad::GenericPad(DeviceToken* token) -: TDeviceBase(dev_typeid(GenericPad), token) -{ - -} +GenericPad::GenericPad(DeviceToken* token) : TDeviceBase(dev_typeid(GenericPad), token) {} GenericPad::~GenericPad() {} -void GenericPad::deviceDisconnected() -{ - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerDisconnected(); +void GenericPad::deviceDisconnected() { + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(); } -void GenericPad::initialCycle() -{ +void GenericPad::initialCycle() { #if _WIN32 #if !WINDOWS_STORE - const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor(); - m_parser.Parse(reportDesc); + const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor(); + m_parser.Parse(reportDesc); #endif #else - std::vector reportDesc = getReportDescriptor(); - m_parser.Parse(reportDesc.data(), reportDesc.size()); + std::vector reportDesc = getReportDescriptor(); + m_parser.Parse(reportDesc.data(), reportDesc.size()); #endif - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerConnected(); + std::lock_guard 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 lk(m_callbackLock); - if (length == 0 || tp != HIDReportType::Input || !m_callback) - return; - std::function func = - [this](const HIDMainItem& item, int32_t value) - { - m_callback->valueUpdate(item, value); - return true; - }; - m_parser.ScanValues(func, data, length); +void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { + std::lock_guard lk(m_callbackLock); + if (length == 0 || tp != HIDReportType::Input || !m_callback) + return; + std::function 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& valueCB) const -{ - m_parser.EnumerateValues(valueCB); +void GenericPad::enumerateValues(const std::function& valueCB) const { + m_parser.EnumerateValues(valueCB); } -} +} // namespace boo diff --git a/lib/inputdev/HIDDeviceBSD.cpp b/lib/inputdev/HIDDeviceBSD.cpp index 947f842..56c0752 100644 --- a/lib/inputdev/HIDDeviceBSD.cpp +++ b/lib/inputdev/HIDDeviceBSD.cpp @@ -1,31 +1,21 @@ #include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/DeviceFinder.hpp" +namespace boo { -namespace boo -{ +class HIDListenerBSD final : public IHIDListener { + DeviceFinder& m_finder; -class HIDListenerBSD final : public IHIDListener -{ - DeviceFinder& m_finder; public: - HIDListenerBSD(DeviceFinder& finder) - : m_finder(finder) - { - } + HIDListenerBSD(DeviceFinder& finder) : m_finder(finder) {} - ~HIDListenerBSD() - { - } + ~HIDListenerBSD() {} - bool startScanning() { return false; } - bool stopScanning() { return false; } + bool startScanning() { return false; } + bool stopScanning() { return false; } - bool scanNow() { return false; } + bool scanNow() { return false; } }; -IHIDListener* IHIDListenerNew(DeviceFinder &finder) -{ - return new HIDListenerBSD(finder); -} -} +IHIDListener* IHIDListenerNew(DeviceFinder& finder) { return new HIDListenerBSD(finder); } +} // namespace boo diff --git a/lib/inputdev/HIDDeviceIOKit.cpp b/lib/inputdev/HIDDeviceIOKit.cpp index 8fb2a85..52e0ed0 100644 --- a/lib/inputdev/HIDDeviceIOKit.cpp +++ b/lib/inputdev/HIDDeviceIOKit.cpp @@ -5,380 +5,320 @@ #include "IOKitPointer.hpp" #include -namespace boo -{ +namespace boo { -class HIDDeviceIOKit : public IHIDDevice -{ - DeviceToken& m_token; - std::shared_ptr m_devImp; +class HIDDeviceIOKit : public IHIDDevice { + DeviceToken& m_token; + std::shared_ptr m_devImp; - IUnknownPointer m_usbIntf; - uint8_t m_usbIntfInPipe = 0; - uint8_t m_usbIntfOutPipe = 0; - CFPointer m_hidIntf; - bool m_runningTransferLoop = false; - bool m_isBt = false; + IUnknownPointer m_usbIntf; + uint8_t m_usbIntfInPipe = 0; + uint8_t m_usbIntfOutPipe = 0; + CFPointer 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; + 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) - { - if (m_usbIntf) - { - IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length); - return res == kIOReturnSuccess; - } - return false; + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { + 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) - { - 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; - } + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { + 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 _getReportDescriptor() - { - if (m_hidIntf) - { - if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey))) - { - CFIndex len = CFDataGetLength(CFDataRef(desc)); - std::vector ret(len, '\0'); - CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]); - return ret; - } - } - return {}; + std::vector _getReportDescriptor() { + if (m_hidIntf) { + if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey))) { + CFIndex len = CFDataGetLength(CFDataRef(desc)); + std::vector 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) - { - /* 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; + bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { + /* 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) - { - if (m_hidIntf) - { - CFIndex readSize = length; - IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize); - if (res != kIOReturnSuccess) - return 0; - return readSize; - } + size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { + 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 device) { + char thrName[128]; + snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); + pthread_setname_np(thrName); + char errStr[256]; + std::unique_lock lk(device->m_initMutex); + + /* Get the HID element's parent (USB interrupt transfer-interface) */ + IOObjectPointer devIter; + IOObjectPointer devEntry = + IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data()); + IOObjectPointer interfaceEntry; + IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter); + while (IOObjectPointer obj = IOIteratorNext(devIter.get())) { + if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) { + interfaceEntry = obj; + break; + } + } + if (!interfaceEntry) { + snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } - static void _threadProcUSBLL(std::shared_ptr device) - { - char thrName[128]; - snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); - pthread_setname_np(thrName); - char errStr[256]; - std::unique_lock lk(device->m_initMutex); - - /* Get the HID element's parent (USB interrupt transfer-interface) */ - IOObjectPointer devIter; - IOObjectPointer devEntry = IORegistryEntryFromPath(kIOMasterPortDefault, - device->m_devPath.data()); - IOObjectPointer interfaceEntry; - IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter); - while (IOObjectPointer obj = IOIteratorNext(devIter.get())) - { - if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) - { - interfaceEntry = obj; - break; - } - } - if (!interfaceEntry) - { - snprintf(errStr, 256, "Unable to find interface for %s@%s\n", - device->m_token.getProductName().data(), - device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - 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) - { - snprintf(errStr, 256, "Unable to open %s@%s\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - return; - } - - /* USB interface function-pointer table */ - IUnknownPointer intf; - err = iodev.As(&intf, kIOUSBInterfaceInterfaceID); - if (err) - { - snprintf(errStr, 256, "Unable to open %s@%s\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - 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) - { - snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - } - else - { - snprintf(errStr, 256, "Unable to open %s@%s\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - } - 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 ; iGetPipeProperties(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; + /* IOKit Plugin COM interface (WTF Apple???) */ + IOCFPluginPointer iodev; + SInt32 score; + IOReturn err; + err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, &iodev, &score); + if (err) { + snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } - static void _threadProcBTLL(std::shared_ptr device) - { - std::unique_lock 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(); + /* USB interface function-pointer table */ + IUnknownPointer intf; + err = iodev.As(&intf, kIOUSBInterfaceInterfaceID); + if (err) { + snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } - static void _hidRemoveCb(void * _Nullable context, - IOReturn result, - void * _Nullable sender) - { - reinterpret_cast(context)->m_runningTransferLoop = false; + /* Obtain exclusive lock on device */ + device->m_usbIntf = intf; + err = intf->USBInterfaceOpen(intf.storage()); + if (err != kIOReturnSuccess) { + if (err == kIOReturnExclusiveAccess) { + snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + } else { + snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + } + lk.unlock(); + device->m_initCond.notify_one(); + return; } - static void _hidReportCb(void * _Nullable context, - IOReturn, - void * _Nullable, - IOHIDReportType type, - uint32_t reportID, - uint8_t * report, - CFIndex reportLength) - { - reinterpret_cast(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID); + /* 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; + } } - static void _threadProcHID(std::shared_ptr device) - { - char thrName[128]; - snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); - pthread_setname_np(thrName); - char errStr[256]; - std::unique_lock lk(device->m_initMutex); + /* Return control to main thread */ + device->m_runningTransferLoop = true; + lk.unlock(); + device->m_initCond.notify_one(); - /* Get the HID element's object (HID device interface) */ - IOObjectPointer interfaceEntry = - IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data()); - if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) - { - snprintf(errStr, 256, "Unable to find interface for %s@%s\n", - device->m_token.getProductName().data(), - device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - return; - } + /* Start transfer loop */ + device->m_devImp->initialCycle(); + while (device->m_runningTransferLoop) + device->m_devImp->transferCycle(); + device->m_devImp->finalCycle(); - device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get()); - if (!device->m_hidIntf) - { - snprintf(errStr, 256, "Unable to open %s@%s\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - return; - } + /* Cleanup */ + intf->USBInterfaceClose(intf.storage()); + device->m_usbIntf = nullptr; + } - /* Open device */ - IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone); - if (err != kIOReturnSuccess) - { - if (err == kIOReturnExclusiveAccess) - { - snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - } - else - { - snprintf(errStr, 256, "Unable to open %s@%s\n", - device->m_token.getProductName().data(), device->m_devPath.data()); - device->m_devImp->deviceError(errStr); - } - lk.unlock(); - device->m_initCond.notify_one(); - return; - } + static void _threadProcBTLL(std::shared_ptr device) { + std::unique_lock lk(device->m_initMutex); - /* Register removal callback */ - IOHIDDeviceRegisterRemovalCallback(device->m_hidIntf.get(), _hidRemoveCb, device.get()); + /* Return control to main thread */ + device->m_runningTransferLoop = true; + lk.unlock(); + device->m_initCond.notify_one(); - /* 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; + /* Start transfer loop */ + device->m_devImp->initialCycle(); + while (device->m_runningTransferLoop) + device->m_devImp->transferCycle(); + device->m_devImp->finalCycle(); + } - /* Register input buffer */ - std::unique_ptr 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(new uint8_t[bufSize]); - IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize, - _hidReportCb, device->m_devImp.get()); - IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - } + static void _hidRemoveCb(void* _Nullable context, IOReturn result, void* _Nullable sender) { + reinterpret_cast(context)->m_runningTransferLoop = false; + } - /* Return control to main thread */ - device->m_runningTransferLoop = true; - lk.unlock(); - device->m_initCond.notify_one(); + static void _hidReportCb(void* _Nullable context, IOReturn, void* _Nullable, IOHIDReportType type, uint32_t reportID, + uint8_t* report, CFIndex reportLength) { + reinterpret_cast(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID); + } - /* 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(); + static void _threadProcHID(std::shared_ptr device) { + char thrName[128]; + snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); + pthread_setname_np(thrName); + char errStr[256]; + std::unique_lock lk(device->m_initMutex); - /* Cleanup */ - IOHIDDeviceClose(device->m_hidIntf.get(), kIOHIDOptionsTypeNone); - device->m_hidIntf.reset(); + /* Get the HID element's object (HID device interface) */ + IOObjectPointer interfaceEntry = + IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data()); + if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) { + snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } - void _deviceDisconnected() - { - m_runningTransferLoop = false; + device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get()); + if (!device->m_hidIntf) { + snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } + /* Open device */ + IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone); + if (err != kIOReturnSuccess) { + if (err == kIOReturnExclusiveAccess) { + snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + } else { + snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(), + device->m_devPath.data()); + device->m_devImp->deviceError(errStr); + } + 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 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(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() { m_runningTransferLoop = false; } + public: + HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr& devImp) + : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {} - HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) - { + void _startThread() { + std::unique_lock lk(m_initMutex); + DeviceType dType = m_token.getDeviceType(); + if (dType == DeviceType::USB) + m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::Bluetooth) + m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::HID) + m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); + else { + fprintf(stderr, "invalid token supplied to device constructor\n"); + return; } + m_initCond.wait(lk); + } - void _startThread() - { - std::unique_lock lk(m_initMutex); - DeviceType dType = m_token.getDeviceType(); - if (dType == DeviceType::USB) - m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::Bluetooth) - m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::HID) - m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); - else - { - fprintf(stderr, "invalid token supplied to device constructor\n"); - return; - } - m_initCond.wait(lk); - } - - ~HIDDeviceIOKit() - { - m_runningTransferLoop = false; - if (m_thread.joinable()) - m_thread.detach(); - } + ~HIDDeviceIOKit() { + m_runningTransferLoop = false; + if (m_thread.joinable()) + m_thread.detach(); + } }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } -} +} // namespace boo diff --git a/lib/inputdev/HIDDeviceNX.cpp b/lib/inputdev/HIDDeviceNX.cpp index 78f5fe9..4dc0fe0 100644 --- a/lib/inputdev/HIDDeviceNX.cpp +++ b/lib/inputdev/HIDDeviceNX.cpp @@ -1,34 +1,27 @@ #include "IHIDDevice.hpp" -namespace boo -{ +namespace boo { -class HIDDeviceNX : public IHIDDevice -{ - DeviceToken& m_token; - std::shared_ptr m_devImp; - std::string_view m_devPath; +class HIDDeviceNX : public IHIDDevice { + DeviceToken& m_token; + std::shared_ptr m_devImp; + std::string_view m_devPath; public: - HIDDeviceNX(DeviceToken& token, const std::shared_ptr& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) - { - } + HIDDeviceNX(DeviceToken& token, const std::shared_ptr& devImp) + : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {} - void _deviceDisconnected() {} - bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; } - size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; } - std::vector _getReportDescriptor() { return {}; } - bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; } - size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return 0; } - void _startThread() {} + void _deviceDisconnected() {} + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; } + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; } + std::vector _getReportDescriptor() { return {}; } + bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; } + size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return 0; } + void _startThread() {} }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } -} +} // namespace boo diff --git a/lib/inputdev/HIDDeviceUWP.cpp b/lib/inputdev/HIDDeviceUWP.cpp index d173c99..a372e96 100644 --- a/lib/inputdev/HIDDeviceUWP.cpp +++ b/lib/inputdev/HIDDeviceUWP.cpp @@ -3,28 +3,22 @@ #include "boo/inputdev/DeviceToken.hpp" #include "boo/inputdev/DeviceBase.hpp" -namespace boo -{ +namespace boo { -class HIDDeviceUWP : public IHIDDevice -{ +class HIDDeviceUWP : public IHIDDevice { public: - HIDDeviceUWP(DeviceToken& token, const std::shared_ptr& devImp) - { + HIDDeviceUWP(DeviceToken& token, const std::shared_ptr& 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, HIDReportType tp, uint32_t message) { return false; } - size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; } - void _startThread() {} + 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, HIDReportType tp, uint32_t message) { return false; } + size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; } + void _startThread() {} }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } -} +} // namespace boo diff --git a/lib/inputdev/HIDDeviceUdev.cpp b/lib/inputdev/HIDDeviceUdev.cpp index 5cbd66c..cfbfa52 100644 --- a/lib/inputdev/HIDDeviceUdev.cpp +++ b/lib/inputdev/HIDDeviceUdev.cpp @@ -18,8 +18,7 @@ #include #include "boo/inputdev/HIDParser.hpp" -namespace boo -{ +namespace boo { udev* GetUdev(); @@ -27,331 +26,270 @@ udev* GetUdev(); * Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html */ -class HIDDeviceUdev final : public IHIDDevice -{ - DeviceToken& m_token; - std::shared_ptr m_devImp; +class HIDDeviceUdev final : public IHIDDevice { + DeviceToken& m_token; + std::shared_ptr m_devImp; - int m_devFd = 0; - unsigned m_usbIntfInPipe = 0; - unsigned m_usbIntfOutPipe = 0; - bool m_runningTransferLoop = false; + 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; + 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) - { - 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; - } + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { + 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) { + 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 device) { + int i; + char errStr[256]; + std::unique_lock 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) { + snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno)); + device->m_devImp->deviceError(errStr); + 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; + } + } + } } - size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) - { - if (m_devFd) - { - usbdevfs_bulktransfer xfer = - { - m_usbIntfInPipe | USB_DIR_IN, - (unsigned)length, - 30, - data - }; - return ioctl(m_devFd, USBDEVFS_BULK, &xfer); - } - return 0; + /* Request that kernel disconnects existing driver */ + usbdevfs_ioctl disconnectReq = {0, USBDEVFS_DISCONNECT, NULL}; + 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 device) { + std::unique_lock 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 device) { + char errStr[256]; + std::unique_lock 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) { + snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno)); + device->m_devImp->deviceError(errStr); + 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) { + snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n", device->m_token.getProductName().data(), + dp, strerror(errno)); + device->m_devImp->deviceError(errStr); + close(fd); + return; } - static void _threadProcUSBLL(std::shared_ptr device) - { - int i; - char errStr[256]; - std::unique_lock 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) - { - snprintf(errStr, 256, "Unable to open %s@%s: %s\n", - device->m_token.getProductName().data(), dp, strerror(errno)); - device->m_devImp->deviceError(errStr); - 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 ; im_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, - NULL - }; - 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); + /* Get report descriptor */ + hidraw_report_descriptor reportDesc; + reportDesc.size = reportDescSize; + if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) { + snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n", device->m_token.getProductName().data(), dp, + strerror(errno)); + device->m_devImp->deviceError(errStr); + close(fd); + return; } + size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size); + std::unique_ptr readBuf(new uint8_t[readSz]); - static void _threadProcBTLL(std::shared_ptr device) - { - std::unique_lock 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 device) - { - char errStr[256]; - std::unique_lock 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) - { - snprintf(errStr, 256, "Unable to open %s@%s: %s\n", - device->m_token.getProductName().data(), dp, strerror(errno)); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - udev_device_unref(udevDev); - return; + /* 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]); } - 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) - { - snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n", - device->m_token.getProductName().data(), dp, strerror(errno)); - device->m_devImp->deviceError(errStr); - close(fd); - return; - } - - /* Get report descriptor */ - hidraw_report_descriptor reportDesc; - reportDesc.size = reportDescSize; - if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) - { - snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n", - device->m_token.getProductName().data(), dp, strerror(errno)); - device->m_devImp->deviceError(errStr); - close(fd); - return; - } - size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size); - std::unique_ptr 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); + } + if (device->m_runningTransferLoop) + device->m_devImp->transferCycle(); } + device->m_devImp->finalCycle(); - void _deviceDisconnected() - { - m_runningTransferLoop = false; + /* Cleanup */ + close(fd); + device->m_devFd = 0; + udev_device_unref(udevDev); + } + + void _deviceDisconnected() { m_runningTransferLoop = false; } + + std::vector _getReportDescriptor() { + /* 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 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) { + 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; + } - std::vector _getReportDescriptor() - { - /* 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 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) - { - 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) - { - 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; + size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { + 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& devImp) + : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {} - HIDDeviceUdev(DeviceToken& token, const std::shared_ptr& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) - { + void _startThread() { + std::unique_lock lk(m_initMutex); + DeviceType dType = m_token.getDeviceType(); + if (dType == DeviceType::USB) + m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::Bluetooth) + m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::HID) + m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); + else { + fprintf(stderr, "invalid token supplied to device constructor"); + abort(); } + m_initCond.wait(lk); + } - void _startThread() - { - std::unique_lock lk(m_initMutex); - DeviceType dType = m_token.getDeviceType(); - if (dType == DeviceType::USB) - m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::Bluetooth) - m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::HID) - m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); - else - { - fprintf(stderr, "invalid token supplied to device constructor"); - abort(); - } - m_initCond.wait(lk); - } - - ~HIDDeviceUdev() - { - m_runningTransferLoop = false; - if (m_thread.joinable()) - m_thread.detach(); - } - - + ~HIDDeviceUdev() { + m_runningTransferLoop = false; + if (m_thread.joinable()) + m_thread.detach(); + } }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } -} +} // namespace boo diff --git a/lib/inputdev/HIDDeviceWinUSB.cpp b/lib/inputdev/HIDDeviceWinUSB.cpp index 793030f..571f034 100644 --- a/lib/inputdev/HIDDeviceWinUSB.cpp +++ b/lib/inputdev/HIDDeviceWinUSB.cpp @@ -21,378 +21,311 @@ #undef min #undef max -namespace boo -{ +namespace boo { -class HIDDeviceWinUSB final : public IHIDDevice -{ - DeviceToken& m_token; - std::shared_ptr m_devImp; +class HIDDeviceWinUSB final : public IHIDDevice { + DeviceToken& m_token; + std::shared_ptr m_devImp; - HANDLE m_devHandle = 0; - HANDLE m_hidHandle = 0; - WINUSB_INTERFACE_HANDLE m_usbHandle = nullptr; - unsigned m_usbIntfInPipe = 0; - unsigned m_usbIntfOutPipe = 0; - bool m_runningTransferLoop = false; + HANDLE m_devHandle = 0; + HANDLE m_hidHandle = 0; + 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; + 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) - { - if (m_usbHandle) - { - ULONG lengthTransferred = 0; - if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, - (ULONG)length, &lengthTransferred, NULL) || - lengthTransferred != length) - return false; - return true; - } + bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { + if (m_usbHandle) { + ULONG lengthTransferred = 0; + if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, NULL) || + lengthTransferred != length) return false; + return true; + } + return false; + } + + size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { + if (m_usbHandle) { + ULONG lengthTransferred = 0; + if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, NULL)) + return 0; + return lengthTransferred; + } + return 0; + } + + static void _threadProcUSBLL(std::shared_ptr device) { + unsigned i; + char errStr[256]; + std::unique_lock 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, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (INVALID_HANDLE_VALUE == device->m_devHandle) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(), + device->m_devPath.data(), GetLastError()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; } - size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) - { - if (m_usbHandle) - { - ULONG lengthTransferred = 0; - if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, - (ULONG)length, &lengthTransferred, NULL)) - return 0; - return lengthTransferred; + if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(), + device->m_devPath.data(), GetLastError()); + device->m_devImp->deviceError(errStr); + 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)) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(), + device->m_devPath.data(), GetLastError()); + device->m_devImp->deviceError(errStr); + 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 device) { + std::unique_lock 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 device) { + char errStr[256]; + std::unique_lock 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, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (INVALID_HANDLE_VALUE == device->m_hidHandle) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(), + device->m_devPath.data(), GetLastError()); + device->m_devImp->deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; + } + + if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) { + _snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n", device->m_token.getProductName().data(), + device->m_devPath.data(), GetLastError()); + device->m_devImp->deviceError(errStr); + 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 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() { m_runningTransferLoop = false; } + + std::vector m_sendBuf; + std::vector m_recvBuf; + + const PHIDP_PREPARSED_DATA _getReportDescriptor() { return m_preparsedData; } + + bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { + 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) { + fprintf(stderr, "Write Failed %08X\n", int(Error)); + return false; + } + } + + if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) { + DWORD Error = GetLastError(); + fprintf(stderr, "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) { + 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; } - static void _threadProcUSBLL(std::shared_ptr device) - { - unsigned i; - char errStr[256]; - std::unique_lock 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, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); - if (INVALID_HANDLE_VALUE == device->m_devHandle) - { - _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", - device->m_token.getProductName().data(), - device->m_devPath.data(), GetLastError()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - return; - } - - if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) - { - _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", - device->m_token.getProductName().data(), - device->m_devPath.data(), GetLastError()); - device->m_devImp->deviceError(errStr); - 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)) - { - _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", - device->m_token.getProductName().data(), - device->m_devPath.data(), GetLastError()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - CloseHandle(device->m_devHandle); - return; - } - for (i=0 ; im_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 device) - { - std::unique_lock 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 device) - { - char errStr[256]; - std::unique_lock 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, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); - if (INVALID_HANDLE_VALUE == device->m_hidHandle) - { - _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", - device->m_token.getProductName().data(), - device->m_devPath.data(), GetLastError()); - device->m_devImp->deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - return; - } - - if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) - { - _snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n", - device->m_token.getProductName().data(), - device->m_devPath.data(), GetLastError()); - device->m_devImp->deviceError(errStr); - 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 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() - { - m_runningTransferLoop = false; - } - - std::vector m_sendBuf; - std::vector m_recvBuf; - - const PHIDP_PREPARSED_DATA _getReportDescriptor() - { - return m_preparsedData; - } - - bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) - { - 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) - { - fprintf(stderr, "Write Failed %08X\n", int(Error)); - return false; - } - } - - if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) - { - DWORD Error = GetLastError(); - fprintf(stderr, "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) - { - 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; - } + memmove(data, m_recvBuf.data(), length); + return length; + } public: + HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr& devImp) + : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {} - HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) - { - } + void _startThread() { + std::unique_lock lk(m_initMutex); + DeviceType dType = m_token.getDeviceType(); + if (dType == DeviceType::USB) + m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::Bluetooth) + m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); + else if (dType == DeviceType::HID) + m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); + else + throw std::runtime_error("invalid token supplied to device constructor"); + m_initCond.wait(lk); + } - void _startThread() - { - std::unique_lock lk(m_initMutex); - DeviceType dType = m_token.getDeviceType(); - if (dType == DeviceType::USB) - m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::Bluetooth) - m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); - else if (dType == DeviceType::HID) - m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); - else - throw std::runtime_error("invalid token supplied to device constructor"); - m_initCond.wait(lk); - } + ~HIDDeviceWinUSB() { + m_runningTransferLoop = false; + if (m_thread.joinable()) + m_thread.detach(); + } - ~HIDDeviceWinUSB() - { + 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; - if (m_thread.joinable()) - m_thread.detach(); + return; + } else if (Error != ERROR_IO_PENDING) { + fprintf(stderr, "Read Failed: %08X\n", int(Error)); + return; + } else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE)) { + return; + } } - 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) - { - fprintf(stderr, "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]); - } + m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]); + } }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } -} +} // namespace boo diff --git a/lib/inputdev/HIDListenerBSD.cpp b/lib/inputdev/HIDListenerBSD.cpp index 09ccb52..33a64b5 100644 --- a/lib/inputdev/HIDListenerBSD.cpp +++ b/lib/inputdev/HIDListenerBSD.cpp @@ -2,33 +2,25 @@ #include "boo/inputdev/DeviceToken.hpp" #include "boo/inputdev/DeviceBase.hpp" -namespace boo -{ +namespace boo { -class HIDDeviceBSD final : public IHIDDevice -{ - DeviceToken& m_token; - DeviceBase& m_devImp; +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; } - 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(DeviceToken& token, DeviceBase& devImp) : m_token(token), m_devImp(devImp) {} - ~HIDDeviceBSD() - { - } + ~HIDDeviceBSD() {} }; -std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) -{ - return std::make_shared(token, devImp); -} +std::shared_ptr IHIDDeviceNew(DeviceToken& token, const std::shared_ptr& devImp) { + return std::make_shared(token, devImp); } +} // namespace boo diff --git a/lib/inputdev/HIDListenerIOKit.cpp b/lib/inputdev/HIDListenerIOKit.cpp index 4e5ea97..389ea0a 100644 --- a/lib/inputdev/HIDListenerIOKit.cpp +++ b/lib/inputdev/HIDListenerIOKit.cpp @@ -11,326 +11,285 @@ #include "IOKitPointer.hpp" #include "../CFPointer.hpp" -namespace boo -{ +namespace boo { /* * Reference: http://oroboro.com/usb-serial-number-osx/ */ -static bool getUSBStringDescriptor(const IUnknownPointer& 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(kUSBIn, - kUSBStandard, - 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; +static bool getUSBStringDescriptor(const IUnknownPointer& usbDevice, UInt8 idx, char* out) { + UInt16 buffer[128]; - unsigned count = (request.wLenDone - 1) / 2; - unsigned i; - for (i=0 ; iDeviceRequest(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 m_llAddNotif, m_llRemoveNotif; - IOObjectPointer m_hidAddNotif, m_hidRemoveNotif; - const char* m_usbClass; - bool m_scanningEnabled; - - static void devicesConnectedUSBLL(HIDListenerIOKit* listener, - io_iterator_t iterator) - { - while (IOObjectPointer obj = IOIteratorNext(iterator)) - { - io_string_t devPath; - if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) - continue; +class HIDListenerIOKit : public IHIDListener { + DeviceFinder& m_finder; - 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) - { - fprintf(stderr, "unable to open IOKit plugin interface\n"); - continue; - } + CFRunLoopRef m_listenerRunLoop; + IONotificationPortRef m_llPort; + IOObjectPointer m_llAddNotif, m_llRemoveNotif; + IOObjectPointer m_hidAddNotif, m_hidRemoveNotif; + const char* m_usbClass; + bool m_scanningEnabled; - IUnknownPointer dev; - err = devServ.As(&dev, kIOUSBDeviceInterfaceID182); - if (err != kIOReturnSuccess) - { - fprintf(stderr, "unable to open IOKit device interface\n"); - continue; - } + static void devicesConnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) { + while (IOObjectPointer obj = IOIteratorNext(iterator)) { + io_string_t devPath; + if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) + continue; - dev->GetDeviceVendor(dev.storage(), &vid); - dev->GetDeviceProduct(dev.storage(), &pid); + if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath)) + continue; - 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(DeviceType::USB, - vid, pid, vstr, pstr, devPath)); - - //printf("ADDED %08X %s\n", obj.get(), devPath); + 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) { + fprintf(stderr, "unable to open IOKit plugin interface\n"); + continue; } + + IUnknownPointer dev; + err = devServ.As(&dev, kIOUSBDeviceInterfaceID182); + if (err != kIOReturnSuccess) { + fprintf(stderr, "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(DeviceType::USB, vid, pid, vstr, pstr, devPath)); + + // printf("ADDED %08X %s\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 obj = IOIteratorNext(iterator)) - { - io_string_t devPath; - if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) - continue; - listener->m_finder._removeToken(devPath); - //printf("REMOVED %08X %s\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; } - - static void devicesConnectedHID(HIDListenerIOKit* listener, - io_iterator_t iterator) - { - while (IOObjectPointer 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) - { - fprintf(stderr, "unable to open IOKit plugin interface\n"); - continue; - } - - IUnknownPointer dev; - err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID); - if (err != kIOReturnSuccess) - { - fprintf(stderr, "unable to open IOKit device interface\n"); - continue; - } - - /* Game controllers only */ - CFPointer usagePage; - dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsagePageKey), (CFTypeRef*)&usagePage); - CFPointer 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 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 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(DeviceType::HID, - vidv, pidv, vstr, pstr, devPath)); - - //printf("ADDED %08X %s\n", obj, devPath); - } + while (IOObjectPointer obj = IOIteratorNext(iterator)) { + io_string_t devPath; + if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) + continue; + listener->m_finder._removeToken(devPath); + // printf("REMOVED %08X %s\n", obj.get(), 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; + static void devicesConnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) { + while (IOObjectPointer 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) { + fprintf(stderr, "unable to open IOKit plugin interface\n"); + continue; } - while (IOObjectPointer obj = IOIteratorNext(iterator)) - { - io_string_t devPath; - if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) - continue; - listener->m_finder._removeToken(devPath); - //printf("REMOVED %08X %s\n", obj, devPath); + + IUnknownPointer dev; + err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID); + if (err != kIOReturnSuccess) { + fprintf(stderr, "unable to open IOKit device interface\n"); + continue; } + + /* Game controllers only */ + CFPointer usagePage; + dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsagePageKey), (CFTypeRef*)&usagePage); + CFPointer 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 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 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(DeviceType::HID, vidv, pidv, vstr, pstr, devPath)); + + // printf("ADDED %08X %s\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 obj = IOIteratorNext(iterator)) { + io_string_t devPath; + if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) + continue; + listener->m_finder._removeToken(devPath); + // printf("REMOVED %08X %s\n", obj, devPath); + } + } public: - HIDListenerIOKit(DeviceFinder& finder) - : m_finder(finder) + 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 */ { - struct utsname kernInfo; - uname(&kernInfo); - int release = atoi(kernInfo.release); - m_usbClass = release >= 15 ? "IOUSBHostDevice" : kIOUSBDeviceClassName; + CFMutableDictionaryRef matchDict = IOServiceMatching("IOHIDDevice"); + CFRetain(matchDict); - m_listenerRunLoop = CFRunLoopGetMain(); - m_llPort = IONotificationPortCreate(kIOMasterPortDefault); - CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort); - CFRunLoopAddSource(m_listenerRunLoop, rlSrc, kCFRunLoopDefaultMode); - m_scanningEnabled = true; + kern_return_t hidRet = + IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict, + (IOServiceMatchingCallback)devicesConnectedHID, this, &m_hidAddNotif); + if (hidRet == kIOReturnSuccess) + devicesConnectedHID(this, m_hidAddNotif.get()); - /* 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; + hidRet = + IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict, + (IOServiceMatchingCallback)devicesDisconnectedHID, this, &m_hidRemoveNotif); + if (hidRet == kIOReturnSuccess) + devicesDisconnectedHID(this, m_hidRemoveNotif.get()); } - - ~HIDListenerIOKit() + + /* Register Low-Level USB Matcher */ { - //CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode); - IONotificationPortDestroy(m_llPort); + 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()); } - - /* Automatic device scanning */ - bool startScanning() - { - m_scanningEnabled = true; - return true; + + m_scanningEnabled = false; + } + + ~HIDListenerIOKit() { + // CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode); + IONotificationPortDestroy(m_llPort); + } + + /* Automatic device scanning */ + bool startScanning() { + m_scanningEnabled = true; + return true; + } + bool stopScanning() { + m_scanningEnabled = false; + return true; + } + + /* Manual device scanning */ + bool scanNow() { + IOObjectPointer iter; + if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) { + devicesConnectedUSBLL(this, iter.get()); } - bool stopScanning() - { - m_scanningEnabled = false; - return true; - } - - /* Manual device scanning */ - bool scanNow() - { - IOObjectPointer iter; - if (IOServiceGetMatchingServices(kIOMasterPortDefault, - IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) - { - devicesConnectedUSBLL(this, iter.get()); - } - return true; - } - + return true; + } }; -std::unique_ptr IHIDListenerNew(DeviceFinder& finder) -{ - return std::make_unique(finder); +std::unique_ptr IHIDListenerNew(DeviceFinder& finder) { + return std::make_unique(finder); } -} +} // namespace boo diff --git a/lib/inputdev/HIDListenerNX.cpp b/lib/inputdev/HIDListenerNX.cpp index b680273..0044781 100644 --- a/lib/inputdev/HIDListenerNX.cpp +++ b/lib/inputdev/HIDListenerNX.cpp @@ -1,25 +1,18 @@ #include "boo/inputdev/IHIDListener.hpp" -namespace boo -{ +namespace boo { -class HIDListenerNX : public IHIDListener -{ - DeviceFinder& m_finder; +class HIDListenerNX : public IHIDListener { + DeviceFinder& m_finder; public: - HIDListenerNX(DeviceFinder& finder) - : m_finder(finder) - {} + HIDListenerNX(DeviceFinder& finder) : m_finder(finder) {} - bool startScanning() { return false; } - bool stopScanning() { return false; } - bool scanNow() { return false; } + bool startScanning() { return false; } + bool stopScanning() { return false; } + bool scanNow() { return false; } }; -std::unique_ptr IHIDListenerNew(DeviceFinder& finder) -{ - return std::make_unique(finder); -} +std::unique_ptr IHIDListenerNew(DeviceFinder& finder) { return std::make_unique(finder); } -} +} // namespace boo diff --git a/lib/inputdev/HIDListenerUWP.cpp b/lib/inputdev/HIDListenerUWP.cpp index e9eda97..21d3400 100644 --- a/lib/inputdev/HIDListenerUWP.cpp +++ b/lib/inputdev/HIDListenerUWP.cpp @@ -2,25 +2,20 @@ #include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/DeviceFinder.hpp" -namespace boo -{ +namespace boo { -class HIDListenerUWP : public IHIDListener -{ +class HIDListenerUWP : public IHIDListener { public: - HIDListenerUWP(DeviceFinder& finder) {} + HIDListenerUWP(DeviceFinder& finder) {} - /* Automatic device scanning */ - bool startScanning() { return false; } - bool stopScanning() { return false; } + /* Automatic device scanning */ + bool startScanning() { return false; } + bool stopScanning() { return false; } - /* Manual device scanning */ - bool scanNow() { return false; } + /* Manual device scanning */ + bool scanNow() { return false; } }; -std::unique_ptr IHIDListenerNew(DeviceFinder& finder) -{ - return std::make_unique(finder); -} +std::unique_ptr IHIDListenerNew(DeviceFinder& finder) { return std::make_unique(finder); } -} +} // namespace boo diff --git a/lib/inputdev/HIDListenerUdev.cpp b/lib/inputdev/HIDListenerUdev.cpp index 0d3b451..6af242b 100644 --- a/lib/inputdev/HIDListenerUdev.cpp +++ b/lib/inputdev/HIDListenerUdev.cpp @@ -12,122 +12,110 @@ #include #include -namespace boo -{ +namespace boo { static udev* UDEV_INST = nullptr; -udev* GetUdev() -{ - if (!UDEV_INST) - UDEV_INST = udev_new(); - return UDEV_INST; +udev* GetUdev() { + if (!UDEV_INST) + UDEV_INST = udev_new(); + return UDEV_INST; } -class HIDListenerUdev final : public IHIDListener -{ - DeviceFinder& m_finder; +class HIDListenerUdev final : public IHIDListener { + DeviceFinder& m_finder; - udev_monitor* m_udevMon; - std::thread m_udevThread; - bool m_scanningEnabled; + udev_monitor* m_udevMon; + std::thread m_udevThread; + bool m_scanningEnabled; - void deviceConnected(udev_device* device) - { - if (!m_scanningEnabled) - return; + 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; + /* 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; - 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; + /* Filter to USB/BT */ + const char* dt = udev_device_get_devtype(device); + DeviceType type; + 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* 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* 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* 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* 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* 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; - } + 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; + /* 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; - } + /* 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); + /* 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 usage = - HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size); - if (usage.first != HIDUsagePage::GenericDesktop || - (usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad)) - return; - } + std::pair 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; @@ -140,120 +128,105 @@ class HIDListenerUdev final : public IHIDListener fprintf(stderr, "\n\n"); #endif - m_finder._insertToken(std::make_unique(type, vid, pid, manuf, product, devPath)); - } + m_finder._insertToken(std::make_unique(type, vid, pid, manuf, product, devPath)); + } - void deviceDisconnected(udev_device* device) - { - const char* devPath = udev_device_get_syspath(device); - m_finder._removeToken(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(); - } + 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) - { - fprintf(stderr, "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(DeviceFinder& finder) : m_finder(finder) { + /* Setup hotplug events */ + m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev"); + if (!m_udevMon) { + fprintf(stderr, "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); - ~HIDListenerUdev() - { - pthread_cancel(m_udevThread.native_handle()); - if (m_udevThread.joinable()) - m_udevThread.join(); - udev_monitor_unref(m_udevMon); - } + /* Initial HID Device Add */ + m_scanningEnabled = true; + scanNow(); + m_scanningEnabled = false; - /* Automatic device scanning */ - bool startScanning() - { - m_scanningEnabled = true; - return true; - } - bool stopScanning() - { - m_scanningEnabled = false; - return true; - } + /* Start hotplug thread */ + m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this); + } - /* Manual device scanning */ - bool scanNow() - { - 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; - } + ~HIDListenerUdev() { + pthread_cancel(m_udevThread.native_handle()); + if (m_udevThread.joinable()) + m_udevThread.join(); + udev_monitor_unref(m_udevMon); + } + /* Automatic device scanning */ + bool startScanning() { + m_scanningEnabled = true; + return true; + } + bool stopScanning() { + m_scanningEnabled = false; + return true; + } + + /* Manual device scanning */ + bool scanNow() { + 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 IHIDListenerNew(DeviceFinder& finder) -{ - return std::make_unique(finder); +std::unique_ptr IHIDListenerNew(DeviceFinder& finder) { + return std::make_unique(finder); } -} +} // namespace boo diff --git a/lib/inputdev/HIDListenerWinUSB.cpp b/lib/inputdev/HIDListenerWinUSB.cpp index 46d82b0..6fdcb11 100644 --- a/lib/inputdev/HIDListenerWinUSB.cpp +++ b/lib/inputdev/HIDListenerWinUSB.cpp @@ -18,306 +18,257 @@ #include #include -namespace boo -{ +namespace boo { -class HIDListenerWinUSB final : public IHIDListener -{ - DeviceFinder& m_finder; +class HIDListenerWinUSB final : public IHIDListener { + DeviceFinder& m_finder; - bool m_scanningEnabled; + bool m_scanningEnabled; - /* - * Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c - */ + /* + * 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]; + 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(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE); - if (hDevInfo == INVALID_HANDLE_VALUE) - return; + /* List all connected HID devices */ + hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE); + if (hDevInfo == INVALID_HANDLE_VALUE) + return; - for (i=0 ; ; ++i) - { - if (!SetupDiEnumDeviceInterfaces(hDevInfo, - NULL, - TypeGUID, - i, - &DeviceInterfaceData)) - break; + for (i = 0;; ++i) { + if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, TypeGUID, i, &DeviceInterfaceData)) + break; - DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, - &DeviceInterfaceData, - &DeviceInterfaceDetailData.wtf, - sizeof(DeviceInterfaceDetailData), - NULL, - &DeviceInfoData)) - continue; + DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, &DeviceInterfaceData, &DeviceInterfaceDetailData.wtf, + sizeof(DeviceInterfaceDetailData), NULL, &DeviceInfoData)) + continue; - r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0); - if (r != CR_SUCCESS) - 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 != NULL) - { - 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(NULL, "\\#&", &pszNextToken); + /* 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 != NULL) { + 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; } - - if (!szVid[0] || !szPid[0]) - continue; - - unsigned vid = strtol(szVid+4, NULL, 16); - unsigned pid = strtol(szPid+4, NULL, 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, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); - 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( - type, vid, pid, manuf, productW, - DeviceInterfaceDetailData.wtf.DevicePath)); + } } + pszToken = strtok_s(NULL, "\\#&", &pszNextToken); + } - SetupDiDestroyDeviceInfoList(hDevInfo); - } + if (!szVid[0] || !szPid[0]) + continue; - void _pollDevices(const char* pathFilter) - { - _enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter); - _enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter); - } + unsigned vid = strtol(szVid + 4, NULL, 16); + unsigned pid = strtol(szPid + 4, NULL, 16); - static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad) - { - return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger, - pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY}; - } + 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); - std::thread m_xinputThread; - bool m_xinputRunning = true; - DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)}; - std::vector m_xinputTokens; - void _xinputProc() - { - m_xinputTokens.reserve(4); - for (int i=0 ; i<4 ; ++i) - m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", ""); + 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); - 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(*tok.m_connectedDev); - std::lock_guard lk(pad.m_callbackLock); - if (pad.m_callback) - pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad)); - } - } - if (tok.m_connectedDev) - { - XInputPad& pad = static_cast(*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(*tok.m_connectedDev); - pad.deviceDisconnected(); - } - m_finder.deviceDisconnected(tok, tok.m_connectedDev.get()); - } - } - Sleep(10); + if (type == DeviceType::HID) { + HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + 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(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 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(*tok.m_connectedDev); + std::lock_guard lk(pad.m_callbackLock); + if (pad.m_callback) + pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad)); + } + } + if (tok.m_connectedDev) { + XInputPad& pad = static_cast(*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(*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 */ - _pollDevices(nullptr); + HIDListenerWinUSB(DeviceFinder& finder) : m_finder(finder) { + /* Initial HID Device Add */ + _pollDevices(nullptr); - /* 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; - } - } + /* 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() - { - m_xinputRunning = false; - if (m_xinputThread.joinable()) - m_xinputThread.join(); - } + ~HIDListenerWinUSB() { + m_xinputRunning = false; + if (m_xinputThread.joinable()) + m_xinputThread.join(); + } - /* Automatic device scanning */ - bool startScanning() - { - m_scanningEnabled = true; - return true; - } - bool stopScanning() - { - m_scanningEnabled = false; - return true; - } + /* Automatic device scanning */ + bool startScanning() { + m_scanningEnabled = true; + return true; + } + bool stopScanning() { + m_scanningEnabled = false; + return true; + } - /* Manual device scanning */ - bool scanNow() - { - _pollDevices(nullptr); - return true; - } + /* Manual device scanning */ + bool scanNow() { + _pollDevices(nullptr); + return true; + } - bool _extDevConnect(const char* path) - { - char upperPath[1024]; - strcpy_s(upperPath, 1024, path); - CharUpperA(upperPath); - if (m_scanningEnabled && !m_finder._hasToken(upperPath)) - _pollDevices(upperPath); - return true; - } + bool _extDevConnect(const char* path) { + 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) - { - char upperPath[1024]; - strcpy_s(upperPath, 1024, path); - CharUpperA(upperPath); - m_finder._removeToken(upperPath); - return true; - } + bool _extDevDisconnect(const char* path) { + char upperPath[1024]; + strcpy_s(upperPath, 1024, path); + CharUpperA(upperPath); + m_finder._removeToken(upperPath); + return true; + } }; -std::unique_ptr IHIDListenerNew(DeviceFinder& finder) -{ - return std::make_unique(finder); +std::unique_ptr IHIDListenerNew(DeviceFinder& finder) { + return std::make_unique(finder); } -} +} // namespace boo diff --git a/lib/inputdev/HIDParser.cpp b/lib/inputdev/HIDParser.cpp index c13213f..e8f1620 100644 --- a/lib/inputdev/HIDParser.cpp +++ b/lib/inputdev/HIDParser.cpp @@ -5,234 +5,319 @@ #undef min #undef max -namespace boo -{ +namespace boo { /* Based on "Device Class Definition for Human Interface Devices (HID)" * http://www.usb.org/developers/hidpage/HID1_11.pdf */ -static const char* UsagePageNames[] = -{ - "Undefined", - "Generic Desktop", - "Simulation", - "VR", - "Sport", - "Game Controls", - "Generic Device", - "Keyboard", - "LEDs", - "Button", - "Ordinal", - "Telephony", - "Consumer", - "Digitizer" +static const char* UsagePageNames[] = {"Undefined", "Generic Desktop", "Simulation", "VR", "Sport", + "Game Controls", "Generic Device", "Keyboard", "LEDs", "Button", + "Ordinal", "Telephony", "Consumer", "Digitizer"}; + +static const char* 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"}; + +static const char* 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 }; -static const char* 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" +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, }; -static const char* 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" -}; +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; -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 m_usage; - HIDRange m_usageRange = {}; + /* [6.2.2.8] Local Items */ + std::vector m_usage; + HIDRange m_usageRange = {}; #if 0 std::vector m_designatorIndex; std::vector m_designatorRange; @@ -241,10 +326,9 @@ struct HIDItemState std::vector m_delimiter; #endif - void ResetLocalItems() - { - m_usage.clear(); - m_usageRange = HIDRange(); + void ResetLocalItems() { + m_usage.clear(); + m_usageRange = HIDRange(); #if 0 m_designatorIndex.clear(); m_designatorRange.clear(); @@ -252,618 +336,549 @@ struct HIDItemState m_stringRange.clear(); m_delimiter.clear(); #endif - } + } - template - static T _GetLocal(const std::vector& v, uint32_t idx) - { - if (v.empty()) - return {}; - if (idx >= v.size()) - return v[0]; - return v[idx]; - } + template + static T _GetLocal(const std::vector& 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); - } + 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; +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)) - {} + 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) +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 = state.m_usagePage; - m_usage = state.GetUsage(reportIdx); - m_logicalRange = state.m_logicalRange; - m_reportSize = state.m_reportSize; +, m_usagePage(usagePage) +, m_usage(usage) +, m_logicalRange(logicalRange) +, m_reportSize(reportSize) {} + +const char* HIDMainItem::GetUsagePageName() const { + if (int(m_usagePage) >= std::extent::value) + return nullptr; + return UsagePageNames[int(m_usagePage)]; } -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 -{ - if (int(m_usagePage) >= std::extent::value) - return nullptr; - return UsagePageNames[int(m_usagePage)]; +const char* HIDMainItem::GetUsageName() const { + switch (m_usagePage) { + case HIDUsagePage::GenericDesktop: + if (int(m_usage) >= std::extent::value) + return nullptr; + return GenericDesktopUsages[int(m_usage)]; + case HIDUsagePage::Game: + if (int(m_usage) >= std::extent::value) + return nullptr; + return GameUsages[int(m_usage)]; + default: + return nullptr; + } } -const char* HIDMainItem::GetUsageName() const -{ - switch (m_usagePage) - { - case HIDUsagePage::GenericDesktop: - if (int(m_usage) >= std::extent::value) - return nullptr; - return GenericDesktopUsages[int(m_usage)]; - case HIDUsagePage::Game: - if (int(m_usage) >= std::extent::value) - return nullptr; - return GameUsages[int(m_usage)]; - default: - return nullptr; - } -} +struct HIDReports { + std::map> m_inputReports; + std::map> m_outputReports; + std::map> m_featureReports; -struct HIDReports -{ - std::map> m_inputReports; - std::map> m_outputReports; - std::map> m_featureReports; + static void _AddItem(std::map>& m, uint32_t flags, const HIDItemState& state) { + std::vector& report = m[state.m_reportID]; + report.reserve(report.size() + state.m_reportCount); + for (int i = 0; i < state.m_reportCount; ++i) + report.emplace_back(flags, state, i); + } - static void _AddItem(std::map>& m, uint32_t flags, const HIDItemState& state) - { - std::vector& report = m[state.m_reportID]; - report.reserve(report.size() + state.m_reportCount); - for (int i=0 ; i inputItems; + std::map inputItems; - { - /* First enumerate buttons */ - USHORT length = caps.NumberInputButtonCaps; - std::vector bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS()); - HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData); - for (const HIDP_BUTTON_CAPS& caps : bCaps) - { - if (caps.IsRange) - { - int usage = caps.Range.UsageMin; - for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) - { - inputItems.insert(std::make_pair(i, - HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), - HIDUsage(usage), std::make_pair(0, 1), 1))); - } - } - else - { - inputItems.insert(std::make_pair(caps.NotRange.DataIndex, - HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), - HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1))); - } + { + /* First enumerate buttons */ + USHORT length = caps.NumberInputButtonCaps; + std::vector bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS()); + HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData); + for (const HIDP_BUTTON_CAPS& caps : bCaps) { + if (caps.IsRange) { + int usage = caps.Range.UsageMin; + for (int i = caps.Range.DataIndexMin; i <= caps.Range.DataIndexMax; ++i, ++usage) { + inputItems.insert(std::make_pair( + i, HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage), std::make_pair(0, 1), 1))); } + } else { + inputItems.insert(std::make_pair(caps.NotRange.DataIndex, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), + HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1))); + } } + } - { - /* Now enumerate values */ - USHORT length = caps.NumberInputValueCaps; - std::vector vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS()); - HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData); - for (const HIDP_VALUE_CAPS& caps : vCaps) - { - if (caps.IsRange) - { - int usage = caps.Range.UsageMin; - for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) - { - inputItems.insert(std::make_pair(i, - HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage), - std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); - } - } - else - { - inputItems.insert(std::make_pair(caps.NotRange.DataIndex, - HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage), - HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); - } + { + /* Now enumerate values */ + USHORT length = caps.NumberInputValueCaps; + std::vector vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS()); + HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData); + for (const HIDP_VALUE_CAPS& caps : vCaps) { + if (caps.IsRange) { + int usage = caps.Range.UsageMin; + for (int i = caps.Range.DataIndexMin; i <= caps.Range.DataIndexMax; ++i, ++usage) { + inputItems.insert( + std::make_pair(i, HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage), + std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); } + } else { + inputItems.insert( + std::make_pair(caps.NotRange.DataIndex, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage), + HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); + } } + } - m_itemPool.reserve(inputItems.size()); - for (const auto& item : inputItems) - m_itemPool.push_back(item.second); + m_itemPool.reserve(inputItems.size()); + for (const auto& item : inputItems) + m_itemPool.push_back(item.second); - m_status = ParserStatus::Done; - return ParserStatus::Done; + 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 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; +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 0; return *oldIt; + case 2: + status = AdvanceIt(it, end, 2); + if (status == HIDParser::ParserStatus::Error) + return 0; + return *reinterpret_cast(&*oldIt); + case 3: + status = AdvanceIt(it, end, 4); + if (status == HIDParser::ParserStatus::Error) + return 0; + return *reinterpret_cast(&*oldIt); + default: + break; + } + return 0; } -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(&*oldIt); - case 3: - status = AdvanceIt(it, end, 4); - if (status == HIDParser::ParserStatus::Error) - return 0; - return *reinterpret_cast(&*oldIt); - default: +HIDParser::ParserStatus HIDParser::ParseItem(HIDReports& reportsOut, std::stack& stateStack, + std::stack& 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; - } - return 0; -} - -HIDParser::ParserStatus -HIDParser::ParseItem(HIDReports& reportsOut, - std::stack& stateStack, - std::stack& 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 stateStack; - stateStack.emplace(); - std::stack 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& out, const std::map>& 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 stateStack; - stateStack.emplace(); - std::stack 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 HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) -{ - std::stack stateStack; - stateStack.emplace(); - std::stack 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); + 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()) - continue; - if (collectionStack.top().m_type == HIDCollectionType::Application) - return { collectionStack.top().m_usagePage, collectionStack.top().m_usage }; - if (status != ParserStatus::OK) - break; + 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 {}; + return it == end ? ParserStatus::Done : ParserStatus::OK; +} + +HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t len) { + std::stack stateStack; + stateStack.emplace(); + std::stack 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& out, const std::map>& 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 stateStack; + stateStack.emplace(); + std::stack 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 HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) { + std::stack stateStack; + stateStack.emplace(); + std::stack 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& valueCB) const -{ +void HIDParser::EnumerateValues(const std::function& valueCB) const { #if !WINDOWS_STORE - if (m_status != ParserStatus::Done) - return; + if (m_status != ParserStatus::Done) + return; - for (const HIDMainItem& item : m_itemPool) - { - if (item.IsConstant()) - continue; - if (!valueCB(item)) - return; - } + for (const HIDMainItem& item : m_itemPool) { + if (item.IsConstant()) + continue; + if (!valueCB(item)) + return; + } #endif } #else -void HIDParser::EnumerateValues(const std::function& valueCB) const -{ - if (m_status != ParserStatus::Done) - return; +void HIDParser::EnumerateValues(const std::function& valueCB) const { + if (m_status != ParserStatus::Done) + return; - for (uint32_t i=m_inputReports.first ; i& valueCB, - const uint8_t* data, size_t len) const -{ + const uint8_t* data, size_t len) const { #if !WINDOWS_STORE - if (m_status != ParserStatus::Done) - return; + 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; + 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& data = *it; - if (data.DataIndex == idx) - { - value = data.RawValue; - ++it; - } - } - if (!valueCB(item, value)) - return; - ++idx; + 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& data = *it; + if (data.DataIndex == idx) { + value = data.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) {} +class BitwiseIterator { + const uint8_t*& m_it; + const uint8_t* m_end; + int m_bit = 0; - uint32_t GetUnsignedValue(int numBits, HIDParser::ParserStatus& status) - { - uint32_t val = 0; - for (int i=0 ; i= 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; +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& valueCB, - const uint8_t* data, size_t len) const -{ - if (m_status != ParserStatus::Done) + 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; - - 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) + if (item.IsConstant()) + continue; + if (!valueCB(item, val)) return; - - BitwiseIterator bitIt(it, end); - - for (uint32_t i=m_inputReports.first ; i #endif -namespace boo -{ +namespace boo { -class IHIDDevice : public std::enable_shared_from_this -{ - 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; +class IHIDDevice : public std::enable_shared_from_this { + 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; + virtual const PHIDP_PREPARSED_DATA _getReportDescriptor() = 0; #endif #else - virtual std::vector _getReportDescriptor()=0; + virtual std::vector _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; + 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; + virtual ~IHIDDevice() = default; }; -} - +} // namespace boo diff --git a/lib/inputdev/IOKitPointer.hpp b/lib/inputdev/IOKitPointer.hpp index 9eb8a64..9340f2d 100644 --- a/lib/inputdev/IOKitPointer.hpp +++ b/lib/inputdev/IOKitPointer.hpp @@ -7,113 +7,97 @@ #include /// A smart pointer that can manage the lifecycle of IOKit objects. -template +template class IOObjectPointer { public: - IOObjectPointer() : storage(0) { } + IOObjectPointer() : storage(0) {} - IOObjectPointer(T pointer) : storage(toStorageType(pointer)) { - if (storage) { - IOObjectRetain(storage); - } + 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(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& 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(IOObjectPointer&& other) : storage(std::exchange(other.storage, 0)) {} - ~IOObjectPointer() { - if (io_object_t pointer = storage) { - IOObjectRelease(pointer); - } + ~IOObjectPointer() { + if (io_object_t pointer = storage) { + IOObjectRelease(pointer); } + } - static inline IOObjectPointer adopt(T ptr) { - return IOObjectPointer(ptr, IOObjectPointer::Adopt); - } + static inline IOObjectPointer adopt(T ptr) { return IOObjectPointer(ptr, IOObjectPointer::Adopt); } - T get() const { - return fromStorageType(storage); + T get() const { return fromStorageType(storage); } + io_object_t* operator&() { + if (io_object_t pointer = storage) { + IOObjectRelease(pointer); } - io_object_t* operator&() - { - if (io_object_t pointer = storage) { - IOObjectRelease(pointer); - } - return &storage; - } - operator bool() const { return storage != 0; } + return &storage; + } + operator bool() const { return storage != 0; } private: - io_object_t storage; + io_object_t storage; - enum AdoptTag { Adopt }; - IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) { } + 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 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; - } + inline T fromStorageType(io_object_t pointer) const { return (T)pointer; } - void swap(IOObjectPointer &other) { - std::swap(storage, other.storage); - } + 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() : _storage(nullptr) {} - IOCFPluginPointer(const IOCFPluginPointer & other) = delete; + IOCFPluginPointer(const IOCFPluginPointer& other) = delete; - IOCFPluginPointer(IOCFPluginPointer && other) : _storage(std::exchange(other._storage, nullptr)) { } + IOCFPluginPointer(IOCFPluginPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {} - ~IOCFPluginPointer() { - if (IOCFPlugInInterface** pointer = _storage) { - IODestroyPlugInInterface(pointer); - } + ~IOCFPluginPointer() { + if (IOCFPlugInInterface** pointer = _storage) { + IODestroyPlugInInterface(pointer); } + } - IOCFPlugInInterface*** operator&() - { - if (IOCFPlugInInterface** pointer = _storage) { - IODestroyPlugInInterface(pointer); - } - return &_storage; + 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); - } + 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; } + operator bool() const { return _storage != nullptr; } - IOCFPlugInInterface** storage() const { return _storage; } + IOCFPlugInInterface** storage() const { return _storage; } private: - IOCFPlugInInterface** _storage; - void swap(IOCFPluginPointer &other) { - std::swap(_storage, other._storage); - } + IOCFPlugInInterface** _storage; + void swap(IOCFPluginPointer& other) { std::swap(_storage, other._storage); } }; - diff --git a/lib/inputdev/NintendoPowerA.cpp b/lib/inputdev/NintendoPowerA.cpp index 50e53d5..8a31d2d 100644 --- a/lib/inputdev/NintendoPowerA.cpp +++ b/lib/inputdev/NintendoPowerA.cpp @@ -1,56 +1,44 @@ #include "boo/inputdev/NintendoPowerA.hpp" #include "boo/inputdev/DeviceSignature.hpp" #include -namespace boo -{ +namespace boo { NintendoPowerA::NintendoPowerA(DeviceToken* token) -: TDeviceBase(dev_typeid(NintendoPowerA), token) -{ +: TDeviceBase(dev_typeid(NintendoPowerA), token) {} -} +NintendoPowerA::~NintendoPowerA() {} -NintendoPowerA::~NintendoPowerA() -{ -} - -void NintendoPowerA::deviceDisconnected() -{ - std::lock_guard lk(m_callbackLock); - if (m_callback) - m_callback->controllerDisconnected(); +void NintendoPowerA::deviceDisconnected() { + std::lock_guard lk(m_callbackLock); + if (m_callback) + m_callback->controllerDisconnected(); } void NintendoPowerA::initialCycle() {} -void NintendoPowerA::transferCycle() -{ - uint8_t payload[8]; - size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); - if (recvSz != 8) - return; +void NintendoPowerA::transferCycle() { + uint8_t payload[8]; + size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); + if (recvSz != 8) + return; - NintendoPowerAState state = *reinterpret_cast(&payload); + NintendoPowerAState state = *reinterpret_cast(&payload); - std::lock_guard lk(m_callbackLock); - if (state != m_last && m_callback) - m_callback->controllerUpdate(state); - m_last = state; + std::lock_guard lk(m_callbackLock); + if (state != m_last && m_callback) + 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) -{ +void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {} + +bool NintendoPowerAState::operator==(const NintendoPowerAState& other) { + return !memcmp(this, &other, sizeof(NintendoPowerAState)); } -bool NintendoPowerAState::operator==(const NintendoPowerAState &other) -{ - return !memcmp(this, &other, sizeof(NintendoPowerAState)); +bool NintendoPowerAState::operator!=(const NintendoPowerAState& other) { + return memcmp(this, &other, sizeof(NintendoPowerAState)); } -bool NintendoPowerAState::operator!=(const NintendoPowerAState &other) -{ - return memcmp(this, &other, sizeof(NintendoPowerAState)); -} - -} +} // namespace boo diff --git a/lib/mac/CocoaCommon.hpp b/lib/mac/CocoaCommon.hpp index 3ffc0d3..dc08ba6 100644 --- a/lib/mac/CocoaCommon.hpp +++ b/lib/mac/CocoaCommon.hpp @@ -12,32 +12,28 @@ #include #include -namespace boo -{ +namespace boo { class IWindow; -struct MetalContext -{ - id m_dev = nullptr; - id m_q = nullptr; - struct Window - { - CAMetalLayer* m_metalLayer = nullptr; - std::mutex m_resizeLock; - bool m_needsResize; - CGSize m_size; - }; - std::unordered_map m_windows; - uint32_t m_sampleCount = 1; - uint32_t m_anisotropy = 1; - MTLPixelFormat m_pixelFormat = MTLPixelFormatBGRA8Unorm; +struct MetalContext { + id m_dev = nullptr; + id m_q = nullptr; + struct Window { + CAMetalLayer* m_metalLayer = nullptr; + std::mutex m_resizeLock; + bool m_needsResize; + CGSize m_size; + }; + std::unordered_map 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 { +struct MetalContext {}; +} // namespace boo #endif #endif // __APPLE__ diff --git a/lib/nx/ApplicationNX.cpp b/lib/nx/ApplicationNX.cpp index 8b2d78a..b0b8342 100644 --- a/lib/nx/ApplicationNX.cpp +++ b/lib/nx/ApplicationNX.cpp @@ -7,133 +7,95 @@ #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::NXApplication"); std::shared_ptr _WindowNXNew(std::string_view title, NXContext* nxCtx); -class ApplicationNX : public IApplication -{ - IApplicationCallback& m_callback; - const std::string m_uniqueName; - const std::string m_friendlyName; - const std::string m_pname; - const std::vector m_args; +class ApplicationNX : public IApplication { + IApplicationCallback& m_callback; + const std::string m_uniqueName; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; - NXContext m_nxCtx; + NXContext m_nxCtx; - void _deletedWindow(IWindow* window) {} + void _deletedWindow(IWindow* window) {} public: - ApplicationNX(IApplicationCallback& callback, - std::string_view uniqueName, - std::string_view friendlyName, - std::string_view pname, - const std::vector& 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) - {} + ApplicationNX(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName, + std::string_view pname, const std::vector& 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) {} - EPlatformType getPlatformType() const { return EPlatformType::NX; } + EPlatformType getPlatformType() const { return EPlatformType::NX; } - int run() - { - /* Spawn client thread */ - int clientReturn = INT_MIN; - std::mutex initmt; - std::condition_variable initcv; - std::unique_lock outerLk(initmt); - std::thread clientThread([&]() - { - std::unique_lock innerLk(initmt); - innerLk.unlock(); - initcv.notify_one(); - std::string thrName = std::string(getFriendlyName()) + " Client"; - logvisor::RegisterThreadName(thrName.c_str()); - clientReturn = m_callback.appMain(this); - }); - initcv.wait(outerLk); + int run() { + /* Spawn client thread */ + int clientReturn = INT_MIN; + std::mutex initmt; + std::condition_variable initcv; + std::unique_lock outerLk(initmt); + std::thread clientThread([&]() { + std::unique_lock innerLk(initmt); + innerLk.unlock(); + initcv.notify_one(); + std::string thrName = std::string(getFriendlyName()) + " Client"; + logvisor::RegisterThreadName(thrName.c_str()); + clientReturn = m_callback.appMain(this); + }); + initcv.wait(outerLk); - // Main graphics loop - while (clientReturn == INT_MIN && appletMainLoop()) - { - // Get and process input - hidScanInput(); - u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO); - if (kDown & KEY_PLUS) - break; - } - - m_callback.appQuitting(this); - if (clientThread.joinable()) - clientThread.join(); - - return 0; + // Main graphics loop + while (clientReturn == INT_MIN && appletMainLoop()) { + // Get and process input + hidScanInput(); + u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO); + if (kDown & KEY_PLUS) + break; } - std::string_view getUniqueName() const - { - return m_uniqueName; - } + m_callback.appQuitting(this); + if (clientThread.joinable()) + clientThread.join(); - std::string_view getFriendlyName() const - { - return m_friendlyName; - } + return 0; + } - std::string_view getProcessName() const - { - return m_pname; - } + std::string_view getUniqueName() const { return m_uniqueName; } - const std::vector& getArgs() const - { - return m_args; - } + std::string_view getFriendlyName() const { return m_friendlyName; } - std::shared_ptr m_window; - std::shared_ptr newWindow(std::string_view title) - { - if (m_window) - Log.report(logvisor::Fatal, "Only 1 window allowed on NX"); - m_window = _WindowNXNew(title, &m_nxCtx); - return m_window; - } + std::string_view getProcessName() const { return m_pname; } + + const std::vector& getArgs() const { return m_args; } + + std::shared_ptr m_window; + std::shared_ptr newWindow(std::string_view title) { + if (m_window) + Log.report(logvisor::Fatal, "Only 1 window allowed on NX"); + m_window = _WindowNXNew(title, &m_nxCtx); + return m_window; + } }; IApplication* APP = nullptr; -int ApplicationRun(IApplication::EPlatformType platform, - IApplicationCallback& cb, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& 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()); +int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName, + SystemStringView friendlyName, SystemStringView pname, const std::vector& 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; - APP = new ApplicationNX(cb, uniqueName, friendlyName, pname, args, gfxApi, - samples, anisotropy, deepColor, singleInstance); - int ret = APP->run(); - delete APP; - APP = nullptr; - return ret; + if (APP) + return 1; + APP = new ApplicationNX(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor, + singleInstance); + int ret = APP->run(); + delete APP; + APP = nullptr; + return ret; } -} +} // namespace boo diff --git a/lib/nx/WindowNX.cpp b/lib/nx/WindowNX.cpp index 50c0178..5047c66 100644 --- a/lib/nx/WindowNX.cpp +++ b/lib/nx/WindowNX.cpp @@ -5,116 +5,111 @@ #include -namespace boo -{ +namespace boo { std::unique_ptr _NewNXCommandQueue(NXContext* ctx, IGraphicsContext* parent); std::unique_ptr _NewNXDataFactory(IGraphicsContext* parent, NXContext* ctx); -struct GraphicsContextNX : IGraphicsContext -{ - NXContext* m_nxCtx; - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; +struct GraphicsContextNX : IGraphicsContext { + NXContext* m_nxCtx; + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; + public: - explicit GraphicsContextNX(NXContext* nxCtx) - : m_nxCtx(nxCtx) - { - m_dataFactory = _NewNXDataFactory(this, nxCtx); - m_commandQueue = _NewNXCommandQueue(nxCtx, this); - } + explicit GraphicsContextNX(NXContext* nxCtx) : m_nxCtx(nxCtx) { + m_dataFactory = _NewNXDataFactory(this, nxCtx); + m_commandQueue = _NewNXCommandQueue(nxCtx, this); + } - EGraphicsAPI getAPI() const { return EGraphicsAPI::NX; } - EPixelFormat getPixelFormat() const { return EPixelFormat::RGBA8; } - void setPixelFormat(EPixelFormat pf) {} - bool initializeContext(void* handle) { return m_nxCtx->initialize(); } - void makeCurrent() {} - void postInit() {} - void present() {} + EGraphicsAPI getAPI() const { return EGraphicsAPI::NX; } + EPixelFormat getPixelFormat() const { return EPixelFormat::RGBA8; } + void setPixelFormat(EPixelFormat pf) {} + bool initializeContext(void* handle) { return m_nxCtx->initialize(); } + void makeCurrent() {} + void postInit() {} + void present() {} - IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } - IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } - IGraphicsDataFactory* getMainContextDataFactory() { return m_dataFactory.get(); } - IGraphicsDataFactory* getLoadContextDataFactory() { return m_dataFactory.get(); } + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } + IGraphicsDataFactory* getMainContextDataFactory() { return m_dataFactory.get(); } + IGraphicsDataFactory* getLoadContextDataFactory() { return m_dataFactory.get(); } }; -class WindowNX : public IWindow -{ - std::string m_title; - std::unique_ptr m_gfxCtx; - IWindowCallback* m_callback = nullptr; +class WindowNX : public IWindow { + std::string m_title; + std::unique_ptr m_gfxCtx; + IWindowCallback* m_callback = nullptr; + public: - WindowNX(std::string_view title, NXContext* nxCtx) - : m_title(title), m_gfxCtx(new GraphicsContextNX(nxCtx)) - { - m_gfxCtx->initializeContext(nullptr); - } + WindowNX(std::string_view title, NXContext* nxCtx) : m_title(title), m_gfxCtx(new GraphicsContextNX(nxCtx)) { + m_gfxCtx->initializeContext(nullptr); + } - void setCallback(IWindowCallback* cb) { m_callback = cb; } + void setCallback(IWindowCallback* cb) { m_callback = cb; } - void closeWindow() {} - void showWindow() {} - void hideWindow() {} + void closeWindow() {} + void showWindow() {} + void hideWindow() {} - SystemString getTitle() { return m_title; } - void setTitle(SystemStringView title) { m_title = title; } + SystemString getTitle() { return m_title; } + void setTitle(SystemStringView title) { m_title = title; } - void setCursor(EMouseCursor cursor) {} - void setWaitCursor(bool wait) {} + void setCursor(EMouseCursor cursor) {} + void setWaitCursor(bool wait) {} - void setWindowFrameDefault() {} - void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const - { - u32 width, height; - gfxGetFramebufferResolution(&width, &height); - xOut = 0; - yOut = 0; - wOut = width; - hOut = height; - } - void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const - { - u32 width, height; - gfxGetFramebufferResolution(&width, &height); - xOut = 0; - yOut = 0; - wOut = width; - hOut = height; - } - void setWindowFrame(float x, float y, float w, float h) {} - void setWindowFrame(int x, int y, int w, int h) {} - float getVirtualPixelFactor() const { return 1.f; } + void setWindowFrameDefault() {} + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const { + u32 width, height; + gfxGetFramebufferResolution(&width, &height); + xOut = 0; + yOut = 0; + wOut = width; + hOut = height; + } + void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const { + u32 width, height; + gfxGetFramebufferResolution(&width, &height); + xOut = 0; + yOut = 0; + wOut = width; + hOut = height; + } + void setWindowFrame(float x, float y, float w, float h) {} + void setWindowFrame(int x, int y, int w, int h) {} + float getVirtualPixelFactor() const { return 1.f; } - bool isFullscreen() const { return true; } - void setFullscreen(bool fs) {} + bool isFullscreen() const { return true; } + void setFullscreen(bool fs) {} - void claimKeyboardFocus(const int coord[2]) {} - bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { return false; } - std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { return {}; } + void claimKeyboardFocus(const int coord[2]) {} + bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { return false; } + std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { return {}; } - void waitForRetrace() {} + void waitForRetrace() {} - uintptr_t getPlatformHandle() const { return 0; } - bool _incomingEvent(void* event) {(void)event; return false;} - void _cleanup() {} + uintptr_t getPlatformHandle() const { return 0; } + bool _incomingEvent(void* event) { + (void)event; + return false; + } + void _cleanup() {} - ETouchType getTouchType() const { return ETouchType::Display; } + ETouchType getTouchType() const { return ETouchType::Display; } - void setStyle(EWindowStyle style) {} - EWindowStyle getStyle() const { return EWindowStyle::None; } + void setStyle(EWindowStyle style) {} + EWindowStyle getStyle() const { return EWindowStyle::None; } - void setTouchBarProvider(void*) {} + void setTouchBarProvider(void*) {} - IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx->getCommandQueue(); } - IGraphicsDataFactory* getDataFactory() { return m_gfxCtx->getDataFactory(); } - IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx->getMainContextDataFactory(); } - IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } + IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx->getCommandQueue(); } + IGraphicsDataFactory* getDataFactory() { return m_gfxCtx->getDataFactory(); } + IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx->getMainContextDataFactory(); } + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } }; -std::shared_ptr _WindowNXNew(std::string_view title, NXContext* nxCtx) -{ - std::shared_ptr ret = std::make_shared(title, nxCtx); - return ret; +std::shared_ptr _WindowNXNew(std::string_view title, NXContext* nxCtx) { + std::shared_ptr ret = std::make_shared(title, nxCtx); + return ret; } -} +} // namespace boo diff --git a/lib/win/ApplicationUWP.cpp b/lib/win/ApplicationUWP.cpp index f4c57e1..d828bfb 100644 --- a/lib/win/ApplicationUWP.cpp +++ b/lib/win/ApplicationUWP.cpp @@ -25,294 +25,234 @@ PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignaturePROC = nullptr; pD3DCompile D3DCompilePROC = nullptr; pD3DCreateBlob D3DCreateBlobPROC = nullptr; -static bool FindBestD3DCompile() -{ - D3DCompilePROC = D3DCompile; - D3DCreateBlobPROC = D3DCreateBlob; - return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr; +static bool FindBestD3DCompile() { + D3DCompilePROC = D3DCompile; + D3DCreateBlobPROC = D3DCreateBlob; + return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr; } -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::ApplicationUWP"); std::shared_ptr _WindowUWPNew(SystemStringView title, Boo3DAppContextUWP& d3dCtx); -class ApplicationUWP final : public IApplication -{ - friend ref class AppView; - IApplicationCallback& m_callback; - const SystemString m_uniqueName; - const SystemString m_friendlyName; - const SystemString m_pname; - const std::vector m_args; - std::shared_ptr m_window; - bool m_singleInstance; - bool m_issuedWindow = false; +class ApplicationUWP final : public IApplication { + friend ref class AppView; + IApplicationCallback& m_callback; + const SystemString m_uniqueName; + const SystemString m_friendlyName; + const SystemString m_pname; + const std::vector m_args; + std::shared_ptr m_window; + bool m_singleInstance; + bool m_issuedWindow = false; - Boo3DAppContextUWP m_3dCtx; + Boo3DAppContextUWP m_3dCtx; - void _deletedWindow(IWindow* window) - { - } + void _deletedWindow(IWindow* window) {} public: + ApplicationUWP(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName, + SystemStringView pname, const std::vector& args, bool singleInstance) + : m_callback(callback) + , m_uniqueName(uniqueName) + , m_friendlyName(friendlyName) + , m_pname(pname) + , m_args(args) + , m_singleInstance(singleInstance) { + typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory); + CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1; - ApplicationUWP(IApplicationCallback& callback, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& args, - bool singleInstance) - : m_callback(callback), - m_uniqueName(uniqueName), - m_friendlyName(friendlyName), - m_pname(pname), - m_args(args), - m_singleInstance(singleInstance) - { - typedef HRESULT(WINAPI*CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void **ppFactory); - CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1; - - bool no12 = true; - for (const SystemString& arg : args) - if (!arg.compare(L"--d3d12")) - no12 = false; + bool no12 = true; + for (const SystemString& arg : args) + if (!arg.compare(L"--d3d12")) + no12 = false; #if _WIN32_WINNT_WIN10 - if (!no12) - { - if (!FindBestD3DCompile()) - Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); + if (!no12) { + if (!FindBestD3DCompile()) + Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); - D3D12SerializeRootSignaturePROC = D3D12SerializeRootSignature; + D3D12SerializeRootSignaturePROC = D3D12SerializeRootSignature; - /* Create device */ - PFN_D3D12_CREATE_DEVICE MyD3D12CreateDevice = D3D12CreateDevice; + /* 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, "unable to create DXGI factory"); + /* Obtain DXGI Factory */ + HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory2), &m_3dCtx.m_ctx12.m_dxFactory); + if (FAILED(hr)) + Log.report(logvisor::Fatal, "unable to create DXGI factory"); - /* Adapter */ - ComPtr ppAdapter; - for (UINT adapterIndex = 0; ; ++adapterIndex) - { - ComPtr pAdapter; - if (DXGI_ERROR_NOT_FOUND == m_3dCtx.m_ctx12.m_dxFactory->EnumAdapters1(adapterIndex, &pAdapter)) - break; + /* Adapter */ + ComPtr ppAdapter; + for (UINT adapterIndex = 0;; ++adapterIndex) { + ComPtr 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, "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, "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, "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, "unable to create loader list"); - - Log.report(logvisor::Info, "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(); - } + // 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, "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, "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, "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, "unable to create loader list"); + + Log.report(logvisor::Info, "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, "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 tempDev; - ComPtr 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, "unable to create D3D11 device"); - - ComPtr device; - if (FAILED(tempDev.As(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || - FAILED(tempCtx.As(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || - FAILED(m_3dCtx.m_ctx11.m_dev.As(&device)) || !device) - { - exit(1); - } - - /* Obtain DXGI Factory */ - ComPtr 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, "initialized D3D11 renderer"); - return; - } - - Log.report(logvisor::Fatal, "system doesn't support D3D11 or D3D12"); - } - - EPlatformType getPlatformType() const { - return EPlatformType::UWP; + if (!FindBestD3DCompile()) + Log.report(logvisor::Fatal, "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 tempDev; + ComPtr 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, "unable to create D3D11 device"); + + ComPtr device; + if (FAILED(tempDev.As(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || + FAILED(tempCtx.As(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || + FAILED(m_3dCtx.m_ctx11.m_dev.As(&device)) || !device) { + exit(1); + } + + /* Obtain DXGI Factory */ + ComPtr 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, "initialized D3D11 renderer"); + return; } + Log.report(logvisor::Fatal, "system doesn't support D3D11 or D3D12"); + } - std::thread m_clientThread; - int run() - { - /* Spawn client thread */ - int clientReturn = 0; - m_clientThread = std::thread([&]() - { - std::string thrName = WCSTMBS(getFriendlyName().data()) + " Client Thread"; - logvisor::RegisterThreadName(thrName.c_str()); - clientReturn = m_callback.appMain(this); - }); + EPlatformType getPlatformType() const { return EPlatformType::UWP; } - CoreWindow::GetForCurrentThread()->Activate(); - CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit); - return 0; + std::thread m_clientThread; + int run() { + /* Spawn client thread */ + int clientReturn = 0; + m_clientThread = std::thread([&]() { + std::string thrName = WCSTMBS(getFriendlyName().data()) + " 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(); + } + + SystemStringView getUniqueName() const { return m_uniqueName; } + + SystemStringView getFriendlyName() const { return m_friendlyName; } + + SystemStringView getProcessName() const { return m_pname; } + + const std::vector& getArgs() const { return m_args; } + + std::shared_ptr newWindow(SystemStringView title, uint32_t sampleCount) { + if (!m_issuedWindow) { + m_issuedWindow = true; + return m_window; } + return {}; + } - void quit() - { - m_callback.appQuitting(this); - if (m_clientThread.joinable()) - m_clientThread.join(); - } - - SystemStringView getUniqueName() const - { - return m_uniqueName; - } - - SystemStringView getFriendlyName() const - { - return m_friendlyName; - } - - SystemStringView getProcessName() const - { - return m_pname; - } - - const std::vector& getArgs() const - { - return m_args; - } - - std::shared_ptr newWindow(SystemStringView title, uint32_t sampleCount) - { - if (!m_issuedWindow) - { - m_issuedWindow = true; - return m_window; - } - return {}; - } - - void _setWindow(CoreWindow^ window) - { - m_window = _WindowUWPNew(m_friendlyName, m_3dCtx); - } + void _setWindow(CoreWindow ^ window) { m_window = _WindowUWPNew(m_friendlyName, m_3dCtx); } }; IApplication* APP = NULL; -ref class AppView sealed : public IFrameworkView -{ - ApplicationUWP m_app; +ref class AppView sealed : public IFrameworkView { + ApplicationUWP m_app; -internal: - AppView(IApplicationCallback& callback, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& args, - bool singleInstance) - : m_app(callback, uniqueName, friendlyName, pname, args, singleInstance) { APP = &m_app; } + internal : AppView(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName, + SystemStringView pname, const std::vector& 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(this, &AppView::OnActivated); - } + virtual void Initialize(CoreApplicationView ^ applicationView) { + applicationView->Activated += + ref new TypedEventHandler(this, &AppView::OnActivated); + } - virtual void SetWindow(CoreWindow^ window) - { - m_app._setWindow(window); - } + virtual void SetWindow(CoreWindow ^ window) { m_app._setWindow(window); } - virtual void Load(String^ entryPoint) - { + virtual void Load(String ^ entryPoint) {} - } + virtual void Run() { m_app.run(); } - virtual void Run() - { - m_app.run(); - } + virtual void Uninitialize() { m_app.quit(); } - virtual void Uninitialize() - { - m_app.quit(); - } - - void OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) - { - CoreWindow::GetForCurrentThread()->Activate(); - } + 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); -} - +IFrameworkView ^ ViewProvider::CreateView() { + return ref new AppView(m_appCb, m_uniqueName, m_friendlyName, m_pname, m_args, m_singleInstance); } +} // namespace boo diff --git a/lib/win/ApplicationWin32.cpp b/lib/win/ApplicationWin32.cpp index 7feaf40..1ed16c5 100644 --- a/lib/win/ApplicationWin32.cpp +++ b/lib/win/ApplicationWin32.cpp @@ -33,565 +33,467 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l pD3DCompile D3DCompilePROC = nullptr; pD3DCreateBlob D3DCreateBlobPROC = 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"); - } - } +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; + } + if (d3dCompilelib) { + D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile"); + D3DCreateBlobPROC = (pD3DCreateBlob)GetProcAddress(d3dCompilelib, "D3DCreateBlob"); + return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr; + } + return false; } -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::ApplicationWin32"); Win32Cursors WIN32_CURSORS; std::shared_ptr _WindowWin32New(SystemStringView title, Boo3DAppContextWin32& d3dCtx); -class ApplicationWin32 final : public IApplication -{ - IApplicationCallback& m_callback; - const SystemString m_uniqueName; - const SystemString m_friendlyName; - const SystemString m_pname; - const std::vector m_args; - std::unordered_map> m_allWindows; +class ApplicationWin32 final : public IApplication { + IApplicationCallback& m_callback; + const SystemString m_uniqueName; + const SystemString m_friendlyName; + const SystemString m_pname; + const std::vector m_args; + std::unordered_map> m_allWindows; - Boo3DAppContextWin32 m_3dCtx; + Boo3DAppContextWin32 m_3dCtx; #if BOO_HAS_VULKAN - PFN_vkGetInstanceProcAddr m_getVkProc = nullptr; + PFN_vkGetInstanceProcAddr m_getVkProc = nullptr; #endif - void _deletedWindow(IWindow* window) - { - m_allWindows.erase(HWND(window->getPlatformHandle())); - } + void _deletedWindow(IWindow* window) { m_allWindows.erase(HWND(window->getPlatformHandle())); } public: - - ApplicationWin32(IApplicationCallback& callback, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& 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; - 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; + ApplicationWin32(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName, + SystemStringView pname, const std::vector& 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; + 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; #if BOO_HAS_VULKAN - g_VulkanContext.m_sampleCountColor = samples; - g_VulkanContext.m_sampleCountDepth = samples; - g_VulkanContext.m_anisotropy = anisotropy; - g_VulkanContext.m_deepColor = deepColor; + 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, "unable to load dxgi.dll"); + HMODULE dxgilib = LoadLibraryW(L"dxgi.dll"); + if (!dxgilib) + Log.report(logvisor::Fatal, "unable to load dxgi.dll"); - typedef HRESULT(WINAPI*CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void **ppFactory); - CreateDXGIFactory1PROC MyCreateDXGIFactory1 = (CreateDXGIFactory1PROC)GetProcAddress(dxgilib, "CreateDXGIFactory1"); - if (!MyCreateDXGIFactory1) - Log.report(logvisor::Fatal, "unable to find CreateDXGIFactory1 in DXGI.dll\n"); + typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory); + CreateDXGIFactory1PROC MyCreateDXGIFactory1 = (CreateDXGIFactory1PROC)GetProcAddress(dxgilib, "CreateDXGIFactory1"); + if (!MyCreateDXGIFactory1) + Log.report(logvisor::Fatal, "unable to find CreateDXGIFactory1 in DXGI.dll\n"); - bool noD3d = false; + bool noD3d = false; #if BOO_HAS_VULKAN - bool useVulkan = false; + bool useVulkan = false; #endif - if (!gfxApi.empty()) - { + if (!gfxApi.empty()) { #if BOO_HAS_VULKAN - if (!gfxApi.compare("Vulkan")) - { - noD3d = true; - useVulkan = true; - } - if (!gfxApi.compare("OpenGL")) - { - noD3d = true; - useVulkan = false; - } + if (!gfxApi.compare("Vulkan")) { + noD3d = true; + useVulkan = true; + } + if (!gfxApi.compare("OpenGL")) { + noD3d = true; + useVulkan = false; + } #else - if (!gfxApi.compare("OpenGL")) - noD3d = true; + if (!gfxApi.compare("OpenGL")) + noD3d = true; #endif - } - for (const SystemString& arg : args) - { + } + for (const SystemString& arg : args) { #if BOO_HAS_VULKAN - if (!arg.compare(L"--d3d11")) - { - useVulkan = false; - noD3d = false; - } - if (!arg.compare(L"--vulkan")) - { - noD3d = true; - useVulkan = true; - } - if (!arg.compare(L"--gl")) - { - noD3d = true; - useVulkan = false; - } + if (!arg.compare(L"--d3d11")) { + useVulkan = false; + noD3d = false; + } + if (!arg.compare(L"--vulkan")) { + noD3d = true; + useVulkan = true; + } + if (!arg.compare(L"--gl")) { + noD3d = true; + useVulkan = false; + } #else - if (!arg.compare(L"--d3d11")) - noD3d = false; - if (!arg.compare(L"--gl")) - noD3d = true; + if (!arg.compare(L"--d3d11")) + noD3d = false; + if (!arg.compare(L"--gl")) + noD3d = true; #endif - } + } - HMODULE d3d11lib = nullptr; - if (!noD3d) - d3d11lib = LoadLibraryW(L"D3D11.dll"); - if (d3d11lib) - { - if (!FindBestD3DCompile()) - Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); + HMODULE d3d11lib = nullptr; + if (!noD3d) + d3d11lib = LoadLibraryW(L"D3D11.dll"); + if (d3d11lib) { + if (!FindBestD3DCompile()) + Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); - /* Create device proc */ - PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11lib, "D3D11CreateDevice"); - if (!MyD3D11CreateDevice) - Log.report(logvisor::Fatal, "unable to find D3D11CreateDevice in D3D11.dll"); + /* Create device proc */ + PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice = + (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11lib, "D3D11CreateDevice"); + if (!MyD3D11CreateDevice) + Log.report(logvisor::Fatal, "unable to find D3D11CreateDevice in D3D11.dll"); - /* Create device */ - D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0; - ComPtr tempDev; - ComPtr 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, "unable to create D3D11 device"); + /* Create device */ + D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0; + ComPtr tempDev; + ComPtr 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, "unable to create D3D11 device"); - ComPtr device; - if (FAILED(tempDev.As(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || - FAILED(tempCtx.As(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || - FAILED(m_3dCtx.m_ctx11.m_dev.As(&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); - } + ComPtr device; + if (FAILED(tempDev.As(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || + FAILED(tempCtx.As(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || + FAILED(m_3dCtx.m_ctx11.m_dev.As(&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 adapter; - device->GetParent(__uuidof(IDXGIAdapter), &adapter); - adapter->GetParent(__uuidof(IDXGIFactory2), &m_3dCtx.m_ctx11.m_dxFactory); + /* Obtain DXGI Factory */ + ComPtr 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)); + 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]); + /* 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; + 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_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; + 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]); + 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, "initialized D3D11 renderer"); - return; - } + Log.report(logvisor::Info, "initialized D3D11 renderer"); + return; + } #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(WCSTMBS(appName.data()).c_str(), 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, "unable to create DXGI factory"); + 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(WCSTMBS(appName.data()).c_str(), 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, "unable to create DXGI factory"); - Log.report(logvisor::Info, "initialized Vulkan renderer"); - return; - } - } - } - } + Log.report(logvisor::Info, "initialized Vulkan renderer"); + return; + } } + } } + } + } #endif - /* Finally try OpenGL */ - { - /* Obtain DXGI Factory */ - HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_ctxOgl.m_dxFactory); - if (FAILED(hr)) - Log.report(logvisor::Fatal, "unable to create DXGI factory"); + /* Finally try OpenGL */ + { + /* Obtain DXGI Factory */ + HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_ctxOgl.m_dxFactory); + if (FAILED(hr)) + Log.report(logvisor::Fatal, "unable to create DXGI factory"); - Log.report(logvisor::Info, "initialized OpenGL renderer"); - return; - } - - Log.report(logvisor::Fatal, "system doesn't support Vulkan, D3D11, or OpenGL"); + Log.report(logvisor::Info, "initialized OpenGL renderer"); + return; } - EPlatformType getPlatformType() const - { - return EPlatformType::Win32; + Log.report(logvisor::Fatal, "system doesn't support Vulkan, D3D11, or OpenGL"); + } + + EPlatformType getPlatformType() const { 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 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); } - 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 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); - } + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); } + } - template - static void DoSetFullscreen(W& win, bool fs) - { - std::lock_guard 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); + template + static void DoSetFullscreen(W& win, bool fs) { + std::lock_guard 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); - SetWindowLong(win.m_hwnd, GWL_STYLE, - win.m_fsStyle & ~(WS_CAPTION | WS_THICKFRAME)); - SetWindowLong(win.m_hwnd, GWL_EXSTYLE, - win.m_fsExStyle & ~(WS_EX_DLGMODALFRAME | - WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle & ~(WS_CAPTION | WS_THICKFRAME)); + SetWindowLong(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, NULL, 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); + MONITORINFO monitor_info; + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(MonitorFromWindow(win.m_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info); + SetWindowPos(win.m_hwnd, NULL, 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 - { - SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle); - SetWindowLong(win.m_hwnd, GWL_EXSTYLE, win.m_fsExStyle); + win.m_fs = true; + } else { + SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle); + SetWindowLong(win.m_hwnd, GWL_EXSTYLE, win.m_fsExStyle); - SetWindowPos(win.m_hwnd, NULL, 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); + SetWindowPos(win.m_hwnd, NULL, 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(); + win.m_fs = false; } + g_nwcv.notify_one(); + } - int run() - { - g_mainThreadId = GetCurrentThreadId(); + int run() { + g_mainThreadId = GetCurrentThreadId(); - /* Spawn client thread */ - int clientReturn = 0; - std::thread clientThread([&]() - { - std::string thrName = WCSTMBS(getFriendlyName().data()) + " 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); - }); + /* Spawn client thread */ + int clientReturn = 0; + std::thread clientThread([&]() { + std::string thrName = WCSTMBS(getFriendlyName().data()) + " 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 = {0}; - while (GetMessage(&msg, NULL, 0, 0)) - { - if (!msg.hwnd) - { - /* PostThreadMessage events */ - switch (msg.message) - { - case WM_USER: - { - /* New-window message (coalesced onto main thread) */ - std::lock_guard lk(g_nwmt); - SystemStringView* title = reinterpret_cast(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(msg.wParam), msg.lParam); - continue; + /* Pump messages */ + MSG msg = {0}; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!msg.hwnd) { + /* PostThreadMessage events */ + switch (msg.message) { + case WM_USER: { + /* New-window message (coalesced onto main thread) */ + std::lock_guard lk(g_nwmt); + SystemStringView* title = reinterpret_cast(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(msg.wParam), msg.lParam); + continue; #if BOO_HAS_VULKAN - case WM_USER+6: - /* SetFullscreen call for Vulkan window */ - DoSetFullscreen(*reinterpret_cast(msg.wParam), msg.lParam); - continue; + case WM_USER + 6: + /* SetFullscreen call for Vulkan window */ + DoSetFullscreen(*reinterpret_cast(msg.wParam), msg.lParam); + continue; #endif - default: break; - } - } - TranslateMessage(&msg); - DispatchMessage(&msg); + default: + break; } - - m_callback.appQuitting(this); - clientThread.join(); - return clientReturn; + } + TranslateMessage(&msg); + DispatchMessage(&msg); } - ~ApplicationWin32() - { - for (auto& p : m_allWindows) - if (auto w = p.second.lock()) - w->_cleanup(); + m_callback.appQuitting(this); + clientThread.join(); + return clientReturn; + } + + ~ApplicationWin32() { + for (auto& p : m_allWindows) + if (auto w = p.second.lock()) + w->_cleanup(); + } + + SystemStringView getUniqueName() const { return m_uniqueName; } + + SystemStringView getFriendlyName() const { return m_friendlyName; } + + SystemStringView getProcessName() const { return m_pname; } + + const std::vector& getArgs() const { return m_args; } + + std::shared_ptr m_mwret; + std::shared_ptr newWindow(SystemStringView title) { + if (GetCurrentThreadId() != g_mainThreadId) { + std::unique_lock lk(g_nwmt); + if (!PostThreadMessageW(g_mainThreadId, WM_USER, WPARAM(&title), 0)) + Log.report(logvisor::Fatal, "PostThreadMessage error"); + g_nwcv.wait(lk); + std::shared_ptr ret = std::move(m_mwret); + m_mwret.reset(); + return ret; } - SystemStringView getUniqueName() const - { - return m_uniqueName; - } - - SystemStringView getFriendlyName() const - { - return m_friendlyName; - } - - SystemStringView getProcessName() const - { - return m_pname; - } - - const std::vector& getArgs() const - { - return m_args; - } - - std::shared_ptr m_mwret; - std::shared_ptr newWindow(SystemStringView title) - { - if (GetCurrentThreadId() != g_mainThreadId) - { - std::unique_lock lk(g_nwmt); - if (!PostThreadMessageW(g_mainThreadId, WM_USER, WPARAM(&title), 0)) - Log.report(logvisor::Fatal, "PostThreadMessage error"); - g_nwcv.wait(lk); - std::shared_ptr ret = std::move(m_mwret); - m_mwret.reset(); - return ret; - } - - std::shared_ptr window = _WindowWin32New(title, m_3dCtx); - HWND hwnd = HWND(window->getPlatformHandle()); - m_allWindows[hwnd] = window; - return window; - } + std::shared_ptr window = _WindowWin32New(title, m_3dCtx); + HWND hwnd = HWND(window->getPlatformHandle()); + m_allWindows[hwnd] = window; + return window; + } }; IApplication* APP = NULL; -int ApplicationRun(IApplication::EPlatformType platform, - IApplicationCallback& cb, - SystemStringView uniqueName, - SystemStringView friendlyName, - SystemStringView pname, - const std::vector& args, - std::string_view gfxApi, - uint32_t samples, - uint32_t anisotropy, - bool deepColor, - bool singleInstance) -{ - std::string thrName = WCSTMBS(friendlyName.data()) + " Main Thread"; - logvisor::RegisterThreadName(thrName.c_str()); - if (APP) - return 1; - if (platform != IApplication::EPlatformType::Win32 && - platform != IApplication::EPlatformType::Auto) - return 1; +int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName, + SystemStringView friendlyName, SystemStringView pname, const std::vector& args, + std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor, + bool singleInstance) { + std::string thrName = WCSTMBS(friendlyName.data()) + " 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"); + /* 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_hResize = LoadCursor(nullptr, IDC_SIZEWE); - WIN32_CURSORS.m_vResize = 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_arrow = LoadCursor(nullptr, IDC_ARROW); + WIN32_CURSORS.m_hResize = LoadCursor(nullptr, IDC_SIZEWE); + WIN32_CURSORS.m_vResize = 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); - /* One class for *all* boo windows */ - WNDCLASS wndClass = - { - 0, - WindowProc, - 0, - 0, - GetModuleHandle(nullptr), - 0, - 0, - 0, - 0, - L"BooWindow" - }; - wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101)); - wndClass.hCursor = WIN32_CURSORS.m_arrow; - RegisterClassW(&wndClass); + /* One class for *all* boo windows */ + WNDCLASS wndClass = {0, WindowProc, 0, 0, GetModuleHandle(nullptr), 0, 0, 0, 0, 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; + 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 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::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam); +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::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam); } - diff --git a/lib/win/UWPCommon.hpp b/lib/win/UWPCommon.hpp index 7f33784..399fe0c 100644 --- a/lib/win/UWPCommon.hpp +++ b/lib/win/UWPCommon.hpp @@ -2,84 +2,73 @@ #include "WinCommon.hpp" -struct Boo3DAppContextUWP : Boo3DAppContext -{ - bool isFullscreen(const boo::IWindow* window) - { +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; + 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) - { + 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 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 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 (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 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 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; + } }; - diff --git a/lib/win/Win32Common.hpp b/lib/win/Win32Common.hpp index 371e860..60edb55 100644 --- a/lib/win/Win32Common.hpp +++ b/lib/win/Win32Common.hpp @@ -20,150 +20,133 @@ extern std::condition_variable g_nwcv; #if _WIN32_WINNT_WINBLUE && !WINDOWS_STORE #include -typedef HRESULT (WINAPI* PFN_GetScaleFactorForMonitor)( _In_ HMONITOR, _Out_ DEVICE_SCALE_FACTOR *); +typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(_In_ HMONITOR, _Out_ DEVICE_SCALE_FACTOR*); extern PFN_GetScaleFactorForMonitor MyGetScaleFactorForMonitor; #endif -struct OGLContext -{ - ComPtr m_dxFactory; - HGLRC m_lastContext = 0; - struct Window - { - HWND m_hwnd; - HDC m_deviceContext; - HGLRC m_mainContext; - HGLRC m_renderContext; - bool m_needsResize = false; - size_t width, height; +struct OGLContext { + ComPtr m_dxFactory; + HGLRC m_lastContext = 0; + 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 m_fsStyle; - LONG m_fsExStyle; - RECT m_fsRect; - int m_fsCountDown = 0; - }; - std::unordered_map m_windows; + bool m_fs = false; + LONG m_fsStyle; + LONG m_fsExStyle; + RECT m_fsRect; + int m_fsCountDown = 0; + }; + std::unordered_map m_windows; - boo::GLContext m_glCtx; + boo::GLContext m_glCtx; }; #if !WINDOWS_STORE -static inline void SetFullscreen(OGLContext::Window& win, bool fs) -{ - std::unique_lock lk(g_nwmt); - PostThreadMessageW(g_mainThreadId, WM_USER+5, WPARAM(&win), LPARAM(fs)); - g_nwcv.wait(lk); +static inline void SetFullscreen(OGLContext::Window& win, bool fs) { + std::unique_lock 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 lk(g_nwmt); - PostThreadMessageW(g_mainThreadId, WM_USER+6, WPARAM(&win), LPARAM(fs)); - g_nwcv.wait(lk); +static inline void SetFullscreen(boo::VulkanContext::Window& win, bool fs) { + std::unique_lock 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 m_vulkanDxFactory; +struct Boo3DAppContextWin32 : Boo3DAppContext { + OGLContext m_ctxOgl; + ComPtr m_vulkanDxFactory; - bool isFullscreen(const boo::IWindow* window) - { + 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; + if (m_vulkanDxFactory) { + boo::VulkanContext::Window& win = *boo::g_VulkanContext.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 (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; + } - if (fs) - { - ComPtr out; - win.m_swapChain->GetContainingOutput(&out); - DXGI_OUTPUT_DESC outDesc; - out->GetDesc(&outDesc); + 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 - 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 (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 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); + 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; - } + return true; + } }; -struct HWNDEvent -{ - UINT uMsg; - WPARAM wParam; - LPARAM lParam; - HWNDEvent(UINT m, WPARAM w, LPARAM l) - : uMsg(m), wParam(w), lParam(l) {} +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_hResize; - HCURSOR m_vResize; - HCURSOR m_ibeam; - HCURSOR m_crosshairs; - HCURSOR m_wait; +struct Win32Cursors { + HCURSOR m_arrow; + HCURSOR m_hResize; + HCURSOR m_vResize; + HCURSOR m_ibeam; + HCURSOR m_crosshairs; + HCURSOR m_wait; }; -namespace boo -{ +namespace boo { extern Win32Cursors WIN32_CURSORS; } - diff --git a/lib/win/WinCommon.hpp b/lib/win/WinCommon.hpp index cd96b3d..7b85a38 100644 --- a/lib/win/WinCommon.hpp +++ b/lib/win/WinCommon.hpp @@ -3,7 +3,9 @@ #include #include "boo/IWindow.hpp" -namespace boo {class IWindow;} +namespace boo { +class IWindow; +} #if _WIN32_WINNT_WIN10 #include @@ -12,7 +14,6 @@ namespace boo {class IWindow;} #include #include - #elif _WIN32_WINNT_WIN7 #include #include @@ -22,113 +23,100 @@ namespace boo {class IWindow;} #error Unsupported Windows target #endif -struct D3D12Context -{ - ComPtr m_dxFactory; - ComPtr m_dev; - ComPtr m_qalloc[2]; - ComPtr m_q; - ComPtr m_loadqalloc; - ComPtr m_loadq; - ComPtr m_loadfence; - UINT64 m_loadfenceval = 0; - HANDLE m_loadfencehandle; - ComPtr m_loadlist; - ComPtr m_rs; - struct Window - { - ComPtr m_swapChain; - std::unordered_map> m_rtvHeaps; - UINT m_backBuf = 0; - bool m_needsResize = false; - size_t width, height; - }; - std::unordered_map m_windows; +struct D3D12Context { + ComPtr m_dxFactory; + ComPtr m_dev; + ComPtr m_qalloc[2]; + ComPtr m_q; + ComPtr m_loadqalloc; + ComPtr m_loadq; + ComPtr m_loadfence; + UINT64 m_loadfenceval = 0; + HANDLE m_loadfencehandle; + ComPtr m_loadlist; + ComPtr m_rs; + struct Window { + ComPtr m_swapChain; + std::unordered_map> m_rtvHeaps; + UINT m_backBuf = 0; + bool m_needsResize = false; + size_t width, height; + }; + std::unordered_map m_windows; - uint32_t m_sampleCount = 1; - uint32_t m_anisotropy = 1; + 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 m_dxFactory; - ComPtr m_dev; - ComPtr m_devCtx; - ComPtr m_ss[5]; - struct Window - { - ComPtr m_swapChain; - ComPtr m_swapChainTex; - ComPtr 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& 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 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; + 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; }; -static inline std::string WCSTMBS(const wchar_t* wstr) -{ - int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr) - 1; - std::string strTo(sizeNeeded, 0); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &strTo[0], sizeNeeded, nullptr, nullptr); - return strTo; +struct D3D11Context { + ComPtr m_dxFactory; + ComPtr m_dev; + ComPtr m_devCtx; + ComPtr m_ss[5]; + struct Window { + ComPtr m_swapChain; + ComPtr m_swapChainTex; + ComPtr 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& 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 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; + } +}; + +static inline std::string WCSTMBS(const wchar_t* wstr) { + int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr) - 1; + std::string strTo(sizeNeeded, 0); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &strTo[0], sizeNeeded, nullptr, nullptr); + return strTo; } -static inline std::wstring MBSTWCS(const char* str) -{ - int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0) - 1; - std::wstring strTo(sizeNeeded, 0); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &strTo[0], sizeNeeded); - return strTo; +static inline std::wstring MBSTWCS(const char* str) { + int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0) - 1; + std::wstring strTo(sizeNeeded, 0); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &strTo[0], sizeNeeded); + return strTo; } - diff --git a/lib/win/WindowUWP.cpp b/lib/win/WindowUWP.cpp index b250932..13a8fc7 100644 --- a/lib/win/WindowUWP.cpp +++ b/lib/win/WindowUWP.cpp @@ -17,621 +17,473 @@ using namespace Platform; #include -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::WindowWin32"); #if _WIN32_WINNT_WIN10 -IGraphicsCommandQueue* _NewD3D12CommandQueue(D3D12Context* ctx, D3D12Context::Window* windowCtx, IGraphicsContext* parent, - ID3D12CommandQueue** cmdQueueOut); +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); +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 m_output; - GraphicsContextUWP(EGraphicsAPI api, IWindow* parentWindow, Boo3DAppContextUWP& b3dCtx) - : m_api(api), - m_pf(EPixelFormat::RGBA8), - m_parentWindow(parentWindow), - m_3dCtx(b3dCtx) {} +struct GraphicsContextUWP : IGraphicsContext { + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + Boo3DAppContextUWP& m_3dCtx; + ComPtr 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]); - } + virtual void resized(const SWindowRect& rect) { m_3dCtx.resize(m_parentWindow, rect.size[0], rect.size[1]); } }; -struct GraphicsContextUWPD3D : GraphicsContextUWP -{ - ComPtr m_swapChain; +struct GraphicsContextUWPD3D : GraphicsContextUWP { + ComPtr m_swapChain; - IGraphicsCommandQueue* m_commandQueue = nullptr; - IGraphicsDataFactory* m_dataFactory = nullptr; + IGraphicsCommandQueue* m_commandQueue = nullptr; + IGraphicsDataFactory* m_dataFactory = nullptr; public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextUWPD3D(EGraphicsAPI api, IWindow* parentWindow, Agile& 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; + GraphicsContextUWPD3D(EGraphicsAPI api, IWindow* parentWindow, Agile& 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; + scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; #else - scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; #endif - scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - IUnknown* cw = reinterpret_cast(coreWindow.Get()); + IUnknown* cw = reinterpret_cast(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; + 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); + 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, "unable to create swap chain"); + 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, "unable to create swap chain"); - m_swapChain.As(&w.m_swapChain); - ComPtr 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; + m_swapChain.As(&w.m_swapChain); + ComPtr 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, "unable to get DXGI output"); - } - else + if (FAILED(m_swapChain->GetContainingOutput(&m_output))) + Log.report(logvisor::Fatal, "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, "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(&w.m_swapChain); - ComPtr 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, "unable to get DXGI output"); - } - } - - ~GraphicsContextUWPD3D() { + if (FAILED(b3dCtx.m_ctx11.m_dxFactory->CreateSwapChainForCoreWindow(b3dCtx.m_ctx11.m_dev.Get(), cw, &scDesc, + nullptr, &m_swapChain))) + Log.report(logvisor::Fatal, "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(&w.m_swapChain); + ComPtr 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, "unable to get DXGI output"); + } + } + + ~GraphicsContextUWPD3D() { #if _WIN32_WINNT_WIN10 - if (m_3dCtx.m_ctx12.m_dev) - m_3dCtx.m_ctx12.m_windows.erase(m_parentWindow); - else + 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); - } + m_3dCtx.m_ctx11.m_windows.erase(m_parentWindow); + } - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } + void _setCallback(IWindowCallback* cb) { m_callback = cb; } - EGraphicsAPI getAPI() const - { - return m_api; - } + EGraphicsAPI getAPI() const { return m_api; } - EPixelFormat getPixelFormat() const - { - return m_pf; - } + EPixelFormat getPixelFormat() const { return m_pf; } - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } - bool initializeContext(void*) {return true;} + bool initializeContext(void*) { return true; } - void makeCurrent() {} + void makeCurrent() {} - void postInit() {} + void postInit() {} - void present() {} + void present() {} - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue; - } + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue; } - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory; - } + IGraphicsDataFactory* getDataFactory() { return m_dataFactory; } - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_dataFactory; - } + IGraphicsDataFactory* getMainContextDataFactory() { return m_dataFactory; } - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_dataFactory; - } + IGraphicsDataFactory* getLoadContextDataFactory() { 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::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 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::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; +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 m_coreWindow; - Rect m_bounds; - float m_dispInfoDpiFactor = 1.f; - std::unique_ptr m_gfxCtx; - IWindowCallback* m_callback = nullptr; +class WindowUWP : public IWindow { + friend struct GraphicsContextUWP; + ApplicationView ^ m_appView = ApplicationView::GetForCurrentView(); + Platform::Agile m_coreWindow; + Rect m_bounds; + float m_dispInfoDpiFactor = 1.f; + std::unique_ptr m_gfxCtx; + IWindowCallback* m_callback = nullptr; public: + ref struct EventReceiver sealed { + void OnKeyDown(CoreWindow ^ window, KeyEventArgs ^ keyEventArgs) { w.OnKeyDown(window, keyEventArgs); } - 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 OnKeyUp(CoreWindow^ window, KeyEventArgs^ keyEventArgs) - { - w.OnKeyUp(window, keyEventArgs); - } + void OnPointerEntered(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerEntered(window, args); } - void OnPointerEntered(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerEntered(window, args); - } + void OnPointerExited(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerExited(window, args); } - void OnPointerExited(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerExited(window, args); - } + void OnPointerMoved(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerMoved(window, args); } - void OnPointerMoved(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerMoved(window, args); - } + void OnPointerPressed(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerPressed(window, args); } - void OnPointerPressed(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerPressed(window, args); - } + void OnPointerReleased(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerReleased(window, args); } - void OnPointerReleased(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerReleased(window, args); - } + void OnPointerWheelChanged(CoreWindow ^ window, PointerEventArgs ^ args) { w.OnPointerWheelChanged(window, args); } - void OnPointerWheelChanged(CoreWindow^ window, PointerEventArgs^ args) - { - w.OnPointerWheelChanged(window, args); - } + void OnClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ args) { w.OnClosed(sender, args); } - void OnClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) - { - w.OnClosed(sender, args); - } + void SizeChanged(CoreWindow ^ window, WindowSizeChangedEventArgs ^) { + w.m_bounds = window->Bounds; + w._resized(); + } - 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(); + } - 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(this, &EventReceiver::OnKeyDown); + w.m_coreWindow->KeyUp += ref new TypedEventHandler(this, &EventReceiver::OnKeyUp); + w.m_coreWindow->PointerEntered += + ref new TypedEventHandler(this, &EventReceiver::OnPointerEntered); + w.m_coreWindow->PointerExited += + ref new TypedEventHandler(this, &EventReceiver::OnPointerExited); + w.m_coreWindow->PointerMoved += + ref new TypedEventHandler(this, &EventReceiver::OnPointerMoved); + w.m_coreWindow->PointerPressed += + ref new TypedEventHandler(this, &EventReceiver::OnPointerPressed); + w.m_coreWindow->PointerReleased += + ref new TypedEventHandler(this, &EventReceiver::OnPointerReleased); + w.m_coreWindow->PointerWheelChanged += + ref new TypedEventHandler(this, &EventReceiver::OnPointerWheelChanged); + w.m_coreWindow->Closed += + ref new TypedEventHandler(this, &EventReceiver::OnClosed); + w.m_coreWindow->SizeChanged += + ref new TypedEventHandler(this, &EventReceiver::SizeChanged); + DisplayInformation::GetForCurrentView()->DpiChanged += + ref new TypedEventHandler(this, &EventReceiver::DisplayInfoChanged); + } + }; + EventReceiver ^ m_eventReceiver; - internal: - WindowUWP& w; - EventReceiver(WindowUWP& w) : w(w) - { - w.m_coreWindow->KeyDown += ref new TypedEventHandler(this, &EventReceiver::OnKeyDown); - w.m_coreWindow->KeyUp += ref new TypedEventHandler(this, &EventReceiver::OnKeyUp); - w.m_coreWindow->PointerEntered += ref new TypedEventHandler(this, &EventReceiver::OnPointerEntered); - w.m_coreWindow->PointerExited += ref new TypedEventHandler(this, &EventReceiver::OnPointerExited); - w.m_coreWindow->PointerMoved += ref new TypedEventHandler(this, &EventReceiver::OnPointerMoved); - w.m_coreWindow->PointerPressed += ref new TypedEventHandler(this, &EventReceiver::OnPointerPressed); - w.m_coreWindow->PointerReleased += ref new TypedEventHandler(this, &EventReceiver::OnPointerReleased); - w.m_coreWindow->PointerWheelChanged += ref new TypedEventHandler(this, &EventReceiver::OnPointerWheelChanged); - w.m_coreWindow->Closed += ref new TypedEventHandler(this, &EventReceiver::OnClosed); - w.m_coreWindow->SizeChanged += ref new TypedEventHandler(this, &EventReceiver::SizeChanged); - DisplayInformation::GetForCurrentView()->DpiChanged += - ref new TypedEventHandler(this, &EventReceiver::DisplayInfoChanged); - } - }; - EventReceiver^ m_eventReceiver; - - WindowUWP(SystemStringView title, Boo3DAppContextUWP& b3dCtx) - : m_coreWindow(CoreWindow::GetForCurrentThread()), - m_eventReceiver(ref new EventReceiver(*this)) - { - IGraphicsContext::EGraphicsAPI api = IGraphicsContext::EGraphicsAPI::D3D11; + WindowUWP(SystemStringView 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; + if (b3dCtx.m_ctx12.m_dev) + api = IGraphicsContext::EGraphicsAPI::D3D12; #endif - m_gfxCtx.reset(new GraphicsContextUWPD3D(api, this, m_coreWindow, b3dCtx)); + 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 }; + 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->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; - } + titleBar->ButtonInactiveBackgroundColor = grey; + titleBar->ButtonInactiveForegroundColor = transWhite; + titleBar->InactiveBackgroundColor = grey; + titleBar->InactiveForegroundColor = transWhite; } + } - ~WindowUWP() - { + ~WindowUWP() {} - } + void setCallback(IWindowCallback* cb) { m_callback = cb; } - void setCallback(IWindowCallback* cb) - { - m_callback = cb; - } + void closeWindow() { m_coreWindow->Close(); } - void closeWindow() - { - m_coreWindow->Close(); - } + void showWindow() {} - void showWindow() - { - } + void hideWindow() {} - void hideWindow() - { - } + SystemString getTitle() { return SystemString(m_appView->Title->Data()); } - SystemString getTitle() - { - return SystemString(m_appView->Title->Data()); - } + void setTitle(SystemStringView title) { m_appView->Title = ref new Platform::String(title.data()); } - void setTitle(SystemStringView title) - { - m_appView->Title = ref new Platform::String(title.data()); - } + void setCursor(EMouseCursor cursor) {} - void setCursor(EMouseCursor cursor) - { - } + void setWaitCursor(bool wait) {} - void setWaitCursor(bool wait) - { - } + void setWindowFrameDefault() {} - void setWindowFrameDefault() - { - } + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const { + 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(float& xOut, float& yOut, float& wOut, float& hOut) const - { - 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 { + 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 - { - 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) {} - void setWindowFrame(float x, float y, float w, float h) - { - } + void setWindowFrame(int x, int y, int w, int h) {} - void setWindowFrame(int x, int y, int w, int h) - { - } + float getVirtualPixelFactor() const { return m_dispInfoDpiFactor; } - float getVirtualPixelFactor() const - { - return m_dispInfoDpiFactor; - } + bool isFullscreen() const { return ApplicationView::GetForCurrentView()->IsFullScreenMode; } - bool isFullscreen() const - { - return ApplicationView::GetForCurrentView()->IsFullScreenMode; - } + void setFullscreen(bool fs) { + if (fs) + ApplicationView::GetForCurrentView()->TryEnterFullScreenMode(); + else + ApplicationView::GetForCurrentView()->ExitFullScreenMode(); + } - void setFullscreen(bool fs) - { - if (fs) - ApplicationView::GetForCurrentView()->TryEnterFullScreenMode(); - else - ApplicationView::GetForCurrentView()->ExitFullScreenMode(); - } + void claimKeyboardFocus(const int coord[2]) {} - void claimKeyboardFocus(const int coord[2]) - { - } + bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { return false; } - bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) - { - return false; - } + std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { return std::unique_ptr(); } - std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) - { - return std::unique_ptr(); - } + void waitForRetrace(IAudioVoiceEngine* engine) { + if (engine) + engine->pumpAndMixVoices(); + m_gfxCtx->m_output->WaitForVBlank(); + } - void waitForRetrace(IAudioVoiceEngine* engine) - { - if (engine) - engine->pumpAndMixVoices(); - m_gfxCtx->m_output->WaitForVBlank(); - } + uintptr_t getPlatformHandle() const { return 0; } - uintptr_t getPlatformHandle() const - { - return 0; - } + bool _incomingEvent(void* ev) { return false; } - bool _incomingEvent(void* ev) - { - 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 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); + } - 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; + } - 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 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 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)); + } - 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; + } - 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 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 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 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); + } - 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 { return ETouchType::None; } - ETouchType getTouchType() const - { - return ETouchType::None; - } + void setStyle(EWindowStyle style) {} - void setStyle(EWindowStyle style) - { - } + EWindowStyle getStyle() const { + EWindowStyle retval = EWindowStyle::None; + return retval; + } - EWindowStyle getStyle() const - { - EWindowStyle retval = EWindowStyle::None; - return retval; - } + IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx->getCommandQueue(); } + IGraphicsDataFactory* getDataFactory() { return m_gfxCtx->getDataFactory(); } - IGraphicsCommandQueue* getCommandQueue() - { - return m_gfxCtx->getCommandQueue(); - } - IGraphicsDataFactory* getDataFactory() - { - return m_gfxCtx->getDataFactory(); - } - - /* Creates a new context on current thread!! Call from main client thread */ - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_gfxCtx->getMainContextDataFactory(); - } - - /* Creates a new context on current thread!! Call from client loading thread */ - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_gfxCtx->getLoadContextDataFactory(); - } + /* Creates a new context on current thread!! Call from main client thread */ + IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx->getMainContextDataFactory(); } + /* Creates a new context on current thread!! Call from client loading thread */ + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } }; -std::shared_ptr _WindowUWPNew(SystemStringView title, Boo3DAppContextUWP& d3dCtx) -{ - return std::make_shared(title, d3dCtx); +std::shared_ptr _WindowUWPNew(SystemStringView title, Boo3DAppContextUWP& d3dCtx) { + return std::make_shared(title, d3dCtx); } -} +} // namespace boo diff --git a/lib/win/WindowWin32.cpp b/lib/win/WindowWin32.cpp index 12a3d4c..8268137 100644 --- a/lib/win/WindowWin32.cpp +++ b/lib/win/WindowWin32.cpp @@ -19,767 +19,638 @@ #include #endif -static const int ContextAttribs[] = -{ - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - //WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, - //WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - 0, 0 -}; +static const int ContextAttribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 3, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + // WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, + // WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + 0, 0}; -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::WindowWin32"); -std::unique_ptr -_NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, IGraphicsContext* parent); -std::unique_ptr -_NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent); -std::unique_ptr -_NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx); -std::unique_ptr -_NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx); +std::unique_ptr _NewD3D11CommandQueue(D3D11Context* ctx, D3D11Context::Window* windowCtx, + IGraphicsContext* parent); +std::unique_ptr _NewD3D11DataFactory(D3D11Context* ctx, IGraphicsContext* parent); +std::unique_ptr _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx); +std::unique_ptr _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx); #if BOO_HAS_VULKAN -std::unique_ptr -_NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent); -std::unique_ptr -_NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx); +std::unique_ptr _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, + IGraphicsContext* parent); +std::unique_ptr _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx); #endif -struct GraphicsContextWin32 : IGraphicsContext -{ - EGraphicsAPI m_api; - EPixelFormat m_pf; - IWindow* m_parentWindow; - Boo3DAppContextWin32& m_3dCtx; - ComPtr m_output; - GraphicsContextWin32(EGraphicsAPI api, IWindow* parentWindow, Boo3DAppContextWin32& b3dCtx) - : m_api(api), - m_pf(EPixelFormat::RGBA8), - m_parentWindow(parentWindow), - m_3dCtx(b3dCtx) {} +struct GraphicsContextWin32 : IGraphicsContext { + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + Boo3DAppContextWin32& m_3dCtx; + ComPtr m_output; + GraphicsContextWin32(EGraphicsAPI api, IWindow* parentWindow, Boo3DAppContextWin32& 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]); - } + virtual void resized(const SWindowRect& rect) { m_3dCtx.resize(m_parentWindow, rect.size[0], rect.size[1]); } }; -struct GraphicsContextWin32D3D : GraphicsContextWin32 -{ - ComPtr m_swapChain; +struct GraphicsContextWin32D3D : GraphicsContextWin32 { + ComPtr m_swapChain; - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextWin32D3D(EGraphicsAPI api, IWindow* parentWindow, HWND hwnd, - Boo3DAppContextWin32& b3dCtx) - : GraphicsContextWin32(api, parentWindow, b3dCtx) - { - /* Create Swap Chain */ - DXGI_SWAP_CHAIN_DESC1 scDesc = {}; - scDesc.SampleDesc.Count = 1; - scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - scDesc.BufferCount = 2; - scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + GraphicsContextWin32D3D(EGraphicsAPI api, IWindow* parentWindow, HWND hwnd, Boo3DAppContextWin32& b3dCtx) + : GraphicsContextWin32(api, parentWindow, b3dCtx) { + /* Create Swap Chain */ + DXGI_SWAP_CHAIN_DESC1 scDesc = {}; + scDesc.SampleDesc.Count = 1; + scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scDesc.BufferCount = 2; + scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - scDesc.Format = b3dCtx.m_ctx11.m_fbFormat; - if (FAILED(b3dCtx.m_ctx11.m_dxFactory->CreateSwapChainForHwnd(b3dCtx.m_ctx11.m_dev.Get(), - hwnd, &scDesc, nullptr, nullptr, &m_swapChain))) - Log.report(logvisor::Fatal, "unable to create swap chain"); - b3dCtx.m_ctx11.m_dxFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); + scDesc.Format = b3dCtx.m_ctx11.m_fbFormat; + if (FAILED(b3dCtx.m_ctx11.m_dxFactory->CreateSwapChainForHwnd(b3dCtx.m_ctx11.m_dev.Get(), hwnd, &scDesc, nullptr, + nullptr, &m_swapChain))) + Log.report(logvisor::Fatal, "unable to create swap chain"); + b3dCtx.m_ctx11.m_dxFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); - auto insIt = b3dCtx.m_ctx11.m_windows.emplace(std::make_pair(parentWindow, D3D11Context::Window())); - D3D11Context::Window& w = insIt.first->second; - w.setupRTV(m_swapChain, b3dCtx.m_ctx11.m_dev.Get()); + auto insIt = b3dCtx.m_ctx11.m_windows.emplace(std::make_pair(parentWindow, D3D11Context::Window())); + D3D11Context::Window& w = insIt.first->second; + w.setupRTV(m_swapChain, b3dCtx.m_ctx11.m_dev.Get()); - m_dataFactory = _NewD3D11DataFactory(&b3dCtx.m_ctx11, this); - m_commandQueue = _NewD3D11CommandQueue(&b3dCtx.m_ctx11, &insIt.first->second, this); - m_commandQueue->startRenderer(); + m_dataFactory = _NewD3D11DataFactory(&b3dCtx.m_ctx11, this); + m_commandQueue = _NewD3D11CommandQueue(&b3dCtx.m_ctx11, &insIt.first->second, this); + m_commandQueue->startRenderer(); - if (FAILED(m_swapChain->GetContainingOutput(&m_output))) - Log.report(logvisor::Fatal, "unable to get DXGI output"); - } + if (FAILED(m_swapChain->GetContainingOutput(&m_output))) + Log.report(logvisor::Fatal, "unable to get DXGI output"); + } - ~GraphicsContextWin32D3D() - { - m_3dCtx.m_ctx11.m_windows.erase(m_parentWindow); - } + ~GraphicsContextWin32D3D() { m_3dCtx.m_ctx11.m_windows.erase(m_parentWindow); } - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } + void _setCallback(IWindowCallback* cb) { m_callback = cb; } - EGraphicsAPI getAPI() const - { - return m_api; - } + EGraphicsAPI getAPI() const { return m_api; } - EPixelFormat getPixelFormat() const - { - return m_pf; - } + EPixelFormat getPixelFormat() const { return m_pf; } - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } - bool initializeContext(void*) {return true;} + bool initializeContext(void*) { return true; } - void makeCurrent() {} + void makeCurrent() {} - void postInit() {} + void postInit() {} - void present() {} + void present() {} - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue.get(); - } + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory.get(); - } + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_dataFactory.get(); - } + IGraphicsDataFactory* getMainContextDataFactory() { return m_dataFactory.get(); } - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_dataFactory.get(); - } + IGraphicsDataFactory* getLoadContextDataFactory() { return m_dataFactory.get(); } }; -struct GraphicsContextWin32GL : GraphicsContextWin32 -{ - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; +struct GraphicsContextWin32GL : GraphicsContextWin32 { + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextWin32GL(EGraphicsAPI api, IWindow* parentWindow, HWND hwnd, - Boo3DAppContextWin32& b3dCtx) - : GraphicsContextWin32(api, parentWindow, b3dCtx) - { + GraphicsContextWin32GL(EGraphicsAPI api, IWindow* parentWindow, HWND hwnd, Boo3DAppContextWin32& b3dCtx) + : GraphicsContextWin32(api, parentWindow, b3dCtx) { - HMONITOR testMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - ComPtr adapter; - ComPtr foundOut; - int i=0; - while (b3dCtx.m_ctxOgl.m_dxFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND) - { - int j=0; - ComPtr out; - while (adapter->EnumOutputs(j, &out) != DXGI_ERROR_NOT_FOUND) - { - DXGI_OUTPUT_DESC desc; - out->GetDesc(&desc); - if (desc.Monitor == testMon) - { - out.As(&m_output); - break; - } - ++j; - } - if (m_output) - break; - ++i; + HMONITOR testMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + ComPtr adapter; + ComPtr foundOut; + int i = 0; + while (b3dCtx.m_ctxOgl.m_dxFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND) { + int j = 0; + ComPtr out; + while (adapter->EnumOutputs(j, &out) != DXGI_ERROR_NOT_FOUND) { + DXGI_OUTPUT_DESC desc; + out->GetDesc(&desc); + if (desc.Monitor == testMon) { + out.As(&m_output); + break; } + ++j; + } + if (m_output) + break; + ++i; + } - if (!m_output) - Log.report(logvisor::Fatal, "unable to find window's IDXGIOutput"); + if (!m_output) + Log.report(logvisor::Fatal, "unable to find window's IDXGIOutput"); - auto insIt = b3dCtx.m_ctxOgl.m_windows.emplace(std::make_pair(parentWindow, OGLContext::Window())); - OGLContext::Window& w = insIt.first->second; - w.m_hwnd = hwnd; - w.m_deviceContext = GetDC(hwnd); - if (!w.m_deviceContext) - Log.report(logvisor::Fatal, "unable to create window's device context"); + auto insIt = b3dCtx.m_ctxOgl.m_windows.emplace(std::make_pair(parentWindow, OGLContext::Window())); + OGLContext::Window& w = insIt.first->second; + w.m_hwnd = hwnd; + w.m_deviceContext = GetDC(hwnd); + if (!w.m_deviceContext) + Log.report(logvisor::Fatal, "unable to create window's device context"); - if (!m_3dCtx.m_ctxOgl.m_lastContext) - { - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags - PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette. - 32, //Colordepth of the framebuffer. - 0, 0, 0, 0, 0, 0, 0, 0, - 0, - 0, 0, 0, 0, - 24, //Number of bits for the depthbuffer - 8, //Number of bits for the stencilbuffer - 0, //Number of Aux buffers in the framebuffer. - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; + if (!m_3dCtx.m_ctxOgl.m_lastContext) { + PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags + PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. + 32, // Colordepth of the framebuffer. + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 24, // Number of bits for the depthbuffer + 8, // Number of bits for the stencilbuffer + 0, // Number of Aux buffers in the framebuffer. + PFD_MAIN_PLANE, + 0, + 0, + 0, + 0}; - int pf = ChoosePixelFormat(w.m_deviceContext, &pfd); - SetPixelFormat(w.m_deviceContext, pf, &pfd); + int pf = ChoosePixelFormat(w.m_deviceContext, &pfd); + SetPixelFormat(w.m_deviceContext, pf, &pfd); #if 1 - HGLRC tmpCtx = wglCreateContext(w.m_deviceContext); - wglMakeCurrent(w.m_deviceContext, tmpCtx); - if (glewInit() != GLEW_OK) - Log.report(logvisor::Fatal, "glewInit failed"); - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) - wglGetProcAddress("wglCreateContextAttribsARB"); - wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) - wglGetProcAddress("wglChoosePixelFormatARB"); - wglMakeCurrent(w.m_deviceContext, 0); - wglDeleteContext(tmpCtx); + HGLRC tmpCtx = wglCreateContext(w.m_deviceContext); + wglMakeCurrent(w.m_deviceContext, tmpCtx); + if (glewInit() != GLEW_OK) + Log.report(logvisor::Fatal, "glewInit failed"); + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + wglMakeCurrent(w.m_deviceContext, 0); + wglDeleteContext(tmpCtx); - if (b3dCtx.m_ctxOgl.m_glCtx.m_deepColor) - { - const int attribs1[] = - { - WGL_SUPPORT_OPENGL_ARB, TRUE, - WGL_DRAW_TO_WINDOW_ARB, TRUE, - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, - WGL_RED_BITS_ARB, 10, - WGL_GREEN_BITS_ARB, 10, - WGL_BLUE_BITS_ARB, 10, - WGL_ALPHA_BITS_ARB, 2, - WGL_DOUBLE_BUFFER_ARB, TRUE, - 0, // zero terminates the list - }; - float fattribs[] = { - 0.0f, // zero terminates the list - }; + if (b3dCtx.m_ctxOgl.m_glCtx.m_deepColor) { + const int attribs1[] = { + WGL_SUPPORT_OPENGL_ARB, + TRUE, + WGL_DRAW_TO_WINDOW_ARB, + TRUE, + WGL_PIXEL_TYPE_ARB, + WGL_TYPE_RGBA_ARB, + WGL_RED_BITS_ARB, + 10, + WGL_GREEN_BITS_ARB, + 10, + WGL_BLUE_BITS_ARB, + 10, + WGL_ALPHA_BITS_ARB, + 2, + WGL_DOUBLE_BUFFER_ARB, + TRUE, + 0, // zero terminates the list + }; + float fattribs[] = { + 0.0f, // zero terminates the list + }; - int pixelFormat; - UINT numFormats; + int pixelFormat; + UINT numFormats; - wglChoosePixelFormatARB(w.m_deviceContext, attribs1, fattribs, 1, &pixelFormat, &numFormats); - if (numFormats) - SetPixelFormat(w.m_deviceContext, pixelFormat, nullptr); - } + wglChoosePixelFormatARB(w.m_deviceContext, attribs1, fattribs, 1, &pixelFormat, &numFormats); + if (numFormats) + SetPixelFormat(w.m_deviceContext, pixelFormat, nullptr); + } #endif - } - - //w.m_mainContext = wglCreateContext(w.m_deviceContext); - w.m_mainContext = wglCreateContextAttribsARB(w.m_deviceContext, 0, ContextAttribs); - if (!w.m_mainContext) - Log.report(logvisor::Fatal, "unable to create window's main context"); - if (m_3dCtx.m_ctxOgl.m_lastContext) - if (!wglShareLists(w.m_mainContext, m_3dCtx.m_ctxOgl.m_lastContext)) - Log.report(logvisor::Fatal, "unable to share contexts"); - m_3dCtx.m_ctxOgl.m_lastContext = w.m_mainContext; - - m_dataFactory = _NewGLDataFactory(this, &b3dCtx.m_ctxOgl.m_glCtx); - m_commandQueue = _NewGLCommandQueue(this, &b3dCtx.m_ctxOgl.m_glCtx); - m_commandQueue->startRenderer(); } - ~GraphicsContextWin32GL() - { - m_3dCtx.m_ctxOgl.m_windows.erase(m_parentWindow); + // w.m_mainContext = wglCreateContext(w.m_deviceContext); + w.m_mainContext = wglCreateContextAttribsARB(w.m_deviceContext, 0, ContextAttribs); + if (!w.m_mainContext) + Log.report(logvisor::Fatal, "unable to create window's main context"); + if (m_3dCtx.m_ctxOgl.m_lastContext) + if (!wglShareLists(w.m_mainContext, m_3dCtx.m_ctxOgl.m_lastContext)) + Log.report(logvisor::Fatal, "unable to share contexts"); + m_3dCtx.m_ctxOgl.m_lastContext = w.m_mainContext; + + m_dataFactory = _NewGLDataFactory(this, &b3dCtx.m_ctxOgl.m_glCtx); + m_commandQueue = _NewGLCommandQueue(this, &b3dCtx.m_ctxOgl.m_glCtx); + m_commandQueue->startRenderer(); + } + + ~GraphicsContextWin32GL() { m_3dCtx.m_ctxOgl.m_windows.erase(m_parentWindow); } + + void _setCallback(IWindowCallback* cb) { m_callback = cb; } + + EGraphicsAPI getAPI() const { return m_api; } + + EPixelFormat getPixelFormat() const { return m_pf; } + + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } + + bool initializeContext(void*) { return true; } + + void makeCurrent() { + OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; + // if (!wglMakeCurrent(w.m_deviceContext, w.m_mainContext)) + // Log.report(logvisor::Fatal, "unable to make WGL context current"); + + w.m_renderContext = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); + if (!w.m_renderContext) + Log.report(logvisor::Fatal, "unable to make new WGL context"); + if (!wglMakeCurrent(w.m_deviceContext, w.m_renderContext)) + Log.report(logvisor::Fatal, "unable to make WGL context current"); + } + + void postInit() { + // OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; + + // wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + // wglGetProcAddress("wglCreateContextAttribsARB"); + // w.m_renderContext = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); + // if (!w.m_renderContext) + // Log.report(logvisor::Fatal, "unable to make new WGL context"); + // if (!wglMakeCurrent(w.m_deviceContext, w.m_renderContext)) + // Log.report(logvisor::Fatal, "unable to make WGL context current"); + + if (!WGLEW_EXT_swap_control) + Log.report(logvisor::Fatal, "WGL_EXT_swap_control not available"); + wglSwapIntervalEXT(1); + } + + void present() { + OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; + SwapBuffers(w.m_deviceContext); + } + + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } + + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } + + /* Creates a new context on current thread!! Call from client loading thread */ + HGLRC m_mainCtx = 0; + IGraphicsDataFactory* getMainContextDataFactory() { + OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; + if (!m_mainCtx) { + m_mainCtx = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); + if (!m_mainCtx) + Log.report(logvisor::Fatal, "unable to make main WGL context"); } + if (!wglMakeCurrent(w.m_deviceContext, m_mainCtx)) + Log.report(logvisor::Fatal, "unable to make main WGL context current"); + return m_dataFactory.get(); + } - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } - - EGraphicsAPI getAPI() const - { - return m_api; - } - - EPixelFormat getPixelFormat() const - { - return m_pf; - } - - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } - - bool initializeContext(void*) {return true;} - - void makeCurrent() - { - OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; - //if (!wglMakeCurrent(w.m_deviceContext, w.m_mainContext)) - // Log.report(logvisor::Fatal, "unable to make WGL context current"); - - w.m_renderContext = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); - if (!w.m_renderContext) - Log.report(logvisor::Fatal, "unable to make new WGL context"); - if (!wglMakeCurrent(w.m_deviceContext, w.m_renderContext)) - Log.report(logvisor::Fatal, "unable to make WGL context current"); - } - - void postInit() - { - //OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; - - //wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) - // wglGetProcAddress("wglCreateContextAttribsARB"); - //w.m_renderContext = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); - //if (!w.m_renderContext) - // Log.report(logvisor::Fatal, "unable to make new WGL context"); - //if (!wglMakeCurrent(w.m_deviceContext, w.m_renderContext)) - // Log.report(logvisor::Fatal, "unable to make WGL context current"); - - if (!WGLEW_EXT_swap_control) - Log.report(logvisor::Fatal, "WGL_EXT_swap_control not available"); - wglSwapIntervalEXT(1); - } - - void present() - { - OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; - SwapBuffers(w.m_deviceContext); - } - - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue.get(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory.get(); - } - - /* Creates a new context on current thread!! Call from client loading thread */ - HGLRC m_mainCtx = 0; - IGraphicsDataFactory* getMainContextDataFactory() - { - OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; - if (!m_mainCtx) - { - m_mainCtx = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); - if (!m_mainCtx) - Log.report(logvisor::Fatal, "unable to make main WGL context"); - } - if (!wglMakeCurrent(w.m_deviceContext, m_mainCtx)) - Log.report(logvisor::Fatal, "unable to make main WGL context current"); - return m_dataFactory.get(); - } - - /* Creates a new context on current thread!! Call from client loading thread */ - HGLRC m_loadCtx = 0; - IGraphicsDataFactory* getLoadContextDataFactory() - { - OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; - if (!m_loadCtx) - { - m_loadCtx = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); - if (!m_loadCtx) - Log.report(logvisor::Fatal, "unable to make load WGL context"); - } - if (!wglMakeCurrent(w.m_deviceContext, m_loadCtx)) - Log.report(logvisor::Fatal, "unable to make load WGL context current"); - return m_dataFactory.get(); + /* Creates a new context on current thread!! Call from client loading thread */ + HGLRC m_loadCtx = 0; + IGraphicsDataFactory* getLoadContextDataFactory() { + OGLContext::Window& w = m_3dCtx.m_ctxOgl.m_windows[m_parentWindow]; + if (!m_loadCtx) { + m_loadCtx = wglCreateContextAttribsARB(w.m_deviceContext, w.m_mainContext, ContextAttribs); + if (!m_loadCtx) + Log.report(logvisor::Fatal, "unable to make load WGL context"); } + if (!wglMakeCurrent(w.m_deviceContext, m_loadCtx)) + Log.report(logvisor::Fatal, "unable to make load WGL context current"); + return m_dataFactory.get(); + } }; #if BOO_HAS_VULKAN -struct GraphicsContextWin32Vulkan : GraphicsContextWin32 -{ - HINSTANCE m_appInstance; - HWND m_hwnd; - VulkanContext* m_ctx; - VkSurfaceKHR m_surface = VK_NULL_HANDLE; - VkFormat m_format = VK_FORMAT_UNDEFINED; - VkColorSpaceKHR m_colorspace; +struct GraphicsContextWin32Vulkan : GraphicsContextWin32 { + HINSTANCE m_appInstance; + HWND m_hwnd; + VulkanContext* m_ctx; + VkSurfaceKHR m_surface = VK_NULL_HANDLE; + VkFormat m_format = VK_FORMAT_UNDEFINED; + VkColorSpaceKHR m_colorspace; - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; - std::thread m_vsyncThread; - bool m_vsyncRunning; + std::thread m_vsyncThread; + bool m_vsyncRunning; - static void ThrowIfFailed(VkResult res) - { - if (res != VK_SUCCESS) - Log.report(logvisor::Fatal, "%d\n", res); - } + static void ThrowIfFailed(VkResult res) { + if (res != VK_SUCCESS) + Log.report(logvisor::Fatal, "%d\n", res); + } public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextWin32Vulkan(IWindow* parentWindow, HINSTANCE appInstance, HWND hwnd, - VulkanContext* ctx, Boo3DAppContextWin32& b3dCtx) - : GraphicsContextWin32(EGraphicsAPI::Vulkan, parentWindow, b3dCtx), - m_appInstance(appInstance), m_hwnd(hwnd), m_ctx(ctx) - { - HMONITOR testMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - ComPtr adapter; - ComPtr foundOut; - int i=0; - while (b3dCtx.m_vulkanDxFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND) - { - int j=0; - ComPtr out; - while (adapter->EnumOutputs(j, &out) != DXGI_ERROR_NOT_FOUND) - { - DXGI_OUTPUT_DESC desc; - out->GetDesc(&desc); - if (desc.Monitor == testMon) - { - out.As(&m_output); - break; - } - ++j; - } - if (m_output) - break; - ++i; + GraphicsContextWin32Vulkan(IWindow* parentWindow, HINSTANCE appInstance, HWND hwnd, VulkanContext* ctx, + Boo3DAppContextWin32& b3dCtx) + : GraphicsContextWin32(EGraphicsAPI::Vulkan, parentWindow, b3dCtx) + , m_appInstance(appInstance) + , m_hwnd(hwnd) + , m_ctx(ctx) { + HMONITOR testMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + ComPtr adapter; + ComPtr foundOut; + int i = 0; + while (b3dCtx.m_vulkanDxFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND) { + int j = 0; + ComPtr out; + while (adapter->EnumOutputs(j, &out) != DXGI_ERROR_NOT_FOUND) { + DXGI_OUTPUT_DESC desc; + out->GetDesc(&desc); + if (desc.Monitor == testMon) { + out.As(&m_output); + break; } - - if (!m_output) - Log.report(logvisor::Fatal, "unable to find window's IDXGIOutput"); + ++j; + } + if (m_output) + break; + ++i; } - void destroy() - { - VulkanContext::Window& m_windowCtx = *m_ctx->m_windows[m_parentWindow]; - m_windowCtx.m_swapChains[0].destroy(m_ctx->m_dev); - m_windowCtx.m_swapChains[1].destroy(m_ctx->m_dev); - //vk::DestroySurfaceKHR(m_ctx->m_instance, m_surface, nullptr); + if (!m_output) + Log.report(logvisor::Fatal, "unable to find window's IDXGIOutput"); + } - if (m_vsyncRunning) - { - m_vsyncRunning = false; - if (m_vsyncThread.joinable()) - m_vsyncThread.join(); + void destroy() { + VulkanContext::Window& m_windowCtx = *m_ctx->m_windows[m_parentWindow]; + m_windowCtx.m_swapChains[0].destroy(m_ctx->m_dev); + m_windowCtx.m_swapChains[1].destroy(m_ctx->m_dev); + // vk::DestroySurfaceKHR(m_ctx->m_instance, m_surface, nullptr); + + if (m_vsyncRunning) { + m_vsyncRunning = false; + if (m_vsyncThread.joinable()) + m_vsyncThread.join(); + } + + m_ctx->m_windows.erase(m_parentWindow); + } + + ~GraphicsContextWin32Vulkan() { destroy(); } + + VulkanContext::Window* m_windowCtx = nullptr; + + void resized(const SWindowRect& rect) { + if (m_windowCtx) + m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect); + } + + void _setCallback(IWindowCallback* cb) { m_callback = cb; } + + EGraphicsAPI getAPI() const { return m_api; } + + EPixelFormat getPixelFormat() const { return m_pf; } + + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } + + bool initializeContext(void*) { + m_windowCtx = m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, std::make_unique())) + .first->second.get(); + m_windowCtx->m_hwnd = m_hwnd; + + VkWin32SurfaceCreateInfoKHR surfaceInfo = {}; + surfaceInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surfaceInfo.hinstance = m_appInstance; + surfaceInfo.hwnd = m_hwnd; + ThrowIfFailed(vk::CreateWin32SurfaceKHR(m_ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); + + /* Iterate over each queue to learn whether it supports presenting */ + VkBool32* supportsPresent = (VkBool32*)malloc(m_ctx->m_queueCount * sizeof(VkBool32)); + for (uint32_t i = 0; i < m_ctx->m_queueCount; ++i) + vk::GetPhysicalDeviceSurfaceSupportKHR(m_ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); + + /* Search for a graphics queue and a present queue in the array of queue + * families, try to find one that supports both */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) { + /* First window, init device */ + for (uint32_t i = 0; i < m_ctx->m_queueCount; ++i) { + if ((m_ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { + if (supportsPresent[i] == VK_TRUE) { + m_ctx->m_graphicsQueueFamilyIndex = i; + } } + } - m_ctx->m_windows.erase(m_parentWindow); + /* Generate error if could not find a queue that supports both a graphics + * and present */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) + Log.report(logvisor::Fatal, "Could not find a queue that supports both graphics and present"); + + m_ctx->initDevice(); + } else { + /* Subsequent window, verify present */ + if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) + Log.report(logvisor::Fatal, "subsequent surface doesn't support present"); + } + free(supportsPresent); + + if (!vk::GetPhysicalDeviceWin32PresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex)) { + Log.report(logvisor::Fatal, "Win32 doesn't support vulkan present"); + return false; } - ~GraphicsContextWin32Vulkan() {destroy();} + /* Get the list of VkFormats that are supported */ + uint32_t formatCount; + ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, nullptr)); + VkSurfaceFormatKHR* surfFormats = (VkSurfaceFormatKHR*)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); + ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, surfFormats)); - VulkanContext::Window* m_windowCtx = nullptr; - - void resized(const SWindowRect& rect) - { - if (m_windowCtx) - m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect); - } - - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } - - EGraphicsAPI getAPI() const - { - return m_api; - } - - EPixelFormat getPixelFormat() const - { - return m_pf; - } - - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } - - bool initializeContext(void*) - { - m_windowCtx = - m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, - std::make_unique())).first->second.get(); - m_windowCtx->m_hwnd = m_hwnd; - - VkWin32SurfaceCreateInfoKHR surfaceInfo = {}; - surfaceInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - surfaceInfo.hinstance = m_appInstance; - surfaceInfo.hwnd = m_hwnd; - ThrowIfFailed(vk::CreateWin32SurfaceKHR(m_ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); - - /* Iterate over each queue to learn whether it supports presenting */ - VkBool32 *supportsPresent = (VkBool32*)malloc(m_ctx->m_queueCount * sizeof(VkBool32)); - for (uint32_t i=0 ; im_queueCount ; ++i) - vk::GetPhysicalDeviceSurfaceSupportKHR(m_ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); - - /* Search for a graphics queue and a present queue in the array of queue - * families, try to find one that supports both */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - { - /* First window, init device */ - for (uint32_t i=0 ; im_queueCount; ++i) - { - if ((m_ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) - { - if (supportsPresent[i] == VK_TRUE) - { - m_ctx->m_graphicsQueueFamilyIndex = i; - } - } - } - - /* Generate error if could not find a queue that supports both a graphics - * and present */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - Log.report(logvisor::Fatal, - "Could not find a queue that supports both graphics and present"); - - m_ctx->initDevice(); + /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, + * the surface has no preferred format. Otherwise, at least one + * supported format will be returned. */ + if (formatCount >= 1) { + if (m_ctx->m_deepColor) { + for (int i = 0; i < formatCount; ++i) { + if (surfFormats[i].format == VK_FORMAT_R16G16B16A16_UNORM) { + m_format = surfFormats[i].format; + m_colorspace = surfFormats[i].colorSpace; + break; + } } - else - { - /* Subsequent window, verify present */ - if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) - Log.report(logvisor::Fatal, "subsequent surface doesn't support present"); + } + if (m_format == VK_FORMAT_UNDEFINED) { + for (int i = 0; i < formatCount; ++i) { + if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) { + m_format = surfFormats[i].format; + m_colorspace = surfFormats[i].colorSpace; + break; + } } - free(supportsPresent); + } + } else + Log.report(logvisor::Fatal, "no surface formats available for Vulkan swapchain"); - if (!vk::GetPhysicalDeviceWin32PresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex)) - { - Log.report(logvisor::Fatal, "Win32 doesn't support vulkan present"); - return false; - } + if (m_format == VK_FORMAT_UNDEFINED) + Log.report(logvisor::Fatal, "no UNORM formats available for Vulkan swapchain"); - /* Get the list of VkFormats that are supported */ - uint32_t formatCount; - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, nullptr)); - VkSurfaceFormatKHR* surfFormats = (VkSurfaceFormatKHR*)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, surfFormats)); + m_ctx->initSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); + m_dataFactory = _NewVulkanDataFactory(this, m_ctx); + m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); + m_commandQueue->startRenderer(); + return true; + } - /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, - * the surface has no preferred format. Otherwise, at least one - * supported format will be returned. */ - if (formatCount >= 1) - { - if (m_ctx->m_deepColor) - { - for (int i=0 ; iinitSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } - m_dataFactory = _NewVulkanDataFactory(this, m_ctx); - m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); - m_commandQueue->startRenderer(); - return true; - } + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } - void makeCurrent() {} + IGraphicsDataFactory* getMainContextDataFactory() { return getDataFactory(); } - void postInit() {} - - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue.get(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory.get(); - } - - IGraphicsDataFactory* getMainContextDataFactory() - { - return getDataFactory(); - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - return getDataFactory(); - } - - void present() {} + IGraphicsDataFactory* getLoadContextDataFactory() { return getDataFactory(); } + void present() {} }; #endif -static void genFrameDefault(MONITORINFO* screen, int& xOut, int& yOut, int& wOut, int& hOut) -{ - float width = screen->rcMonitor.right * 2.0 / 3.0; - float height = screen->rcMonitor.bottom * 2.0 / 3.0; - xOut = (screen->rcMonitor.right - width) / 2.0; - yOut = (screen->rcMonitor.bottom - height) / 2.0; - wOut = width; - hOut = height; +static void genFrameDefault(MONITORINFO* screen, int& xOut, int& yOut, int& wOut, int& hOut) { + float width = screen->rcMonitor.right * 2.0 / 3.0; + float height = screen->rcMonitor.bottom * 2.0 / 3.0; + xOut = (screen->rcMonitor.right - width) / 2.0; + yOut = (screen->rcMonitor.bottom - height) / 2.0; + wOut = width; + hOut = height; } -static uint32_t translateKeysym(WPARAM sym, UINT scancode, ESpecialKey& specialSym, EModifierKey& modifierSym) -{ - specialSym = ESpecialKey::None; - modifierSym = EModifierKey::None; - if (sym >= VK_F1 && sym <= VK_F12) - specialSym = ESpecialKey(uint32_t(ESpecialKey::F1) + sym - VK_F1); - else if (sym == VK_ESCAPE) - specialSym = ESpecialKey::Esc; - else if (sym == VK_RETURN) - specialSym = ESpecialKey::Enter; - else if (sym == VK_BACK) - specialSym = ESpecialKey::Backspace; - else if (sym == VK_INSERT) - specialSym = ESpecialKey::Insert; - else if (sym == VK_DELETE) - specialSym = ESpecialKey::Delete; - else if (sym == VK_HOME) - specialSym = ESpecialKey::Home; - else if (sym == VK_END) - specialSym = ESpecialKey::End; - else if (sym == VK_PRIOR) - specialSym = ESpecialKey::PgUp; - else if (sym == VK_NEXT) - specialSym = ESpecialKey::PgDown; - else if (sym == VK_LEFT) - specialSym = ESpecialKey::Left; - else if (sym == VK_RIGHT) - specialSym = ESpecialKey::Right; - else if (sym == VK_UP) - specialSym = ESpecialKey::Up; - else if (sym == VK_DOWN) - specialSym = ESpecialKey::Down; - else if (sym == VK_SHIFT) - modifierSym = EModifierKey::Shift; - else if (sym == VK_CONTROL) - modifierSym = EModifierKey::Ctrl; - else if (sym == VK_MENU) - modifierSym = EModifierKey::Alt; +static uint32_t translateKeysym(WPARAM sym, UINT scancode, ESpecialKey& specialSym, EModifierKey& modifierSym) { + specialSym = ESpecialKey::None; + modifierSym = EModifierKey::None; + if (sym >= VK_F1 && sym <= VK_F12) + specialSym = ESpecialKey(uint32_t(ESpecialKey::F1) + sym - VK_F1); + else if (sym == VK_ESCAPE) + specialSym = ESpecialKey::Esc; + else if (sym == VK_RETURN) + specialSym = ESpecialKey::Enter; + else if (sym == VK_BACK) + specialSym = ESpecialKey::Backspace; + else if (sym == VK_INSERT) + specialSym = ESpecialKey::Insert; + else if (sym == VK_DELETE) + specialSym = ESpecialKey::Delete; + else if (sym == VK_HOME) + specialSym = ESpecialKey::Home; + else if (sym == VK_END) + specialSym = ESpecialKey::End; + else if (sym == VK_PRIOR) + specialSym = ESpecialKey::PgUp; + else if (sym == VK_NEXT) + specialSym = ESpecialKey::PgDown; + else if (sym == VK_LEFT) + specialSym = ESpecialKey::Left; + else if (sym == VK_RIGHT) + specialSym = ESpecialKey::Right; + else if (sym == VK_UP) + specialSym = ESpecialKey::Up; + else if (sym == VK_DOWN) + specialSym = ESpecialKey::Down; + else if (sym == VK_SHIFT) + modifierSym = EModifierKey::Shift; + else if (sym == VK_CONTROL) + modifierSym = EModifierKey::Ctrl; + else if (sym == VK_MENU) + modifierSym = EModifierKey::Alt; + else { + BYTE kbState[256]; + GetKeyboardState(kbState); + kbState[VK_CONTROL] = 0; + WORD ch = 0; + ToAscii(sym, scancode, kbState, &ch, 0); + return ch; + } + return 0; +} + +static EModifierKey translateModifiers(UINT msg) { + EModifierKey retval = EModifierKey::None; + if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) + retval |= EModifierKey::Shift; + if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) + retval |= EModifierKey::Ctrl; + if ((GetKeyState(VK_MENU) & 0x8000) != 0) + retval |= EModifierKey::Alt; + if (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) + retval |= EModifierKey::Alt; + return retval; +} + +static HGLOBAL MakeANSICRLF(const char* data, size_t sz) { + size_t retSz = 1; + char lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + char ch = data[i]; + if (ch == '\n' && lastCh != '\r') + retSz += 2; else - { - BYTE kbState[256]; - GetKeyboardState(kbState); - kbState[VK_CONTROL] = 0; - WORD ch = 0; - ToAscii(sym, scancode, kbState, &ch, 0); - return ch; + retSz += 1; + lastCh = ch; + } + HGLOBAL ret = GlobalAlloc(GMEM_MOVEABLE, retSz); + char* retData = reinterpret_cast(GlobalLock(ret)); + lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + char ch = data[i]; + if (ch == '\n' && lastCh != '\r') { + *retData = '\r'; + ++retData; + *retData = '\n'; + ++retData; + } else { + *retData = ch; + ++retData; } - return 0; + lastCh = ch; + } + *retData = '\0'; + GlobalUnlock(ret); + return ret; } -static EModifierKey translateModifiers(UINT msg) -{ - EModifierKey retval = EModifierKey::None; - if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) - retval |= EModifierKey::Shift; - if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) - retval |= EModifierKey::Ctrl; - if ((GetKeyState(VK_MENU) & 0x8000) != 0) - retval |= EModifierKey::Alt; - if (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) - retval |= EModifierKey::Alt; - return retval; -} - -static HGLOBAL MakeANSICRLF(const char* data, size_t sz) -{ - size_t retSz = 1; - char lastCh = 0; - for (size_t i=0 ; i MakeANSILF(const char* data, size_t sz, size_t& szOut) { + szOut = 0; + char lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + char ch = data[i]; + if (ch == '\n' && lastCh == '\r') { + } else + szOut += 1; + lastCh = ch; + } + std::unique_ptr ret(new uint8_t[szOut]); + uint8_t* retPtr = ret.get(); + lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + char ch = data[i]; + if (ch == '\n' && lastCh == '\r') + retPtr[-1] = uint8_t('\n'); + else { + *retPtr = uint8_t(ch); + ++retPtr; } - HGLOBAL ret = GlobalAlloc(GMEM_MOVEABLE, retSz); - char* retData = reinterpret_cast(GlobalLock(ret)); - lastCh = 0; - for (size_t i=0 ; i MakeANSILF(const char* data, size_t sz, size_t& szOut) -{ - szOut = 0; - char lastCh = 0; - for (size_t i=0 ; i ret(new uint8_t[szOut]); - uint8_t* retPtr = ret.get(); - lastCh = 0; - for (size_t i=0 ; i MakeANSILF(const char* data, size_t sz, size_t /** Invalid options have been used. */ #define UTF8PROC_ERROR_INVALIDOPTS -5 -#define UTF8PROC_cont(ch) (((ch) & 0xc0) == 0x80) +#define UTF8PROC_cont(ch) (((ch)&0xc0) == 0x80) -static inline int utf8proc_iterate(const uint8_t *str, int strlen, int32_t *dst) { +static inline int utf8proc_iterate(const uint8_t* str, int strlen, int32_t* dst) { uint32_t uc; - const uint8_t *end; + const uint8_t* end; *dst = -1; - if (!strlen) return 0; + if (!strlen) + return 0; end = str + ((strlen < 0) ? 4 : strlen); uc = *str++; if (uc < 0x80) { @@ -808,90 +680,86 @@ static inline int utf8proc_iterate(const uint8_t *str, int strlen, int32_t *dst) return 1; } // Must be between 0xc2 and 0xf4 inclusive to be valid - if ((uc - 0xc2) > (0xf4-0xc2)) return UTF8PROC_ERROR_INVALIDUTF8; - if (uc < 0xe0) { // 2-byte sequence - // Must have valid continuation character - if (!UTF8PROC_cont(*str)) return UTF8PROC_ERROR_INVALIDUTF8; - *dst = ((uc & 0x1f)<<6) | (*str & 0x3f); - return 2; + if ((uc - 0xc2) > (0xf4 - 0xc2)) + return UTF8PROC_ERROR_INVALIDUTF8; + if (uc < 0xe0) { // 2-byte sequence + // Must have valid continuation character + if (!UTF8PROC_cont(*str)) + return UTF8PROC_ERROR_INVALIDUTF8; + *dst = ((uc & 0x1f) << 6) | (*str & 0x3f); + return 2; } - if (uc < 0xf0) { // 3-byte sequence - if ((str + 1 >= end) || !UTF8PROC_cont(*str) || !UTF8PROC_cont(str[1])) - return UTF8PROC_ERROR_INVALIDUTF8; - // Check for surrogate chars - if (uc == 0xed && *str > 0x9f) - return UTF8PROC_ERROR_INVALIDUTF8; - uc = ((uc & 0xf)<<12) | ((*str & 0x3f)<<6) | (str[1] & 0x3f); - if (uc < 0x800) - return UTF8PROC_ERROR_INVALIDUTF8; - *dst = uc; - return 3; + if (uc < 0xf0) { // 3-byte sequence + if ((str + 1 >= end) || !UTF8PROC_cont(*str) || !UTF8PROC_cont(str[1])) + return UTF8PROC_ERROR_INVALIDUTF8; + // Check for surrogate chars + if (uc == 0xed && *str > 0x9f) + return UTF8PROC_ERROR_INVALIDUTF8; + uc = ((uc & 0xf) << 12) | ((*str & 0x3f) << 6) | (str[1] & 0x3f); + if (uc < 0x800) + return UTF8PROC_ERROR_INVALIDUTF8; + *dst = uc; + return 3; } // 4-byte sequence // Must have 3 valid continuation characters if ((str + 2 >= end) || !UTF8PROC_cont(*str) || !UTF8PROC_cont(str[1]) || !UTF8PROC_cont(str[2])) - return UTF8PROC_ERROR_INVALIDUTF8; + return UTF8PROC_ERROR_INVALIDUTF8; // Make sure in correct range (0x10000 - 0x10ffff) if (uc == 0xf0) { - if (*str < 0x90) return UTF8PROC_ERROR_INVALIDUTF8; + if (*str < 0x90) + return UTF8PROC_ERROR_INVALIDUTF8; } else if (uc == 0xf4) { - if (*str > 0x8f) return UTF8PROC_ERROR_INVALIDUTF8; + if (*str > 0x8f) + return UTF8PROC_ERROR_INVALIDUTF8; } - *dst = ((uc & 7)<<18) | ((*str & 0x3f)<<12) | ((str[1] & 0x3f)<<6) | (str[2] & 0x3f); + *dst = ((uc & 7) << 18) | ((*str & 0x3f) << 12) | ((str[1] & 0x3f) << 6) | (str[2] & 0x3f); return 4; } -static HGLOBAL MakeUnicodeCRLF(const char* data, size_t sz) -{ - size_t retSz = 2; - int32_t lastCh = 0; - for (size_t i=0 ; i(data+i), -1, &ch); - if (chSz < 0) - Log.report(logvisor::Fatal, "invalid UTF-8 char"); - if (ch <= 0xffff) - { - if (ch == '\n' && lastCh != '\r') - retSz += 4; - else - retSz += 2; - lastCh = ch; - } - i += chSz; +static HGLOBAL MakeUnicodeCRLF(const char* data, size_t sz) { + size_t retSz = 2; + int32_t lastCh = 0; + for (size_t i = 0; i < sz;) { + int32_t ch; + int chSz = utf8proc_iterate(reinterpret_cast(data + i), -1, &ch); + if (chSz < 0) + Log.report(logvisor::Fatal, "invalid UTF-8 char"); + if (ch <= 0xffff) { + if (ch == '\n' && lastCh != '\r') + retSz += 4; + else + retSz += 2; + lastCh = ch; } - HGLOBAL ret = GlobalAlloc(GMEM_MOVEABLE, retSz); - wchar_t* retData = reinterpret_cast(GlobalLock(ret)); - lastCh = 0; - for (size_t i=0 ; i(data+i), -1, &ch); - if (ch <= 0xffff) - { - if (ch == '\n' && lastCh != '\r') - { - *retData = L'\r'; - ++retData; - *retData = L'\n'; - ++retData; - } - else - { - *retData = wchar_t(ch); - ++retData; - } - lastCh = ch; - } - i += chSz; + i += chSz; + } + HGLOBAL ret = GlobalAlloc(GMEM_MOVEABLE, retSz); + wchar_t* retData = reinterpret_cast(GlobalLock(ret)); + lastCh = 0; + for (size_t i = 0; i < sz;) { + int32_t ch; + int chSz = utf8proc_iterate(reinterpret_cast(data + i), -1, &ch); + if (ch <= 0xffff) { + if (ch == '\n' && lastCh != '\r') { + *retData = L'\r'; + ++retData; + *retData = L'\n'; + ++retData; + } else { + *retData = wchar_t(ch); + ++retData; + } + lastCh = ch; } - *retData = L'\0'; - GlobalUnlock(ret); - return ret; + i += chSz; + } + *retData = L'\0'; + GlobalUnlock(ret); + return ret; } -static inline int utf8proc_encode_char(int32_t uc, uint8_t *dst) { +static inline int utf8proc_encode_char(int32_t uc, uint8_t* dst) { if (uc < 0x00) { return 0; } else if (uc < 0x80) { @@ -901,8 +769,8 @@ static inline int utf8proc_encode_char(int32_t uc, uint8_t *dst) { dst[0] = 0xC0 + (uc >> 6); dst[1] = 0x80 + (uc & 0x3F); return 2; - // Note: we allow encoding 0xd800-0xdfff here, so as not to change - // the API, however, these are actually invalid in UTF-8 + // Note: we allow encoding 0xd800-0xdfff here, so as not to change + // the API, however, these are actually invalid in UTF-8 } else if (uc < 0x10000) { dst[0] = 0xE0 + (uc >> 12); dst[1] = 0x80 + ((uc >> 6) & 0x3F); @@ -914,698 +782,554 @@ static inline int utf8proc_encode_char(int32_t uc, uint8_t *dst) { dst[2] = 0x80 + ((uc >> 6) & 0x3F); dst[3] = 0x80 + (uc & 0x3F); return 4; - } else return 0; + } else + return 0; } -static std::unique_ptr MakeUnicodeLF(const wchar_t* data, size_t sz, size_t& szOut) -{ - szOut = 0; - wchar_t lastCh = 0; - for (size_t i=0 ; i MakeUnicodeLF(const wchar_t* data, size_t sz, size_t& szOut) { + szOut = 0; + wchar_t lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + wchar_t ch = data[i]; + if (ch == L'\n' && lastCh == L'\r') { + } else { + uint8_t dummy[4]; + szOut += utf8proc_encode_char(ch, dummy); } - std::unique_ptr ret(new uint8_t[szOut]); - uint8_t* retPtr = ret.get(); - lastCh = 0; - for (size_t i=0 ; i ret(new uint8_t[szOut]); + uint8_t* retPtr = ret.get(); + lastCh = 0; + for (size_t i = 0; i < sz; ++i) { + wchar_t ch = data[i]; + if (ch == L'\n' && lastCh == L'\r') + retPtr[-1] = uint8_t('\n'); + else + retPtr += utf8proc_encode_char(ch, retPtr); + lastCh = ch; + } + return ret; } -class WindowWin32 : public IWindow -{ - friend struct GraphicsContextWin32; - HWND m_hwnd; - HIMC m_imc; - std::unique_ptr m_gfxCtx; - IWindowCallback* m_callback = nullptr; - EMouseCursor m_cursor = EMouseCursor::None; - bool m_cursorWait = false; - bool m_openGL = false; - static HCURSOR GetWin32Cursor(EMouseCursor cur) - { - switch (cur) - { - case EMouseCursor::Pointer: - return WIN32_CURSORS.m_arrow; - case EMouseCursor::HorizontalArrow: - return WIN32_CURSORS.m_hResize; - case EMouseCursor::VerticalArrow: - return WIN32_CURSORS.m_vResize; - case EMouseCursor::IBeam: - return WIN32_CURSORS.m_ibeam; - case EMouseCursor::Crosshairs: - return WIN32_CURSORS.m_crosshairs; - default: break; - } - return WIN32_CURSORS.m_arrow; +class WindowWin32 : public IWindow { + friend struct GraphicsContextWin32; + HWND m_hwnd; + HIMC m_imc; + std::unique_ptr m_gfxCtx; + IWindowCallback* m_callback = nullptr; + EMouseCursor m_cursor = EMouseCursor::None; + bool m_cursorWait = false; + bool m_openGL = false; + static HCURSOR GetWin32Cursor(EMouseCursor cur) { + switch (cur) { + case EMouseCursor::Pointer: + return WIN32_CURSORS.m_arrow; + case EMouseCursor::HorizontalArrow: + return WIN32_CURSORS.m_hResize; + case EMouseCursor::VerticalArrow: + return WIN32_CURSORS.m_vResize; + case EMouseCursor::IBeam: + return WIN32_CURSORS.m_ibeam; + case EMouseCursor::Crosshairs: + return WIN32_CURSORS.m_crosshairs; + default: + break; } + return WIN32_CURSORS.m_arrow; + } public: + WindowWin32(SystemStringView title, Boo3DAppContextWin32& b3dCtx) { + const POINT ptZero = {0, 0}; + HMONITOR monitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO monInfo = {}; + monInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitor, &monInfo); + int x, y, w, h; + genFrameDefault(&monInfo, x, y, w, h); + RECT r = {x, y, x + w, y + h}; + AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); - WindowWin32(SystemStringView title, Boo3DAppContextWin32& b3dCtx) - { - const POINT ptZero = { 0, 0 }; - HMONITOR monitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO monInfo = {}; - monInfo.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(monitor, &monInfo); - int x, y, w, h; - genFrameDefault(&monInfo, x, y, w, h); - RECT r = {x, y, x + w, y + h}; - AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); - - m_hwnd = CreateWindowW(L"BooWindow", title.data(), WS_OVERLAPPEDWINDOW, - r.left, r.top, r.right - r.left, r.bottom - r.top, - NULL, NULL, NULL, NULL); - HINSTANCE wndInstance = HINSTANCE(GetWindowLongPtr(m_hwnd, GWLP_HINSTANCE)); - m_imc = ImmGetContext(m_hwnd); + m_hwnd = CreateWindowW(L"BooWindow", title.data(), WS_OVERLAPPEDWINDOW, r.left, r.top, r.right - r.left, + r.bottom - r.top, NULL, NULL, NULL, NULL); + HINSTANCE wndInstance = HINSTANCE(GetWindowLongPtr(m_hwnd, GWLP_HINSTANCE)); + m_imc = ImmGetContext(m_hwnd); #if BOO_HAS_VULKAN - if (b3dCtx.m_vulkanDxFactory) - { - m_gfxCtx.reset(new GraphicsContextWin32Vulkan(this, wndInstance, m_hwnd, &g_VulkanContext, b3dCtx)); - if (m_gfxCtx->initializeContext(nullptr)) - return; - } + if (b3dCtx.m_vulkanDxFactory) { + m_gfxCtx.reset(new GraphicsContextWin32Vulkan(this, wndInstance, m_hwnd, &g_VulkanContext, b3dCtx)); + if (m_gfxCtx->initializeContext(nullptr)) + return; + } #else - (void)wndInstance; + (void)wndInstance; #endif - IGraphicsContext::EGraphicsAPI api = IGraphicsContext::EGraphicsAPI::D3D11; - if (b3dCtx.m_ctxOgl.m_dxFactory) - { - m_gfxCtx.reset(new GraphicsContextWin32GL(IGraphicsContext::EGraphicsAPI::OpenGL3_3, - this, m_hwnd, b3dCtx)); - m_openGL = true; - return; - } - m_gfxCtx.reset(new GraphicsContextWin32D3D(api, this, m_hwnd, b3dCtx)); + IGraphicsContext::EGraphicsAPI api = IGraphicsContext::EGraphicsAPI::D3D11; + if (b3dCtx.m_ctxOgl.m_dxFactory) { + m_gfxCtx.reset(new GraphicsContextWin32GL(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, m_hwnd, b3dCtx)); + m_openGL = true; + return; } + m_gfxCtx.reset(new GraphicsContextWin32D3D(api, this, m_hwnd, b3dCtx)); + } - void _cleanup() - { - m_gfxCtx.reset(); + void _cleanup() { m_gfxCtx.reset(); } + + void setCallback(IWindowCallback* cb) { m_callback = cb; } + + void closeWindow() { + // TODO: Perform thread-coalesced deallocation + ShowWindow(m_hwnd, SW_HIDE); + } + + void showWindow() { ShowWindow(m_hwnd, SW_SHOW); } + + void hideWindow() { ShowWindow(m_hwnd, SW_HIDE); } + + SystemString getTitle() { + wchar_t title[256]; + int c = GetWindowTextW(m_hwnd, title, 256); + return SystemString(title, c); + } + + void setTitle(SystemStringView title) { SetWindowTextW(m_hwnd, title.data()); } + + static void _setCursor(HCURSOR cur) { PostThreadMessageW(g_mainThreadId, WM_USER + 2, WPARAM(cur), 0); } + + void setCursor(EMouseCursor cursor) { + if (cursor == m_cursor && !m_cursorWait) + return; + m_cursor = cursor; + _setCursor(GetWin32Cursor(cursor)); + } + + void setWaitCursor(bool wait) { + if (wait && !m_cursorWait) { + _setCursor(WIN32_CURSORS.m_wait); + m_cursorWait = true; + } else if (!wait && m_cursorWait) { + setCursor(m_cursor); + m_cursorWait = false; } + } - void setCallback(IWindowCallback* cb) - { - m_callback = cb; - } + void setWindowFrameDefault() { + MONITORINFO monInfo = {}; + monInfo.cbSize = sizeof(MONITORINFO); + HMONITOR mon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTOPRIMARY); + GetMonitorInfo(mon, &monInfo); + int x, y, w, h; + genFrameDefault(&monInfo, x, y, w, h); + setWindowFrame(x, y, w, h); + } - void closeWindow() - { - // TODO: Perform thread-coalesced deallocation - ShowWindow(m_hwnd, SW_HIDE); - } + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const { + RECT rct; + GetClientRect(m_hwnd, &rct); + POINT pt; + pt.x = rct.left; + pt.y = rct.top; + MapWindowPoints(m_hwnd, HWND_DESKTOP, &pt, 1); + xOut = pt.x; + yOut = pt.y; + wOut = rct.right; + hOut = rct.bottom; + } - void showWindow() - { - ShowWindow(m_hwnd, SW_SHOW); - } + void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const { + RECT rct; + GetClientRect(m_hwnd, &rct); + POINT pt; + pt.x = rct.left; + pt.y = rct.top; + MapWindowPoints(m_hwnd, HWND_DESKTOP, &pt, 1); + xOut = pt.x; + yOut = pt.y; + wOut = rct.right; + hOut = rct.bottom; + } - void hideWindow() - { - ShowWindow(m_hwnd, SW_HIDE); - } + void setWindowFrame(float x, float y, float w, float h) { setWindowFrame(int(x), int(y), int(w), int(h)); } - SystemString getTitle() - { - wchar_t title[256]; - int c = GetWindowTextW(m_hwnd, title, 256); - return SystemString(title, c); - } + void setWindowFrame(int x, int y, int w, int h) { + RECT r = {x, y, x + w, y + h}; + AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); + MoveWindow(m_hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, true); + } - void setTitle(SystemStringView title) - { - SetWindowTextW(m_hwnd, title.data()); - } - - static void _setCursor(HCURSOR cur) - { - PostThreadMessageW(g_mainThreadId, WM_USER+2, WPARAM(cur), 0); - } - - void setCursor(EMouseCursor cursor) - { - if (cursor == m_cursor && !m_cursorWait) - return; - m_cursor = cursor; - _setCursor(GetWin32Cursor(cursor)); - } - - void setWaitCursor(bool wait) - { - if (wait && !m_cursorWait) - { - _setCursor(WIN32_CURSORS.m_wait); - m_cursorWait = true; - } - else if (!wait && m_cursorWait) - { - setCursor(m_cursor); - m_cursorWait = false; - } - } - - void setWindowFrameDefault() - { - MONITORINFO monInfo = {}; - monInfo.cbSize = sizeof(MONITORINFO); - HMONITOR mon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTOPRIMARY); - GetMonitorInfo(mon, &monInfo); - int x, y, w, h; - genFrameDefault(&monInfo, x, y, w, h); - setWindowFrame(x, y, w, h); - } - - void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const - { - RECT rct; - GetClientRect(m_hwnd, &rct); - POINT pt; - pt.x = rct.left; - pt.y = rct.top; - MapWindowPoints(m_hwnd, HWND_DESKTOP, &pt, 1); - xOut = pt.x; - yOut = pt.y; - wOut = rct.right; - hOut = rct.bottom; - } - - void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const - { - RECT rct; - GetClientRect(m_hwnd, &rct); - POINT pt; - pt.x = rct.left; - pt.y = rct.top; - MapWindowPoints(m_hwnd, HWND_DESKTOP, &pt, 1); - xOut = pt.x; - yOut = pt.y; - wOut = rct.right; - hOut = rct.bottom; - } - - void setWindowFrame(float x, float y, float w, float h) - { - setWindowFrame(int(x), int(y), int(w), int(h)); - } - - void setWindowFrame(int x, int y, int w, int h) - { - RECT r = {x, y, x + w, y + h}; - AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); - MoveWindow(m_hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, true); - } - - float getVirtualPixelFactor() const - { + float getVirtualPixelFactor() const { #if _WIN32_WINNT_WINBLUE - if (MyGetScaleFactorForMonitor) - { - DEVICE_SCALE_FACTOR Factor; - HMONITOR mon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTOPRIMARY); - MyGetScaleFactorForMonitor(mon, &Factor); - if (Factor == 0) - return 1.f; - return Factor / 100.f; - } -#endif + if (MyGetScaleFactorForMonitor) { + DEVICE_SCALE_FACTOR Factor; + HMONITOR mon = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTOPRIMARY); + MyGetScaleFactorForMonitor(mon, &Factor); + if (Factor == 0) return 1.f; + return Factor / 100.f; } +#endif + return 1.f; + } - bool isFullscreen() const - { - return m_gfxCtx->m_3dCtx.isFullscreen(this); + bool isFullscreen() const { return m_gfxCtx->m_3dCtx.isFullscreen(this); } + + void setFullscreen(bool fs) { m_gfxCtx->m_3dCtx.setFullscreen(this, fs); } + + void _immSetOpenStatus(bool open) { + if (GetCurrentThreadId() != g_mainThreadId) { + if (!PostThreadMessageW(g_mainThreadId, WM_USER + 3, WPARAM(m_imc), LPARAM(open))) + Log.report(logvisor::Fatal, "PostThreadMessage error"); + return; } + ImmSetOpenStatus(m_imc, open); + } - void setFullscreen(bool fs) - { - m_gfxCtx->m_3dCtx.setFullscreen(this, fs); + COMPOSITIONFORM m_cForm = {CFS_POINT}; + void _immSetCompositionWindow(const int coord[2]) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + m_cForm.ptCurrentPos.x = coord[0]; + m_cForm.ptCurrentPos.y = h - coord[1]; + + if (GetCurrentThreadId() != g_mainThreadId) { + if (!PostThreadMessageW(g_mainThreadId, WM_USER + 4, WPARAM(m_imc), LPARAM(&m_cForm))) + Log.report(logvisor::Fatal, "PostThreadMessage error"); + return; } + ImmSetCompositionWindow(m_imc, &m_cForm); + } - void _immSetOpenStatus(bool open) - { - if (GetCurrentThreadId() != g_mainThreadId) - { - if (!PostThreadMessageW(g_mainThreadId, WM_USER+3, WPARAM(m_imc), LPARAM(open))) - Log.report(logvisor::Fatal, "PostThreadMessage error"); - return; - } - ImmSetOpenStatus(m_imc, open); + void claimKeyboardFocus(const int coord[2]) { + if (!coord) { + //_immSetOpenStatus(false); + return; } + _immSetCompositionWindow(coord); + //_immSetOpenStatus(true); + } - COMPOSITIONFORM m_cForm = {CFS_POINT}; - void _immSetCompositionWindow(const int coord[2]) - { + bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { + switch (type) { + case EClipboardType::String: { + HGLOBAL gStr = MakeANSICRLF(reinterpret_cast(data), sz); + OpenClipboard(m_hwnd); + EmptyClipboard(); + SetClipboardData(CF_TEXT, gStr); + CloseClipboard(); + return true; + } + case EClipboardType::UTF8String: { + HGLOBAL gStr = MakeUnicodeCRLF(reinterpret_cast(data), sz); + OpenClipboard(m_hwnd); + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, gStr); + CloseClipboard(); + return true; + } + default: + break; + } + return false; + } + + std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { + switch (type) { + case EClipboardType::String: { + OpenClipboard(m_hwnd); + HGLOBAL gStr = GetClipboardData(CF_TEXT); + if (!gStr) + break; + const char* str = reinterpret_cast(GlobalLock(gStr)); + std::unique_ptr ret = MakeANSILF(str, GlobalSize(gStr), sz); + GlobalUnlock(gStr); + CloseClipboard(); + return ret; + } + case EClipboardType::UTF8String: { + OpenClipboard(m_hwnd); + HGLOBAL gStr = GetClipboardData(CF_UNICODETEXT); + if (!gStr) + break; + const wchar_t* str = reinterpret_cast(GlobalLock(gStr)); + std::unique_ptr ret = MakeUnicodeLF(str, GlobalSize(gStr) / 2, sz); + GlobalUnlock(gStr); + CloseClipboard(); + return ret; + } + default: + break; + } + return std::unique_ptr(); + } + + void waitForRetrace() { m_gfxCtx->m_output->WaitForVBlank(); } + + uintptr_t getPlatformHandle() const { return uintptr_t(m_hwnd); } + + void buttonDown(HWNDEvent& e, EMouseButton button) { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + EModifierKey modifierMask = translateModifiers(e.uMsg); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + m_callback->mouseDown(coord, button, modifierMask); + } + } + + void buttonUp(HWNDEvent& e, EMouseButton button) { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + EModifierKey modifierMask = translateModifiers(e.uMsg); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + m_callback->mouseUp(coord, button, modifierMask); + } + } + + void _trackMouse() { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_NONCLIENT | TME_HOVER | TME_LEAVE; + tme.dwHoverTime = 500; + tme.hwndTrack = m_hwnd; + } + + bool mouseTracking = false; + bool _incomingEvent(void* ev) { + HWNDEvent& e = *static_cast(ev); + switch (e.uMsg) { + case WM_CLOSE: + if (m_callback) + m_callback->destroyed(); + return true; + case WM_SIZE: { + SWindowRect rect; + getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); + if (!rect.size[0] || !rect.size[1]) + return false; + m_gfxCtx->resized(rect); + if (m_callback) + m_callback->resized(rect, m_openGL); + return false; + } + case WM_MOVING: { + SWindowRect rect; + getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); + if (!rect.size[0] || !rect.size[1]) + return false; + + if (m_callback) + m_callback->windowMoved(rect); + return false; + } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: { + if (m_callback) { + ESpecialKey specialKey; + EModifierKey modifierKey; + uint32_t charCode = translateKeysym(e.wParam, (e.lParam >> 16) & 0xff, specialKey, modifierKey); + EModifierKey modifierMask = translateModifiers(e.uMsg); + if (charCode) + m_callback->charKeyDown(charCode, modifierMask, (HIWORD(e.lParam) & KF_REPEAT) != 0); + else if (specialKey != ESpecialKey::None) + m_callback->specialKeyDown(specialKey, modifierMask, (HIWORD(e.lParam) & KF_REPEAT) != 0); + else if (modifierKey != EModifierKey::None) + m_callback->modKeyDown(modifierKey, (HIWORD(e.lParam) & KF_REPEAT) != 0); + } + return false; + } + case WM_KEYUP: + case WM_SYSKEYUP: { + if (m_callback) { + ESpecialKey specialKey; + EModifierKey modifierKey; + uint32_t charCode = translateKeysym(e.wParam, (e.lParam >> 16) & 0xff, specialKey, modifierKey); + EModifierKey modifierMask = translateModifiers(e.uMsg); + 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); + } + return false; + } + case WM_LBUTTONDOWN: { + buttonDown(e, EMouseButton::Primary); + return false; + } + case WM_LBUTTONUP: { + buttonUp(e, EMouseButton::Primary); + return false; + } + case WM_RBUTTONDOWN: { + buttonDown(e, EMouseButton::Secondary); + return false; + } + case WM_RBUTTONUP: { + buttonUp(e, EMouseButton::Secondary); + return false; + } + case WM_MBUTTONDOWN: { + buttonDown(e, EMouseButton::Middle); + return false; + } + case WM_MBUTTONUP: { + buttonUp(e, EMouseButton::Middle); + return false; + } + case WM_XBUTTONDOWN: { + if (HIWORD(e.wParam) == XBUTTON1) + buttonDown(e, EMouseButton::Aux1); + else if (HIWORD(e.wParam) == XBUTTON2) + buttonDown(e, EMouseButton::Aux2); + return false; + } + case WM_XBUTTONUP: { + if (HIWORD(e.wParam) == XBUTTON1) + buttonUp(e, EMouseButton::Aux1); + else if (HIWORD(e.wParam) == XBUTTON2) + buttonUp(e, EMouseButton::Aux2); + return false; + } + case WM_MOUSEMOVE: { + if (m_callback) { int x, y, w, h; getWindowFrame(x, y, w, h); - m_cForm.ptCurrentPos.x = coord[0]; - m_cForm.ptCurrentPos.y = h - coord[1]; + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + if (!mouseTracking) { + _trackMouse(); + mouseTracking = true; + m_callback->mouseEnter(coord); + } else + m_callback->mouseMove(coord); + } - if (GetCurrentThreadId() != g_mainThreadId) - { - if (!PostThreadMessageW(g_mainThreadId, WM_USER+4, WPARAM(m_imc), LPARAM(&m_cForm))) - Log.report(logvisor::Fatal, "PostThreadMessage error"); - return; - } - ImmSetCompositionWindow(m_imc, &m_cForm); + return false; + } + case WM_MOUSELEAVE: + case WM_NCMOUSELEAVE: { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + m_callback->mouseLeave(coord); + mouseTracking = false; + } + return false; + } + case WM_NCMOUSEHOVER: + case WM_MOUSEHOVER: { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + m_callback->mouseEnter(coord); + } + return false; + } + case WM_MOUSEWHEEL: { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + SScrollDelta scroll = {}; + scroll.delta[1] = GET_WHEEL_DELTA_WPARAM(e.wParam) / double(WHEEL_DELTA); + m_callback->scroll(coord, scroll); + } + return false; + } + case WM_MOUSEHWHEEL: { + if (m_callback) { + int x, y, w, h; + getWindowFrame(x, y, w, h); + SWindowCoord coord = {{GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {GET_X_LPARAM(e.lParam), h - GET_Y_LPARAM(e.lParam)}, + {float(GET_X_LPARAM(e.lParam)) / float(w), float(h - GET_Y_LPARAM(e.lParam)) / float(h)}}; + SScrollDelta scroll = {}; + scroll.delta[0] = GET_WHEEL_DELTA_WPARAM(e.wParam) / double(-WHEEL_DELTA); + m_callback->scroll(coord, scroll); + } + return false; + } + case WM_CHAR: + case WM_UNICHAR: { + if (m_callback) { + ITextInputCallback* inputCb = m_callback->getTextInputCallback(); + uint8_t utf8ch[4]; + size_t len = utf8proc_encode_char(e.wParam, utf8ch); + if (inputCb && len) + inputCb->insertText(std::string((char*)utf8ch, len)); + } + return false; + } + default: + break; } - void claimKeyboardFocus(const int coord[2]) - { - if (!coord) - { - //_immSetOpenStatus(false); - return; - } - _immSetCompositionWindow(coord); - //_immSetOpenStatus(true); - } + return false; + } - bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) - { - switch (type) - { - case EClipboardType::String: - { - HGLOBAL gStr = MakeANSICRLF(reinterpret_cast(data), sz); - OpenClipboard(m_hwnd); - EmptyClipboard(); - SetClipboardData(CF_TEXT, gStr); - CloseClipboard(); - return true; - } - case EClipboardType::UTF8String: - { - HGLOBAL gStr = MakeUnicodeCRLF(reinterpret_cast(data), sz); - OpenClipboard(m_hwnd); - EmptyClipboard(); - SetClipboardData(CF_UNICODETEXT, gStr); - CloseClipboard(); - return true; - } - default: break; - } - return false; - } + ETouchType getTouchType() const { return ETouchType::None; } - std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) - { - switch (type) - { - case EClipboardType::String: - { - OpenClipboard(m_hwnd); - HGLOBAL gStr = GetClipboardData(CF_TEXT); - if (!gStr) - break; - const char* str = reinterpret_cast(GlobalLock(gStr)); - std::unique_ptr ret = MakeANSILF(str, GlobalSize(gStr), sz); - GlobalUnlock(gStr); - CloseClipboard(); - return ret; - } - case EClipboardType::UTF8String: - { - OpenClipboard(m_hwnd); - HGLOBAL gStr = GetClipboardData(CF_UNICODETEXT); - if (!gStr) - break; - const wchar_t* str = reinterpret_cast(GlobalLock(gStr)); - std::unique_ptr ret = MakeUnicodeLF(str, GlobalSize(gStr)/2, sz); - GlobalUnlock(gStr); - CloseClipboard(); - return ret; - } - default: break; - } - return std::unique_ptr(); - } + void setStyle(EWindowStyle style) { + LONG sty = GetWindowLong(m_hwnd, GWL_STYLE); - void waitForRetrace() - { - m_gfxCtx->m_output->WaitForVBlank(); - } + if ((style & EWindowStyle::Titlebar) != EWindowStyle::None) + sty |= WS_CAPTION; + else + sty &= ~WS_CAPTION; - uintptr_t getPlatformHandle() const - { - return uintptr_t(m_hwnd); - } + if ((style & EWindowStyle::Resize) != EWindowStyle::None) + sty |= WS_THICKFRAME; + else + sty &= ~WS_THICKFRAME; - void buttonDown(HWNDEvent& e, EMouseButton button) - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - EModifierKey modifierMask = translateModifiers(e.uMsg); - SWindowCoord coord = - { - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h)} - }; - m_callback->mouseDown(coord, button, modifierMask); - } - } + if ((style & EWindowStyle::Close) != EWindowStyle::None) + sty |= (WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + else + sty &= ~(WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); - void buttonUp(HWNDEvent& e, EMouseButton button) - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - EModifierKey modifierMask = translateModifiers(e.uMsg); - SWindowCoord coord = - { - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h)} - }; - m_callback->mouseUp(coord, button, modifierMask); - } - } + SetWindowLong(m_hwnd, GWL_STYLE, sty); + } - void _trackMouse() - { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_NONCLIENT | TME_HOVER | TME_LEAVE; - tme.dwHoverTime = 500; - tme.hwndTrack = m_hwnd; - } + EWindowStyle getStyle() const { + LONG sty = GetWindowLong(m_hwnd, GWL_STYLE); + EWindowStyle retval = EWindowStyle::None; + if ((sty & WS_CAPTION) != 0) + retval |= EWindowStyle::Titlebar; + if ((sty & WS_THICKFRAME) != 0) + retval |= EWindowStyle::Resize; + if ((sty & WS_SYSMENU)) + retval |= EWindowStyle::Close; + return retval; + } - bool mouseTracking = false; - bool _incomingEvent(void* ev) - { - HWNDEvent& e = *static_cast(ev); - switch (e.uMsg) - { - case WM_CLOSE: - if (m_callback) - m_callback->destroyed(); - return true; - case WM_SIZE: - { - SWindowRect rect; - getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); - if (!rect.size[0] || !rect.size[1]) - return false; - m_gfxCtx->resized(rect); - if (m_callback) - m_callback->resized(rect, m_openGL); - return false; - } - case WM_MOVING: - { - SWindowRect rect; - getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); - if (!rect.size[0] || !rect.size[1]) - return false; + IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx->getCommandQueue(); } + IGraphicsDataFactory* getDataFactory() { return m_gfxCtx->getDataFactory(); } - if (m_callback) - m_callback->windowMoved(rect); - return false; - } - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - { - if (m_callback) - { - ESpecialKey specialKey; - EModifierKey modifierKey; - uint32_t charCode = translateKeysym(e.wParam, (e.lParam >> 16) & 0xff, specialKey, modifierKey); - EModifierKey modifierMask = translateModifiers(e.uMsg); - if (charCode) - m_callback->charKeyDown(charCode, modifierMask, (HIWORD(e.lParam) & KF_REPEAT) != 0); - else if (specialKey != ESpecialKey::None) - m_callback->specialKeyDown(specialKey, modifierMask, (HIWORD(e.lParam) & KF_REPEAT) != 0); - else if (modifierKey != EModifierKey::None) - m_callback->modKeyDown(modifierKey, (HIWORD(e.lParam) & KF_REPEAT) != 0); - } - return false; - } - case WM_KEYUP: - case WM_SYSKEYUP: - { - if (m_callback) - { - ESpecialKey specialKey; - EModifierKey modifierKey; - uint32_t charCode = translateKeysym(e.wParam, (e.lParam >> 16) & 0xff, specialKey, modifierKey); - EModifierKey modifierMask = translateModifiers(e.uMsg); - 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); - } - return false; - } - case WM_LBUTTONDOWN: - { - buttonDown(e, EMouseButton::Primary); - return false; - } - case WM_LBUTTONUP: - { - buttonUp(e, EMouseButton::Primary); - return false; - } - case WM_RBUTTONDOWN: - { - buttonDown(e, EMouseButton::Secondary); - return false; - } - case WM_RBUTTONUP: - { - buttonUp(e, EMouseButton::Secondary); - return false; - } - case WM_MBUTTONDOWN: - { - buttonDown(e, EMouseButton::Middle); - return false; - } - case WM_MBUTTONUP: - { - buttonUp(e, EMouseButton::Middle); - return false; - } - case WM_XBUTTONDOWN: - { - if (HIWORD(e.wParam) == XBUTTON1) - buttonDown(e, EMouseButton::Aux1); - else if (HIWORD(e.wParam) == XBUTTON2) - buttonDown(e, EMouseButton::Aux2); - return false; - } - case WM_XBUTTONUP: - { - if (HIWORD(e.wParam) == XBUTTON1) - buttonUp(e, EMouseButton::Aux1); - else if (HIWORD(e.wParam) == XBUTTON2) - buttonUp(e, EMouseButton::Aux2); - return false; - } - case WM_MOUSEMOVE: - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - SWindowCoord coord = - { - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam)}, - {float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h)} - }; - if (!mouseTracking) - { - _trackMouse(); - mouseTracking = true; - m_callback->mouseEnter(coord); - } - else - m_callback->mouseMove(coord); - } - - return false; - } - case WM_MOUSELEAVE: - case WM_NCMOUSELEAVE: - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - SWindowCoord coord = - { - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h) } - }; - m_callback->mouseLeave(coord); - mouseTracking = false; - } - return false; - } - case WM_NCMOUSEHOVER: - case WM_MOUSEHOVER: - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - SWindowCoord coord = - { - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h) } - }; - m_callback->mouseEnter(coord); - } - return false; - } - case WM_MOUSEWHEEL: - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - SWindowCoord coord = - { - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h) } - }; - SScrollDelta scroll = {}; - scroll.delta[1] = GET_WHEEL_DELTA_WPARAM(e.wParam) / double(WHEEL_DELTA); - m_callback->scroll(coord, scroll); - } - return false; - } - case WM_MOUSEHWHEEL: - { - if (m_callback) - { - int x, y, w, h; - getWindowFrame(x, y, w, h); - SWindowCoord coord = - { - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { GET_X_LPARAM(e.lParam), h-GET_Y_LPARAM(e.lParam) }, - { float(GET_X_LPARAM(e.lParam)) / float(w), float(h-GET_Y_LPARAM(e.lParam)) / float(h) } - }; - SScrollDelta scroll = {}; - scroll.delta[0] = GET_WHEEL_DELTA_WPARAM(e.wParam) / double(-WHEEL_DELTA); - m_callback->scroll(coord, scroll); - } - return false; - } - case WM_CHAR: - case WM_UNICHAR: - { - if (m_callback) - { - ITextInputCallback* inputCb = m_callback->getTextInputCallback(); - uint8_t utf8ch[4]; - size_t len = utf8proc_encode_char(e.wParam, utf8ch); - if (inputCb && len) - inputCb->insertText(std::string((char*)utf8ch, len)); - } - return false; - } - default: break; - } - - return false; - } - - ETouchType getTouchType() const - { - return ETouchType::None; - } - - void setStyle(EWindowStyle style) - { - LONG sty = GetWindowLong(m_hwnd, GWL_STYLE); - - if ((style & EWindowStyle::Titlebar) != EWindowStyle::None) - sty |= WS_CAPTION; - else - sty &= ~WS_CAPTION; - - if ((style & EWindowStyle::Resize) != EWindowStyle::None) - sty |= WS_THICKFRAME; - else - sty &= ~WS_THICKFRAME; - - if ((style & EWindowStyle::Close) != EWindowStyle::None) - sty |= (WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); - else - sty &= ~(WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); - - SetWindowLong(m_hwnd, GWL_STYLE, sty); - } - - EWindowStyle getStyle() const - { - LONG sty = GetWindowLong(m_hwnd, GWL_STYLE); - EWindowStyle retval = EWindowStyle::None; - if ((sty & WS_CAPTION) != 0) - retval |= EWindowStyle::Titlebar; - if ((sty & WS_THICKFRAME) != 0) - retval |= EWindowStyle::Resize; - if ((sty & WS_SYSMENU)) - retval |= EWindowStyle::Close; - return retval; - } - - IGraphicsCommandQueue* getCommandQueue() - { - return m_gfxCtx->getCommandQueue(); - } - IGraphicsDataFactory* getDataFactory() - { - return m_gfxCtx->getDataFactory(); - } - - /* Creates a new context on current thread!! Call from main client thread */ - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_gfxCtx->getMainContextDataFactory(); - } - - /* Creates a new context on current thread!! Call from client loading thread */ - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_gfxCtx->getLoadContextDataFactory(); - } + /* Creates a new context on current thread!! Call from main client thread */ + IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx->getMainContextDataFactory(); } + /* Creates a new context on current thread!! Call from client loading thread */ + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } }; -std::shared_ptr _WindowWin32New(SystemStringView title, Boo3DAppContextWin32& d3dCtx) -{ - return std::make_shared(title, d3dCtx); +std::shared_ptr _WindowWin32New(SystemStringView title, Boo3DAppContextWin32& d3dCtx) { + return std::make_shared(title, d3dCtx); } -} +} // namespace boo diff --git a/lib/x11/ApplicationUnix.cpp b/lib/x11/ApplicationUnix.cpp index 056632d..07346f7 100644 --- a/lib/x11/ApplicationUnix.cpp +++ b/lib/x11/ApplicationUnix.cpp @@ -11,74 +11,62 @@ #include /* No icon by default */ -extern "C" const uint8_t MAINICON_NETWM[] __attribute__ ((weak)) = {}; -extern "C" const size_t MAINICON_NETWM_SZ __attribute__ ((weak)) = 0; +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); +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)) - { - fprintf(stderr, "DBus Connection Error (%s)\n", err.message); - dbus_error_free(&err); - } - if (NULL == conn) - return NULL; + /* connect to the bus and check for errors */ + DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "DBus Connection Error (%s)\n", err.message); + dbus_error_free(&err); + } + if (NULL == conn) + return NULL; - /* request our name on the bus and check for errors */ - char busName[256]; - snprintf(busName, 256, "boo.%s.unique", appName); - int ret = dbus_bus_request_name(conn, busName, DBUS_NAME_FLAG_DO_NOT_QUEUE , &err); - if (dbus_error_is_set(&err)) - { - fprintf(stderr, "DBus Name Error (%s)\n", err.message); - dbus_error_free(&err); - dbus_connection_close(conn); - return NULL; - } - if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) - isFirst = false; - - return conn; + /* request our name on the bus and check for errors */ + char busName[256]; + snprintf(busName, 256, "boo.%s.unique", appName); + int ret = dbus_bus_request_name(conn, busName, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "DBus Name Error (%s)\n", err.message); + dbus_error_free(&err); + dbus_connection_close(conn); + return NULL; + } + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) + isFirst = false; + return conn; } -namespace boo -{ +namespace boo { 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& 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; -} - +int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, std::string_view uniqueName, + std::string_view friendlyName, std::string_view pname, const std::vector& 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 diff --git a/lib/x11/ApplicationWayland.hpp b/lib/x11/ApplicationWayland.hpp index 6721b47..f63c78d 100644 --- a/lib/x11/ApplicationWayland.hpp +++ b/lib/x11/ApplicationWayland.hpp @@ -7,81 +7,47 @@ #include DBusConnection* RegisterDBus(const char* appName, bool& isFirst); -namespace boo -{ - +namespace boo { + std::shared_ptr _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 m_args; - bool m_singleInstance; - void _deletedWindow(IWindow* window) - { - (void)window; - } - +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 m_args; + bool m_singleInstance; + + void _deletedWindow(IWindow* window) { (void)window; } + public: - ApplicationWayland(IApplicationCallback& callback, - std::string_view uniqueName, - std::string_view friendlyName, - std::string_view pname, - const std::vector& 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 - { - return EPlatformType::Wayland; - } - - int run() - { - return 0; - } + ApplicationWayland(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName, + std::string_view pname, const std::vector& 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; + } - std::string_view getUniqueName() const - { - return m_uniqueName; - } + EPlatformType getPlatformType() const { return EPlatformType::Wayland; } - std::string_view getFriendlyName() const - { - return m_friendlyName; - } - - std::string_view getProcessName() const - { - return m_pname; - } - - const std::vector& getArgs() const - { - return m_args; - } - - std::shared_ptr newWindow(std::string_view title) - { - return _WindowWaylandNew(title); - } + int run() { return 0; } + + std::string_view getUniqueName() const { return m_uniqueName; } + + std::string_view getFriendlyName() const { return m_friendlyName; } + + std::string_view getProcessName() const { return m_pname; } + + const std::vector& getArgs() const { return m_args; } + + std::shared_ptr newWindow(std::string_view title) { return _WindowWaylandNew(title); } }; - -} + +} // namespace boo diff --git a/lib/x11/ApplicationXlib.hpp b/lib/x11/ApplicationXlib.hpp index dc6e4c8..5f7a248 100644 --- a/lib/x11/ApplicationXlib.hpp +++ b/lib/x11/ApplicationXlib.hpp @@ -33,567 +33,484 @@ DBusConnection* RegisterDBus(const char* appName, bool& isFirst); #include "boo/graphicsdev/Vulkan.hpp" #endif -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::ApplicationXlib"); XlibCursors X_CURSORS; int XINPUT_OPCODE = 0; -static Window GetWindowOfEvent(XEvent* event, bool& windowEvent) -{ - switch (event->type) - { - case SelectionRequest: - { +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 event->xselectionrequest.owner; + return ev->event; + } + } } - 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; + } + } + windowEvent = false; + return 0; } - -std::shared_ptr _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; +std::shared_ptr _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 -{ - IApplicationCallback& m_callback; - const std::string m_uniqueName; - const std::string m_friendlyName; - const std::string m_pname; - const std::vector m_args; - GLContext m_glContext; - /* DBus single-instance */ - bool m_singleInstance; - DBusConnection* m_dbus = nullptr; +class ApplicationXlib final : public IApplication { + IApplicationCallback& m_callback; + const std::string m_uniqueName; + const std::string m_friendlyName; + const std::string m_pname; + const std::vector m_args; + GLContext m_glContext; - /* All windows */ - std::unordered_map> m_windows; + /* DBus single-instance */ + bool m_singleInstance; + DBusConnection* m_dbus = nullptr; - 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; + /* All windows */ + std::unordered_map> 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; + /* 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; + 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); + handle = dlopen(UNINSTALLED_LOADER, RTLD_LAZY); + if (!handle) + handle = dlopen(filename, RTLD_LAZY); #else - handle = dlopen(filename, RTLD_LAZY); + handle = dlopen(filename, RTLD_LAZY); #endif - if (handle) - symbol = dlsym(handle, "vkGetInstanceProcAddr"); + if (handle) + symbol = dlsym(handle, "vkGetInstanceProcAddr"); - if (!handle || !symbol) { + if (!handle || !symbol) { - if (handle) - dlclose(handle); - return false; - } - - m_vkHandle = handle; - m_getVkProc = reinterpret_cast(symbol); - return true; + if (handle) + dlclose(handle); + return false; } + + m_vkHandle = handle; + m_getVkProc = reinterpret_cast(symbol); + return true; + } #endif - - void _deletedWindow(IWindow* window) - { - m_windows.erase((Window)window->getPlatformHandle()); - } - + + void _deletedWindow(IWindow* window) { 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& 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; + ApplicationXlib(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName, + std::string_view pname, const std::vector& 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; + 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.compare("OpenGL")) - tryVulkan = false; - for (const std::string& arg : args) - { - if (!arg.compare("--gl")) - { - tryVulkan = false; - break; - } - if (!arg.compare("--vulkan")) - { - tryVulkan = true; - break; - } - } + /* Check for Vulkan presence and preference */ + bool tryVulkan = true; + if (!gfxApi.compare("OpenGL")) + tryVulkan = false; + for (const std::string& arg : args) { + if (!arg.compare("--gl")) { + tryVulkan = false; + break; + } + if (!arg.compare("--vulkan")) { + tryVulkan = true; + break; + } + } - if (tryVulkan) - loadVk(); + if (tryVulkan) + loadVk(); - if (m_getVkProc) - Log.report(logvisor::Info, "using Vulkan renderer"); - else + if (m_getVkProc) + Log.report(logvisor::Info, "using Vulkan renderer"); + else #endif - Log.report(logvisor::Info, "using OpenGL renderer"); + Log.report(logvisor::Info, "using OpenGL renderer"); - /* 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"); + /* 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); - } + /* 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_flush(m_dbus); - } + /* 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_flush(m_dbus); + } + } - if (!XInitThreads()) - { - Log.report(logvisor::Fatal, "X doesn't support multithreading"); - return; - } + if (!XInitThreads()) { + Log.report(logvisor::Fatal, "X doesn't support multithreading"); + return; + } - /* Program is portable to all locales */ - setlocale(LC_ALL, ""); + /* Program is portable to all locales */ + setlocale(LC_ALL, ""); - /* Open Xlib Display */ - m_xDisp = XOpenDisplay(0); - if (!m_xDisp) - { - Log.report(logvisor::Fatal, "Can't open X display"); - return; - } + /* Open Xlib Display */ + m_xDisp = XOpenDisplay(0); + if (!m_xDisp) { + Log.report(logvisor::Fatal, "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, "Can't cast Display to XCB connection for Vulkan"); - return; - } + /* Cast Display to XCB connection for vulkan */ + m_xcbConn = XGetXCBConnection(m_xDisp); + if (!m_xcbConn) { + Log.report(logvisor::Fatal, "Can't cast Display to XCB connection for Vulkan"); + return; + } #endif - /* Configure locale */ - if (!XSupportsLocale()) { - Log.report(logvisor::Fatal, "X does not support locale %s.", - setlocale(LC_ALL, nullptr)); - return; - } - if (XSetLocaleModifiers("") == nullptr) - Log.report(logvisor::Warning, "Cannot set locale modifiers."); + /* Configure locale */ + if (!XSupportsLocale()) { + Log.report(logvisor::Fatal, "X does not support locale %s.", setlocale(LC_ALL, nullptr)); + return; + } + if (XSetLocaleModifiers("") == nullptr) + Log.report(logvisor::Warning, "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-*-*-*-*-*-*,\ + 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); + &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 ; icount_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, "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_hArrow = XCreateFontCursor(m_xDisp, XC_sb_h_double_arrow); - X_CURSORS.m_vArrow = 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); - - /* 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); - dbus_connection_get_unix_fd(m_dbus, &m_dbusFd); - m_maxFd = MAX(m_x11Fd, m_dbusFd); - - XFlush(m_xDisp); + /* 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, "interaction style not supported."); + return; + } + XFree(im_supported_styles); } - ~ApplicationXlib() - { - for (auto& p : m_windows) - if (auto w = p.second.lock()) - w->_cleanup(); + m_xDefaultScreen = DefaultScreen(m_xDisp); + X_CURSORS.m_pointer = XCreateFontCursor(m_xDisp, XC_left_ptr); + X_CURSORS.m_hArrow = XCreateFontCursor(m_xDisp, XC_sb_h_double_arrow); + X_CURSORS.m_vArrow = 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); + + /* 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); + dbus_connection_get_unix_fd(m_dbus, &m_dbusFd); + m_maxFd = MAX(m_x11Fd, m_dbusFd); + + XFlush(m_xDisp); + } + + ~ApplicationXlib() { + for (auto& p : m_windows) + if (auto w = p.second.lock()) + w->_cleanup(); #if BOO_HAS_VULKAN - g_VulkanContext.destroyDevice(); + g_VulkanContext.destroyDevice(); #endif - if (m_fontset) - XFreeFontSet(m_xDisp, m_fontset); - if (m_xIM) - XCloseIM(m_xIM); - XCloseDisplay(m_xDisp); - } - - EPlatformType getPlatformType() const - { - return EPlatformType::Xlib; - } - - /* Empty handler for SIGINT */ - static void _sigint(int) {} + if (m_fontset) + XFreeFontSet(m_xDisp, m_fontset); + if (m_xIM) + XCloseIM(m_xIM); + XCloseDisplay(m_xDisp); + } - int run() - { - if (!m_xDisp) - return 1; + EPlatformType getPlatformType() const { return EPlatformType::Xlib; } - /* 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); + /* Empty handler for SIGINT */ + static void _sigint(int) {} - sigset_t waitmask, origmask; - sigemptyset(&waitmask); - sigaddset(&waitmask, SIGINT); - sigaddset(&waitmask, SIGUSR2); - pthread_sigmask(SIG_BLOCK, &waitmask, &origmask); + int run() { + if (!m_xDisp) + return 1; - /* Spawn client thread */ - int clientReturn = INT_MIN; - std::mutex initmt; - std::condition_variable initcv; - std::unique_lock outerLk(initmt); - std::thread clientThread([&]() - { - std::unique_lock 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); + /* 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); - /* 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, NULL, NULL, NULL, &origmask) < 0) - { - /* SIGINT/SIGUSR2 handled here */ - if (errno == EINTR) - break; - } + sigset_t waitmask, origmask; + sigemptyset(&waitmask); + sigaddset(&waitmask, SIGINT); + sigaddset(&waitmask, SIGUSR2); + pthread_sigmask(SIG_BLOCK, &waitmask, &origmask); - if (FD_ISSET(m_x11Fd, &fds)) - { - bool needsQuit = false; + /* Spawn client thread */ + int clientReturn = INT_MIN; + std::mutex initmt; + std::condition_variable initcv; + std::unique_lock outerLk(initmt); + std::thread clientThread([&]() { + std::unique_lock 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); - 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) - { - auto window = m_windows.find(evWindow); - if (window != m_windows.end()) - if (std::shared_ptr w = window->second.lock()) - if (w->_incomingEvent(&event) && m_windows.size() == 1) - { - needsQuit = true; - break; - } - } - } - XUnlockDisplay(m_xDisp); + /* 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, NULL, NULL, NULL, &origmask) < 0) { + /* SIGINT/SIGUSR2 handled here */ + if (errno == EINTR) + break; + } - if (needsQuit) - break; - } + if (FD_ISSET(m_x11Fd, &fds)) { + bool needsQuit = false; - if (FD_ISSET(m_dbusFd, &fds)) - { - DBusMessage* msg; - dbus_connection_read_write(m_dbus, 0); - while ((msg = dbus_connection_pop_message(m_dbus))) - { - /* check if the message is a signal from the correct interface and with the correct name */ - if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open")) - { - /* read the parameters */ - std::vector paths; - DBusMessageIter iter; - dbus_message_iter_init(msg, &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); - } - dbus_message_unref(msg); - } - } - } - - m_callback.appQuitting(this); - if (clientThread.joinable()) - clientThread.join(); - - return clientReturn; - } - - std::string_view getUniqueName() const - { - return m_uniqueName; - } - - std::string_view getFriendlyName() const - { - return m_friendlyName; - } - - std::string_view getProcessName() const - { - return m_pname; - } - - const std::vector& getArgs() const - { - return m_args; - } - - std::shared_ptr newWindow(std::string_view title) - { XLockDisplay(m_xDisp); -#if BOO_HAS_VULKAN - std::shared_ptr 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 newWindow = _WindowXlibNew(title, m_xDisp, nullptr, m_xDefaultScreen, m_xIM, - m_bestStyle, m_fontset, m_lastGlxCtx, nullptr, &m_glContext); -#endif - m_windows[(Window)newWindow->getPlatformHandle()] = newWindow; + while (XPending(m_xDisp)) { + XEvent event; + XNextEvent(m_xDisp, &event); + if (XFilterEvent(&event, None)) + continue; + bool windowEvent; + Window evWindow = GetWindowOfEvent(&event, windowEvent); + if (windowEvent) { + auto window = m_windows.find(evWindow); + if (window != m_windows.end()) + if (std::shared_ptr w = window->second.lock()) + if (w->_incomingEvent(&event) && m_windows.size() == 1) { + needsQuit = true; + break; + } + } + } XUnlockDisplay(m_xDisp); - return newWindow; + + if (needsQuit) + break; + } + + if (FD_ISSET(m_dbusFd, &fds)) { + DBusMessage* msg; + dbus_connection_read_write(m_dbus, 0); + while ((msg = dbus_connection_pop_message(m_dbus))) { + /* check if the message is a signal from the correct interface and with the correct name */ + if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open")) { + /* read the parameters */ + std::vector paths; + DBusMessageIter iter; + dbus_message_iter_init(msg, &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); + } + dbus_message_unref(msg); + } + } } - /* Last GLX context */ - GLXContext m_lastGlxCtx = nullptr; + m_callback.appQuitting(this); + if (clientThread.joinable()) + clientThread.join(); + + return clientReturn; + } + + std::string_view getUniqueName() const { return m_uniqueName; } + + std::string_view getFriendlyName() const { return m_friendlyName; } + + std::string_view getProcessName() const { return m_pname; } + + const std::vector& getArgs() const { return m_args; } + + std::shared_ptr newWindow(std::string_view title) { + XLockDisplay(m_xDisp); +#if BOO_HAS_VULKAN + std::shared_ptr 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 newWindow = _WindowXlibNew(title, m_xDisp, nullptr, m_xDefaultScreen, m_xIM, m_bestStyle, + m_fontset, m_lastGlxCtx, nullptr, &m_glContext); +#endif + m_windows[(Window)newWindow->getPlatformHandle()] = newWindow; + XUnlockDisplay(m_xDisp); + return newWindow; + } + + /* Last GLX context */ + GLXContext m_lastGlxCtx = nullptr; }; -void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx) -{ - static_cast(APP)->m_lastGlxCtx = lastGlxCtx; -} - -} +void _XlibUpdateLastGlxCtx(GLXContext lastGlxCtx) { static_cast(APP)->m_lastGlxCtx = lastGlxCtx; } + +} // namespace boo diff --git a/lib/x11/WindowWayland.cpp b/lib/x11/WindowWayland.cpp index bb9fca0..0110c11 100644 --- a/lib/x11/WindowWayland.cpp +++ b/lib/x11/WindowWayland.cpp @@ -5,246 +5,115 @@ #include #undef None -namespace boo -{ - -struct GraphicsContextWayland : IGraphicsContext -{ +namespace boo { - EGraphicsAPI m_api; - EPixelFormat m_pf; - IWindow* m_parentWindow; +struct GraphicsContextWayland : IGraphicsContext { + + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow) - : m_api(api), - m_pf(EPixelFormat::RGBA8), - m_parentWindow(parentWindow) - {} + GraphicsContextWayland(EGraphicsAPI api, IWindow* parentWindow) + : m_api(api), m_pf(EPixelFormat::RGBA8), m_parentWindow(parentWindow) {} - ~GraphicsContextWayland() - { + ~GraphicsContextWayland() {} - } + void _setCallback(IWindowCallback* cb) { m_callback = cb; } - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } + EGraphicsAPI getAPI() const { return m_api; } - EGraphicsAPI getAPI() const - { - return m_api; - } + EPixelFormat getPixelFormat() const { return m_pf; } - EPixelFormat getPixelFormat() const - { - return m_pf; - } + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } + bool initializeContext(void*) { return false; } - bool initializeContext(void*) - { - return false; - } + void makeCurrent() {} - void makeCurrent() - { - } + void postInit() {} - void postInit() - { - } + IGraphicsCommandQueue* getCommandQueue() { return nullptr; } - IGraphicsCommandQueue* getCommandQueue() - { - return nullptr; - } + IGraphicsDataFactory* getDataFactory() { return nullptr; } - IGraphicsDataFactory* getDataFactory() - { - return nullptr; - } + IGraphicsDataFactory* getMainContextDataFactory() { return nullptr; } - IGraphicsDataFactory* getMainContextDataFactory() - { - return nullptr; - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - return nullptr; - } - - void present() - { - } - -}; - -struct WindowWayland : IWindow -{ - GraphicsContextWayland m_gfxCtx; - - WindowWayland(std::string_view title) - : m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this) - { - - } - - ~WindowWayland() - { - - } - - void setCallback(IWindowCallback* cb) - { - - } - - void closeWindow() - { - - } - - void showWindow() - { - - } - - void hideWindow() - { - - } - - std::string getTitle() - { - return ""; - } - - void setTitle(std::string_view title) - { - - } - - void setCursor(EMouseCursor cursor) - { - } - - void setWaitCursor(bool wait) - { - } - - void setWindowFrameDefault() - { - - } - - void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const - { - - } - - void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const - { - - } - - void setWindowFrame(float x, float y, float w, float h) - { - - } - - void setWindowFrame(int x, int y, int w, int h) - { - - } - - float getVirtualPixelFactor() const - { - return 0; - } - - void setStyle(EWindowStyle /*style*/) - {} - - EWindowStyle getStyle() const - { - return EWindowStyle::None; - } - - bool isFullscreen() const - { - return false; - } - - void setFullscreen(bool fs) - { - - } - - void claimKeyboardFocus(const int coord[2]) - { - } - - bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) - { - return false; - } - - std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) - { - return std::unique_ptr(); - } - - void waitForRetrace() - { - } - - uintptr_t getPlatformHandle() const - { - return 0; - } - - ETouchType getTouchType() const - { - return ETouchType::None; - } - - - IGraphicsCommandQueue* getCommandQueue() - { - return m_gfxCtx.getCommandQueue(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_gfxCtx.getDataFactory(); - } - - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_gfxCtx.getMainContextDataFactory(); - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_gfxCtx.getLoadContextDataFactory(); - } + IGraphicsDataFactory* getLoadContextDataFactory() { return nullptr; } + void present() {} }; -std::shared_ptr _WindowWaylandNew(std::string_view title) -{ - return std::make_shared(title); -} - -} +struct WindowWayland : IWindow { + GraphicsContextWayland m_gfxCtx; + + WindowWayland(std::string_view title) : m_gfxCtx(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this) {} + + ~WindowWayland() {} + + void setCallback(IWindowCallback* cb) {} + + void closeWindow() {} + + void showWindow() {} + + void hideWindow() {} + + std::string getTitle() { return ""; } + + void setTitle(std::string_view title) {} + + void setCursor(EMouseCursor cursor) {} + + void setWaitCursor(bool wait) {} + + void setWindowFrameDefault() {} + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const {} + + void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const {} + + void setWindowFrame(float x, float y, float w, float h) {} + + void setWindowFrame(int x, int y, int w, int h) {} + + float getVirtualPixelFactor() const { return 0; } + + void setStyle(EWindowStyle /*style*/) {} + + EWindowStyle getStyle() const { return EWindowStyle::None; } + + bool isFullscreen() const { return false; } + + void setFullscreen(bool fs) {} + + void claimKeyboardFocus(const int coord[2]) {} + + bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { return false; } + + std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { return std::unique_ptr(); } + + void waitForRetrace() {} + + uintptr_t getPlatformHandle() const { return 0; } + + ETouchType getTouchType() const { return ETouchType::None; } + + IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx.getCommandQueue(); } + + IGraphicsDataFactory* getDataFactory() { return m_gfxCtx.getDataFactory(); } + + IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx.getMainContextDataFactory(); } + + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx.getLoadContextDataFactory(); } +}; + +std::shared_ptr _WindowWaylandNew(std::string_view title) { return std::make_shared(title); } + +} // namespace boo diff --git a/lib/x11/WindowXlib.cpp b/lib/x11/WindowXlib.cpp index afe281b..28186f7 100644 --- a/lib/x11/WindowXlib.cpp +++ b/lib/x11/WindowXlib.cpp @@ -37,21 +37,21 @@ #define REF_DPMM 3.78138 #define FS_ATOM "_NET_WM_STATE_FULLSCREEN" -#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) -#define MWM_DECOR_BORDER (1L<<1) -#define MWM_DECOR_RESIZEH (1L<<2) -#define MWM_DECOR_TITLE (1L<<3) -#define MWM_DECOR_MENU (1L<<4) -#define MWM_DECOR_MINIMIZE (1L<<5) -#define MWM_DECOR_MAXIMIZE (1L<<6) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) -#define MWM_FUNC_RESIZE (1L<<1) -#define MWM_FUNC_MOVE (1L<<2) -#define MWM_FUNC_MINIMIZE (1L<<3) -#define MWM_FUNC_MAXIMIZE (1L<<4) -#define MWM_FUNC_CLOSE (1L<<5) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) #undef None @@ -60,62 +60,37 @@ static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; typedef int (*glXWaitVideoSyncSGIProc)(int divisor, int remainder, unsigned int* count); static glXWaitVideoSyncSGIProc glXWaitVideoSyncSGI = 0; static bool s_glxError; -static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) -{ - s_glxError = true; - return 0; +static int ctxErrorHandler(Display* dpy, XErrorEvent* ev) { + s_glxError = true; + return 0; } -static const int ContextAttribList[7][7] = -{ -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 5, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 4, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 1, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, -{ GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 -}, +static const int ContextAttribList[7][7] = { + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 5, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 4, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 2, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, + {GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0}, }; extern "C" const uint8_t MAINICON_NETWM[]; extern "C" const size_t MAINICON_NETWM_SZ; -namespace boo -{ +namespace boo { static logvisor::Module Log("boo::WindowXlib"); std::unique_ptr _NewGLCommandQueue(IGraphicsContext* parent, GLContext* glCtx); std::unique_ptr _NewGLDataFactory(IGraphicsContext* parent, GLContext* glCtx); #if BOO_HAS_VULKAN -std::unique_ptr _NewVulkanCommandQueue(VulkanContext* ctx, - VulkanContext::Window* windowCtx, +std::unique_ptr _NewVulkanCommandQueue(VulkanContext* ctx, VulkanContext::Window* windowCtx, IGraphicsContext* parent); std::unique_ptr _NewVulkanDataFactory(IGraphicsContext* parent, VulkanContext* ctx); #endif @@ -125,1491 +100,1268 @@ void GLXEnableVSync(Display* disp, GLXWindow drawable); extern int XINPUT_OPCODE; -static std::string translateUTF8(XKeyEvent* ev, XIC xIC) -{ - char chs[512]; +static std::string translateUTF8(XKeyEvent* ev, XIC xIC) { + char chs[512]; + KeySym ks; + Status stat; + int len = Xutf8LookupString(xIC, ev, chs, 512, &ks, &stat); + if (len > 1 && (stat == XLookupChars || stat == XLookupBoth)) + return std::string(chs, len); + return std::string(); +} + +static char translateKeysym(XKeyEvent* ev, ESpecialKey& specialSym, EModifierKey& modifierSym) { + KeySym sym = XLookupKeysym(ev, 0); + + specialSym = ESpecialKey::None; + modifierSym = EModifierKey::None; + if (sym >= XK_F1 && sym <= XK_F12) + specialSym = ESpecialKey(int(ESpecialKey::F1) + sym - XK_F1); + else if (sym == XK_Escape) + specialSym = ESpecialKey::Esc; + else if (sym == XK_Return) + specialSym = ESpecialKey::Enter; + else if (sym == XK_BackSpace) + specialSym = ESpecialKey::Backspace; + else if (sym == XK_Insert) + specialSym = ESpecialKey::Insert; + else if (sym == XK_Delete) + specialSym = ESpecialKey::Delete; + else if (sym == XK_Home) + specialSym = ESpecialKey::Home; + else if (sym == XK_End) + specialSym = ESpecialKey::End; + else if (sym == XK_Page_Up) + specialSym = ESpecialKey::PgUp; + else if (sym == XK_Page_Down) + specialSym = ESpecialKey::PgDown; + else if (sym == XK_Left) + specialSym = ESpecialKey::Left; + else if (sym == XK_Right) + specialSym = ESpecialKey::Right; + else if (sym == XK_Up) + specialSym = ESpecialKey::Up; + else if (sym == XK_Down) + specialSym = ESpecialKey::Down; + else if (sym == XK_Shift_L || sym == XK_Shift_R) + modifierSym = EModifierKey::Shift; + else if (sym == XK_Control_L || sym == XK_Control_R) + modifierSym = EModifierKey::Ctrl; + else if (sym == XK_Alt_L || sym == XK_Alt_R) + modifierSym = EModifierKey::Alt; + else { + char ch = 0; KeySym ks; - Status stat; - int len = Xutf8LookupString(xIC, ev, chs, 512, &ks, &stat); - if (len > 1 && (stat == XLookupChars || stat == XLookupBoth)) - return std::string(chs, len); - return std::string(); + XLookupString(ev, (char*)&ch, 1, &ks, nullptr); + return ch; + } + return 0; } -static char translateKeysym(XKeyEvent* ev, ESpecialKey& specialSym, EModifierKey& modifierSym) -{ - KeySym sym = XLookupKeysym(ev, 0); - - specialSym = ESpecialKey::None; - modifierSym = EModifierKey::None; - if (sym >= XK_F1 && sym <= XK_F12) - specialSym = ESpecialKey(int(ESpecialKey::F1) + sym - XK_F1); - else if (sym == XK_Escape) - specialSym = ESpecialKey::Esc; - else if (sym == XK_Return) - specialSym = ESpecialKey::Enter; - else if (sym == XK_BackSpace) - specialSym = ESpecialKey::Backspace; - else if (sym == XK_Insert) - specialSym = ESpecialKey::Insert; - else if (sym == XK_Delete) - specialSym = ESpecialKey::Delete; - else if (sym == XK_Home) - specialSym = ESpecialKey::Home; - else if (sym == XK_End) - specialSym = ESpecialKey::End; - else if (sym == XK_Page_Up) - specialSym = ESpecialKey::PgUp; - else if (sym == XK_Page_Down) - specialSym = ESpecialKey::PgDown; - else if (sym == XK_Left) - specialSym = ESpecialKey::Left; - else if (sym == XK_Right) - specialSym = ESpecialKey::Right; - else if (sym == XK_Up) - specialSym = ESpecialKey::Up; - else if (sym == XK_Down) - specialSym = ESpecialKey::Down; - else if (sym == XK_Shift_L || sym == XK_Shift_R) - modifierSym = EModifierKey::Shift; - else if (sym == XK_Control_L || sym == XK_Control_R) - modifierSym = EModifierKey::Ctrl; - else if (sym == XK_Alt_L || sym == XK_Alt_R) - modifierSym = EModifierKey::Alt; - else - { - char ch = 0; - KeySym ks; - XLookupString(ev, (char*)&ch, 1, &ks, nullptr); - return ch; - } - return 0; +static EModifierKey translateModifiers(unsigned state) { + EModifierKey retval = EModifierKey::None; + if (state & ShiftMask) + retval |= EModifierKey::Shift; + if (state & ControlMask) + retval |= EModifierKey::Ctrl; + if (state & Mod1Mask) + retval |= EModifierKey::Alt; + return retval; } -static EModifierKey translateModifiers(unsigned state) -{ - EModifierKey retval = EModifierKey::None; - if (state & ShiftMask) - retval |= EModifierKey::Shift; - if (state & ControlMask) - retval |= EModifierKey::Ctrl; - if (state & Mod1Mask) - retval |= EModifierKey::Alt; - return retval; +static EMouseButton translateButton(unsigned detail) { + switch (detail) { + case 1: + return EMouseButton::Primary; + case 3: + return EMouseButton::Secondary; + case 2: + return EMouseButton::Middle; + case 8: + return EMouseButton::Aux1; + case 9: + return EMouseButton::Aux2; + default: + break; + } + return EMouseButton::None; } -static EMouseButton translateButton(unsigned detail) -{ - switch (detail) - { - case 1: - return EMouseButton::Primary; - case 3: - return EMouseButton::Secondary; - case 2: - return EMouseButton::Middle; - case 8: - return EMouseButton::Aux1; - case 9: - return EMouseButton::Aux2; - default: break; - } - return EMouseButton::None; -} - -struct XlibAtoms -{ - Atom m_wmProtocols = 0; - Atom m_wmDeleteWindow = 0; - Atom m_netSupported = 0; - Atom m_netwmIcon = 0; - Atom m_netwmIconName = 0; - Atom m_netwmState = 0; - Atom m_netwmStateFullscreen = 0; - Atom m_netwmStateAdd = 0; - Atom m_netwmStateRemove = 0; - Atom m_motifWmHints = 0; - Atom m_targets = 0; - Atom m_clipboard = 0; - Atom m_clipdata = 0; - Atom m_utf8String = 0; - Atom m_imagePng = 0; - XlibAtoms(Display* disp) - { - m_wmProtocols = XInternAtom(disp, "WM_PROTOCOLS", True); - m_wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", True); - m_netSupported = XInternAtom(disp, "_NET_SUPPORTED", True); - m_netwmIcon = XInternAtom(disp, "_NET_WM_ICON", False); - m_netwmIconName = XInternAtom(disp, "_NET_WM_ICON_NAME", False); - m_netwmState = XInternAtom(disp, "_NET_WM_STATE", False); - m_netwmStateFullscreen = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False); - m_netwmStateAdd = XInternAtom(disp, "_NET_WM_STATE_ADD", False); - m_netwmStateRemove = XInternAtom(disp, "_NET_WM_STATE_REMOVE", False); - m_motifWmHints = XInternAtom(disp, "_MOTIF_WM_HINTS", True); - m_targets = XInternAtom(disp, "TARGETS", False); - m_clipboard = XInternAtom(disp, "CLIPBOARD", False); - m_clipdata = XInternAtom(disp, "CLIPDATA", False); - m_utf8String = XInternAtom(disp, "UTF8_STRING", False); - m_imagePng = XInternAtom(disp, "image/png", False); - } +struct XlibAtoms { + Atom m_wmProtocols = 0; + Atom m_wmDeleteWindow = 0; + Atom m_netSupported = 0; + Atom m_netwmIcon = 0; + Atom m_netwmIconName = 0; + Atom m_netwmState = 0; + Atom m_netwmStateFullscreen = 0; + Atom m_netwmStateAdd = 0; + Atom m_netwmStateRemove = 0; + Atom m_motifWmHints = 0; + Atom m_targets = 0; + Atom m_clipboard = 0; + Atom m_clipdata = 0; + Atom m_utf8String = 0; + Atom m_imagePng = 0; + XlibAtoms(Display* disp) { + m_wmProtocols = XInternAtom(disp, "WM_PROTOCOLS", True); + m_wmDeleteWindow = XInternAtom(disp, "WM_DELETE_WINDOW", True); + m_netSupported = XInternAtom(disp, "_NET_SUPPORTED", True); + m_netwmIcon = XInternAtom(disp, "_NET_WM_ICON", False); + m_netwmIconName = XInternAtom(disp, "_NET_WM_ICON_NAME", False); + m_netwmState = XInternAtom(disp, "_NET_WM_STATE", False); + m_netwmStateFullscreen = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False); + m_netwmStateAdd = XInternAtom(disp, "_NET_WM_STATE_ADD", False); + m_netwmStateRemove = XInternAtom(disp, "_NET_WM_STATE_REMOVE", False); + m_motifWmHints = XInternAtom(disp, "_MOTIF_WM_HINTS", True); + m_targets = XInternAtom(disp, "TARGETS", False); + m_clipboard = XInternAtom(disp, "CLIPBOARD", False); + m_clipdata = XInternAtom(disp, "CLIPDATA", False); + m_utf8String = XInternAtom(disp, "UTF8_STRING", False); + m_imagePng = XInternAtom(disp, "image/png", False); + } }; static XlibAtoms* S_ATOMS = NULL; -static Atom GetClipboardTypeAtom(EClipboardType t) -{ - switch (t) - { - case EClipboardType::String: - return XA_STRING; - case EClipboardType::UTF8String: - return S_ATOMS->m_utf8String; - case EClipboardType::PNGImage: - return S_ATOMS->m_imagePng; - default: return 0; - } +static Atom GetClipboardTypeAtom(EClipboardType t) { + switch (t) { + case EClipboardType::String: + return XA_STRING; + case EClipboardType::UTF8String: + return S_ATOMS->m_utf8String; + case EClipboardType::PNGImage: + return S_ATOMS->m_imagePng; + default: + return 0; + } } -static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int& hOut) -{ - float width = screen->width * 2.0 / 3.0; - float height = screen->height * 2.0 / 3.0; - xOut = (screen->width - width) / 2.0; - yOut = (screen->height - height) / 2.0; - wOut = width; - hOut = height; +static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int& hOut) { + float width = screen->width * 2.0 / 3.0; + float height = screen->height * 2.0 / 3.0; + xOut = (screen->width - width) / 2.0; + yOut = (screen->height - height) / 2.0; + wOut = width; + hOut = height; } -static void genFrameDefault(XRRMonitorInfo* screen, int& xOut, int& yOut, int& wOut, int& hOut) -{ - float width = screen->width * 2.0 / 3.0; - float height = screen->height * 2.0 / 3.0; - xOut = (screen->width - width) / 2.0 + screen->x; - yOut = (screen->height - height) / 2.0 + screen->y; - wOut = width; - hOut = height; +static void genFrameDefault(XRRMonitorInfo* screen, int& xOut, int& yOut, int& wOut, int& hOut) { + float width = screen->width * 2.0 / 3.0; + float height = screen->height * 2.0 / 3.0; + xOut = (screen->width - width) / 2.0 + screen->x; + yOut = (screen->height - height) / 2.0 + screen->y; + wOut = width; + hOut = height; } -struct GraphicsContextXlib : IGraphicsContext -{ - EGraphicsAPI m_api; - EPixelFormat m_pf; - uint32_t m_drawSamples; - IWindow* m_parentWindow; - GLContext* m_glCtx; - Display* m_xDisp; +struct GraphicsContextXlib : IGraphicsContext { + EGraphicsAPI m_api; + EPixelFormat m_pf; + uint32_t m_drawSamples; + IWindow* m_parentWindow; + GLContext* m_glCtx; + Display* m_xDisp; - std::mutex m_initmt; - std::condition_variable m_initcv; - std::mutex m_vsyncmt; - std::condition_variable m_vsynccv; + std::mutex m_initmt; + std::condition_variable m_initcv; + std::mutex m_vsyncmt; + std::condition_variable m_vsynccv; - GraphicsContextXlib(EGraphicsAPI api, EPixelFormat pf, IWindow* parentWindow, Display* disp, GLContext* glCtx) - : m_api(api), - m_pf(pf), - m_parentWindow(parentWindow), - m_glCtx(glCtx), - m_xDisp(disp) {} - virtual void destroy()=0; - virtual void resized(const SWindowRect& rect)=0; + GraphicsContextXlib(EGraphicsAPI api, EPixelFormat pf, IWindow* parentWindow, Display* disp, GLContext* glCtx) + : m_api(api), m_pf(pf), m_parentWindow(parentWindow), m_glCtx(glCtx), m_xDisp(disp) {} + virtual void destroy() = 0; + virtual void resized(const SWindowRect& rect) = 0; }; - -struct GraphicsContextXlibGLX : GraphicsContextXlib -{ - GLXContext m_lastCtx = 0; - GLXFBConfig m_fbconfig = 0; - int m_visualid = 0; - int m_attribIdx = 0; - GLXWindow m_glxWindow = 0; - GLXContext m_glxCtx = 0; +struct GraphicsContextXlibGLX : GraphicsContextXlib { + GLXContext m_lastCtx = 0; - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; - GLXContext m_mainCtx = 0; - GLXContext m_loadCtx = 0; + GLXFBConfig m_fbconfig = 0; + int m_visualid = 0; + int m_attribIdx = 0; + GLXWindow m_glxWindow = 0; + GLXContext m_glxCtx = 0; - std::thread m_vsyncThread; - bool m_vsyncRunning; + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; + GLXContext m_mainCtx = 0; + GLXContext m_loadCtx = 0; + + std::thread m_vsyncThread; + bool m_vsyncRunning; public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextXlibGLX(EGraphicsAPI api, IWindow* parentWindow, - Display* display, int defaultScreen, - GLXContext lastCtx, uint32_t& visualIdOut, GLContext* glCtx) - : GraphicsContextXlib(api, glCtx->m_deepColor ? EPixelFormat::RGBA16 : EPixelFormat::RGBA8, - parentWindow, display, glCtx), m_lastCtx(lastCtx) - { - m_dataFactory = _NewGLDataFactory(this, m_glCtx); + GraphicsContextXlibGLX(EGraphicsAPI api, IWindow* parentWindow, Display* display, int defaultScreen, + GLXContext lastCtx, uint32_t& visualIdOut, GLContext* glCtx) + : GraphicsContextXlib(api, glCtx->m_deepColor ? EPixelFormat::RGBA16 : EPixelFormat::RGBA8, parentWindow, display, + glCtx) + , m_lastCtx(lastCtx) { + m_dataFactory = _NewGLDataFactory(this, m_glCtx); - /* Query framebuffer configurations */ - GLXFBConfig* fbConfigs = nullptr; - int numFBConfigs = 0; - fbConfigs = glXGetFBConfigs(display, defaultScreen, &numFBConfigs); - if (!fbConfigs || numFBConfigs == 0) - { - Log.report(logvisor::Fatal, "glXGetFBConfigs failed"); - return; + /* Query framebuffer configurations */ + GLXFBConfig* fbConfigs = nullptr; + int numFBConfigs = 0; + fbConfigs = glXGetFBConfigs(display, defaultScreen, &numFBConfigs); + if (!fbConfigs || numFBConfigs == 0) { + Log.report(logvisor::Fatal, "glXGetFBConfigs failed"); + return; + } + + for (int i = 0; i < numFBConfigs; ++i) { + GLXFBConfig config = fbConfigs[i]; + int visualId, depthSize, colorSize, doubleBuffer; + glXGetFBConfigAttrib(display, config, GLX_VISUAL_ID, &visualId); + glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); + glXGetFBConfigAttrib(display, config, GLX_BUFFER_SIZE, &colorSize); + glXGetFBConfigAttrib(display, config, GLX_DOUBLEBUFFER, &doubleBuffer); + + /* Double-buffer only */ + if (!doubleBuffer || !visualId) + continue; + + if (m_pf == EPixelFormat::RGBA8 && colorSize >= 32) { + m_fbconfig = config; + m_visualid = visualId; + break; + } else if (m_pf == EPixelFormat::RGBA16) { + if (colorSize >= 64) { + m_fbconfig = config; + m_visualid = visualId; + break; + } else if (!m_visualid && colorSize >= 32) { + m_fbconfig = config; + m_visualid = visualId; } + } else if (m_pf == EPixelFormat::RGBA8_Z24 && colorSize >= 32 && depthSize >= 24) { + m_fbconfig = config; + m_visualid = visualId; + break; + } else if (m_pf == EPixelFormat::RGBAF32 && colorSize >= 128) { + m_fbconfig = config; + m_visualid = visualId; + break; + } else if (m_pf == EPixelFormat::RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24) { + m_fbconfig = config; + m_visualid = visualId; + break; + } + } + XFree(fbConfigs); - for (int i=0 ; i EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } + + bool initializeContext(void*) { + if (!glXCreateContextAttribsARB) { + glXCreateContextAttribsARB = + (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); + if (!glXCreateContextAttribsARB) + Log.report(logvisor::Fatal, "unable to resolve glXCreateContextAttribsARB"); + } + if (!glXWaitVideoSyncSGI) { + glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc)glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI"); + if (!glXWaitVideoSyncSGI) + Log.report(logvisor::Fatal, "unable to resolve glXWaitVideoSyncSGI"); + } + + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); + for (m_attribIdx = 0; m_attribIdx < std::extent::value; ++m_attribIdx) { + m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribList[m_attribIdx]); + if (m_glxCtx) + break; + } + XSetErrorHandler(oldHandler); + if (!m_glxCtx) + Log.report(logvisor::Fatal, "unable to make new GLX context"); + m_glxWindow = glXCreateWindow(m_xDisp, m_fbconfig, m_parentWindow->getPlatformHandle(), nullptr); + if (!m_glxWindow) + Log.report(logvisor::Fatal, "unable to make new GLX window"); + _XlibUpdateLastGlxCtx(m_glxCtx); + + if (!glXMakeCurrent(m_xDisp, DefaultRootWindow(m_xDisp), m_glxCtx)) + Log.report(logvisor::Fatal, "unable to make GLX context current"); + if (glewInit() != GLEW_OK) + Log.report(logvisor::Fatal, "glewInit failed"); + glXMakeCurrent(m_xDisp, 0, 0); + + /* Spawn vsync thread */ + m_vsyncRunning = true; + std::unique_lock outerLk(m_initmt); + m_vsyncThread = std::thread([&]() { + Display* vsyncDisp; + GLXContext vsyncCtx; + { + std::unique_lock innerLk(m_initmt); + + vsyncDisp = XOpenDisplay(0); + if (!vsyncDisp) + Log.report(logvisor::Fatal, "unable to open new vsync display"); + XLockDisplay(vsyncDisp); + + static int attributeList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, + 0}; + XVisualInfo* vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp), attributeList); + + vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True); + if (!vsyncCtx) + Log.report(logvisor::Fatal, "unable to make new vsync GLX context"); + + if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx)) + Log.report(logvisor::Fatal, "unable to make vsync context current"); + } + m_initcv.notify_one(); + + while (m_vsyncRunning) { { - GLXFBConfig config = fbConfigs[i]; - int visualId, depthSize, colorSize, doubleBuffer; - glXGetFBConfigAttrib(display, config, GLX_VISUAL_ID, &visualId); - glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); - glXGetFBConfigAttrib(display, config, GLX_BUFFER_SIZE, &colorSize); - glXGetFBConfigAttrib(display, config, GLX_DOUBLEBUFFER, &doubleBuffer); - - /* Double-buffer only */ - if (!doubleBuffer || !visualId) - continue; - - if (m_pf == EPixelFormat::RGBA8 && colorSize >= 32) - { - m_fbconfig = config; - m_visualid = visualId; - break; - } - else if (m_pf == EPixelFormat::RGBA16) - { - if (colorSize >= 64) - { - m_fbconfig = config; - m_visualid = visualId; - break; - } - else if (!m_visualid && colorSize >= 32) - { - m_fbconfig = config; - m_visualid = visualId; - } - } - else if (m_pf == EPixelFormat::RGBA8_Z24 && colorSize >= 32 && depthSize >= 24) - { - m_fbconfig = config; - m_visualid = visualId; - break; - } - else if (m_pf == EPixelFormat::RGBAF32 && colorSize >= 128) - { - m_fbconfig = config; - m_visualid = visualId; - break; - } - else if (m_pf == EPixelFormat::RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24) - { - m_fbconfig = config; - m_visualid = visualId; - break; - } + unsigned int sync; + int err = glXWaitVideoSyncSGI(1, 0, &sync); + if (err) + Log.report(logvisor::Fatal, "wait err"); } - XFree(fbConfigs); + m_vsynccv.notify_one(); + } - if (!m_fbconfig) - { - Log.report(logvisor::Fatal, "unable to find suitable pixel format"); - return; - } + glXMakeCurrent(vsyncDisp, 0, nullptr); + glXDestroyContext(vsyncDisp, vsyncCtx); + XUnlockDisplay(vsyncDisp); + XCloseDisplay(vsyncDisp); + }); + m_initcv.wait(outerLk); - visualIdOut = m_visualid; + XUnlockDisplay(m_xDisp); + m_commandQueue = _NewGLCommandQueue(this, m_glCtx); + m_commandQueue->startRenderer(); + XLockDisplay(m_xDisp); + + return true; + } + + void makeCurrent() { + XLockDisplay(m_xDisp); + if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_glxCtx)) + Log.report(logvisor::Fatal, "unable to make GLX context current"); + XUnlockDisplay(m_xDisp); + } + + void postInit() { + GLXExtensionCheck(); + XLockDisplay(m_xDisp); + GLXEnableVSync(m_xDisp, m_glxWindow); + XUnlockDisplay(m_xDisp); + } + + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } + + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } + + IGraphicsDataFactory* getMainContextDataFactory() { + XLockDisplay(m_xDisp); + if (!m_mainCtx) { + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); + m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]); + XSetErrorHandler(oldHandler); + if (!m_mainCtx) + Log.report(logvisor::Fatal, "unable to make main GLX context"); } + if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_mainCtx)) + Log.report(logvisor::Fatal, "unable to make main GLX context current"); + XUnlockDisplay(m_xDisp); + return getDataFactory(); + } - void destroy() - { - if (m_glxCtx) - { - glXDestroyContext(m_xDisp, m_glxCtx); - m_glxCtx = nullptr; - } - if (m_glxWindow) - { - glXDestroyWindow(m_xDisp, m_glxWindow); - m_glxWindow = 0; - } - if (m_loadCtx) - { - glXDestroyContext(m_xDisp, m_loadCtx); - m_loadCtx = nullptr; - } - if (m_vsyncRunning) - { - m_vsyncRunning = false; - m_vsyncThread.join(); - } + IGraphicsDataFactory* getLoadContextDataFactory() { + XLockDisplay(m_xDisp); + if (!m_loadCtx) { + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); + m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]); + XSetErrorHandler(oldHandler); + if (!m_loadCtx) + Log.report(logvisor::Fatal, "unable to make load GLX context"); } + if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_loadCtx)) + Log.report(logvisor::Fatal, "unable to make load GLX context current"); + XUnlockDisplay(m_xDisp); + return getDataFactory(); + } - ~GraphicsContextXlibGLX() {destroy();} - - void resized(const SWindowRect& rect) - { - } - - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } - - EGraphicsAPI getAPI() const - { - return m_api; - } - - EPixelFormat getPixelFormat() const - { - return m_pf; - } - - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } - - bool initializeContext(void*) - { - if (!glXCreateContextAttribsARB) - { - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) - glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); - if (!glXCreateContextAttribsARB) - Log.report(logvisor::Fatal, "unable to resolve glXCreateContextAttribsARB"); - } - if (!glXWaitVideoSyncSGI) - { - glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc) - glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI"); - if (!glXWaitVideoSyncSGI) - Log.report(logvisor::Fatal, "unable to resolve glXWaitVideoSyncSGI"); - } - - s_glxError = false; - XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); - for (m_attribIdx=0 ; m_attribIdx::value ; ++m_attribIdx) - { - m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribList[m_attribIdx]); - if (m_glxCtx) - break; - } - XSetErrorHandler(oldHandler); - if (!m_glxCtx) - Log.report(logvisor::Fatal, "unable to make new GLX context"); - m_glxWindow = glXCreateWindow(m_xDisp, m_fbconfig, m_parentWindow->getPlatformHandle(), nullptr); - if (!m_glxWindow) - Log.report(logvisor::Fatal, "unable to make new GLX window"); - _XlibUpdateLastGlxCtx(m_glxCtx); - - if (!glXMakeCurrent(m_xDisp, DefaultRootWindow(m_xDisp), m_glxCtx)) - Log.report(logvisor::Fatal, "unable to make GLX context current"); - if (glewInit() != GLEW_OK) - Log.report(logvisor::Fatal, "glewInit failed"); - glXMakeCurrent(m_xDisp, 0, 0); - - /* Spawn vsync thread */ - m_vsyncRunning = true; - std::unique_lock outerLk(m_initmt); - m_vsyncThread = std::thread([&]() - { - Display* vsyncDisp; - GLXContext vsyncCtx; - { - std::unique_lock innerLk(m_initmt); - - vsyncDisp = XOpenDisplay(0); - if (!vsyncDisp) - Log.report(logvisor::Fatal, "unable to open new vsync display"); - XLockDisplay(vsyncDisp); - - static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, 0 }; - XVisualInfo *vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp), attributeList); - - vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True); - if (!vsyncCtx) - Log.report(logvisor::Fatal, "unable to make new vsync GLX context"); - - if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx)) - Log.report(logvisor::Fatal, "unable to make vsync context current"); - } - m_initcv.notify_one(); - - while (m_vsyncRunning) - { - { - unsigned int sync; - int err = glXWaitVideoSyncSGI(1, 0, &sync); - if (err) - Log.report(logvisor::Fatal, "wait err"); - } - m_vsynccv.notify_one(); - } - - glXMakeCurrent(vsyncDisp, 0, nullptr); - glXDestroyContext(vsyncDisp, vsyncCtx); - XUnlockDisplay(vsyncDisp); - XCloseDisplay(vsyncDisp); - }); - m_initcv.wait(outerLk); - - XUnlockDisplay(m_xDisp); - m_commandQueue = _NewGLCommandQueue(this, m_glCtx); - m_commandQueue->startRenderer(); - XLockDisplay(m_xDisp); - - return true; - } - - void makeCurrent() - { - XLockDisplay(m_xDisp); - if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_glxCtx)) - Log.report(logvisor::Fatal, "unable to make GLX context current"); - XUnlockDisplay(m_xDisp); - } - - void postInit() - { - GLXExtensionCheck(); - XLockDisplay(m_xDisp); - GLXEnableVSync(m_xDisp, m_glxWindow); - XUnlockDisplay(m_xDisp); - } - - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue.get(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory.get(); - } - - IGraphicsDataFactory* getMainContextDataFactory() - { - XLockDisplay(m_xDisp); - if (!m_mainCtx) - { - s_glxError = false; - XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); - m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]); - XSetErrorHandler(oldHandler); - if (!m_mainCtx) - Log.report(logvisor::Fatal, "unable to make main GLX context"); - } - if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_mainCtx)) - Log.report(logvisor::Fatal, "unable to make main GLX context current"); - XUnlockDisplay(m_xDisp); - return getDataFactory(); - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - XLockDisplay(m_xDisp); - if (!m_loadCtx) - { - s_glxError = false; - XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler); - m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]); - XSetErrorHandler(oldHandler); - if (!m_loadCtx) - Log.report(logvisor::Fatal, "unable to make load GLX context"); - } - if (!glXMakeContextCurrent(m_xDisp, m_glxWindow, m_glxWindow, m_loadCtx)) - Log.report(logvisor::Fatal, "unable to make load GLX context current"); - XUnlockDisplay(m_xDisp); - return getDataFactory(); - } - - void present() - { glXSwapBuffers(m_xDisp, m_glxWindow); } - + void present() { glXSwapBuffers(m_xDisp, m_glxWindow); } }; #if BOO_HAS_VULKAN -struct GraphicsContextXlibVulkan : GraphicsContextXlib -{ - xcb_connection_t* m_xcbConn; - VulkanContext* m_ctx; - VkSurfaceKHR m_surface = VK_NULL_HANDLE; - VkFormat m_format = VK_FORMAT_UNDEFINED; - VkColorSpaceKHR m_colorspace; +struct GraphicsContextXlibVulkan : GraphicsContextXlib { + xcb_connection_t* m_xcbConn; + VulkanContext* m_ctx; + VkSurfaceKHR m_surface = VK_NULL_HANDLE; + VkFormat m_format = VK_FORMAT_UNDEFINED; + VkColorSpaceKHR m_colorspace; - GLXFBConfig m_fbconfig = 0; - int m_visualid = 0; + GLXFBConfig m_fbconfig = 0; + int m_visualid = 0; - std::unique_ptr m_dataFactory; - std::unique_ptr m_commandQueue; + std::unique_ptr m_dataFactory; + std::unique_ptr m_commandQueue; - std::thread m_vsyncThread; - std::atomic_bool m_vsyncRunning; + std::thread m_vsyncThread; + std::atomic_bool m_vsyncRunning; - static void ThrowIfFailed(VkResult res) - { - if (res != VK_SUCCESS) - Log.report(logvisor::Fatal, "%d\n", res); - } + static void ThrowIfFailed(VkResult res) { + if (res != VK_SUCCESS) + Log.report(logvisor::Fatal, "%d\n", res); + } public: - IWindowCallback* m_callback; + IWindowCallback* m_callback; - GraphicsContextXlibVulkan(IWindow* parentWindow, - Display* display, xcb_connection_t* xcbConn, int defaultScreen, - VulkanContext* ctx, uint32_t& visualIdOut, GLContext* glCtx) - : GraphicsContextXlib(EGraphicsAPI::Vulkan, ctx->m_deepColor ? EPixelFormat::RGBA16 : EPixelFormat::RGBA8, - parentWindow, display, glCtx), - m_xcbConn(xcbConn), m_ctx(ctx) - { - Screen* screen = ScreenOfDisplay(display, defaultScreen); - m_visualid = screen->root_visual->visualid; - visualIdOut = screen->root_visual->visualid; + GraphicsContextXlibVulkan(IWindow* parentWindow, Display* display, xcb_connection_t* xcbConn, int defaultScreen, + VulkanContext* ctx, uint32_t& visualIdOut, GLContext* glCtx) + : GraphicsContextXlib(EGraphicsAPI::Vulkan, ctx->m_deepColor ? EPixelFormat::RGBA16 : EPixelFormat::RGBA8, + parentWindow, display, glCtx) + , m_xcbConn(xcbConn) + , m_ctx(ctx) { + Screen* screen = ScreenOfDisplay(display, defaultScreen); + m_visualid = screen->root_visual->visualid; + visualIdOut = screen->root_visual->visualid; + } + + void destroy() { + VulkanContext::Window& m_windowCtx = *m_ctx->m_windows[m_parentWindow]; + m_windowCtx.m_swapChains[0].destroy(m_ctx->m_dev); + m_windowCtx.m_swapChains[1].destroy(m_ctx->m_dev); + if (m_surface) { + vk::DestroySurfaceKHR(m_ctx->m_instance, m_surface, nullptr); + m_surface = VK_NULL_HANDLE; } - void destroy() - { - VulkanContext::Window& m_windowCtx = *m_ctx->m_windows[m_parentWindow]; - m_windowCtx.m_swapChains[0].destroy(m_ctx->m_dev); - m_windowCtx.m_swapChains[1].destroy(m_ctx->m_dev); - if (m_surface) - { - vk::DestroySurfaceKHR(m_ctx->m_instance, m_surface, nullptr); - m_surface = VK_NULL_HANDLE; + if (m_vsyncRunning.load()) { + m_vsyncRunning.store(false); + if (m_vsyncThread.joinable()) + m_vsyncThread.join(); + } + } + + ~GraphicsContextXlibVulkan() { destroy(); } + + VulkanContext::Window* m_windowCtx = nullptr; + + void resized(const SWindowRect& rect) { + if (m_windowCtx) + m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect); + } + + void _setCallback(IWindowCallback* cb) { m_callback = cb; } + + EGraphicsAPI getAPI() const { return m_api; } + + EPixelFormat getPixelFormat() const { return m_pf; } + + void setPixelFormat(EPixelFormat pf) { + if (pf > EPixelFormat::RGBAF32_Z24) + return; + m_pf = pf; + } + + bool initializeContext(void* getVkProc) { + if (!glXWaitVideoSyncSGI) { + glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc)glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI"); + if (!glXWaitVideoSyncSGI) + Log.report(logvisor::Fatal, "unable to resolve glXWaitVideoSyncSGI"); + } + + if (m_ctx->m_instance == VK_NULL_HANDLE) + m_ctx->initVulkan(APP->getUniqueName(), PFN_vkGetInstanceProcAddr(getVkProc)); + + if (!m_ctx->enumerateDevices()) + return false; + + m_windowCtx = m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, std::make_unique())) + .first->second.get(); + + VkXcbSurfaceCreateInfoKHR surfaceInfo = {}; + surfaceInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + surfaceInfo.connection = m_xcbConn; + surfaceInfo.window = m_parentWindow->getPlatformHandle(); + ThrowIfFailed(vk::CreateXcbSurfaceKHR(m_ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); + + /* Iterate over each queue to learn whether it supports presenting */ + VkBool32* supportsPresent = (VkBool32*)malloc(m_ctx->m_queueCount * sizeof(VkBool32)); + for (uint32_t i = 0; i < m_ctx->m_queueCount; ++i) + vk::GetPhysicalDeviceSurfaceSupportKHR(m_ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); + + /* Search for a graphics queue and a present queue in the array of queue + * families, try to find one that supports both */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) { + /* First window, init device */ + for (uint32_t i = 0; i < m_ctx->m_queueCount; ++i) { + if ((m_ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { + if (supportsPresent[i] == VK_TRUE) { + m_ctx->m_graphicsQueueFamilyIndex = i; + } } + } - if (m_vsyncRunning.load()) - { - m_vsyncRunning.store(false); - if (m_vsyncThread.joinable()) - m_vsyncThread.join(); - } + /* Generate error if could not find a queue that supports both a graphics + * and present */ + if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) + Log.report(logvisor::Fatal, "Could not find a queue that supports both graphics and present"); + + m_ctx->initDevice(); + } else { + /* Subsequent window, verify present */ + if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) + Log.report(logvisor::Fatal, "subsequent surface doesn't support present"); + } + free(supportsPresent); + + if (!vk::GetPhysicalDeviceXcbPresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex, m_xcbConn, + m_visualid)) { + Log.report(logvisor::Fatal, "XCB visual doesn't support vulkan present"); + return false; } - ~GraphicsContextXlibVulkan() {destroy();} + /* Get the list of VkFormats that are supported */ + uint32_t formatCount; + ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, nullptr)); + std::vector surfFormats(formatCount); + ThrowIfFailed( + vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, surfFormats.data())); - VulkanContext::Window* m_windowCtx = nullptr; - - void resized(const SWindowRect& rect) - { - if (m_windowCtx) - m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect); - } - - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } - - EGraphicsAPI getAPI() const - { - return m_api; - } - - EPixelFormat getPixelFormat() const - { - return m_pf; - } - - void setPixelFormat(EPixelFormat pf) - { - if (pf > EPixelFormat::RGBAF32_Z24) - return; - m_pf = pf; - } - - bool initializeContext(void* getVkProc) - { - if (!glXWaitVideoSyncSGI) - { - glXWaitVideoSyncSGI = (glXWaitVideoSyncSGIProc) - glXGetProcAddressARB((const GLubyte*)"glXWaitVideoSyncSGI"); - if (!glXWaitVideoSyncSGI) - Log.report(logvisor::Fatal, "unable to resolve glXWaitVideoSyncSGI"); - } - - if (m_ctx->m_instance == VK_NULL_HANDLE) - m_ctx->initVulkan(APP->getUniqueName(), PFN_vkGetInstanceProcAddr(getVkProc)); - - if (!m_ctx->enumerateDevices()) - return false; - - m_windowCtx = - m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, - std::make_unique())).first->second.get(); - - VkXcbSurfaceCreateInfoKHR surfaceInfo = {}; - surfaceInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - surfaceInfo.connection = m_xcbConn; - surfaceInfo.window = m_parentWindow->getPlatformHandle(); - ThrowIfFailed(vk::CreateXcbSurfaceKHR(m_ctx->m_instance, &surfaceInfo, nullptr, &m_surface)); - - /* Iterate over each queue to learn whether it supports presenting */ - VkBool32 *supportsPresent = (VkBool32*)malloc(m_ctx->m_queueCount * sizeof(VkBool32)); - for (uint32_t i=0 ; im_queueCount ; ++i) - vk::GetPhysicalDeviceSurfaceSupportKHR(m_ctx->m_gpus[0], i, m_surface, &supportsPresent[i]); - - /* Search for a graphics queue and a present queue in the array of queue - * families, try to find one that supports both */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - { - /* First window, init device */ - for (uint32_t i=0 ; im_queueCount; ++i) - { - if ((m_ctx->m_queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) - { - if (supportsPresent[i] == VK_TRUE) - { - m_ctx->m_graphicsQueueFamilyIndex = i; - } - } - } - - /* Generate error if could not find a queue that supports both a graphics - * and present */ - if (m_ctx->m_graphicsQueueFamilyIndex == UINT32_MAX) - Log.report(logvisor::Fatal, - "Could not find a queue that supports both graphics and present"); - - m_ctx->initDevice(); - } - else - { - /* Subsequent window, verify present */ - if (supportsPresent[m_ctx->m_graphicsQueueFamilyIndex] == VK_FALSE) - Log.report(logvisor::Fatal, "subsequent surface doesn't support present"); - } - free(supportsPresent); - - if (!vk::GetPhysicalDeviceXcbPresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex, m_xcbConn, m_visualid)) - { - Log.report(logvisor::Fatal, "XCB visual doesn't support vulkan present"); - return false; - } - - /* Get the list of VkFormats that are supported */ - uint32_t formatCount; - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, nullptr)); - std::vector surfFormats(formatCount); - ThrowIfFailed(vk::GetPhysicalDeviceSurfaceFormatsKHR(m_ctx->m_gpus[0], m_surface, &formatCount, surfFormats.data())); - - - /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, - * the surface has no preferred format. Otherwise, at least one - * supported format will be returned. */ - if (formatCount >= 1) - { - if (m_ctx->m_deepColor) - { - for (int i=0 ; iinitSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); - - /* Spawn vsync thread */ - m_vsyncRunning.store(true); - std::unique_lock outerLk(m_initmt); - m_vsyncThread = std::thread([&]() - { - logvisor::RegisterThreadName("Boo VSync"); - Display* vsyncDisp; - GLXContext vsyncCtx; - { - std::unique_lock innerLk(m_initmt); - - vsyncDisp = XOpenDisplay(0); - if (!vsyncDisp) - Log.report(logvisor::Fatal, "unable to open new vsync display"); - XLockDisplay(vsyncDisp); - - static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, 0 }; - XVisualInfo *vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp), attributeList); - - vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True); - if (!vsyncCtx) - Log.report(logvisor::Fatal, "unable to make new vsync GLX context"); - - if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx)) - Log.report(logvisor::Fatal, "unable to make vsync context current"); - } - m_initcv.notify_one(); - - while (m_vsyncRunning.load()) - { - unsigned int sync; - int err = glXWaitVideoSyncSGI(1, 0, &sync); - if (err) - Log.report(logvisor::Fatal, "wait err"); - m_vsynccv.notify_one(); - } - - glXMakeCurrent(vsyncDisp, 0, nullptr); - glXDestroyContext(vsyncDisp, vsyncCtx); - XUnlockDisplay(vsyncDisp); - XCloseDisplay(vsyncDisp); - }); - m_initcv.wait(outerLk); - - m_dataFactory = _NewVulkanDataFactory(this, m_ctx); - m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); - m_commandQueue->startRenderer(); - - return true; - } - - void makeCurrent() {} - - void postInit() {} - - IGraphicsCommandQueue* getCommandQueue() - { - return m_commandQueue.get(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_dataFactory.get(); - } - - IGraphicsDataFactory* getMainContextDataFactory() - { - return getDataFactory(); - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - return getDataFactory(); - } - - void present() {} - -}; -#endif - -class WindowXlib : public IWindow -{ - Display* m_xDisp; - IWindowCallback* m_callback; - Colormap m_colormapId; - Window m_windowId; - XIMStyle m_bestStyle; - XIC m_xIC = nullptr; - std::unique_ptr m_gfxCtx; - uint32_t m_visualId; - - /* Key state trackers (for auto-repeat detection) */ - std::unordered_set m_charKeys; - std::unordered_set m_specialKeys; - std::unordered_set m_modKeys; - - - /* Last known input device id (0xffff if not yet set) */ - int m_lastInputID = 0xffff; - ETouchType m_touchType = ETouchType::None; - - /* Scroll valuators */ - int m_hScrollValuator = -1; - int m_vScrollValuator = -1; - double m_hScrollLast = 0.0; - double m_vScrollLast = 0.0; - - /* Cached window rectangle (to avoid repeated X queries) */ - boo::SWindowRect m_wrect; - float m_pixelFactor; - bool m_inFs = false; - - /* Cached window style */ - EWindowStyle m_styleFlags; - - /* Current cursor enum */ - EMouseCursor m_cursor = EMouseCursor::None; - bool m_cursorWait = false; - static Cursor GetXCursor(EMouseCursor cur) - { - switch (cur) - { - case EMouseCursor::Pointer: - return X_CURSORS.m_pointer; - case EMouseCursor::HorizontalArrow: - return X_CURSORS.m_hArrow; - case EMouseCursor::VerticalArrow: - return X_CURSORS.m_vArrow; - case EMouseCursor::IBeam: - return X_CURSORS.m_ibeam; - case EMouseCursor::Crosshairs: - return X_CURSORS.m_crosshairs; - default: break; - } - return X_CURSORS.m_pointer; - } - - bool m_openGL = false; - -public: - WindowXlib(std::string_view title, - Display* display, void* xcbConn, - int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, void* vulkanHandle, GLContext* glCtx) - : m_xDisp(display), m_callback(nullptr), - m_bestStyle(bestInputStyle) - { - if (!S_ATOMS) - S_ATOMS = new XlibAtoms(display); - - for (int i = 1; i >= 0 ; --i) - { -#if BOO_HAS_VULKAN - if (vulkanHandle && i == 1) - { - m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen, - &g_VulkanContext, m_visualId, glCtx)); - } - else -#endif - { - i = 0; - m_gfxCtx.reset(new GraphicsContextXlibGLX(IGraphicsContext::EGraphicsAPI::OpenGL3_3, - this, display, defaultScreen, lastCtx, m_visualId, glCtx)); - m_openGL = true; - } - - XVisualInfo visTemplate; - visTemplate.screen = defaultScreen; - int numVisuals; - XVisualInfo* visualList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &numVisuals); - Visual* selectedVisual = nullptr; - for (int i=0 ; iroot, selectedVisual, AllocNone); - - /* Create window */ - int x, y, w, h; - int nmonitors = 0; - XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors); - if (nmonitors) - { - genFrameDefault(mInfo, x, y, w, h); - m_pixelFactor = mInfo->width / (float)mInfo->mwidth / REF_DPMM; - } - else - { - genFrameDefault(screen, x, y, w, h); - m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM; - } - XRRFreeMonitors(mInfo); - XSetWindowAttributes swa; - swa.colormap = m_colormapId; - swa.border_pixmap = 0; - swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask; - - m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10, - CopyFromParent, CopyFromParent, selectedVisual, - CWBorderPixel | CWEventMask | CWColormap, &swa); - - /* - * Now go create an IC using the style we chose. - * Also set the window and fontset attributes now. - */ - if (xIM) - { - XPoint pt = {0,0}; - XVaNestedList nlist; - m_xIC = XCreateIC(xIM, XNInputStyle, bestInputStyle, - XNClientWindow, m_windowId, - XNFocusWindow, m_windowId, - XNPreeditAttributes, nlist = XVaCreateNestedList(0, - XNSpotLocation, &pt, - XNFontSet, fontset, - nullptr), - nullptr); - XFree(nlist); - long im_event_mask; - XGetICValues(m_xIC, XNFilterEvents, &im_event_mask, nullptr); - XSelectInput(display, m_windowId, swa.event_mask | im_event_mask); - XSetICFocus(m_xIC); - } - - /* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */ - XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)}; - mask.mask = (unsigned char*)malloc(mask.mask_len); - memset(mask.mask, 0, mask.mask_len); - /* XISetMask(mask.mask, XI_Motion); Can't do this without losing mouse move events :( */ - XISetMask(mask.mask, XI_TouchBegin); - XISetMask(mask.mask, XI_TouchUpdate); - XISetMask(mask.mask, XI_TouchEnd); - XISelectEvents(m_xDisp, m_windowId, &mask, 1); - free(mask.mask); - - - /* Register netwm extension atom for window closing */ - XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1); - - /* Set the title of the window */ - const unsigned char* c_title = (unsigned char*)title.data(); - XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length()); - - /* Set the title of the window icon */ - XChangeProperty(m_xDisp, m_windowId, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length()); - - /* Add window icon */ - if (MAINICON_NETWM_SZ && S_ATOMS->m_netwmIcon) - { - XChangeProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmIcon, XA_CARDINAL, - 32, PropModeReplace, MAINICON_NETWM, MAINICON_NETWM_SZ / sizeof(unsigned long)); - } - - /* Initialize context */ - XMapWindow(m_xDisp, m_windowId); - setStyle(EWindowStyle::Default); - setCursor(EMouseCursor::Pointer); - setWindowFrameDefault(); - XFlush(m_xDisp); - - if (!m_gfxCtx->initializeContext(vulkanHandle)) - { - XUnmapWindow(m_xDisp, m_windowId); - XDestroyWindow(m_xDisp, m_windowId); - XFreeColormap(m_xDisp, m_colormapId); - continue; - } + /* If the format list includes just one entry of VK_FORMAT_UNDEFINED, + * the surface has no preferred format. Otherwise, at least one + * supported format will be returned. */ + if (formatCount >= 1) { + if (m_ctx->m_deepColor) { + for (int i = 0; i < formatCount; ++i) { + if (surfFormats[i].format == VK_FORMAT_R16G16B16A16_UNORM) { + m_format = surfFormats[i].format; + m_colorspace = surfFormats[i].colorSpace; break; + } } - } - - ~WindowXlib() - { - _cleanup(); - if (APP) - APP->_deletedWindow(this); - } - - void setCallback(IWindowCallback* cb) - { - XLockDisplay(m_xDisp); - m_callback = cb; - XUnlockDisplay(m_xDisp); - } + } + if (m_format == VK_FORMAT_UNDEFINED) { + for (int i = 0; i < formatCount; ++i) { + if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) { + m_format = surfFormats[i].format; + m_colorspace = surfFormats[i].colorSpace; + break; + } + } + } + } else + Log.report(logvisor::Fatal, "no surface formats available for Vulkan swapchain"); - void closeWindow() - { - // TODO: Free window resources and prevent further access - XLockDisplay(m_xDisp); + if (m_format == VK_FORMAT_UNDEFINED) + Log.report(logvisor::Fatal, "no UNORM formats available for Vulkan swapchain"); + + m_ctx->initSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); + + /* Spawn vsync thread */ + m_vsyncRunning.store(true); + std::unique_lock outerLk(m_initmt); + m_vsyncThread = std::thread([&]() { + logvisor::RegisterThreadName("Boo VSync"); + Display* vsyncDisp; + GLXContext vsyncCtx; + { + std::unique_lock innerLk(m_initmt); + + vsyncDisp = XOpenDisplay(0); + if (!vsyncDisp) + Log.report(logvisor::Fatal, "unable to open new vsync display"); + XLockDisplay(vsyncDisp); + + static int attributeList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, + 0}; + XVisualInfo* vi = glXChooseVisual(vsyncDisp, DefaultScreen(vsyncDisp), attributeList); + + vsyncCtx = glXCreateContext(vsyncDisp, vi, nullptr, True); + if (!vsyncCtx) + Log.report(logvisor::Fatal, "unable to make new vsync GLX context"); + + if (!glXMakeCurrent(vsyncDisp, DefaultRootWindow(vsyncDisp), vsyncCtx)) + Log.report(logvisor::Fatal, "unable to make vsync context current"); + } + m_initcv.notify_one(); + + while (m_vsyncRunning.load()) { + unsigned int sync; + int err = glXWaitVideoSyncSGI(1, 0, &sync); + if (err) + Log.report(logvisor::Fatal, "wait err"); + m_vsynccv.notify_one(); + } + + glXMakeCurrent(vsyncDisp, 0, nullptr); + glXDestroyContext(vsyncDisp, vsyncCtx); + XUnlockDisplay(vsyncDisp); + XCloseDisplay(vsyncDisp); + }); + m_initcv.wait(outerLk); + + m_dataFactory = _NewVulkanDataFactory(this, m_ctx); + m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); + m_commandQueue->startRenderer(); + + return true; + } + + void makeCurrent() {} + + void postInit() {} + + IGraphicsCommandQueue* getCommandQueue() { return m_commandQueue.get(); } + + IGraphicsDataFactory* getDataFactory() { return m_dataFactory.get(); } + + IGraphicsDataFactory* getMainContextDataFactory() { return getDataFactory(); } + + IGraphicsDataFactory* getLoadContextDataFactory() { return getDataFactory(); } + + void present() {} +}; +#endif + +class WindowXlib : public IWindow { + Display* m_xDisp; + IWindowCallback* m_callback; + Colormap m_colormapId; + Window m_windowId; + XIMStyle m_bestStyle; + XIC m_xIC = nullptr; + std::unique_ptr m_gfxCtx; + uint32_t m_visualId; + + /* Key state trackers (for auto-repeat detection) */ + std::unordered_set m_charKeys; + std::unordered_set m_specialKeys; + std::unordered_set m_modKeys; + + /* Last known input device id (0xffff if not yet set) */ + int m_lastInputID = 0xffff; + ETouchType m_touchType = ETouchType::None; + + /* Scroll valuators */ + int m_hScrollValuator = -1; + int m_vScrollValuator = -1; + double m_hScrollLast = 0.0; + double m_vScrollLast = 0.0; + + /* Cached window rectangle (to avoid repeated X queries) */ + boo::SWindowRect m_wrect; + float m_pixelFactor; + bool m_inFs = false; + + /* Cached window style */ + EWindowStyle m_styleFlags; + + /* Current cursor enum */ + EMouseCursor m_cursor = EMouseCursor::None; + bool m_cursorWait = false; + static Cursor GetXCursor(EMouseCursor cur) { + switch (cur) { + case EMouseCursor::Pointer: + return X_CURSORS.m_pointer; + case EMouseCursor::HorizontalArrow: + return X_CURSORS.m_hArrow; + case EMouseCursor::VerticalArrow: + return X_CURSORS.m_vArrow; + case EMouseCursor::IBeam: + return X_CURSORS.m_ibeam; + case EMouseCursor::Crosshairs: + return X_CURSORS.m_crosshairs; + default: + break; + } + return X_CURSORS.m_pointer; + } + + bool m_openGL = false; + +public: + WindowXlib(std::string_view title, Display* display, void* xcbConn, int defaultScreen, XIM xIM, + XIMStyle bestInputStyle, XFontSet fontset, GLXContext lastCtx, void* vulkanHandle, GLContext* glCtx) + : m_xDisp(display), m_callback(nullptr), m_bestStyle(bestInputStyle) { + if (!S_ATOMS) + S_ATOMS = new XlibAtoms(display); + + for (int i = 1; i >= 0; --i) { +#if BOO_HAS_VULKAN + if (vulkanHandle && i == 1) { + m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen, + &g_VulkanContext, m_visualId, glCtx)); + } else +#endif + { + i = 0; + m_gfxCtx.reset(new GraphicsContextXlibGLX(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, display, + defaultScreen, lastCtx, m_visualId, glCtx)); + m_openGL = true; + } + + XVisualInfo visTemplate; + visTemplate.screen = defaultScreen; + int numVisuals; + XVisualInfo* visualList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &numVisuals); + Visual* selectedVisual = nullptr; + for (int i = 0; i < numVisuals; ++i) { + if (visualList[i].visualid == m_visualId) { + selectedVisual = visualList[i].visual; + break; + } + } + XFree(visualList); + + /* Create colormap */ + Screen* screen = ScreenOfDisplay(display, defaultScreen); + m_colormapId = XCreateColormap(m_xDisp, screen->root, selectedVisual, AllocNone); + + /* Create window */ + int x, y, w, h; + int nmonitors = 0; + XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors); + if (nmonitors) { + genFrameDefault(mInfo, x, y, w, h); + m_pixelFactor = mInfo->width / (float)mInfo->mwidth / REF_DPMM; + } else { + genFrameDefault(screen, x, y, w, h); + m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM; + } + XRRFreeMonitors(mInfo); + XSetWindowAttributes swa; + swa.colormap = m_colormapId; + swa.border_pixmap = 0; + swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask; + + m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10, CopyFromParent, CopyFromParent, selectedVisual, + CWBorderPixel | CWEventMask | CWColormap, &swa); + + /* + * Now go create an IC using the style we chose. + * Also set the window and fontset attributes now. + */ + if (xIM) { + XPoint pt = {0, 0}; + XVaNestedList nlist; + m_xIC = XCreateIC(xIM, XNInputStyle, bestInputStyle, XNClientWindow, m_windowId, XNFocusWindow, m_windowId, + XNPreeditAttributes, + nlist = XVaCreateNestedList(0, XNSpotLocation, &pt, XNFontSet, fontset, nullptr), nullptr); + XFree(nlist); + long im_event_mask; + XGetICValues(m_xIC, XNFilterEvents, &im_event_mask, nullptr); + XSelectInput(display, m_windowId, swa.event_mask | im_event_mask); + XSetICFocus(m_xIC); + } + + /* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */ + XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)}; + mask.mask = (unsigned char*)malloc(mask.mask_len); + memset(mask.mask, 0, mask.mask_len); + /* XISetMask(mask.mask, XI_Motion); Can't do this without losing mouse move events :( */ + XISetMask(mask.mask, XI_TouchBegin); + XISetMask(mask.mask, XI_TouchUpdate); + XISetMask(mask.mask, XI_TouchEnd); + XISelectEvents(m_xDisp, m_windowId, &mask, 1); + free(mask.mask); + + /* Register netwm extension atom for window closing */ + XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1); + + /* Set the title of the window */ + const unsigned char* c_title = (unsigned char*)title.data(); + XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length()); + + /* Set the title of the window icon */ + XChangeProperty(m_xDisp, m_windowId, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length()); + + /* Add window icon */ + if (MAINICON_NETWM_SZ && S_ATOMS->m_netwmIcon) { + XChangeProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmIcon, XA_CARDINAL, 32, PropModeReplace, MAINICON_NETWM, + MAINICON_NETWM_SZ / sizeof(unsigned long)); + } + + /* Initialize context */ + XMapWindow(m_xDisp, m_windowId); + setStyle(EWindowStyle::Default); + setCursor(EMouseCursor::Pointer); + setWindowFrameDefault(); + XFlush(m_xDisp); + + if (!m_gfxCtx->initializeContext(vulkanHandle)) { XUnmapWindow(m_xDisp, m_windowId); - XUnlockDisplay(m_xDisp); - } - - void showWindow() - { - XLockDisplay(m_xDisp); - XMapWindow(m_xDisp, m_windowId); - XUnlockDisplay(m_xDisp); - } - - void hideWindow() - { - XLockDisplay(m_xDisp); - XUnmapWindow(m_xDisp, m_windowId); - XUnlockDisplay(m_xDisp); + XDestroyWindow(m_xDisp, m_windowId); + XFreeColormap(m_xDisp, m_colormapId); + continue; + } + break; } + } - std::string getTitle() - { - unsigned long nitems; - Atom actualType; - int actualFormat; - unsigned long bytes; - unsigned char* string = nullptr; - XLockDisplay(m_xDisp); - int ret = XGetWindowProperty(m_xDisp, m_windowId, XA_WM_NAME, 0, ~0l, False, - XA_STRING, &actualType, &actualFormat, &nitems, &bytes, &string); - XUnlockDisplay(m_xDisp); - if (ret == Success) - { - std::string retval((const char*)string); - XFree(string); - return retval; + ~WindowXlib() { + _cleanup(); + if (APP) + APP->_deletedWindow(this); + } + + void setCallback(IWindowCallback* cb) { + XLockDisplay(m_xDisp); + m_callback = cb; + XUnlockDisplay(m_xDisp); + } + + void closeWindow() { + // TODO: Free window resources and prevent further access + XLockDisplay(m_xDisp); + XUnmapWindow(m_xDisp, m_windowId); + XUnlockDisplay(m_xDisp); + } + + void showWindow() { + XLockDisplay(m_xDisp); + XMapWindow(m_xDisp, m_windowId); + XUnlockDisplay(m_xDisp); + } + + void hideWindow() { + XLockDisplay(m_xDisp); + XUnmapWindow(m_xDisp, m_windowId); + XUnlockDisplay(m_xDisp); + } + + std::string getTitle() { + unsigned long nitems; + Atom actualType; + int actualFormat; + unsigned long bytes; + unsigned char* string = nullptr; + XLockDisplay(m_xDisp); + int ret = XGetWindowProperty(m_xDisp, m_windowId, XA_WM_NAME, 0, ~0l, False, XA_STRING, &actualType, &actualFormat, + &nitems, &bytes, &string); + XUnlockDisplay(m_xDisp); + if (ret == Success) { + std::string retval((const char*)string); + XFree(string); + return retval; + } + return std::string(); + } + + void setTitle(std::string_view title) { + const unsigned char* c_title = (unsigned char*)title.data(); + XLockDisplay(m_xDisp); + XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length()); + XUnlockDisplay(m_xDisp); + } + + void setCursor(EMouseCursor cursor) { + if (cursor == m_cursor && !m_cursorWait) + return; + m_cursor = cursor; + XLockDisplay(m_xDisp); + XDefineCursor(m_xDisp, m_windowId, GetXCursor(cursor)); + XUnlockDisplay(m_xDisp); + } + + void setWaitCursor(bool wait) { + if (wait && !m_cursorWait) { + XLockDisplay(m_xDisp); + XDefineCursor(m_xDisp, m_windowId, X_CURSORS.m_wait); + XUnlockDisplay(m_xDisp); + m_cursorWait = true; + } else if (!wait && m_cursorWait) { + setCursor(m_cursor); + m_cursorWait = false; + } + } + + void setWindowFrameDefault() { + int x, y, w, h, nmonitors; + Screen* screen = DefaultScreenOfDisplay(m_xDisp); + XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors); + if (nmonitors) + genFrameDefault(mInfo, x, y, w, h); + else + genFrameDefault(screen, x, y, w, h); + XRRFreeMonitors(mInfo); + XWindowChanges values = {(int)x, (int)y, (int)w, (int)h}; + XLockDisplay(m_xDisp); + XConfigureWindow(m_xDisp, m_windowId, CWX | CWY | CWWidth | CWHeight, &values); + XUnlockDisplay(m_xDisp); + } + + void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const { + XWindowAttributes attrs; + XLockDisplay(m_xDisp); + XGetWindowAttributes(m_xDisp, m_windowId, &attrs); + XUnlockDisplay(m_xDisp); + xOut = attrs.x; + yOut = attrs.y; + wOut = attrs.width; + hOut = attrs.height; + } + + void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const { + XWindowAttributes attrs; + XLockDisplay(m_xDisp); + XGetWindowAttributes(m_xDisp, m_windowId, &attrs); + XUnlockDisplay(m_xDisp); + xOut = attrs.x; + yOut = attrs.y; + wOut = attrs.width; + hOut = attrs.height; + } + + void setWindowFrame(float x, float y, float w, float h) { + XWindowChanges values = {(int)x, (int)y, (int)w, (int)h}; + XLockDisplay(m_xDisp); + XConfigureWindow(m_xDisp, m_windowId, CWX | CWY | CWWidth | CWHeight, &values); + XUnlockDisplay(m_xDisp); + } + + void setWindowFrame(int x, int y, int w, int h) { + XWindowChanges values = {x, y, w, h}; + XLockDisplay(m_xDisp); + XConfigureWindow(m_xDisp, m_windowId, CWX | CWY | CWWidth | CWHeight, &values); + XUnlockDisplay(m_xDisp); + } + + float getVirtualPixelFactor() const { return m_pixelFactor; } + + bool isFullscreen() const { + return m_inFs; + unsigned long nitems; + Atom actualType; + int actualFormat; + unsigned long bytes; + Atom* vals = nullptr; + bool fullscreen = false; + XLockDisplay(m_xDisp); + int ret = XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmState, 0, ~0l, False, XA_ATOM, &actualType, + &actualFormat, &nitems, &bytes, (unsigned char**)&vals); + XUnlockDisplay(m_xDisp); + if (ret == Success) { + for (int i = 0; i < nitems; ++i) { + if (vals[i] == S_ATOMS->m_netwmStateFullscreen) { + fullscreen = true; + break; } - return std::string(); - } - - void setTitle(std::string_view title) - { - const unsigned char* c_title = (unsigned char*)title.data(); - XLockDisplay(m_xDisp); - XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, - PropModeReplace, c_title, title.length()); - XUnlockDisplay(m_xDisp); + } + XFree(vals); + return fullscreen; } - void setCursor(EMouseCursor cursor) - { - if (cursor == m_cursor && !m_cursorWait) - return; - m_cursor = cursor; - XLockDisplay(m_xDisp); - XDefineCursor(m_xDisp, m_windowId, GetXCursor(cursor)); - XUnlockDisplay(m_xDisp); + return false; + } + + void setStyle(EWindowStyle style) { + struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long status; + } wmHints = {0}; + + if (S_ATOMS->m_motifWmHints) { + wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; + if ((style & EWindowStyle::Titlebar) != EWindowStyle::None) { + wmHints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; + wmHints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + } + if ((style & EWindowStyle::Resize) != EWindowStyle::None) { + wmHints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; + wmHints.functions |= MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE; + } + + if ((style & EWindowStyle::Close) != EWindowStyle::None) + wmHints.functions |= MWM_FUNC_CLOSE; + + XLockDisplay(m_xDisp); + XChangeProperty(m_xDisp, m_windowId, S_ATOMS->m_motifWmHints, S_ATOMS->m_motifWmHints, 32, PropModeReplace, + (unsigned char*)&wmHints, 5); + XUnlockDisplay(m_xDisp); } - void setWaitCursor(bool wait) - { - if (wait && !m_cursorWait) - { - XLockDisplay(m_xDisp); - XDefineCursor(m_xDisp, m_windowId, X_CURSORS.m_wait); + m_styleFlags = style; + } + + EWindowStyle getStyle() const { return m_styleFlags; } + + void setFullscreen(bool fs) { + if (fs == m_inFs) + return; + + XEvent fsEvent = {0}; + fsEvent.xclient.type = ClientMessage; + fsEvent.xclient.serial = 0; + fsEvent.xclient.send_event = True; + fsEvent.xclient.window = m_windowId; + fsEvent.xclient.message_type = S_ATOMS->m_netwmState; + fsEvent.xclient.format = 32; + fsEvent.xclient.data.l[0] = fs; + fsEvent.xclient.data.l[1] = S_ATOMS->m_netwmStateFullscreen; + fsEvent.xclient.data.l[2] = 0; + XLockDisplay(m_xDisp); + XSendEvent(m_xDisp, DefaultRootWindow(m_xDisp), False, StructureNotifyMask | SubstructureRedirectMask, + (XEvent*)&fsEvent); + XUnlockDisplay(m_xDisp); + + m_inFs = fs; + } + + struct ClipData { + EClipboardType m_type = EClipboardType::None; + std::unique_ptr m_data; + size_t m_sz = 0; + void clear() { + m_type = EClipboardType::None; + m_data.reset(); + m_sz = 0; + } + } m_clipData; + + void claimKeyboardFocus(const int coord[2]) { + if (m_xIC) { + XLockDisplay(m_xDisp); + if (!coord) { + XUnsetICFocus(m_xIC); + XUnlockDisplay(m_xDisp); + return; + } + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + XPoint pt = {short(coord[0]), short(m_wrect.size[1] - coord[1])}; + XVaNestedList list = XVaCreateNestedList(0, XNSpotLocation, &pt, nullptr); + XSetICValues(m_xIC, XNPreeditAttributes, list, nullptr); + XFree(list); + XSetICFocus(m_xIC); + XUnlockDisplay(m_xDisp); + } + } + + bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) { + Atom xType = GetClipboardTypeAtom(type); + if (!xType) + return false; + + XLockDisplay(m_xDisp); + m_clipData.m_type = type; + m_clipData.m_data.reset(new uint8_t[sz]); + m_clipData.m_sz = sz; + memcpy(m_clipData.m_data.get(), data, sz); + XSetSelectionOwner(m_xDisp, S_ATOMS->m_clipboard, m_windowId, CurrentTime); + XUnlockDisplay(m_xDisp); + + return true; + } + + std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) { + Atom xType = GetClipboardTypeAtom(type); + if (!xType) + return {}; + + XLockDisplay(m_xDisp); + XConvertSelection(m_xDisp, S_ATOMS->m_clipboard, xType, S_ATOMS->m_clipdata, m_windowId, CurrentTime); + XFlush(m_xDisp); + XEvent event; + for (int i = 0; i < 20; ++i) { + if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionNotify, &event)) { + if (event.xselection.property != 0) { + XSync(m_xDisp, false); + + unsigned long nitems, rem; + int format; + unsigned char* data; + Atom type; + + // Atom t1 = S_ATOMS->m_clipboard; + // Atom t2 = S_ATOMS->m_clipdata; + + if (XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_clipdata, 0, 32, False, AnyPropertyType, &type, + &format, &nitems, &rem, &data)) { + Log.report(logvisor::Fatal, "Clipboard allocation failed"); XUnlockDisplay(m_xDisp); - m_cursorWait = true; - } - else if (!wait && m_cursorWait) - { - setCursor(m_cursor); - m_cursorWait = false; - } - } - - void setWindowFrameDefault() - { - int x, y, w, h, nmonitors; - Screen* screen = DefaultScreenOfDisplay(m_xDisp); - XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors); - if (nmonitors) - genFrameDefault(mInfo, x, y, w, h); - else - genFrameDefault(screen, x, y, w, h); - XRRFreeMonitors(mInfo); - XWindowChanges values = {(int)x, (int)y, (int)w, (int)h}; - XLockDisplay(m_xDisp); - XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values); - XUnlockDisplay(m_xDisp); - } - - void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const - { - XWindowAttributes attrs; - XLockDisplay(m_xDisp); - XGetWindowAttributes(m_xDisp, m_windowId, &attrs); - XUnlockDisplay(m_xDisp); - xOut = attrs.x; - yOut = attrs.y; - wOut = attrs.width; - hOut = attrs.height; - } - - void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const - { - XWindowAttributes attrs; - XLockDisplay(m_xDisp); - XGetWindowAttributes(m_xDisp, m_windowId, &attrs); - XUnlockDisplay(m_xDisp); - xOut = attrs.x; - yOut = attrs.y; - wOut = attrs.width; - hOut = attrs.height; - } - - void setWindowFrame(float x, float y, float w, float h) - { - XWindowChanges values = {(int)x, (int)y, (int)w, (int)h}; - XLockDisplay(m_xDisp); - XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values); - XUnlockDisplay(m_xDisp); - } - - void setWindowFrame(int x, int y, int w, int h) - { - XWindowChanges values = {x, y, w, h}; - XLockDisplay(m_xDisp); - XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values); - XUnlockDisplay(m_xDisp); - } - - float getVirtualPixelFactor() const - { - return m_pixelFactor; - } - - bool isFullscreen() const - { - return m_inFs; - unsigned long nitems; - Atom actualType; - int actualFormat; - unsigned long bytes; - Atom* vals = nullptr; - bool fullscreen = false; - XLockDisplay(m_xDisp); - int ret = XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_netwmState, 0, ~0l, False, - XA_ATOM, &actualType, &actualFormat, &nitems, &bytes, (unsigned char**)&vals); - XUnlockDisplay(m_xDisp); - if (ret == Success) - { - for (int i=0 ; im_netwmStateFullscreen) - { - fullscreen = true; - break; - } - } - XFree(vals); - return fullscreen; - } - - return false; - } - - void setStyle(EWindowStyle style) - { - struct - { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long inputMode; - unsigned long status; - } wmHints = {0}; - - if (S_ATOMS->m_motifWmHints) - { - wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; - if ((style & EWindowStyle::Titlebar) != EWindowStyle::None) - { - wmHints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; - wmHints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; - } - if ((style & EWindowStyle::Resize) != EWindowStyle::None) - { - wmHints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; - wmHints.functions |= MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE; - } - - if ((style & EWindowStyle::Close) != EWindowStyle::None) - wmHints.functions |= MWM_FUNC_CLOSE; - - XLockDisplay(m_xDisp); - XChangeProperty(m_xDisp, m_windowId, S_ATOMS->m_motifWmHints, S_ATOMS->m_motifWmHints, 32, PropModeReplace, (unsigned char*)&wmHints, 5); - XUnlockDisplay(m_xDisp); - } - - m_styleFlags = style; - } - - EWindowStyle getStyle() const - { - return m_styleFlags; - } - - void setFullscreen(bool fs) - { - if (fs == m_inFs) - return; - - XEvent fsEvent = {0}; - fsEvent.xclient.type = ClientMessage; - fsEvent.xclient.serial = 0; - fsEvent.xclient.send_event = True; - fsEvent.xclient.window = m_windowId; - fsEvent.xclient.message_type = S_ATOMS->m_netwmState; - fsEvent.xclient.format = 32; - fsEvent.xclient.data.l[0] = fs; - fsEvent.xclient.data.l[1] = S_ATOMS->m_netwmStateFullscreen; - fsEvent.xclient.data.l[2] = 0; - XLockDisplay(m_xDisp); - XSendEvent(m_xDisp, DefaultRootWindow(m_xDisp), False, - StructureNotifyMask | SubstructureRedirectMask, (XEvent*)&fsEvent); - XUnlockDisplay(m_xDisp); - - m_inFs = fs; - } - - struct ClipData - { - EClipboardType m_type = EClipboardType::None; - std::unique_ptr m_data; - size_t m_sz = 0; - void clear() - { - m_type = EClipboardType::None; - m_data.reset(); - m_sz = 0; - } - } m_clipData; - - void claimKeyboardFocus(const int coord[2]) - { - if (m_xIC) - { - XLockDisplay(m_xDisp); - if (!coord) - { - XUnsetICFocus(m_xIC); - XUnlockDisplay(m_xDisp); - return; - } - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - XPoint pt = {short(coord[0]), short(m_wrect.size[1] - coord[1])}; - XVaNestedList list = XVaCreateNestedList(0, XNSpotLocation, &pt, nullptr); - XSetICValues(m_xIC, XNPreeditAttributes, list, nullptr); - XFree(list); - XSetICFocus(m_xIC); - XUnlockDisplay(m_xDisp); - } - } - - bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) - { - Atom xType = GetClipboardTypeAtom(type); - if (!xType) - return false; - - XLockDisplay(m_xDisp); - m_clipData.m_type = type; - m_clipData.m_data.reset(new uint8_t[sz]); - m_clipData.m_sz = sz; - memcpy(m_clipData.m_data.get(), data, sz); - XSetSelectionOwner(m_xDisp, S_ATOMS->m_clipboard, m_windowId, CurrentTime); - XUnlockDisplay(m_xDisp); - - return true; - } - - std::unique_ptr clipboardPaste(EClipboardType type, size_t& sz) - { - Atom xType = GetClipboardTypeAtom(type); - if (!xType) return {}; + } - XLockDisplay(m_xDisp); - XConvertSelection(m_xDisp, S_ATOMS->m_clipboard, xType, S_ATOMS->m_clipdata, m_windowId, CurrentTime); - XFlush(m_xDisp); - XEvent event; - for (int i=0 ; i<20; ++i) - { - if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionNotify, &event)) - { - if (event.xselection.property != 0) - { - XSync(m_xDisp, false); + if (rem != 0) { + Log.report(logvisor::Fatal, "partial clipboard read"); + XUnlockDisplay(m_xDisp); + return {}; + } - unsigned long nitems, rem; - int format; - unsigned char* data; - Atom type; - - //Atom t1 = S_ATOMS->m_clipboard; - //Atom t2 = S_ATOMS->m_clipdata; - - if (XGetWindowProperty(m_xDisp, m_windowId, S_ATOMS->m_clipdata, 0, 32, False, AnyPropertyType, - &type, &format, &nitems, &rem, &data)) - { - Log.report(logvisor::Fatal, "Clipboard allocation failed"); - XUnlockDisplay(m_xDisp); - return {}; - } - - if (rem != 0) - { - Log.report(logvisor::Fatal, "partial clipboard read"); - XUnlockDisplay(m_xDisp); - return {}; - } - - sz = nitems * format / 8; - std::unique_ptr ret(new uint8_t[sz]); - memcpy(ret.get(), data, sz); - XFree(data); - XUnlockDisplay(m_xDisp); - return ret; - } - XUnlockDisplay(m_xDisp); - return {}; - } - if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionRequest, &event) && - event.xselectionrequest.owner == m_windowId) - handleSelectionRequest(&event.xselectionrequest); - if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionClear, &event) && - event.xselectionclear.window == m_windowId) - m_clipData.clear(); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sz = nitems * format / 8; + std::unique_ptr ret(new uint8_t[sz]); + memcpy(ret.get(), data, sz); + XFree(data); + XUnlockDisplay(m_xDisp); + return ret; } XUnlockDisplay(m_xDisp); return {}; + } + if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionRequest, &event) && + event.xselectionrequest.owner == m_windowId) + handleSelectionRequest(&event.xselectionrequest); + if (XCheckTypedWindowEvent(m_xDisp, m_windowId, SelectionClear, &event) && + event.xselectionclear.window == m_windowId) + m_clipData.clear(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } + XUnlockDisplay(m_xDisp); + return {}; + } - void handleSelectionRequest(XSelectionRequestEvent* se) - { - XEvent reply; - reply.xselection.type = SelectionNotify; - reply.xselection.display = m_xDisp; - reply.xselection.requestor = se->requestor; - reply.xselection.selection = se->selection; - reply.xselection.target = se->target; - reply.xselection.time = se->time; - reply.xselection.property = se->property; - if (se->target == S_ATOMS->m_targets) - { - Atom ValidTargets[] = {GetClipboardTypeAtom(m_clipData.m_type)}; - XChangeProperty(m_xDisp, se->requestor, se->property, XA_ATOM, - 32, 0, (unsigned char*)ValidTargets, m_clipData.m_type != EClipboardType::None); + void handleSelectionRequest(XSelectionRequestEvent* se) { + XEvent reply; + reply.xselection.type = SelectionNotify; + reply.xselection.display = m_xDisp; + reply.xselection.requestor = se->requestor; + reply.xselection.selection = se->selection; + reply.xselection.target = se->target; + reply.xselection.time = se->time; + reply.xselection.property = se->property; + if (se->target == S_ATOMS->m_targets) { + Atom ValidTargets[] = {GetClipboardTypeAtom(m_clipData.m_type)}; + XChangeProperty(m_xDisp, se->requestor, se->property, XA_ATOM, 32, 0, (unsigned char*)ValidTargets, + m_clipData.m_type != EClipboardType::None); + } else { + if (se->target == GetClipboardTypeAtom(m_clipData.m_type)) { + XChangeProperty(m_xDisp, se->requestor, se->property, se->target, 8, PropModeReplace, m_clipData.m_data.get(), + m_clipData.m_sz); + } else + reply.xselection.property = 0; + } + XSendEvent(m_xDisp, se->requestor, False, 0, &reply); + } + + void waitForRetrace() { + std::unique_lock lk(m_gfxCtx->m_vsyncmt); + m_gfxCtx->m_vsynccv.wait(lk); + } + + uintptr_t getPlatformHandle() const { return (uintptr_t)m_windowId; } + + void _pointingDeviceChanged(int deviceId) { + int nDevices; + XIDeviceInfo* devices = XIQueryDevice(m_xDisp, deviceId, &nDevices); + + for (int i = 0; i < nDevices; ++i) { + XIDeviceInfo* device = &devices[i]; + + /* First iterate classes for scrollables */ + int hScroll = -1; + int vScroll = -1; + m_hScrollLast = 0.0; + m_vScrollLast = 0.0; + m_hScrollValuator = -1; + m_vScrollValuator = -1; + for (int j = 0; j < device->num_classes; ++j) { + XIAnyClassInfo* dclass = device->classes[j]; + if (dclass->type == XIScrollClass) { + XIScrollClassInfo* scrollClass = (XIScrollClassInfo*)dclass; + if (scrollClass->scroll_type == XIScrollTypeVertical) + vScroll = scrollClass->number; + else if (scrollClass->scroll_type == XIScrollTypeHorizontal) + hScroll = scrollClass->number; } - else - { - if (se->target == GetClipboardTypeAtom(m_clipData.m_type)) - { - XChangeProperty(m_xDisp, se->requestor, se->property, se->target, 8, PropModeReplace, - m_clipData.m_data.get(), m_clipData.m_sz); - } - else - reply.xselection.property = 0; + } + + /* Next iterate for touch and scroll valuators */ + for (int j = 0; j < device->num_classes; ++j) { + XIAnyClassInfo* dclass = device->classes[j]; + if (dclass->type == XIValuatorClass) { + XIValuatorClassInfo* valClass = (XIValuatorClassInfo*)dclass; + if (valClass->number == vScroll) { + m_vScrollLast = valClass->value; + m_vScrollValuator = vScroll; + } else if (valClass->number == hScroll) { + m_hScrollLast = valClass->value; + m_hScrollValuator = hScroll; + } + } else if (dclass->type == XITouchClass) { + XITouchClassInfo* touchClass = (XITouchClassInfo*)dclass; + if (touchClass->mode == XIDirectTouch) + m_touchType = ETouchType::Display; + else if (touchClass->mode == XIDependentTouch) + m_touchType = ETouchType::Trackpad; + else + m_touchType = ETouchType::None; } - XSendEvent(m_xDisp, se->requestor, False, 0, &reply); + } } - void waitForRetrace() - { - std::unique_lock lk(m_gfxCtx->m_vsyncmt); - m_gfxCtx->m_vsynccv.wait(lk); - } + XIFreeDeviceInfo(devices); + m_lastInputID = deviceId; + } - uintptr_t getPlatformHandle() const - { - return (uintptr_t)m_windowId; - } - - void _pointingDeviceChanged(int deviceId) - { - int nDevices; - XIDeviceInfo* devices = XIQueryDevice(m_xDisp, deviceId, &nDevices); - - for (int i=0 ; inum_classes ; ++j) - { - XIAnyClassInfo* dclass = device->classes[j]; - if (dclass->type == XIScrollClass) - { - XIScrollClassInfo* scrollClass = (XIScrollClassInfo*)dclass; - if (scrollClass->scroll_type == XIScrollTypeVertical) - vScroll = scrollClass->number; - else if (scrollClass->scroll_type == XIScrollTypeHorizontal) - hScroll = scrollClass->number; - } - } - - /* Next iterate for touch and scroll valuators */ - for (int j=0 ; jnum_classes ; ++j) - { - XIAnyClassInfo* dclass = device->classes[j]; - if (dclass->type == XIValuatorClass) - { - XIValuatorClassInfo* valClass = (XIValuatorClassInfo*)dclass; - if (valClass->number == vScroll) - { - m_vScrollLast = valClass->value; - m_vScrollValuator = vScroll; - } - else if (valClass->number == hScroll) - { - m_hScrollLast = valClass->value; - m_hScrollValuator = hScroll; - } - } - else if (dclass->type == XITouchClass) - { - XITouchClassInfo* touchClass = (XITouchClassInfo*)dclass; - if (touchClass->mode == XIDirectTouch) - m_touchType = ETouchType::Display; - else if (touchClass->mode == XIDependentTouch) - m_touchType = ETouchType::Trackpad; - else - m_touchType = ETouchType::None; - } - } - } - - XIFreeDeviceInfo(devices); - m_lastInputID = deviceId; - } - - SWindowCoord MakeButtonEventCoord(XEvent* event) const - { - int x = event->xbutton.x; - int y = m_wrect.size[1]-event->xbutton.y; - return - { - {x, y}, + SWindowCoord MakeButtonEventCoord(XEvent* event) const { + int x = event->xbutton.x; + int y = m_wrect.size[1] - event->xbutton.y; + return {{x, y}, {int(x / m_pixelFactor), int(y / m_pixelFactor)}, - {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])} - }; - } + {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}}; + } - SWindowCoord MakeMotionEventCoord(XEvent* event) const - { - int x = event->xmotion.x; - int y = m_wrect.size[1]-event->xmotion.y; - return - { - {x, y}, + SWindowCoord MakeMotionEventCoord(XEvent* event) const { + int x = event->xmotion.x; + int y = m_wrect.size[1] - event->xmotion.y; + return {{x, y}, {int(x / m_pixelFactor), int(y / m_pixelFactor)}, - {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])} - }; - } + {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}}; + } - SWindowCoord MakeCrossingEventCoord(XEvent* event) const - { - int x = event->xcrossing.x; - int y = m_wrect.size[1]-event->xcrossing.y; - return - { - {x, y}, + SWindowCoord MakeCrossingEventCoord(XEvent* event) const { + int x = event->xcrossing.x; + int y = m_wrect.size[1] - event->xcrossing.y; + return {{x, y}, {int(x / m_pixelFactor), int(y / m_pixelFactor)}, - {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])} - }; - } + {x / float(m_wrect.size[0]), y / float(m_wrect.size[1])}}; + } #if 0 /* This procedure sets the application's size constraints and returns @@ -1640,436 +1392,336 @@ public: } #endif - bool _incomingEvent(void* e) - { - XEvent* event = (XEvent*)e; - switch (event->type) - { - case SelectionRequest: - { - handleSelectionRequest(&event->xselectionrequest); - return false; - } - case ClientMessage: - { - if (event->xclient.data.l[0] == S_ATOMS->m_wmDeleteWindow && m_callback) - { - m_callback->destroyed(); - m_callback = nullptr; - } - return true; - } - case Expose: - { - Window nw; - XWindowAttributes wxa; - int x, y; - XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xexpose.x, event->xexpose.y, &x, &y, &nw); - XGetWindowAttributes(m_xDisp, m_windowId, &wxa); - m_wrect.location[0] = x - wxa.x; - m_wrect.location[1] = y - wxa.y; + bool _incomingEvent(void* e) { + XEvent* event = (XEvent*)e; + switch (event->type) { + case SelectionRequest: { + handleSelectionRequest(&event->xselectionrequest); + return false; + } + case ClientMessage: { + if (event->xclient.data.l[0] == S_ATOMS->m_wmDeleteWindow && m_callback) { + m_callback->destroyed(); + m_callback = nullptr; + } + return true; + } + case Expose: { + Window nw; + XWindowAttributes wxa; + int x, y; + XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xexpose.x, event->xexpose.y, &x, &y, + &nw); + XGetWindowAttributes(m_xDisp, m_windowId, &wxa); + m_wrect.location[0] = x - wxa.x; + m_wrect.location[1] = y - wxa.y; #if 0 /* This breaks with GNOME, why? */ m_wrect.size[0] = event->xexpose.width; m_wrect.size[1] = event->xexpose.height; #else - m_wrect.size[0] = wxa.width; - m_wrect.size[1] = wxa.height; + m_wrect.size[0] = wxa.width; + m_wrect.size[1] = wxa.height; #endif - if (m_callback) - { - XUnlockDisplay(m_xDisp); - m_gfxCtx->resized(m_wrect); - m_callback->resized(m_wrect, m_openGL); - XLockDisplay(m_xDisp); - } - return false; - } - case ConfigureNotify: - { - Window nw; - XWindowAttributes wxa; - int x, y; - XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xconfigure.x, event->xconfigure.y, &x, &y, &nw); - XGetWindowAttributes(m_xDisp, m_windowId, &wxa); - m_wrect.location[0] = x - wxa.x; - m_wrect.location[1] = y - wxa.y; - m_wrect.size[0] = event->xconfigure.width; - m_wrect.size[1] = event->xconfigure.height; - - if (m_callback) - m_callback->windowMoved(m_wrect); - return false; - } - case KeyPress: - { - if (m_callback) - { - ESpecialKey specialKey; - EModifierKey modifierKey; - unsigned int state = event->xkey.state; - event->xkey.state &= ~ControlMask; - ITextInputCallback* inputCb = m_callback->getTextInputCallback(); - if (m_xIC) - { - std::string utf8Frag = translateUTF8(&event->xkey, m_xIC); - if (utf8Frag.size()) - { - if (inputCb) - inputCb->insertText(utf8Frag); - return false; - } - } - char charCode = translateKeysym(&event->xkey, specialKey, modifierKey); - EModifierKey modifierMask = translateModifiers(state); - if (charCode) - { - if (inputCb && - (modifierMask & (EModifierKey::Ctrl|EModifierKey::Command)) == EModifierKey::None) - inputCb->insertText(std::string(1, charCode)); - - bool isRepeat = m_charKeys.find(charCode) != m_charKeys.cend(); - m_callback->charKeyDown(charCode, modifierMask, isRepeat); - if (!isRepeat) - m_charKeys.insert(charCode); - } - else if (specialKey != ESpecialKey::None) - { - bool isRepeat = m_specialKeys.find((unsigned long)specialKey) != m_specialKeys.cend(); - m_callback->specialKeyDown(specialKey, modifierMask, isRepeat); - if (!isRepeat) - m_specialKeys.insert((unsigned long)specialKey); - } - else if (modifierKey != EModifierKey::None) - { - bool isRepeat = m_modKeys.find((unsigned long)modifierKey) != m_modKeys.cend(); - m_callback->modKeyDown(modifierKey, isRepeat); - if (!isRepeat) - m_modKeys.insert((unsigned long)modifierKey); - } - } - return false; - } - case KeyRelease: - { - if (m_callback) - { - ESpecialKey specialKey; - EModifierKey modifierKey; - unsigned int state = event->xkey.state; - event->xkey.state &= ~ControlMask; - char charCode = translateKeysym(&event->xkey, specialKey, modifierKey); - EModifierKey modifierMask = translateModifiers(state); - if (charCode) - { - m_charKeys.erase(charCode); - m_callback->charKeyUp(charCode, modifierMask); - } - else if (specialKey != ESpecialKey::None) - { - m_specialKeys.erase((unsigned long)specialKey); - m_callback->specialKeyUp(specialKey, modifierMask); - } - else if (modifierKey != EModifierKey::None) - { - m_modKeys.erase((unsigned long)modifierKey); - m_callback->modKeyUp(modifierKey); - } - } - return false; - } - case ButtonPress: - { - if (m_callback) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - EMouseButton button = translateButton(event->xbutton.button); - if (button != EMouseButton::None) - { - EModifierKey modifierMask = translateModifiers(event->xbutton.state); - m_callback->mouseDown(MakeButtonEventCoord(event), (EMouseButton)button, - (EModifierKey)modifierMask); - } - - /* Also handle legacy scroll events here */ - if (event->xbutton.button >= 4 && event->xbutton.button <= 7 && - m_hScrollValuator == -1 && m_vScrollValuator == -1) - { - SScrollDelta scrollDelta = - { - {0.0, 0.0}, - false - }; - if (event->xbutton.button == 4) - scrollDelta.delta[1] = 1.0; - else if (event->xbutton.button == 5) - scrollDelta.delta[1] = -1.0; - else if (event->xbutton.button == 6) - scrollDelta.delta[0] = 1.0; - else if (event->xbutton.button == 7) - scrollDelta.delta[0] = -1.0; - m_callback->scroll(MakeButtonEventCoord(event), scrollDelta); - } - } - return false; - } - case ButtonRelease: - { - if (m_callback) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - EMouseButton button = translateButton(event->xbutton.button); - if (button != EMouseButton::None) - { - EModifierKey modifierMask = translateModifiers(event->xbutton.state); - m_callback->mouseUp(MakeButtonEventCoord(event), (EMouseButton)button, - (EModifierKey)modifierMask); - } - } - return false; - } - case FocusIn: - { - if (m_callback) - m_callback->focusGained(); - return false; - } - case FocusOut: - { - if (m_callback) - m_callback->focusLost(); - return false; - } - case MotionNotify: - { - if (m_callback) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - m_callback->mouseMove(MakeMotionEventCoord(event)); - } - return false; - } - case EnterNotify: - { - if (m_callback) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - m_callback->mouseEnter(MakeCrossingEventCoord(event)); - } - return false; - } - case LeaveNotify: - { - if (m_callback) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - m_callback->mouseLeave(MakeCrossingEventCoord(event)); - } - return false; - } - case GenericEvent: - { - if (event->xgeneric.extension == XINPUT_OPCODE) - { - getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); - switch (event->xgeneric.evtype) - { - case XI_Motion: - { - fprintf(stderr, "motion\n"); - - XIDeviceEvent* ev = (XIDeviceEvent*)event; - if (m_lastInputID != ev->deviceid) - _pointingDeviceChanged(ev->deviceid); - - int cv = 0; - double newScroll[2] = {m_hScrollLast, m_vScrollLast}; - bool didScroll = false; - for (int i=0 ; ivaluators.mask_len*8 ; ++i) - { - if (XIMaskIsSet(ev->valuators.mask, i)) - { - if (i == m_hScrollValuator) - { - newScroll[0] = ev->valuators.values[cv]; - didScroll = true; - } - else if (i == m_vScrollValuator) - { - newScroll[1] = ev->valuators.values[cv]; - didScroll = true; - } - ++cv; - } - } - - SScrollDelta scrollDelta = - { - {newScroll[0] - m_hScrollLast, newScroll[1] - m_vScrollLast}, - true - }; - - m_hScrollLast = newScroll[0]; - m_vScrollLast = newScroll[1]; - - if (m_callback && didScroll) - { - int event_x = int(ev->event_x) >> 16; - int event_y = m_wrect.size[1] - (int(ev->event_y) >> 16); - SWindowCoord coord = - { - {event_x, event_y}, - {int(event_x / m_pixelFactor), int(event_y / m_pixelFactor)}, - {event_x / float(m_wrect.size[0]), event_y / float(m_wrect.size[1])} - }; - m_callback->scroll(coord, scrollDelta); - } - return false; - } - case XI_TouchBegin: - { - XIDeviceEvent* ev = (XIDeviceEvent*)event; - if (m_lastInputID != ev->deviceid) - _pointingDeviceChanged(ev->deviceid); - - int cv = 0; - double vals[32] = {}; - for (int i=0 ; ivaluators.mask_len*8 && i<32 ; ++i) - { - if (XIMaskIsSet(ev->valuators.mask, i)) - { - vals[i] = ev->valuators.values[cv]; - ++cv; - } - } - - STouchCoord coord = - { - {vals[0], vals[1]} - }; - - if (m_callback) - m_callback->touchDown(coord, ev->detail); - return false; - } - case XI_TouchUpdate: - { - XIDeviceEvent* ev = (XIDeviceEvent*)event; - if (m_lastInputID != ev->deviceid) - _pointingDeviceChanged(ev->deviceid); - - int cv = 0; - double vals[32] = {}; - for (int i=0 ; ivaluators.mask_len*8 && i<32 ; ++i) - { - if (XIMaskIsSet(ev->valuators.mask, i)) - { - vals[i] = ev->valuators.values[cv]; - ++cv; - } - } - - STouchCoord coord = - { - {vals[0], vals[1]} - }; - - if (m_callback) - m_callback->touchMove(coord, ev->detail); - return false; - } - case XI_TouchEnd: - { - XIDeviceEvent* ev = (XIDeviceEvent*)event; - if (m_lastInputID != ev->deviceid) - _pointingDeviceChanged(ev->deviceid); - - int cv = 0; - double vals[32] = {}; - for (int i=0 ; ivaluators.mask_len*8 && i<32 ; ++i) - { - if (XIMaskIsSet(ev->valuators.mask, i)) - { - vals[i] = ev->valuators.values[cv]; - ++cv; - } - } - - STouchCoord coord = - { - {vals[0], vals[1]} - }; - - if (m_callback) - m_callback->touchUp(coord, ev->detail); - return false; - } - } - } - } - } - - return false; - } - - void _cleanup() - { - if (m_gfxCtx) - { - XLockDisplay(m_xDisp); - m_gfxCtx->destroy(); - m_gfxCtx.reset(); - XUnmapWindow(m_xDisp, m_windowId); - XDestroyWindow(m_xDisp, m_windowId); - XFreeColormap(m_xDisp, m_colormapId); - XUnlockDisplay(m_xDisp); - } - } - - ETouchType getTouchType() const - { - return m_touchType; - } - - IGraphicsCommandQueue* getCommandQueue() - { - return m_gfxCtx->getCommandQueue(); - } - - IGraphicsDataFactory* getDataFactory() - { - return m_gfxCtx->getDataFactory(); - } - - IGraphicsDataFactory* getMainContextDataFactory() - { - return m_gfxCtx->getMainContextDataFactory(); - } - - IGraphicsDataFactory* getLoadContextDataFactory() - { - return m_gfxCtx->getLoadContextDataFactory(); - } - - bool _isWindowMapped() - { - XWindowAttributes attr; - XLockDisplay(m_xDisp); - XGetWindowAttributes(m_xDisp, m_windowId, &attr); + if (m_callback) { XUnlockDisplay(m_xDisp); - return attr.map_state != IsUnmapped; + m_gfxCtx->resized(m_wrect); + m_callback->resized(m_wrect, m_openGL); + XLockDisplay(m_xDisp); + } + return false; } + case ConfigureNotify: { + Window nw; + XWindowAttributes wxa; + int x, y; + XTranslateCoordinates(m_xDisp, m_windowId, DefaultRootWindow(m_xDisp), event->xconfigure.x, event->xconfigure.y, + &x, &y, &nw); + XGetWindowAttributes(m_xDisp, m_windowId, &wxa); + m_wrect.location[0] = x - wxa.x; + m_wrect.location[1] = y - wxa.y; + m_wrect.size[0] = event->xconfigure.width; + m_wrect.size[1] = event->xconfigure.height; + + if (m_callback) + m_callback->windowMoved(m_wrect); + return false; + } + case KeyPress: { + if (m_callback) { + ESpecialKey specialKey; + EModifierKey modifierKey; + unsigned int state = event->xkey.state; + event->xkey.state &= ~ControlMask; + ITextInputCallback* inputCb = m_callback->getTextInputCallback(); + if (m_xIC) { + std::string utf8Frag = translateUTF8(&event->xkey, m_xIC); + if (utf8Frag.size()) { + if (inputCb) + inputCb->insertText(utf8Frag); + return false; + } + } + char charCode = translateKeysym(&event->xkey, specialKey, modifierKey); + EModifierKey modifierMask = translateModifiers(state); + if (charCode) { + if (inputCb && (modifierMask & (EModifierKey::Ctrl | EModifierKey::Command)) == EModifierKey::None) + inputCb->insertText(std::string(1, charCode)); + + bool isRepeat = m_charKeys.find(charCode) != m_charKeys.cend(); + m_callback->charKeyDown(charCode, modifierMask, isRepeat); + if (!isRepeat) + m_charKeys.insert(charCode); + } else if (specialKey != ESpecialKey::None) { + bool isRepeat = m_specialKeys.find((unsigned long)specialKey) != m_specialKeys.cend(); + m_callback->specialKeyDown(specialKey, modifierMask, isRepeat); + if (!isRepeat) + m_specialKeys.insert((unsigned long)specialKey); + } else if (modifierKey != EModifierKey::None) { + bool isRepeat = m_modKeys.find((unsigned long)modifierKey) != m_modKeys.cend(); + m_callback->modKeyDown(modifierKey, isRepeat); + if (!isRepeat) + m_modKeys.insert((unsigned long)modifierKey); + } + } + return false; + } + case KeyRelease: { + if (m_callback) { + ESpecialKey specialKey; + EModifierKey modifierKey; + unsigned int state = event->xkey.state; + event->xkey.state &= ~ControlMask; + char charCode = translateKeysym(&event->xkey, specialKey, modifierKey); + EModifierKey modifierMask = translateModifiers(state); + if (charCode) { + m_charKeys.erase(charCode); + m_callback->charKeyUp(charCode, modifierMask); + } else if (specialKey != ESpecialKey::None) { + m_specialKeys.erase((unsigned long)specialKey); + m_callback->specialKeyUp(specialKey, modifierMask); + } else if (modifierKey != EModifierKey::None) { + m_modKeys.erase((unsigned long)modifierKey); + m_callback->modKeyUp(modifierKey); + } + } + return false; + } + case ButtonPress: { + if (m_callback) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + EMouseButton button = translateButton(event->xbutton.button); + if (button != EMouseButton::None) { + EModifierKey modifierMask = translateModifiers(event->xbutton.state); + m_callback->mouseDown(MakeButtonEventCoord(event), (EMouseButton)button, (EModifierKey)modifierMask); + } + + /* Also handle legacy scroll events here */ + if (event->xbutton.button >= 4 && event->xbutton.button <= 7 && m_hScrollValuator == -1 && + m_vScrollValuator == -1) { + SScrollDelta scrollDelta = {{0.0, 0.0}, false}; + if (event->xbutton.button == 4) + scrollDelta.delta[1] = 1.0; + else if (event->xbutton.button == 5) + scrollDelta.delta[1] = -1.0; + else if (event->xbutton.button == 6) + scrollDelta.delta[0] = 1.0; + else if (event->xbutton.button == 7) + scrollDelta.delta[0] = -1.0; + m_callback->scroll(MakeButtonEventCoord(event), scrollDelta); + } + } + return false; + } + case ButtonRelease: { + if (m_callback) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + EMouseButton button = translateButton(event->xbutton.button); + if (button != EMouseButton::None) { + EModifierKey modifierMask = translateModifiers(event->xbutton.state); + m_callback->mouseUp(MakeButtonEventCoord(event), (EMouseButton)button, (EModifierKey)modifierMask); + } + } + return false; + } + case FocusIn: { + if (m_callback) + m_callback->focusGained(); + return false; + } + case FocusOut: { + if (m_callback) + m_callback->focusLost(); + return false; + } + case MotionNotify: { + if (m_callback) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + m_callback->mouseMove(MakeMotionEventCoord(event)); + } + return false; + } + case EnterNotify: { + if (m_callback) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + m_callback->mouseEnter(MakeCrossingEventCoord(event)); + } + return false; + } + case LeaveNotify: { + if (m_callback) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + m_callback->mouseLeave(MakeCrossingEventCoord(event)); + } + return false; + } + case GenericEvent: { + if (event->xgeneric.extension == XINPUT_OPCODE) { + getWindowFrame(m_wrect.location[0], m_wrect.location[1], m_wrect.size[0], m_wrect.size[1]); + switch (event->xgeneric.evtype) { + case XI_Motion: { + fprintf(stderr, "motion\n"); + + XIDeviceEvent* ev = (XIDeviceEvent*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + int cv = 0; + double newScroll[2] = {m_hScrollLast, m_vScrollLast}; + bool didScroll = false; + for (int i = 0; i < ev->valuators.mask_len * 8; ++i) { + if (XIMaskIsSet(ev->valuators.mask, i)) { + if (i == m_hScrollValuator) { + newScroll[0] = ev->valuators.values[cv]; + didScroll = true; + } else if (i == m_vScrollValuator) { + newScroll[1] = ev->valuators.values[cv]; + didScroll = true; + } + ++cv; + } + } + + SScrollDelta scrollDelta = {{newScroll[0] - m_hScrollLast, newScroll[1] - m_vScrollLast}, true}; + + m_hScrollLast = newScroll[0]; + m_vScrollLast = newScroll[1]; + + if (m_callback && didScroll) { + int event_x = int(ev->event_x) >> 16; + int event_y = m_wrect.size[1] - (int(ev->event_y) >> 16); + SWindowCoord coord = {{event_x, event_y}, + {int(event_x / m_pixelFactor), int(event_y / m_pixelFactor)}, + {event_x / float(m_wrect.size[0]), event_y / float(m_wrect.size[1])}}; + m_callback->scroll(coord, scrollDelta); + } + return false; + } + case XI_TouchBegin: { + XIDeviceEvent* ev = (XIDeviceEvent*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + int cv = 0; + double vals[32] = {}; + for (int i = 0; i < ev->valuators.mask_len * 8 && i < 32; ++i) { + if (XIMaskIsSet(ev->valuators.mask, i)) { + vals[i] = ev->valuators.values[cv]; + ++cv; + } + } + + STouchCoord coord = {{vals[0], vals[1]}}; + + if (m_callback) + m_callback->touchDown(coord, ev->detail); + return false; + } + case XI_TouchUpdate: { + XIDeviceEvent* ev = (XIDeviceEvent*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + int cv = 0; + double vals[32] = {}; + for (int i = 0; i < ev->valuators.mask_len * 8 && i < 32; ++i) { + if (XIMaskIsSet(ev->valuators.mask, i)) { + vals[i] = ev->valuators.values[cv]; + ++cv; + } + } + + STouchCoord coord = {{vals[0], vals[1]}}; + + if (m_callback) + m_callback->touchMove(coord, ev->detail); + return false; + } + case XI_TouchEnd: { + XIDeviceEvent* ev = (XIDeviceEvent*)event; + if (m_lastInputID != ev->deviceid) + _pointingDeviceChanged(ev->deviceid); + + int cv = 0; + double vals[32] = {}; + for (int i = 0; i < ev->valuators.mask_len * 8 && i < 32; ++i) { + if (XIMaskIsSet(ev->valuators.mask, i)) { + vals[i] = ev->valuators.values[cv]; + ++cv; + } + } + + STouchCoord coord = {{vals[0], vals[1]}}; + + if (m_callback) + m_callback->touchUp(coord, ev->detail); + return false; + } + } + } + } + } + + return false; + } + + void _cleanup() { + if (m_gfxCtx) { + XLockDisplay(m_xDisp); + m_gfxCtx->destroy(); + m_gfxCtx.reset(); + XUnmapWindow(m_xDisp, m_windowId); + XDestroyWindow(m_xDisp, m_windowId); + XFreeColormap(m_xDisp, m_colormapId); + XUnlockDisplay(m_xDisp); + } + } + + ETouchType getTouchType() const { return m_touchType; } + + IGraphicsCommandQueue* getCommandQueue() { return m_gfxCtx->getCommandQueue(); } + + IGraphicsDataFactory* getDataFactory() { return m_gfxCtx->getDataFactory(); } + + IGraphicsDataFactory* getMainContextDataFactory() { return m_gfxCtx->getMainContextDataFactory(); } + + IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } + + bool _isWindowMapped() { + XWindowAttributes attr; + XLockDisplay(m_xDisp); + XGetWindowAttributes(m_xDisp, m_windowId, &attr); + XUnlockDisplay(m_xDisp); + return attr.map_state != IsUnmapped; + } }; -std::shared_ptr _WindowXlibNew(std::string_view title, - Display* display, void* xcbConn, - int defaultScreen, XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, - GLXContext lastCtx, void* vulkanHandle, GLContext* glCtx) -{ - std::shared_ptr ret = std::make_shared(title, display, xcbConn, - defaultScreen, xIM, bestInputStyle, fontset, lastCtx, - vulkanHandle, glCtx); - return ret; -} - +std::shared_ptr _WindowXlibNew(std::string_view title, Display* display, void* xcbConn, int defaultScreen, + XIM xIM, XIMStyle bestInputStyle, XFontSet fontset, GLXContext lastCtx, + void* vulkanHandle, GLContext* glCtx) { + std::shared_ptr ret = std::make_shared(title, display, xcbConn, defaultScreen, xIM, + bestInputStyle, fontset, lastCtx, vulkanHandle, glCtx); + return ret; } + +} // namespace boo diff --git a/lib/x11/XlibCommon.hpp b/lib/x11/XlibCommon.hpp index 198ef40..4c06bf3 100644 --- a/lib/x11/XlibCommon.hpp +++ b/lib/x11/XlibCommon.hpp @@ -2,19 +2,16 @@ #include -namespace boo -{ +namespace boo { -struct XlibCursors -{ - Cursor m_pointer; - Cursor m_hArrow; - Cursor m_vArrow; - Cursor m_ibeam; - Cursor m_crosshairs; - Cursor m_wait; +struct XlibCursors { + Cursor m_pointer; + Cursor m_hArrow; + Cursor m_vArrow; + Cursor m_ibeam; + Cursor m_crosshairs; + Cursor m_wait; }; extern XlibCursors X_CURSORS; -} - +} // namespace boo diff --git a/logvisor b/logvisor index 1b6c2ae..01e2918 160000 --- a/logvisor +++ b/logvisor @@ -1 +1 @@ -Subproject commit 1b6c2ae7159fd4fd7a80b1951d5ed43e4d1a3676 +Subproject commit 01e291833ba4d7f2a596c32cf6158cb6a9327ad7 diff --git a/test/main.cpp b/test/main.cpp index 3afece3..3f30fa6 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -10,577 +10,466 @@ #include #include "logvisor/logvisor.hpp" -namespace boo -{ +namespace boo { -class DolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback -{ - void controllerConnected(unsigned idx, EDolphinControllerType) - { -// printf("CONTROLLER %u CONNECTED\n", idx); - } - void controllerDisconnected(unsigned idx) - { -// printf("CONTROLLER %u DISCONNECTED\n", idx); - } - void controllerUpdate(unsigned idx, EDolphinControllerType, - const DolphinControllerState& state) - { -// 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 DolphinSmashAdapterCallback : public IDolphinSmashAdapterCallback { + void controllerConnected(unsigned idx, EDolphinControllerType) { + // printf("CONTROLLER %u CONNECTED\n", idx); + } + void controllerDisconnected(unsigned idx) { + // printf("CONTROLLER %u DISCONNECTED\n", idx); + } + void controllerUpdate(unsigned idx, EDolphinControllerType, const DolphinControllerState& state) { + // 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() +class DualshockPadCallback : public IDualshockPadCallback { + void controllerDisconnected() { printf("CONTROLLER DISCONNECTED\n"); } + void controllerUpdate(DualshockPad& pad, const DualshockPadState& state) { + static time_t timeTotal; + static time_t lastTime = 0; + timeTotal = time(NULL); + time_t timeDif = timeTotal - lastTime; + /* + if (timeDif >= .15) { - printf("CONTROLLER DISCONNECTED\n"); + uint8_t led = ctrl->getLED(); + led *= 2; + if (led > 0x10) + led = 2; + ctrl->setRawLED(led); + lastTime = timeTotal; } - void controllerUpdate(DualshockPad& pad, const DualshockPadState& state) - { - 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);*/ + */ + 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); - } + 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() - { - printf("CONTROLLER CONNECTED\n"); - } - void controllerDisconnected() - { - printf("CONTROLLER DISCONNECTED\n"); - } - void valueUpdate(const HIDMainItem& item, int32_t value) - { - 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 GenericPadCallback : public IGenericPadCallback { + void controllerConnected() { printf("CONTROLLER CONNECTED\n"); } + void controllerDisconnected() { printf("CONTROLLER DISCONNECTED\n"); } + void valueUpdate(const HIDMainItem& item, int32_t value) { + 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() - { - fprintf(stderr, "CONTROLLER DISCONNECTED\n"); - } - void controllerUpdate(const NintendoPowerAState& state) - { - fprintf(stderr, "%i %i\n" - "%i %i\n", - state.leftX, state.leftY, - state.rightX, state.rightY); - } +class NintendoPowerACallback : public INintendoPowerACallback { + void controllerDisconnected() { fprintf(stderr, "CONTROLLER DISCONNECTED\n"); } + void controllerUpdate(const NintendoPowerAState& state) { + fprintf(stderr, + "%i %i\n" + "%i %i\n", + state.leftX, state.leftY, state.rightX, state.rightY); + } }; -class TestDeviceFinder : public DeviceFinder -{ - std::shared_ptr m_smashAdapter; - std::shared_ptr m_nintendoPowerA; - std::shared_ptr m_ds3; - std::shared_ptr m_generic; - DolphinSmashAdapterCallback m_cb; - NintendoPowerACallback m_nintendoPowerACb; - DualshockPadCallback m_ds3CB; - GenericPadCallback m_genericCb; +class TestDeviceFinder : public DeviceFinder { + std::shared_ptr m_smashAdapter; + std::shared_ptr m_nintendoPowerA; + std::shared_ptr m_ds3; + std::shared_ptr 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) - { - auto dev = tok.openAndGetDevice(); - if (!dev) - return; + TestDeviceFinder() + : DeviceFinder({dev_typeid(DolphinSmashAdapter), dev_typeid(NintendoPowerA), dev_typeid(GenericPad)}) {} + void deviceConnected(DeviceToken& tok) { + auto dev = tok.openAndGetDevice(); + if (!dev) + return; - if (dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) - { - m_smashAdapter = std::static_pointer_cast(dev); - m_smashAdapter->setCallback(&m_cb); - } - else if (dev->getTypeHash() == dev_typeid(NintendoPowerA)) - { - m_nintendoPowerA = std::static_pointer_cast(dev); - m_nintendoPowerA->setCallback(&m_nintendoPowerACb); - } - else if (dev->getTypeHash() == dev_typeid(DualshockPad)) - { - m_ds3 = std::static_pointer_cast(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(dev); - m_generic->setCallback(&m_genericCb); - } - } - void deviceDisconnected(DeviceToken&, DeviceBase* device) - { - 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(); + if (dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) { + m_smashAdapter = std::static_pointer_cast(dev); + m_smashAdapter->setCallback(&m_cb); + } else if (dev->getTypeHash() == dev_typeid(NintendoPowerA)) { + m_nintendoPowerA = std::static_pointer_cast(dev); + m_nintendoPowerA->setCallback(&m_nintendoPowerACb); + } else if (dev->getTypeHash() == dev_typeid(DualshockPad)) { + m_ds3 = std::static_pointer_cast(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(dev); + m_generic->setCallback(&m_genericCb); } + } + void deviceDisconnected(DeviceToken&, DeviceBase* device) { + 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; -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) { + 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 resized(const SWindowRect& rect, bool sync) - { - 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) { + 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) { + fprintf(stderr, "Mouse Up %d (%f,%f)\n", int(button), coord.norm[0], coord.norm[1]); + } + void mouseMove(const SWindowCoord& coord) { + // fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]); + } + void mouseEnter(const SWindowCoord& coord) { + fprintf(stderr, "Mouse entered (%f,%f)\n", coord.norm[0], coord.norm[1]); + } + void mouseLeave(const SWindowCoord& coord) { fprintf(stderr, "Mouse left (%f,%f)\n", coord.norm[0], coord.norm[1]); } + void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { + // fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0], + // scroll.delta[1]); + } - void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) - { - 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) - { - fprintf(stderr, "Mouse Up %d (%f,%f)\n", int(button), coord.norm[0], coord.norm[1]); - } - void mouseMove(const SWindowCoord& coord) - { - //fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]); - } - void mouseEnter(const SWindowCoord &coord) - { - fprintf(stderr, "Mouse entered (%f,%f)\n", coord.norm[0], coord.norm[1]); - } - void mouseLeave(const SWindowCoord &coord) - { - fprintf(stderr, "Mouse left (%f,%f)\n", coord.norm[0], coord.norm[1]); - } - void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) - { - //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) { + // fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } + void touchUp(const STouchCoord& coord, uintptr_t tid) { + // fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } + void touchMove(const STouchCoord& coord, uintptr_t tid) { + // fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); + } - void touchDown(const STouchCoord& coord, uintptr_t tid) - { - //fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } - void touchUp(const STouchCoord& coord, uintptr_t tid) - { - //fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } - void touchMove(const STouchCoord& coord, uintptr_t tid) - { - //fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } + void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) {} + void charKeyUp(unsigned long charCode, EModifierKey mods) {} + void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) { + if (key == ESpecialKey::Enter && (mods & EModifierKey::Alt) != EModifierKey::None) + m_fullscreenToggleRequested = true; + } + void specialKeyUp(ESpecialKey key, EModifierKey mods) {} + void modKeyDown(EModifierKey mod, bool isRepeat) {} + void modKeyUp(EModifierKey mod) {} - void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) - { - - } - void charKeyUp(unsigned long charCode, EModifierKey mods) - { - - } - void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) - { - if (key == ESpecialKey::Enter && (mods & EModifierKey::Alt) != EModifierKey::None) - m_fullscreenToggleRequested = true; - } - void specialKeyUp(ESpecialKey key, EModifierKey mods) - { - - } - void modKeyDown(EModifierKey mod, bool isRepeat) - { - - } - void modKeyUp(EModifierKey mod) - { - - } - - void windowMoved(const SWindowRect& rect) - { - //fprintf(stderr, "Moved %d, %d (%d, %d)\n", rect.size[0], rect.size[1], rect.location[0], rect.location[1]); - } - - void destroyed() - { - m_windowInvalid = true; - } + void windowMoved(const SWindowRect& rect) { + // fprintf(stderr, "Moved %d, %d (%d, %d)\n", rect.size[0], rect.size[1], rect.location[0], rect.location[1]); + } + void destroyed() { m_windowInvalid = true; } }; -struct TestApplicationCallback : IApplicationCallback -{ - std::shared_ptr mainWindow; - boo::TestDeviceFinder devFinder; - CTestWindowCallback windowCallback; - bool running = true; +struct TestApplicationCallback : IApplicationCallback { + std::shared_ptr mainWindow; + boo::TestDeviceFinder devFinder; + CTestWindowCallback windowCallback; + bool running = true; - boo::ObjToken m_binding; - boo::ObjToken m_renderTarget; + boo::ObjToken m_binding; + boo::ObjToken m_renderTarget; - static void LoaderProc(TestApplicationCallback* self) - { - IGraphicsDataFactory* factory = self->mainWindow->getLoadContextDataFactory(); + 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); + 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 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 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 texture = ctx.newStaticTexture(256, 256, 1, TextureFormat::RGBA8, - boo::TextureClampMode::ClampToEdge, tex, 256*256*4).get(); + /* 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 texture = ctx.newStaticTexture(256, 256, 1, TextureFormat::RGBA8, + boo::TextureClampMode::ClampToEdge, tex, 256 * 256 * 4) + .get(); - /* Make shader pipeline */ - boo::ObjToken pipeline; - auto plat = ctx.platform(); + /* Make shader pipeline */ + boo::ObjToken pipeline; + auto plat = ctx.platform(); - AdditionalPipelineInfo info = - { - BlendFactor::One, BlendFactor::Zero, - Primitive::TriStrips, boo::ZTest::LEqual, - true, true, false, CullMode::None - }; + 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"; + 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"; + 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); - 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 + 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"; + 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"; + 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 + 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"; + 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"; + 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 + 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 \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"; + if (plat == IGraphicsDataFactory::Platform::Metal) { + static const char* VS = + "#include \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 \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 tex [[ texture(0) ]])\n" - "{\n" - " return tex.sample(samp, d.out_uv);\n" - "}\n"; + static const char* FS = + "#include \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 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 + 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); + /* Make shader data binding */ + self->m_binding = ctx.newShaderDataBinding(pipeline, vbo.get(), nullptr, nullptr, 0, nullptr, nullptr, 1, + &texture, nullptr, nullptr); - return true; - } BooTrace); - } + return true; + } BooTrace); + } - int appMain(IApplication* app) - { - mainWindow = app->newWindow(_SYS_STR("YAY!")); - mainWindow->setCallback(&windowCallback); - mainWindow->showWindow(); - windowCallback.m_lastRect = mainWindow->getWindowFrame(); - //mainWindow->setFullscreen(true); - devFinder.startScanning(); + int appMain(IApplication* app) { + mainWindow = app->newWindow(_SYS_STR("YAY!")); + mainWindow->setCallback(&windowCallback); + mainWindow->showWindow(); + windowCallback.m_lastRect = mainWindow->getWindowFrame(); + // mainWindow->setFullscreen(true); + devFinder.startScanning(); - IGraphicsCommandQueue* gfxQ = mainWindow->getCommandQueue(); + IGraphicsCommandQueue* gfxQ = mainWindow->getCommandQueue(); - LoaderProc(this); + 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*) - { + 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()); + } } - void appFilesOpen(IApplication*, const std::vector& paths) - { - fprintf(stderr, "OPENING: "); - for (const SystemString& path : paths) - { + + gfxQ->stopRenderer(); + m_renderTarget.reset(); + m_binding.reset(); + return 0; + } + void appQuitting(IApplication*) { running = false; } + void appFilesOpen(IApplication*, const std::vector& paths) { + fprintf(stderr, "OPENING: "); + for (const SystemString& path : paths) { #if _WIN32 - fwprintf(stderr, L"%s ", path.c_str()); + fwprintf(stderr, L"%s ", path.c_str()); #else - fprintf(stderr, "%s ", path.c_str()); + fprintf(stderr, "%s ", path.c_str()); #endif - } - fprintf(stderr, "\n"); } + fprintf(stderr, "\n"); + } }; -} +} // namespace boo #if !WINDOWS_STORE #if _WIN32 @@ -589,46 +478,43 @@ int wmain(int argc, const boo::SystemChar** argv) int main(int argc, const boo::SystemChar** argv) #endif { - logvisor::RegisterStandardExceptions(); - logvisor::RegisterConsoleLogger(); - boo::TestApplicationCallback appCb; - int ret = ApplicationRun(boo::IApplication::EPlatformType::Auto, - appCb, _SYS_STR("boo"), _SYS_STR("boo"), argc, argv, {}, 1, 1, true); - printf("IM DYING!!\n"); - return ret; + logvisor::RegisterStandardExceptions(); + logvisor::RegisterConsoleLogger(); + boo::TestApplicationCallback appCb; + int ret = ApplicationRun(boo::IApplication::EPlatformType::Auto, appCb, _SYS_STR("boo"), _SYS_STR("boo"), argc, argv, + {}, 1, 1, true); + printf("IM DYING!!\n"); + return ret; } #else using namespace Windows::ApplicationModel::Core; -[Platform::MTAThread] -int WINAPIV main(Platform::Array^ params) -{ - logvisor::RegisterStandardExceptions(); - logvisor::RegisterConsoleLogger(); - boo::TestApplicationCallback appCb; - boo::ViewProvider^ viewProvider = - ref new boo::ViewProvider(appCb, _SYS_STR("boo"), _SYS_STR("boo"), _SYS_STR("boo"), params, false); - CoreApplication::Run(viewProvider); - return 0; +[Platform::MTAThread] int WINAPIV main(Platform::Array ^ params) { + logvisor::RegisterStandardExceptions(); + logvisor::RegisterConsoleLogger(); + boo::TestApplicationCallback appCb; + boo::ViewProvider ^ viewProvider = + ref new boo::ViewProvider(appCb, _SYS_STR("boo"), _SYS_STR("boo"), _SYS_STR("boo"), params, false); + CoreApplication::Run(viewProvider); + return 0; } #endif #if _WIN32 && !WINDOWS_STORE -int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) -{ - int argc = 0; - const boo::SystemChar** argv; - if (lpCmdLine[0]) - argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc)); - static boo::SystemChar selfPath[1024]; - GetModuleFileNameW(nullptr, selfPath, 1024); - static const boo::SystemChar* booArgv[32] = {}; - booArgv[0] = selfPath; - for (int i=0 ; i