Huge shader infrastructure refactor

This commit is contained in:
Jack Andersen
2018-10-06 16:49:22 -10:00
parent 08d632a8bd
commit c29d837ab5
55 changed files with 10392 additions and 1472 deletions

View File

@@ -3,6 +3,7 @@
#include <atomic>
#include <mutex>
#include "nxstl/mutex"
namespace boo
{

View File

@@ -4,6 +4,7 @@
#include <boo/boo.hpp>
#include <mutex>
#include <condition_variable>
#include "nxstl/condition_variable"
namespace boo
{

View File

@@ -41,7 +41,8 @@ public:
UWP = 7,
Revolution = 8,
Cafe = 9,
Qt = 10
NX = 10,
Qt = 11
};
virtual EPlatformType getPlatformType() const=0;

View File

@@ -26,7 +26,8 @@ public:
D3D11 = 4,
Metal = 6,
GX = 7,
GX2 = 8
GX2 = 8,
NX = 9
};
enum class EPixelFormat
@@ -39,7 +40,7 @@ public:
RGBAF32_Z24 = 5
};
virtual ~IGraphicsContext() {}
virtual ~IGraphicsContext() = default;
virtual EGraphicsAPI getAPI() const=0;
virtual EPixelFormat getPixelFormat() const=0;

View File

@@ -60,15 +60,15 @@ namespace boo
using SystemString = std::wstring;
using SystemStringView = std::wstring_view;
using SystemChar = wchar_t;
# ifndef _S
# define _S(val) L ## val
# ifndef _SYS_STR
# define _SYS_STR(val) L ## val
# endif
#else
using SystemString = std::string;
using SystemStringView = std::string_view;
using SystemChar = char;
# ifndef _S
# define _S(val) val
# ifndef _SYS_STR
# define _SYS_STR(val) val
# endif
#endif

View File

@@ -1,6 +1,8 @@
#ifndef BOO_THREADLOCALPTR_HPP
#define BOO_THREADLOCALPTR_HPP
#ifndef __SWITCH__
#if _WIN32
#else
#include <pthread.h>
@@ -28,4 +30,6 @@ public:
T* operator->() {return get();}
};
#endif
#endif // BOO_THREADLOCALPTR_HPP

View File

@@ -23,7 +23,7 @@ class D3DDataFactory : public IGraphicsDataFactory
public:
virtual ~D3DDataFactory() {}
class Context : public IGraphicsDataFactory::Context
class Context final : public IGraphicsDataFactory::Context
{
public:
bool bindingNeedsVertexFormat() const {return false;}

View File

@@ -21,7 +21,7 @@ struct GLContext
class GLDataFactory : public IGraphicsDataFactory
{
public:
class Context : public IGraphicsDataFactory::Context
class Context final : public IGraphicsDataFactory::Context
{
friend class GLDataFactoryImpl;
GLDataFactory& m_parent;
@@ -30,7 +30,7 @@ public:
~Context();
public:
Platform platform() const { return Platform::OpenGL; }
const SystemChar* platformName() const { return _S("OpenGL"); }
const SystemChar* platformName() const { return _SYS_STR("OpenGL"); }
ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
@@ -43,28 +43,17 @@ public:
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount);
bool bindingNeedsVertexFormat() const { return true; }
ObjToken<IVertexFormat> newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0);
ObjToken<IShaderStage>
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
size_t texCount, const char** texNames,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling, bool overwriteAlpha = true);
ObjToken<IShaderPipeline> newTessellationShaderPipeline(const char* vertSource, const char* fragSource,
const char* controlSource, const char* evaluationSource,
size_t texCount, const char** texNames,
size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac, uint32_t patchSize,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling, bool overwriteAlpha = true);
ObjToken<IShaderPipeline>
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo);
ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IVertexFormat>& vtxFormat,
const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,

View File

@@ -8,6 +8,10 @@
#include "boo/ThreadLocalPtr.hpp"
#include "boo/BooObject.hpp"
#ifdef __SWITCH__
#include <ctype.h>
#endif
namespace boo
{
struct IGraphicsCommandQueue;
@@ -120,11 +124,6 @@ protected:
ITextureR() : ITexture(TextureType::Render) {}
};
/** Opaque token for representing the data layout of a vertex
* in a VBO. Also able to reference buffers for platforms like
* OpenGL that cache object refs */
struct IVertexFormat : IObj {};
/** Types of vertex attributes */
enum class VertexSemantic
{
@@ -147,16 +146,35 @@ ENABLE_BITWISE_ENUM(VertexSemantic)
/** Used to create IVertexFormat */
struct VertexElementDescriptor
{
ObjToken<IGraphicsBuffer> vertBuffer;
ObjToken<IGraphicsBuffer> indexBuffer;
VertexSemantic semantic;
int semanticIdx = 0;
VertexElementDescriptor() = default;
VertexElementDescriptor(const ObjToken<IGraphicsBuffer>& v, const ObjToken<IGraphicsBuffer>& i,
VertexSemantic s, int idx=0)
: vertBuffer(v), indexBuffer(i), semantic(s), semanticIdx(idx) {}
VertexElementDescriptor(VertexSemantic s, int idx=0)
: semantic(s), semanticIdx(idx) {}
};
/** Structure for passing vertex format info for pipeline construction */
struct VertexFormatInfo
{
size_t elementCount = 0;
const VertexElementDescriptor* elements = nullptr;
VertexFormatInfo() = default;
VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem)
: elementCount(sz), elements(elem) {}
template<typename T>
VertexFormatInfo(const T& tp)
: elementCount(std::extent_v<T>), elements(tp) {}
VertexFormatInfo(const std::initializer_list<VertexElementDescriptor>& l)
: elementCount(l.size()), elements(l.begin()) {}
};
/** Opaque token for referencing a shader stage usable in a graphics pipeline */
struct IShaderStage : IObj {};
/** Opaque token for referencing a complete graphics pipeline state necessary
* to rasterize geometry (shaders and blending modes mainly) */
struct IShaderPipeline : IObj {};
@@ -169,8 +187,12 @@ struct IShaderDataBinding : IObj {};
/** Used wherever distinction of pipeline stages is needed */
enum class PipelineStage
{
Null,
Vertex,
Fragment
Fragment,
Geometry,
Control,
Evaluation
};
/** Used by platform shader pipeline constructors */
@@ -178,7 +200,7 @@ enum class Primitive
{
Triangles,
TriStrips,
Patches /* Do not use directly, construct a tessellation pipeline instead */
Patches
};
/** Used by platform shader pipeline constructors */
@@ -219,6 +241,22 @@ enum class BlendFactor
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;
};
/** Factory object for creating batches of resources as an IGraphicsData token */
struct IGraphicsDataFactory
{
@@ -232,7 +270,7 @@ struct IGraphicsDataFactory
Metal,
Vulkan,
GX,
GX2
NX
};
virtual Platform platform() const=0;
virtual const SystemChar* platformName() const=0;
@@ -259,14 +297,30 @@ struct IGraphicsDataFactory
newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount)=0;
virtual bool bindingNeedsVertexFormat() const=0;
virtual ObjToken<IVertexFormat>
newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0)=0;
virtual ObjToken<IShaderStage>
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage)=0;
ObjToken<IShaderStage>
newShaderStage(const std::vector<uint8_t>& data, PipelineStage stage)
{
return newShaderStage(data.data(), data.size(), stage);
}
virtual ObjToken<IShaderPipeline>
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo)=0;
ObjToken<IShaderPipeline>
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
const VertexFormatInfo& vtxFmt, const AdditionalPipelineInfo& additionalInfo)
{
return newShaderPipeline(vertex, fragment, {}, {}, {}, vtxFmt, additionalInfo);
}
virtual ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IVertexFormat>& vtxFormat,
const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
@@ -278,7 +332,6 @@ struct IGraphicsDataFactory
ObjToken<IShaderDataBinding>
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IVertexFormat>& vtxFormat,
const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
@@ -287,7 +340,7 @@ struct IGraphicsDataFactory
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0)
{
return newShaderDataBinding(pipeline, vtxFormat, vbo, instVbo, ibo,
return newShaderDataBinding(pipeline, vbo, instVbo, ibo,
ubufCount, ubufs, ubufStages, nullptr,
nullptr, texCount, texs, texBindIdx, depthBind,
baseVert, baseInst);

View File

@@ -14,7 +14,7 @@ struct BaseGraphicsData;
class MetalDataFactory : public IGraphicsDataFactory
{
public:
class Context : public IGraphicsDataFactory::Context
class Context final : public IGraphicsDataFactory::Context
{
friend class MetalDataFactoryImpl;
MetalDataFactory& m_parent;

View File

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

View File

@@ -134,7 +134,7 @@ extern VulkanContext g_VulkanContext;
class VulkanDataFactory : public IGraphicsDataFactory
{
public:
class Context : public IGraphicsDataFactory::Context
class Context final : public IGraphicsDataFactory::Context
{
friend class VulkanDataFactoryImpl;
VulkanDataFactory& m_parent;
@@ -143,7 +143,7 @@ public:
~Context();
public:
Platform platform() const {return Platform::Vulkan;}
const SystemChar* platformName() const {return _S("Vulkan");}
const SystemChar* platformName() const {return _SYS_STR("Vulkan");}
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
@@ -157,58 +157,17 @@ public:
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount);
bool bindingNeedsVertexFormat() const {return false;}
boo::ObjToken<IVertexFormat> newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0);
ObjToken<IShaderStage>
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
boo::ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
std::vector<unsigned int>* vertBlobOut,
std::vector<unsigned int>* fragBlobOut,
std::vector<unsigned char>* pipelineBlob,
const boo::ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling, bool overwriteAlpha = true);
boo::ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
const boo::ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
{
return newShaderPipeline(vertSource, fragSource, nullptr, nullptr, nullptr,
vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite,
colorWrite, alphaWrite, culling);
}
boo::ObjToken<IShaderPipeline> newTessellationShaderPipeline(const char* vertSource, const char* fragSource,
const char* controlSource, const char* evaluationSource,
std::vector<unsigned int>* vertBlobOut,
std::vector<unsigned int>* fragBlobOut,
std::vector<unsigned int>* controlBlobOut,
std::vector<unsigned int>* evaluationBlobOut,
std::vector<unsigned char>* pipelineBlob,
const boo::ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, uint32_t patchSize,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling, bool overwriteAlpha = true);
boo::ObjToken<IShaderPipeline> newTessellationShaderPipeline(const char* vertSource, const char* fragSource,
const char* controlSource, const char* evaluationSource,
const boo::ObjToken<IVertexFormat>& vtxFmt,
BlendFactor srcFac, BlendFactor dstFac, uint32_t patchSize,
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
{
return newTessellationShaderPipeline(vertSource, fragSource, controlSource, evaluationSource,
nullptr, nullptr, nullptr, nullptr, nullptr,
vtxFmt, srcFac, dstFac, patchSize, depthTest, depthWrite,
colorWrite, alphaWrite, culling);
}
ObjToken<IShaderPipeline>
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo);
boo::ObjToken<IShaderDataBinding>
newShaderDataBinding(const boo::ObjToken<IShaderPipeline>& pipeline,
const boo::ObjToken<IVertexFormat>& vtxFormat,
const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& instVbo,
const boo::ObjToken<IGraphicsBuffer>& ibo,
@@ -218,6 +177,8 @@ public:
const int* bindIdxs, const bool* bindDepth,
size_t baseVert = 0, size_t baseInst = 0);
};
static std::vector<uint8_t> CompileGLSL(const char* source, PipelineStage stage);
};
}

View File

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

View File

@@ -7,6 +7,7 @@
#include <memory>
#include <vector>
#include <mutex>
#include "nxstl/mutex"
#include "boo/System.hpp"
#if _WIN32
@@ -31,13 +32,17 @@ class DeviceBase : public std::enable_shared_from_this<DeviceBase>
friend struct DeviceSignature;
friend class HIDDeviceIOKit;
uint64_t m_typeHash;
class DeviceToken* m_token;
std::shared_ptr<IHIDDevice> m_hidDev;
void _deviceDisconnected();
public:
DeviceBase(DeviceToken* token);
DeviceBase(uint64_t typeHash, DeviceToken* token);
virtual ~DeviceBase() = default;
uint64_t getTypeHash() const { return m_typeHash; }
void closeDevice();
/* Callbacks */
@@ -76,7 +81,7 @@ protected:
std::mutex m_callbackLock;
CB* m_callback = nullptr;
public:
TDeviceBase(DeviceToken* token) : DeviceBase(token) {}
TDeviceBase(uint64_t typeHash, DeviceToken* token) : DeviceBase(typeHash, token) {}
void setCallback(CB* cb)
{
std::lock_guard<std::mutex> lk(m_callbackLock);

View File

@@ -93,7 +93,7 @@ public:
};
/* Application must specify its interested device-types */
DeviceFinder(std::unordered_set<std::type_index> types)
DeviceFinder(std::unordered_set<uint64_t> types)
{
if (skDevFinder)
{
@@ -101,12 +101,12 @@ public:
abort();
}
skDevFinder = this;
for (const std::type_index& typeIdx : types)
for (const uint64_t& typeHash : types)
{
const DeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name)
{
if (sigIter->m_typeIdx == typeIdx)
if (sigIter->m_typeHash == typeHash)
m_types.push_back(sigIter);
++sigIter;
}

View File

@@ -21,26 +21,28 @@ enum class DeviceType
class DeviceToken;
class DeviceBase;
#define dev_typeid(type) std::hash<std::string>()(#type)
struct DeviceSignature
{
typedef std::vector<const DeviceSignature*> TDeviceSignatureSet;
typedef std::function<std::shared_ptr<DeviceBase>(DeviceToken*)> TFactoryLambda;
const char* m_name;
std::type_index m_typeIdx;
uint64_t m_typeHash;
unsigned m_vid, m_pid;
TFactoryLambda m_factory;
DeviceType m_type;
DeviceSignature() : m_name(NULL), m_typeIdx(typeid(DeviceSignature)) {} /* Sentinel constructor */
DeviceSignature(const char* name, std::type_index&& typeIdx, unsigned vid, unsigned pid,
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_typeIdx(typeIdx), m_vid(vid), m_pid(pid),
: m_name(name), m_typeHash(typeHash), m_vid(vid), m_pid(pid),
m_factory(factory), m_type(type) {}
static bool DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet);
static std::shared_ptr<DeviceBase> DeviceNew(DeviceToken& token);
};
#define DEVICE_SIG(name, vid, pid, type) \
DeviceSignature(#name, typeid(name), vid, pid,\
DeviceSignature(#name, dev_typeid(name), vid, pid,\
[](DeviceToken* tok) -> std::shared_ptr<DeviceBase> {return std::make_shared<name>(tok);}, type)
#define DEVICE_SIG_SENTINEL() DeviceSignature()

View File

@@ -68,7 +68,7 @@ class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallbac
uint8_t m_knownControllers = 0;
uint8_t m_rumbleRequest = 0;
bool m_hardStop[4] = {false};
uint8_t m_rumbleState = 0;
uint8_t m_rumbleState = 0xf; /* Force initial send of stop-rumble command */
void deviceDisconnected();
void initialCycle();
void transferCycle();

View File

@@ -2,6 +2,7 @@
#define XINPUTPAD_HPP
#include "DeviceBase.hpp"
#include "DeviceSignature.hpp"
#include "boo/System.hpp"
namespace boo
@@ -39,7 +40,7 @@ class XInputPad final : public TDeviceBase<IXInputPadCallback>
uint16_t m_rumbleRequest[2] = {};
uint16_t m_rumbleState[2] = {};
public:
XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(token) {}
XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(dev_typeid(XInputPad), token) {}
void deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);