New object management architecture for OpenGL subsystem (more platforms to come)

This commit is contained in:
Jack Andersen 2017-11-02 23:39:26 -10:00
parent 90e2df40dd
commit 021143fd89
10 changed files with 692 additions and 889 deletions

View File

@ -285,6 +285,7 @@ add_library(boo
include/boo/ThreadLocalPtr.hpp include/boo/ThreadLocalPtr.hpp
include/boo/DeferredWindowEvents.hpp include/boo/DeferredWindowEvents.hpp
include/boo/System.hpp include/boo/System.hpp
include/boo/BooObject.hpp
include/boo/boo.hpp include/boo/boo.hpp
InputDeviceClasses.cpp InputDeviceClasses.cpp
${PLAT_SRCS} ${PLAT_SRCS}

47
include/boo/BooObject.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef BOOOBJECT_HPP
#define BOOOBJECT_HPP
#include <atomic>
namespace boo
{
class IObj
{
std::atomic_int m_refCount = {0};
public:
virtual ~IObj() = default;
void increment() { m_refCount++; }
void decrement()
{
if (m_refCount.fetch_sub(1) == 1)
delete this;
}
};
template<class SubCls>
class ObjToken
{
SubCls* m_obj = nullptr;
public:
ObjToken() = default;
ObjToken(SubCls* obj) : m_obj(obj) { m_obj->increment(); }
ObjToken(const ObjToken& other) : m_obj(other.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; m_obj->increment(); return *this; }
ObjToken& operator=(const ObjToken& other)
{ if (m_obj) m_obj->decrement(); m_obj = other.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<class T> T* cast() const { return static_cast<T*>(m_obj); }
operator bool() const { return m_obj != nullptr; }
};
}
#endif // BOOOBJECT_HPP

View File

@ -8,6 +8,7 @@
namespace boo namespace boo
{ {
class BaseGraphicsData;
class GLDataFactory : public IGraphicsDataFactory class GLDataFactory : public IGraphicsDataFactory
{ {
@ -16,40 +17,44 @@ public:
{ {
friend class GLDataFactoryImpl; friend class GLDataFactoryImpl;
GLDataFactory& m_parent; GLDataFactory& m_parent;
Context(GLDataFactory& parent) : m_parent(parent) {} ObjToken<BaseGraphicsData> m_data;
Context(GLDataFactory& parent);
~Context();
public: public:
Platform platform() const {return Platform::OpenGL;} Platform platform() const { return Platform::OpenGL; }
const SystemChar* platformName() const {return _S("OpenGL");} const SystemChar* platformName() const { return _S("OpenGL"); }
IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count); ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, 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); TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode);
ITextureR* newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount); size_t colorBindingCount, size_t depthBindingCount);
bool bindingNeedsVertexFormat() const {return true;} bool bindingNeedsVertexFormat() const { return true; }
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, ObjToken<IVertexFormat> newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0); size_t baseVert = 0, size_t baseInst = 0);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
size_t texCount, const char** texNames, size_t texCount, const char** texNames,
size_t uniformBlockCount, const char** uniformBlockNames, size_t uniformBlockCount, const char** uniformBlockNames,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim, BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite, ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling); bool alphaWrite, CullMode culling);
IShaderDataBinding* ObjToken<IShaderDataBinding>
newShaderDataBinding(IShaderPipeline* pipeline, newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
IVertexFormat* vtxFormat, const ObjToken<IVertexFormat>& vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, const ObjToken<IGraphicsBuffer>& vbo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdx, const bool* depthBind, const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0); size_t baseVert = 0, size_t baseInst = 0);
}; };

View File

@ -16,12 +16,12 @@ struct IGraphicsCommandQueue
virtual Platform platform() const=0; virtual Platform platform() const=0;
virtual const SystemChar* platformName() const=0; virtual const SystemChar* platformName() const=0;
virtual void setShaderDataBinding(IShaderDataBinding* binding)=0; virtual void setShaderDataBinding(const ObjToken<IShaderDataBinding>& binding)=0;
virtual void setRenderTarget(ITextureR* target)=0; virtual void setRenderTarget(const ObjToken<ITextureR>& target)=0;
virtual void setViewport(const SWindowRect& rect, float znear=0.f, float zfar=1.f)=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 setScissor(const SWindowRect& rect)=0;
virtual void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)=0; virtual void resizeRenderTexture(const ObjToken<ITextureR>& tex, size_t width, size_t height)=0;
virtual void schedulePostFrameHandler(std::function<void(void)>&& func)=0; virtual void schedulePostFrameHandler(std::function<void(void)>&& func)=0;
virtual void setClearColor(const float rgba[4])=0; virtual void setClearColor(const float rgba[4])=0;
@ -32,9 +32,9 @@ struct IGraphicsCommandQueue
virtual void drawInstances(size_t start, size_t count, size_t instCount)=0; virtual void drawInstances(size_t start, size_t count, size_t instCount)=0;
virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount)=0; virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount)=0;
virtual void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, virtual void resolveBindTexture(const ObjToken<ITextureR>& texture, const SWindowRect& rect,
bool tlOrigin, int bindIdx, bool color, bool depth)=0; bool tlOrigin, int bindIdx, bool color, bool depth)=0;
virtual void resolveDisplay(ITextureR* source)=0; virtual void resolveDisplay(const ObjToken<ITextureR>& source)=0;
virtual void execute()=0; virtual void execute()=0;
virtual void stopRenderer()=0; virtual void stopRenderer()=0;

View File

@ -6,47 +6,12 @@
#include <stdint.h> #include <stdint.h>
#include "boo/System.hpp" #include "boo/System.hpp"
#include "boo/ThreadLocalPtr.hpp" #include "boo/ThreadLocalPtr.hpp"
#include "boo/BooObject.hpp"
namespace boo namespace boo
{ {
struct IGraphicsCommandQueue; struct IGraphicsCommandQueue;
/** Opaque object for maintaining ownership of factory-created resources */
struct IGraphicsData { virtual ~IGraphicsData() = default; };
class GraphicsDataToken;
/** Opaque object for maintaining ownership of factory-created pool buffers */
struct IGraphicsBufferPool {};
class GraphicsBufferPoolToken;
struct IGraphicsBuffer
{
bool dynamic() const {return m_dynamic;}
IGraphicsData* m_parentData;
protected:
bool m_dynamic;
IGraphicsBuffer(IGraphicsData* parent, bool dynamic)
: m_parentData(parent), m_dynamic(dynamic) {}
virtual ~IGraphicsBuffer() = default;
};
/** Static resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferS : IGraphicsBuffer
{
protected:
IGraphicsBufferS(IGraphicsData* parent) : IGraphicsBuffer(parent, false) {}
};
/** Dynamic resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferD : IGraphicsBuffer
{
virtual void load(const void* data, size_t sz)=0;
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
IGraphicsBufferD(IGraphicsData* parent) : IGraphicsBuffer(parent, true) {}
};
/** Supported buffer uses */ /** Supported buffer uses */
enum class BufferUse enum class BufferUse
{ {
@ -56,6 +21,33 @@ enum class BufferUse
Uniform Uniform
}; };
/** Typeless graphics buffer */
struct IGraphicsBuffer : IObj
{
bool dynamic() const { return m_dynamic; }
protected:
bool m_dynamic;
explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {}
};
/** Static resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferS : IGraphicsBuffer
{
protected:
IGraphicsBufferS() : IGraphicsBuffer(false) {}
};
/** Dynamic resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferD : IGraphicsBuffer
{
virtual void load(const void* data, size_t sz)=0;
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
IGraphicsBufferD() : IGraphicsBuffer(true) {}
};
/** Texture access types */
enum class TextureType enum class TextureType
{ {
Static, Static,
@ -64,48 +56,6 @@ enum class TextureType
Render Render
}; };
struct ITexture
{
TextureType type() const {return m_type;}
IGraphicsData* m_parentData;
protected:
TextureType m_type;
ITexture(IGraphicsData* parent, TextureType type)
: m_parentData(parent), m_type(type) {}
virtual ~ITexture() {}
};
/** Static resource buffer for textures */
struct ITextureS : ITexture
{
protected:
ITextureS(IGraphicsData* parent) : ITexture(parent, TextureType::Static) {}
};
/** Static-array resource buffer for array textures */
struct ITextureSA : ITexture
{
protected:
ITextureSA(IGraphicsData* parent) : ITexture(parent, TextureType::StaticArray) {}
};
/** Dynamic resource buffer for textures */
struct ITextureD : ITexture
{
virtual void load(const void* data, size_t sz)=0;
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
ITextureD(IGraphicsData* parent) : ITexture(parent, TextureType::Dynamic) {}
};
/** Resource buffer for render-target textures */
struct ITextureR : ITexture
{
protected:
ITextureR(IGraphicsData* parent) : ITexture(parent, TextureType::Render) {}
};
/** Supported texture formats */ /** Supported texture formats */
enum class TextureFormat enum class TextureFormat
{ {
@ -115,21 +65,57 @@ enum class TextureFormat
PVRTC4 PVRTC4
}; };
/** Supported texture clamp modes */
enum class TextureClampMode enum class TextureClampMode
{ {
Repeat, Repeat,
ClampToWhite ClampToWhite
}; };
/** Typeless texture */
struct ITexture : IObj
{
TextureType type() const { return m_type; }
protected:
TextureType m_type;
explicit ITexture(TextureType type) : m_type(type) {}
};
/** Static resource buffer for textures */
struct ITextureS : ITexture
{
protected:
ITextureS() : ITexture(TextureType::Static) {}
};
/** Static-array resource buffer for array textures */
struct ITextureSA : ITexture
{
protected:
ITextureSA() : ITexture(TextureType::StaticArray) {}
};
/** Dynamic resource buffer for textures */
struct ITextureD : ITexture
{
virtual void load(const void* data, size_t sz)=0;
virtual void* map(size_t sz)=0;
virtual void unmap()=0;
protected:
ITextureD() : ITexture(TextureType::Dynamic) {}
};
/** Resource buffer for render-target textures */
struct ITextureR : ITexture
{
protected:
ITextureR() : ITexture(TextureType::Render) {}
};
/** Opaque token for representing the data layout of a vertex /** Opaque token for representing the data layout of a vertex
* in a VBO. Also able to reference buffers for platforms like * in a VBO. Also able to reference buffers for platforms like
* OpenGL that cache object refs */ * OpenGL that cache object refs */
struct IVertexFormat struct IVertexFormat : IObj {};
{
IGraphicsData* m_parentData;
protected:
IVertexFormat(IGraphicsData* parent) : m_parentData(parent) {}
};
/** Types of vertex attributes */ /** Types of vertex attributes */
enum class VertexSemantic enum class VertexSemantic
@ -164,17 +150,12 @@ struct VertexElementDescriptor
/** Opaque token for referencing a complete graphics pipeline state necessary /** Opaque token for referencing a complete graphics pipeline state necessary
* to rasterize geometry (shaders and blending modes mainly) */ * to rasterize geometry (shaders and blending modes mainly) */
struct IShaderPipeline struct IShaderPipeline : IObj {};
{
IGraphicsData* m_parentData;
protected:
IShaderPipeline(IGraphicsData* parent) : m_parentData(parent) {}
};
/** Opaque token serving as indirection table for shader resources /** Opaque token serving as indirection table for shader resources
* and IShaderPipeline reference. Each renderable surface-material holds one * and IShaderPipeline reference. Each renderable surface-material holds one
* as a reference */ * as a reference */
struct IShaderDataBinding {}; struct IShaderDataBinding : IObj {};
/** Used wherever distinction of pipeline stages is needed */ /** Used wherever distinction of pipeline stages is needed */
enum class PipelineStage enum class PipelineStage
@ -252,44 +233,48 @@ struct IGraphicsDataFactory
virtual Platform platform() const=0; virtual Platform platform() const=0;
virtual const SystemChar* platformName() const=0; virtual const SystemChar* platformName() const=0;
virtual IGraphicsBufferS* virtual ObjToken<IGraphicsBufferS>
newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)=0; newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)=0;
virtual IGraphicsBufferD* virtual ObjToken<IGraphicsBufferD>
newDynamicBuffer(BufferUse use, size_t stride, size_t count)=0; newDynamicBuffer(BufferUse use, size_t stride, size_t count)=0;
virtual ITextureS* virtual ObjToken<ITextureS>
newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz)=0; TextureClampMode clampMode, const void* data, size_t sz)=0;
virtual ITextureSA* virtual ObjToken<ITextureSA>
newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)=0; TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)=0;
virtual ITextureD* virtual ObjToken<ITextureD>
newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode)=0; newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode)=0;
virtual ITextureR* virtual ObjToken<ITextureR>
newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount)=0; size_t colorBindingCount, size_t depthBindingCount)=0;
virtual bool bindingNeedsVertexFormat() const=0; virtual bool bindingNeedsVertexFormat() const=0;
virtual IVertexFormat* virtual ObjToken<IVertexFormat>
newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0)=0; size_t baseVert = 0, size_t baseInst = 0)=0;
virtual IShaderDataBinding* virtual ObjToken<IShaderDataBinding>
newShaderDataBinding(IShaderPipeline* pipeline, newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
IVertexFormat* vtxFormat, const ObjToken<IVertexFormat>& vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, const ObjToken<IGraphicsBuffer>& vbo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdx, const bool* depthBind, const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0)=0; size_t baseVert = 0, size_t baseInst = 0)=0;
IShaderDataBinding* ObjToken<IShaderDataBinding>
newShaderDataBinding(IShaderPipeline* pipeline, newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
IVertexFormat* vtxFormat, const ObjToken<IVertexFormat>& vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, const ObjToken<IGraphicsBuffer>& vbo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>& instVbo,
size_t texCount, ITexture** texs, const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdx, const bool* depthBind, const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0) size_t baseVert = 0, size_t baseInst = 0)
{ {
@ -300,130 +285,13 @@ struct IGraphicsDataFactory
} }
}; };
virtual GraphicsDataToken commitTransaction(const std::function<bool(Context& ctx)>&)=0; virtual void commitTransaction(const std::function<bool(Context& ctx)>&)=0;
virtual GraphicsBufferPoolToken newBufferPool()=0;
virtual void destroyAllData()=0; virtual ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count)=0;
private:
friend class GraphicsDataToken;
virtual void destroyData(IGraphicsData*)=0;
friend class GraphicsBufferPoolToken;
virtual void destroyPool(IGraphicsBufferPool*)=0;
virtual IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool* pool, BufferUse use,
size_t stride, size_t count)=0;
virtual void deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf)=0;
}; };
using FactoryCommitFunc = std::function<bool(IGraphicsDataFactory::Context& ctx)>; using GraphicsDataFactoryContext = IGraphicsDataFactory::Context;
using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>;
/** Ownership token for maintaining lifetime of factory-created resources.
* Deletion of this token triggers mass-deallocation of the factory's
* IGraphicsData (please don't delete and draw contained resources in the same frame). */
class GraphicsDataToken
{
friend class GLDataFactoryImpl;
friend class D3D12DataFactory;
friend class D3D11DataFactory;
friend class MetalDataFactoryImpl;
friend class VulkanDataFactoryImpl;
IGraphicsDataFactory* m_factory = nullptr;
IGraphicsData* m_data = nullptr;
GraphicsDataToken(IGraphicsDataFactory* factory, IGraphicsData* data)
: m_factory(factory), m_data(data) {}
public:
void doDestroy()
{
if (m_factory && m_data)
{
m_factory->destroyData(m_data);
m_factory = nullptr;
m_data = nullptr;
}
}
GraphicsDataToken() = default;
GraphicsDataToken(const GraphicsDataToken& other) = delete;
GraphicsDataToken(GraphicsDataToken&& other)
{
m_factory = other.m_factory;
other.m_factory = nullptr;
m_data = other.m_data;
other.m_data = nullptr;
}
GraphicsDataToken& operator=(const GraphicsDataToken& other) = delete;
GraphicsDataToken& operator=(GraphicsDataToken&& other)
{
doDestroy();
m_factory = other.m_factory;
other.m_factory = nullptr;
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
~GraphicsDataToken() {doDestroy();}
operator bool() const {return m_factory && m_data;}
};
/** Ownership token for maintaining lifetimes of an appendable list of dynamic buffers.
* Deletion of this token triggers mass-deallocation of the IGraphicsBufferPool
* (please don't delete and draw contained resources in the same frame). */
class GraphicsBufferPoolToken
{
friend class GLDataFactoryImpl;
friend class D3D12DataFactory;
friend class D3D11DataFactory;
friend class MetalDataFactoryImpl;
friend class VulkanDataFactoryImpl;
IGraphicsDataFactory* m_factory = nullptr;
IGraphicsBufferPool* m_pool = nullptr;
GraphicsBufferPoolToken(IGraphicsDataFactory* factory, IGraphicsBufferPool* pool)
: m_factory(factory), m_pool(pool) {}
public:
void doDestroy()
{
if (m_factory && m_pool)
{
m_factory->destroyPool(m_pool);
m_factory = nullptr;
m_pool = nullptr;
}
}
GraphicsBufferPoolToken() = default;
GraphicsBufferPoolToken(const GraphicsBufferPoolToken& other) = delete;
GraphicsBufferPoolToken(GraphicsBufferPoolToken&& other)
{
m_factory = other.m_factory;
other.m_factory = nullptr;
m_pool = other.m_pool;
other.m_pool = nullptr;
}
GraphicsBufferPoolToken& operator=(const GraphicsBufferPoolToken& other) = delete;
GraphicsBufferPoolToken& operator=(GraphicsBufferPoolToken&& other)
{
doDestroy();
m_factory = other.m_factory;
other.m_factory = nullptr;
m_pool = other.m_pool;
other.m_pool = nullptr;
return *this;
}
~GraphicsBufferPoolToken() {doDestroy();}
operator bool() const {return m_factory && m_pool;}
IGraphicsBufferD* newPoolBuffer(BufferUse use,
size_t stride, size_t count)
{
if (m_factory)
return m_factory->newPoolBuffer(m_pool, use, stride, count);
return nullptr;
}
void deletePoolBuffer(IGraphicsBufferD* buf)
{
if (m_factory)
m_factory->deletePoolBuffer(m_pool, buf);
}
};
} }

View File

@ -19,37 +19,41 @@ public:
MetalDataFactory& m_parent; MetalDataFactory& m_parent;
Context(MetalDataFactory& parent) : m_parent(parent) {} Context(MetalDataFactory& parent) : m_parent(parent) {}
public: public:
Platform platform() const {return Platform::Metal;} Platform platform() const { return Platform::Metal; }
const char* platformName() const {return "Metal";} const SystemChar* platformName() const { return _S("Metal"); }
IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count); ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, 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); TextureFormat fmt, TextureClampMode clampMode, const void* data,
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); size_t sz);
ITextureR* newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
size_t colorBindCount, size_t depthBindCount); TextureClampMode clampMode);
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount);
bool bindingNeedsVertexFormat() const {return false;} bool bindingNeedsVertexFormat() const { return false; }
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements, ObjToken<IVertexFormat> newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements,
size_t baseVert = 0, size_t baseInst = 0); size_t baseVert = 0, size_t baseInst = 0);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, ObjToken<IShaderPipeline> newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples, IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim, BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite, ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling); bool alphaWrite, CullMode culling);
IShaderDataBinding* ObjToken<IShaderDataBinding>
newShaderDataBinding(IShaderPipeline* pipeline, newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
IVertexFormat* vtxFormat, const ObjToken<IVertexFormat>& vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, const ObjToken<IGraphicsBuffer>& vbo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdxs, const bool* depthBind, const int* texBindIdxs, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0); size_t baseVert = 0, size_t baseInst = 0);
}; };

View File

@ -6,63 +6,219 @@
#include <atomic> #include <atomic>
#include <vector> #include <vector>
#include <mutex>
#include "boo/graphicsdev/IGraphicsDataFactory.hpp" #include "boo/graphicsdev/IGraphicsDataFactory.hpp"
namespace boo namespace boo
{ {
class IGraphicsDataPriv : public IGraphicsData struct BaseGraphicsData;
struct BaseGraphicsPool;
template<class NodeCls, class DataCls = BaseGraphicsData>
struct GraphicsDataNode;
/** Inherited by data factory implementations to track the head data and pool nodes */
struct GraphicsDataFactoryHead
{ {
std::atomic_int m_refCount = {1}; std::mutex m_dataMutex;
public: BaseGraphicsData* m_dataHead = nullptr;
void increment() { m_refCount++; } BaseGraphicsPool* m_poolHead = nullptr;
void decrement()
{
if (m_refCount.fetch_sub(1) == 1)
delete this;
}
}; };
class IShaderDataBindingPriv : public IShaderDataBinding /** Private generalized data container class.
* Keeps head pointers to all graphics objects by type
*/
struct BaseGraphicsData : IObj
{ {
IGraphicsDataPriv* m_parent; GraphicsDataFactoryHead& m_head;
std::vector<IGraphicsDataPriv*> m_depDatas; BaseGraphicsData* m_next;
BaseGraphicsData* m_prev = nullptr;
GraphicsDataNode<IShaderPipeline, BaseGraphicsData>* m_SPs = nullptr;
GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>* m_SBinds = nullptr;
GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>* m_SBufs = nullptr;
GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>* m_DBufs = nullptr;
GraphicsDataNode<ITextureS, BaseGraphicsData>* m_STexs = nullptr;
GraphicsDataNode<ITextureSA, BaseGraphicsData>* m_SATexs = nullptr;
GraphicsDataNode<ITextureD, BaseGraphicsData>* m_DTexs = nullptr;
GraphicsDataNode<ITextureR, BaseGraphicsData>* m_RTexs = nullptr;
GraphicsDataNode<IVertexFormat, BaseGraphicsData>* m_VFmts = nullptr;
template<class T> GraphicsDataNode<T, BaseGraphicsData>*& getHead();
public: explicit BaseGraphicsData(GraphicsDataFactoryHead& head)
IShaderDataBindingPriv(IGraphicsDataPriv* p) : m_parent(p) {} : m_head(head)
class Token
{ {
IGraphicsDataPriv* m_data = nullptr; std::lock_guard<std::mutex> lk(m_head.m_dataMutex);
public: m_next = head.m_dataHead;
Token() = default; head.m_dataHead = this;
Token(const IShaderDataBindingPriv* p)
: m_data(p->m_parent) { m_data->increment(); }
Token& operator=(const Token&) = delete;
Token(const Token&) = delete;
Token& operator=(Token&& other)
{ m_data = other.m_data; other.m_data = nullptr; return *this; }
Token(Token&& other)
{ m_data = other.m_data; other.m_data = nullptr; }
~Token() { if (m_data) { m_data->decrement(); } }
};
Token lock() const { return Token(this); }
~IShaderDataBindingPriv()
{
for (IGraphicsDataPriv* dep : m_depDatas)
dep->decrement();
} }
~BaseGraphicsData()
protected:
void addDepData(IGraphicsData* data)
{ {
IGraphicsDataPriv* d = static_cast<IGraphicsDataPriv*>(data); std::lock_guard<std::mutex> lk(m_head.m_dataMutex);
if (d != m_parent) if (m_prev)
{ {
m_depDatas.push_back(d); if (m_next)
d->increment(); m_next->m_prev = m_prev;
m_prev->m_next = m_next;
}
else
{
if (m_next)
m_next->m_prev = m_head.m_dataHead;
m_head.m_dataHead = m_next;
} }
} }
class iterator
{
BaseGraphicsData* m_node;
public:
using value_type = BaseGraphicsData;
using pointer = BaseGraphicsData*;
using reference = BaseGraphicsData&;
using iterator_category = std::bidirectional_iterator_tag;
explicit iterator(BaseGraphicsData* node) : m_node(node) {}
BaseGraphicsData& 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); }
};
template <> GraphicsDataNode<IShaderPipeline, BaseGraphicsData>*&
BaseGraphicsData::getHead<IShaderPipeline>() { return m_SPs; }
template <> GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>*&
BaseGraphicsData::getHead<IShaderDataBinding>() { return m_SBinds; }
template <> GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>*&
BaseGraphicsData::getHead<IGraphicsBufferS>() { return m_SBufs; }
template <> GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>*&
BaseGraphicsData::getHead<IGraphicsBufferD>() { return m_DBufs; }
template <> GraphicsDataNode<ITextureS, BaseGraphicsData>*&
BaseGraphicsData::getHead<ITextureS>() { return m_STexs; }
template <> GraphicsDataNode<ITextureSA, BaseGraphicsData>*&
BaseGraphicsData::getHead<ITextureSA>() { return m_SATexs; }
template <> GraphicsDataNode<ITextureD, BaseGraphicsData>*&
BaseGraphicsData::getHead<ITextureD>() { return m_DTexs; }
template <> GraphicsDataNode<ITextureR, BaseGraphicsData>*&
BaseGraphicsData::getHead<ITextureR>() { return m_RTexs; }
template <> GraphicsDataNode<IVertexFormat, BaseGraphicsData>*&
BaseGraphicsData::getHead<IVertexFormat>() { return m_VFmts; }
/** Private generalized pool container class.
* Keeps head pointer to exactly one dynamic buffer while otherwise conforming to IGraphicsData
*/
struct BaseGraphicsPool : IObj
{
GraphicsDataFactoryHead& m_head;
BaseGraphicsPool* m_next;
BaseGraphicsPool* m_prev = nullptr;
GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>* m_DBufs = nullptr;
template<class T> GraphicsDataNode<T, BaseGraphicsPool>*& getHead();
explicit BaseGraphicsPool(GraphicsDataFactoryHead& head)
: m_head(head)
{
std::lock_guard<std::mutex> lk(m_head.m_dataMutex);
m_next = head.m_poolHead;
head.m_poolHead = this;
}
~BaseGraphicsPool()
{
std::lock_guard<std::mutex> lk(m_head.m_dataMutex);
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 = m_head.m_poolHead;
m_head.m_poolHead = m_next;
}
}
class iterator
{
BaseGraphicsPool* m_node;
public:
using value_type = BaseGraphicsPool;
using pointer = BaseGraphicsPool*;
using reference = BaseGraphicsPool&;
using iterator_category = std::bidirectional_iterator_tag;
explicit iterator(BaseGraphicsPool* node) : m_node(node) {}
BaseGraphicsPool& 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); }
};
template <> GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>*&
BaseGraphicsPool::getHead<IGraphicsBufferD>() { return m_DBufs; }
/** Private generalised graphics object node.
* Keeps a strong reference to the data pool that it's a member of;
* as well as doubly-linked pointers to same-type sibling objects
*/
template<class NodeCls, class DataCls>
struct GraphicsDataNode : NodeCls
{
ObjToken<DataCls> m_data;
GraphicsDataNode<NodeCls, DataCls>* m_next;
GraphicsDataNode<NodeCls, DataCls>* m_prev = nullptr;
explicit GraphicsDataNode(const ObjToken<DataCls>& data)
: m_data(data)
{
std::lock_guard<std::mutex> lk(m_data->m_head.m_dataMutex);
m_next = data->template getHead<NodeCls>();
data->template getHead<NodeCls>() = this;
}
~GraphicsDataNode()
{
std::lock_guard<std::mutex> lk(m_data->m_head.m_dataMutex);
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 = m_data->template getHead<NodeCls>();
m_data->template getHead<NodeCls>() = m_next;
}
}
class iterator
{
GraphicsDataNode<NodeCls, DataCls>* m_node;
public:
using value_type = NodeCls;
using pointer = NodeCls*;
using reference = NodeCls&;
using iterator_category = std::bidirectional_iterator_tag;
explicit iterator(GraphicsDataNode<NodeCls, DataCls>* node) : m_node(node) {}
NodeCls& operator*() const { return *m_node; }
bool operator!=(const iterator& other) const { return m_node != other.m_node; }
iterator& operator++() { m_node = m_node->m_next; return *this; }
iterator& operator--() { m_node = m_node->m_prev; return *this; }
};
iterator begin() { return iterator(this); }
iterator end() { return iterator(nullptr); }
}; };
template <class FactoryImpl, class ShaderImpl> template <class FactoryImpl, class ShaderImpl>

File diff suppressed because it is too large Load Diff

View File

@ -29,77 +29,36 @@ struct MetalShareableShader : IShareableShader<MetalDataFactoryImpl, MetalSharea
: IShareableShader(fac, srcKey, 0), m_shader(s) {} : IShareableShader(fac, srcKey, 0), m_shader(s) {}
}; };
class MetalDataFactoryImpl : public MetalDataFactory class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactoryHead
{ {
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
friend class MetalDataFactory::Context; friend class MetalDataFactory::Context;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
static ThreadLocalPtr<struct MetalData> m_deferredData;
std::unordered_set<struct MetalData*> m_committedData;
std::unordered_set<struct MetalPool*> m_committedPools;
std::mutex m_committedMutex;
std::unordered_map<uint64_t, std::unique_ptr<MetalShareableShader>> m_sharedShaders; std::unordered_map<uint64_t, std::unique_ptr<MetalShareableShader>> m_sharedShaders;
struct MetalContext* m_ctx; struct MetalContext* m_ctx;
uint32_t m_sampleCount; uint32_t m_sampleCount;
void destroyData(IGraphicsData*);
void destroyAllData();
void destroyPool(IGraphicsBufferPool*);
IGraphicsBufferD* newPoolBuffer(IGraphicsBufferPool* pool, BufferUse use,
size_t stride, size_t count);
void deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf);
public: public:
MetalDataFactoryImpl(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount); MetalDataFactoryImpl(const ObjToken<BaseGraphicsData>& parent, MetalContext* ctx, uint32_t sampleCount);
~MetalDataFactoryImpl() = default; ~MetalDataFactoryImpl() = default;
Platform platform() const {return Platform::Metal;} Platform platform() const { return Platform::Metal; }
const char* platformName() const {return "Metal";} const char* platformName() const { return "Metal"; }
void commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>&);
GraphicsDataToken commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>&); ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count);
GraphicsBufferPoolToken newBufferPool();
void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) { m_sharedShaders.erase(srcKey); } void _unregisterShareableShader(uint64_t srcKey, uint64_t binKey) { m_sharedShaders.erase(srcKey); }
}; };
ThreadLocalPtr<struct MetalData> MetalDataFactoryImpl::m_deferredData;
struct MetalData : IGraphicsDataPriv
{
std::vector<std::unique_ptr<class MetalShaderPipeline>> m_SPs;
std::vector<std::unique_ptr<struct MetalShaderDataBinding>> m_SBinds;
std::vector<std::unique_ptr<class MetalGraphicsBufferS>> m_SBufs;
std::vector<std::unique_ptr<class MetalGraphicsBufferD>> m_DBufs;
std::vector<std::unique_ptr<class MetalTextureS>> m_STexs;
std::vector<std::unique_ptr<class MetalTextureSA>> m_SATexs;
std::vector<std::unique_ptr<class MetalTextureD>> m_DTexs;
std::vector<std::unique_ptr<class MetalTextureR>> m_RTexs;
std::vector<std::unique_ptr<struct MetalVertexFormat>> m_VFmts;
};
struct MetalPoolItem : IGraphicsDataPriv
{
std::unique_ptr<class MetalGraphicsBufferD> m_buf;
};
struct MetalPool : IGraphicsBufferPool
{
std::unordered_set<MetalPoolItem*> m_items;
~MetalPool()
{
for (auto& item : m_items)
item->decrement();
}
};
#define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared #define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared
#define MTL_DYNAMIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared #define MTL_DYNAMIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared
class MetalGraphicsBufferS : public IGraphicsBufferS class MetalGraphicsBufferS : public GraphicsDataNode<IGraphicsBufferS>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
MetalGraphicsBufferS(IGraphicsData* parent, BufferUse use, MetalContext* ctx, MetalGraphicsBufferS(const ObjToken<BaseGraphicsData>& parent, BufferUse use, MetalContext* ctx,
const void* data, size_t stride, size_t count) const void* data, size_t stride, size_t count)
: boo::IGraphicsBufferS(parent), m_stride(stride), m_count(count), m_sz(stride * count) : GraphicsDataNode<IGraphicsBufferS>(parent), m_stride(stride), m_count(count), m_sz(stride * count)
{ {
m_buf = [ctx->m_dev newBufferWithBytes:data length:m_sz options:MTL_STATIC]; m_buf = [ctx->m_dev newBufferWithBytes:data length:m_sz options:MTL_STATIC];
} }
@ -111,7 +70,8 @@ public:
~MetalGraphicsBufferS() = default; ~MetalGraphicsBufferS() = default;
}; };
class MetalGraphicsBufferD : public IGraphicsBufferD template<class DataCls>
class MetalGraphicsBufferD : public GraphicsDataNode<IGraphicsBufferD, DataCls>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
friend class MetalDataFactoryImpl; friend class MetalDataFactoryImpl;
@ -119,9 +79,10 @@ class MetalGraphicsBufferD : public IGraphicsBufferD
MetalCommandQueue* m_q; MetalCommandQueue* m_q;
std::unique_ptr<uint8_t[]> m_cpuBuf; std::unique_ptr<uint8_t[]> m_cpuBuf;
int m_validSlots = 0; int m_validSlots = 0;
MetalGraphicsBufferD(IGraphicsData* parent, MetalCommandQueue* q, BufferUse use, MetalGraphicsBufferD(const ObjToken<BaseGraphicsData>& parent, MetalCommandQueue* q, BufferUse use,
MetalContext* ctx, size_t stride, size_t count) MetalContext* ctx, size_t stride, size_t count)
: boo::IGraphicsBufferD(parent), m_q(q), m_stride(stride), m_count(count), m_sz(stride * count) : GraphicsDataNode<IGraphicsBufferD, DataCls>(parent), m_q(q), m_stride(stride),
m_count(count), m_sz(stride * count)
{ {
m_cpuBuf.reset(new uint8_t[m_sz]); m_cpuBuf.reset(new uint8_t[m_sz]);
m_bufs[0] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC]; m_bufs[0] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
@ -140,12 +101,12 @@ public:
void unmap(); void unmap();
}; };
class MetalTextureS : public ITextureS class MetalTextureS : public GraphicsDataNode<ITextureS>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
MetalTextureS(IGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t mips, MetalTextureS(BaseGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t mips,
TextureFormat fmt, const void* data, size_t sz) TextureFormat fmt, const void* data, size_t sz)
: ITextureS(parent) : GraphicsDataNode<ITextureS>(parent)
{ {
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm; MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitchNum = 4; NSUInteger ppitchNum = 4;
@ -192,13 +153,13 @@ public:
~MetalTextureS() = default; ~MetalTextureS() = default;
}; };
class MetalTextureSA : public ITextureSA class MetalTextureSA : public GraphicsDataNode<ITextureSA>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
MetalTextureSA(IGraphicsData* parent, MetalContext* ctx, size_t width, MetalTextureSA(BaseGraphicsData* parent, MetalContext* ctx, size_t width,
size_t height, size_t layers, size_t mips, size_t height, size_t layers, size_t mips,
TextureFormat fmt, const void* data, size_t sz) TextureFormat fmt, const void* data, size_t sz)
: ITextureSA(parent) : GraphicsDataNode<ITextureSA>(parent)
{ {
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm; MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitch = 4; NSUInteger ppitch = 4;
@ -247,7 +208,7 @@ public:
~MetalTextureSA() = default; ~MetalTextureSA() = default;
}; };
class MetalTextureD : public ITextureD class MetalTextureD : public GraphicsDataNode<ITextureD>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
@ -258,9 +219,9 @@ class MetalTextureD : public ITextureD
size_t m_cpuSz; size_t m_cpuSz;
size_t m_pxPitch; size_t m_pxPitch;
int m_validSlots = 0; int m_validSlots = 0;
MetalTextureD(IGraphicsData* parent, MetalCommandQueue* q, MetalContext* ctx, MetalTextureD(BaseGraphicsData* parent, MetalCommandQueue* q, MetalContext* ctx,
size_t width, size_t height, TextureFormat fmt) size_t width, size_t height, TextureFormat fmt)
: boo::ITextureD(parent), m_q(q), m_width(width), m_height(height) : GraphicsDataNode<ITextureD>(parent), m_q(q), m_width(width), m_height(height)
{ {
MTLPixelFormat format; MTLPixelFormat format;
switch (fmt) switch (fmt)
@ -303,7 +264,7 @@ public:
#define MAX_BIND_TEXS 4 #define MAX_BIND_TEXS 4
class MetalTextureR : public ITextureR class MetalTextureR : public GraphicsDataNode<ITextureR>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
@ -422,9 +383,9 @@ class MetalTextureR : public ITextureR
} }
} }
MetalTextureR(IGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t samples, MetalTextureR(BaseGraphicsData* parent, MetalContext* ctx, size_t width, size_t height, size_t samples,
size_t colorBindCount, size_t depthBindCount) size_t colorBindCount, size_t depthBindCount)
: boo::ITextureR(parent), m_width(width), m_height(height), m_samples(samples), : GraphicsDataNode<ITextureR>(parent), m_width(width), m_height(height), m_samples(samples),
m_colorBindCount(colorBindCount), m_colorBindCount(colorBindCount),
m_depthBindCount(depthBindCount) m_depthBindCount(depthBindCount)
{ {
@ -485,14 +446,14 @@ static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] =
MTLVertexFormatFloat4 MTLVertexFormatFloat4
}; };
struct MetalVertexFormat : IVertexFormat struct MetalVertexFormat : GraphicsDataNode<IVertexFormat>
{ {
size_t m_elementCount; size_t m_elementCount;
MTLVertexDescriptor* m_vdesc; MTLVertexDescriptor* m_vdesc;
size_t m_stride = 0; size_t m_stride = 0;
size_t m_instStride = 0; size_t m_instStride = 0;
MetalVertexFormat(IGraphicsData* parent, size_t elementCount, const VertexElementDescriptor* elements) MetalVertexFormat(BaseGraphicsData* parent, size_t elementCount, const VertexElementDescriptor* elements)
: boo::IVertexFormat(parent), m_elementCount(elementCount) : GraphicsDataNode<ITextureFormat>(parent), m_elementCount(elementCount)
{ {
for (size_t i=0 ; i<elementCount ; ++i) for (size_t i=0 ; i<elementCount ; ++i)
{ {
@ -568,7 +529,7 @@ static const MTLPrimitiveType PRIMITIVE_TABLE[] =
#define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue) #define COLOR_WRITE_MASK (MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue)
class MetalShaderPipeline : public IShaderPipeline class MetalShaderPipeline : public GraphicsDataNode<IShaderPipeline>
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
@ -579,7 +540,7 @@ class MetalShaderPipeline : public IShaderPipeline
MetalShareableShader::Token m_vert; MetalShareableShader::Token m_vert;
MetalShareableShader::Token m_frag; MetalShareableShader::Token m_frag;
MetalShaderPipeline(IGraphicsData* parent, MetalShaderPipeline(BaseGraphicsData* parent,
MetalContext* ctx, MetalContext* ctx,
MetalShareableShader::Token&& vert, MetalShareableShader::Token&& vert,
MetalShareableShader::Token&& frag, MetalShareableShader::Token&& frag,
@ -587,7 +548,7 @@ class MetalShaderPipeline : public IShaderPipeline
BlendFactor srcFac, BlendFactor dstFac, Primitive prim, BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
ZTest depthTest, bool depthWrite, bool colorWrite, ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling) bool alphaWrite, CullMode culling)
: boo::IShaderPipeline(parent), : GraphicsDataNode<IShaderPipeline>(parent),
m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vtxFmt(vtxFmt), m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vtxFmt(vtxFmt),
m_vert(std::move(vert)), m_frag(std::move(frag)) m_vert(std::move(vert)), m_frag(std::move(frag))
{ {
@ -734,7 +695,7 @@ static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx, int bi
return nullptr; return nullptr;
} }
struct MetalShaderDataBinding : IShaderDataBindingPriv struct MetalShaderDataBinding : GraphicsDataNode<IShaderDataBinding>
{ {
MetalShaderPipeline* m_pipeline; MetalShaderPipeline* m_pipeline;
IGraphicsBuffer* m_vbuf; IGraphicsBuffer* m_vbuf;
@ -764,7 +725,7 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv
size_t texCount, ITexture** texs, size_t texCount, ITexture** texs,
const int* texBindIdxs, const bool* depthBind, const int* texBindIdxs, const bool* depthBind,
size_t baseVert, size_t baseInst) size_t baseVert, size_t baseInst)
: IShaderDataBindingPriv(d), : GraphicsDataNode<IShaderDataBinding>(d),
m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)), m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)),
m_vbuf(vbuf), m_vbuf(vbuf),
m_instVbo(instVbo), m_instVbo(instVbo),
@ -854,8 +815,8 @@ struct MetalShaderDataBinding : IShaderDataBindingPriv
struct MetalCommandQueue : IGraphicsCommandQueue struct MetalCommandQueue : IGraphicsCommandQueue
{ {
Platform platform() const {return IGraphicsDataFactory::Platform::Metal;} Platform platform() const { return IGraphicsDataFactory::Platform::Metal; }
const char* platformName() const {return "Metal";} const char* platformName() const { return "Metal"; }
MetalContext* m_ctx; MetalContext* m_ctx;
IWindow* m_parentWindow; IWindow* m_parentWindow;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
@ -863,8 +824,8 @@ struct MetalCommandQueue : IGraphicsCommandQueue
id<MTLRenderCommandEncoder> m_enc; id<MTLRenderCommandEncoder> m_enc;
bool m_running = true; bool m_running = true;
size_t m_fillBuf = 0; int m_fillBuf = 0;
size_t m_drawBuf = 0; int m_drawBuf = 0;
MetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent) MetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent)
: m_ctx(ctx), m_parentWindow(parentWindow), m_parent(parent) : m_ctx(ctx), m_parentWindow(parentWindow), m_parent(parent)
@ -889,7 +850,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
MetalShaderDataBinding* m_boundData = nullptr; MetalShaderDataBinding* m_boundData = nullptr;
MTLPrimitiveType m_currentPrimitive = MTLPrimitiveTypeTriangle; MTLPrimitiveType m_currentPrimitive = MTLPrimitiveTypeTriangle;
void setShaderDataBinding(IShaderDataBinding* binding) void setShaderDataBinding(const ObjToken<IShaderDataBinding>& binding)
{ {
@autoreleasepool @autoreleasepool
{ {
@ -901,11 +862,11 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
MetalTextureR* m_boundTarget = nullptr; MetalTextureR* m_boundTarget = nullptr;
void _setRenderTarget(ITextureR* target, bool clearColor, bool clearDepth) void _setRenderTarget(const ObjToken<ITextureR>& target, bool clearColor, bool clearDepth)
{ {
MetalTextureR* ctarget = static_cast<MetalTextureR*>(target);
@autoreleasepool @autoreleasepool
{ {
MetalTextureR* ctarget = target.cast<MetalTextureR>();
[m_enc endEncoding]; [m_enc endEncoding];
if (clearColor && clearDepth) if (clearColor && clearDepth)
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearBothPassDesc]; m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearBothPassDesc];
@ -916,19 +877,19 @@ struct MetalCommandQueue : IGraphicsCommandQueue
else else
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_passDesc]; m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_passDesc];
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise]; [m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
if (ctarget == m_boundTarget)
{
if (m_boundVp.width || m_boundVp.height)
[m_enc setViewport:m_boundVp];
if (m_boundScissor.width || m_boundScissor.height)
[m_enc setScissorRect:m_boundScissor];
}
else
m_boundTarget = ctarget;
} }
if (ctarget == m_boundTarget)
{
if (m_boundVp.width || m_boundVp.height)
[m_enc setViewport:m_boundVp];
if (m_boundScissor.width || m_boundScissor.height)
[m_enc setScissorRect:m_boundScissor];
}
else
m_boundTarget = ctarget;
} }
void setRenderTarget(ITextureR* target) void setRenderTarget(const ObjToken<ITextureR>& target)
{ {
_setRenderTarget(target, false, false); _setRenderTarget(target, false, false);
} }
@ -955,9 +916,9 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
std::unordered_map<MetalTextureR*, std::pair<size_t, size_t>> m_texResizes; std::unordered_map<MetalTextureR*, std::pair<size_t, size_t>> m_texResizes;
void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) void resizeRenderTexture(const ObjToken<ITextureR>& tex, size_t width, size_t height)
{ {
MetalTextureR* ctex = static_cast<MetalTextureR*>(tex); MetalTextureR* ctex = tex.cast<MetalTextureR>();
m_texResizes[ctex] = std::make_pair(width, height); m_texResizes[ctex] = std::make_pair(width, height);
} }
@ -968,7 +929,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
void flushBufferUpdates() {} void flushBufferUpdates() {}
float m_clearColor[4] = {0.0,0.0,0.0,0.0}; float m_clearColor[4] = {0.f,0.f,0.f,0.f};
void setClearColor(const float rgba[4]) void setClearColor(const float rgba[4])
{ {
m_clearColor[0] = rgba[0]; m_clearColor[0] = rgba[0];
@ -1078,18 +1039,27 @@ struct MetalCommandQueue : IGraphicsCommandQueue
/* Update dynamic data here */ /* Update dynamic data here */
MetalDataFactoryImpl* gfxF = static_cast<MetalDataFactoryImpl*>(m_parent->getDataFactory()); MetalDataFactoryImpl* gfxF = static_cast<MetalDataFactoryImpl*>(m_parent->getDataFactory());
std::unique_lock<std::mutex> datalk(gfxF->m_committedMutex); std::unique_lock<std::mutex> datalk(gfxF->m_dataMutex);
for (MetalData* d : gfxF->m_committedData) if (gfxF->m_dataHead)
{ {
for (std::unique_ptr<MetalGraphicsBufferD>& b : d->m_DBufs) for (BaseGraphicsData& d : *gfxF->m_dataHead)
b->update(m_fillBuf); {
for (std::unique_ptr<MetalTextureD>& t : d->m_DTexs) if (d.m_DBufs)
t->update(m_fillBuf); for (IGraphicsBufferD& b : *d.m_DBufs)
static_cast<MetalGraphicsBufferD<BaseGraphicsData>&>(b).update(m_fillBuf);
if (d.m_DTexs)
for (ITextureD& t : *d.m_DTexs)
static_cast<MetalTextureD&>(t).update(m_fillBuf);
}
} }
for (MetalPool* p : gfxF->m_committedPools) if (gfxF->m_poolHead)
{ {
for (auto& b : p->m_items) for (BaseGraphicsPool& p : *gfxF->m_poolHead)
b->m_buf->update(m_fillBuf); {
if (p.m_DBufs)
for (IGraphicsBufferD& b : *p.m_DBufs)
static_cast<MetalGraphicsBufferD<BaseGraphicsData>&>(b).update(m_fillBuf);
}
} }
datalk.unlock(); datalk.unlock();
@ -1389,13 +1359,15 @@ IShaderPipeline* MetalDataFactory::Context::newShaderPipeline(const char* vertSo
} }
} }
IShaderDataBinding* ObjToken<IShaderDataBinding>
MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline, MetalDataFactory::Context::newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
IVertexFormat* vtxFormat, const ObjToken<IVertexFormat>& vtxFormat,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, const ObjToken<IGraphicsBuffer>& vbo,
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages,
const size_t* ubufOffs, const size_t* ubufSizes, const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs, size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdxs, const bool* depthBind, const int* texBindIdxs, const bool* depthBind,
size_t baseVert, size_t baseInst) size_t baseVert, size_t baseInst)
{ {
@ -1413,7 +1385,7 @@ MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
} }
} }
GraphicsDataToken MetalDataFactoryImpl::commitTransaction(const FactoryCommitFunc& trans) void MetalDataFactoryImpl::commitTransaction(const FactoryCommitFunc& trans)
{ {
if (m_deferredData.get()) if (m_deferredData.get())
Log.report(logvisor::Fatal, "nested commitTransaction usage detected"); Log.report(logvisor::Fatal, "nested commitTransaction usage detected");
@ -1434,62 +1406,11 @@ GraphicsDataToken MetalDataFactoryImpl::commitTransaction(const FactoryCommitFun
return GraphicsDataToken(this, retval); return GraphicsDataToken(this, retval);
} }
GraphicsBufferPoolToken MetalDataFactoryImpl::newBufferPool() ObjToken<IGraphicsBufferD> MetalDataFactoryImpl::newPoolBuffer(BufferUse use, size_t stride, size_t count)
{ {
std::unique_lock<std::mutex> lk(m_committedMutex); ObjToken<IGraphicsBufferD> pool(new BaseGraphicsPool(*this));
MetalPool* retval = new MetalPool;
m_committedPools.insert(retval);
return GraphicsBufferPoolToken(this, retval);
}
void MetalDataFactoryImpl::destroyData(IGraphicsData* d)
{
std::unique_lock<std::mutex> lk(m_committedMutex);
MetalData* data = static_cast<MetalData*>(d);
m_committedData.erase(data);
data->decrement();
}
void MetalDataFactoryImpl::destroyAllData()
{
std::unique_lock<std::mutex> lk(m_committedMutex);
for (MetalData* data : m_committedData)
data->decrement();
for (MetalPool* pool : m_committedPools)
delete pool;
m_committedData.clear();
m_committedPools.clear();
}
void MetalDataFactoryImpl::destroyPool(IGraphicsBufferPool* p)
{
std::unique_lock<std::mutex> lk(m_committedMutex);
MetalPool* pool = static_cast<MetalPool*>(p);
m_committedPools.erase(pool);
delete pool;
}
IGraphicsBufferD* MetalDataFactoryImpl::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use,
size_t stride, size_t count)
{
MetalPool* pool = static_cast<MetalPool*>(p);
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent->getCommandQueue()); MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent->getCommandQueue());
MetalPoolItem* item = new MetalPoolItem; return {MetalGraphicsBufferD(pool, q, use, m_ctx, stride, count)};
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(item, q, use, m_ctx, stride, count);
item->m_buf.reset(retval);
pool->m_items.emplace(item);
return retval;
}
void MetalDataFactoryImpl::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBufferD* buf)
{
MetalPool* pool = static_cast<MetalPool*>(p);
auto search = pool->m_items.find(static_cast<MetalPoolItem*>(buf->m_parentData));
if (search != pool->m_items.end())
{
(*search)->decrement();
pool->m_items.erase(search);
}
} }
IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,

@ -1 +1 @@
Subproject commit bfe0c1ccad9ee545a6ab9c0b295258c47b55da3c Subproject commit f8ab0e03bae0cad2541f551350dcafb91477b007